NEWDolby Interactivity APIs are now the Dolby.io Communications APIs Learn More >
X

Create a Basic Audio Conference Application for Android

Step 1: Create your project

Open Android Studio and create a new Java project. Select the “Empty activity” template. In this example, only default options are included.

1. Add the following line to the Gradle script build.gradle for the Project (not the Module) at the root of the repository:

allprojects {
    repositories {
        ...
        maven { url "https://android-sdk.voxeet.com/release" }
    }
}

2. Add the following command into the dependencies section of the Gradle script build.gradle for “Module: app”, not the project. Replace VERSION with the latest Java SDK version.

dependencies {
    ...

    implementation ("com.voxeet.sdk:sdk:VERSION") {
        transitive = true
    }
}

3. Use butterknife to facilitate the integration of the SDK and manage injection.

dependencies {
    ...

    implementation 'com.jakewharton:butterknife:7.0.1'
    annotationProcessor 'com.jakewharton:butterknife:7.0.1'
}

4. Make sure to not use Android SDK version older than 21. The SDK is only compatible with android 21+. This change is for the android section of the same Gradle script.

android {
    ...
    defaultConfig {
        ...
        minSdkVersion 21
        ...
    }
    ...
}

5. Make sure that a compilation toolchain uses the Java 8.

android {
    ...

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

6. Android Studio displays a banner above the text editor that informs that the Gradle files have changed. Click the “Sync Now” link.

7. To update the layout, edit the activity_main.xml file from the app/src/main/res/layout/ folder. In Android Studio, this file is found in app/res/layout. Modify its content as in the following example:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <!-- Step 1. Put the layout changes for the open/close session step here -->

        <!-- Step 2. Put the layout changes for the join conference step here -->

        <!-- Step 3. Put the layout changes for the video step here -->

        <!-- Step 4. Put the layout changes for the view participants step here -->

        <!-- Step 5. Put the layout changes for the screen sharing step here -->

        <!-- Step 6. Put the layout changes for the recording step here -->

    </LinearLayout>
</ScrollView>

8. Edit the MainActivity.java file and add the following imports:

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import com.voxeet.VoxeetSDK;
import com.voxeet.android.media.MediaStream;
import com.voxeet.android.media.stream.MediaStreamType;
import com.voxeet.promise.solve.ErrorPromise;
import com.voxeet.promise.solve.ThenPromise;
import com.voxeet.sdk.events.v2.ParticipantAddedEvent;
import com.voxeet.sdk.events.v2.ParticipantUpdatedEvent;
import com.voxeet.sdk.events.v2.StreamAddedEvent;
import com.voxeet.sdk.events.v2.StreamRemovedEvent;
import com.voxeet.sdk.events.v2.StreamUpdatedEvent;
import com.voxeet.sdk.events.promises.ServerErrorException;
import com.voxeet.sdk.json.RecordingStatusUpdatedEvent;
import com.voxeet.sdk.json.ParticipantInfo;
import com.voxeet.sdk.json.internal.ParamsHolder;
import com.voxeet.sdk.models.Conference;
import com.voxeet.sdk.models.Participant;
import com.voxeet.sdk.services.builders.ConferenceCreateOptions;
import com.voxeet.sdk.services.builders.ConferenceJoinOptions;
import com.voxeet.sdk.services.conference.information.ConferenceInformation;
import com.voxeet.sdk.services.screenshare.RequestScreenSharePermissionEvent;
import com.voxeet.sdk.views.VideoView;

import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;

9. To prepare events and logic integration, create a list of views responsible for keeping the views enabled in the following modes:

  • when there are no connected sessions
  • when a session is connected
  • when a conference is connected
  • when there are no connected conferences
  • when your video is not started
  • when your video is started
  • when you are sharing your screen
  • when you are not sharing your screen

Edit the MainActivity class in MainActivity.java and add the following values:

public class MainActivity extends AppCompatActivity {

    protected List<View> views = new ArrayList<>();
    protected List<View> buttonsNotLoggedIn = new ArrayList<>();
    protected List<View> buttonsInConference = new ArrayList<>();
    protected List<View> buttonsNotInConference = new ArrayList<>();
    protected List<View> buttonsInOwnVideo = new ArrayList<>();
    protected List<View> buttonsNotInOwnVideo = new ArrayList<>();
    protected List<View> buttonsInOwnScreenShare = new ArrayList<>();
    protected List<View> buttonsNotInOwnScreenShare = new ArrayList<>();

    ...
    }

10. To simplify creating conferences, add the following code to the MainActivity class. The onCreate method created with the project is replaced.

  • The Butterknife library that is responsible for the injected views.
  • Overridden onResume method to update views.
  • A method for views updates and management.
  • The default error management method.
  • Two methods for managing contextual lists of views.
public class MainActivity extends AppCompatActivity {
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        //all the logic of the onCreate will be put after this comment
    }

    @Override
    protected void onResume() {
        super.onResume();

        //here will be put the permission check

        //we update the various views to enable or disable the ones we want to
        updateViews();
    }

    private void updateViews() {
        //this method will be updated step by step
    }


    private ErrorPromise error() {
        return error -> {
            Toast.makeText(MainActivity.this, "ERROR...", Toast.LENGTH_SHORT).show();
            error.printStackTrace();
            updateViews();
        };
    }

    private void setEnabled(List<View> views, boolean enabled) {
        for (View view : views) view.setEnabled(enabled);
    }

    private MainActivity add(List<View> list, int id) {
        list.add(findViewById(id));
        return this;
    }

}

Step 2: Initialize the SDK with your Dolby.io credentials

There are two methods to initialize the SDK. You can initialize using a token, which requires a server to return the token to the application. Alternately, you can initialize with the secrets, which is not secure. In this example, we are initializing with the secrets. However, we recommend using a token to initialize the SDK. For more information, see Initializing.

Locate your Consumer Key and Consumer Secret. The instructions on how to create or find them is in the Prerequiste section of Initializing. It is recommended that you create a new Sample application for this tutorial.

1. Add the following code to the onCreate method from the MainActivity.java file. Replace the consumerKey and consumerSecret strings with the values you just created.


@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    //we now initialize the sdk
    VoxeetSDK.initialize("consumerKey", "consumerSecret");
}

2. Add the following lines at the end of onResume:

@Override
protected void onResume() {
    super.onResume();

    ...

    //register the current activity in the SDK
    VoxeetSDK.instance().register(this);
}

3. Unregister from the SDK when the MainActivity is in the background by adding onPause.

@Override
protected void onPause() {
    //register the current activity in the SDK
    VoxeetSDK.instance().unregister(this);

    super.onPause();
}

Step 3: Open and close a session

To allow creating and joining conferences, log in with a user name. In this tutorial, random user names are assigned.

1. To modify the layout, edit the main_activity.xml file, adding the following content for Step 1:

<LinearLayout ...>

    <!-- Step 1. Put the layout changes for the open/close session step here -->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="user session" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/user_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="horizontal">

            <Button
                android:id="@+id/login"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="log in" />

            <Button
                android:id="@+id/logout"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="logout" />
        </LinearLayout>
    </LinearLayout>

    <!-- Step 2. ...

</LinearLayout>

2. Modify the interface linking in the MainActivity class in MainActivity.java:

  • New field for MainActivity:
@Bind(R.id.user_name)
EditText user_name;
  • New methods for MainActivity:
@OnClick(R.id.login)
public void onLogin() {

}

@OnClick(R.id.logout)
public void onLogout() {

}
  • Add the following code to the onCreate method:
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    //adding the user_name, login and logout views related to the open/close and conference flow
    add(views, R.id.login);
    add(views, R.id.logout);

    add(buttonsNotLoggedIn, R.id.login);
    add(buttonsNotLoggedIn, R.id.user_name);

    add(buttonsInConference, R.id.logout);

    add(buttonsNotInConference, R.id.logout);

    // Set a random user name
    String[] avengersNames = {
        "Thor",
        "Cap",
        "Tony Stark",
        "Black Panther",
        "Black Widow",
        "Hulk",
        "Spider-Man",
    };
    Random r = new Random();
    user_name.setText(avengersNames[r.nextInt(avengersNames.length)]);
}

3. Add the following logic to the application:

  • Use the following implementation for onLogin:
public void onLogin() {
    VoxeetSDK.session().open(new ParticipantInfo(user_name.getText().toString(), "", ""))
            .then((result, solver) -> {
                Toast.makeText(MainActivity.this, "log in successful", Toast.LENGTH_SHORT).show();
                updateViews();
            })
            .error(error());
}
  • Use the following implementation for onLogout:
public void onLogout() {
    VoxeetSDK.session().close()
            .then((result, solver) -> {
                Toast.makeText(MainActivity.this, "logout done", Toast.LENGTH_SHORT).show();
                updateViews();
            }).error(error());
}
  • Use the following implementation for updateViews:
private void updateViews() {
    //disable every view
    setEnabled(views, false);

    //if the user is not connected, we will only enabled the not logged in buttons
    if (!VoxeetSDK.session().isSocketOpen()) {
        setEnabled(buttonsNotLoggedIn, true);
        return;
    }
}

Step 4: Add a joining option

1. To modify the layout, edit the main_activity.xml file with the following content for Step 2:

<LinearLayout ...>
    ...

    <!-- Step 2. Put the layout changes for the join conference step here -->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="conference name :" />

    <EditText
        android:id="@+id/conference_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/join"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="start" />

        <!-- Step 2.2. The layout will be upgraded in the leave conference step -->
    </LinearLayout>

    <!-- Step 3. ...
</LinearLayout>

2. Modify the interface linking in the MainActivity class in MainActivity.java:

  • New field for MainActivity:
@Bind(R.id.conference_name)
EditText conference_name;
  • New method for MainActivity:
@OnClick(R.id.join)
public void onJoin() {

}
  • Add the following code to the onCreate method:
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    // Add the join button and enable it only when not in a conference
    add(views, R.id.join);
    add(buttonsNotInConference, R.id.join);

    // Set a default conference name
    conference_name.setText("Avengers meeting");
}

3. Add the following logic to the application:

  • Configure permission management in MainActivity onResume. Simplify the permission flow to ask for microphone and camera permissions when the application resumes.
@Override
protected void onResume() {
    ...

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED
            ||
            ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA}, 0x20);
    }
}
  • Bind the join flow implementation in the onJoin method created previously. The method creates and joins the conference.
@OnClick(R.id.join)
public void onJoin() {
    ParamsHolder paramsHolder = new ParamsHolder();
    paramsHolder.setDolbyVoice(true);

    ConferenceCreateOptions conferenceCreateOptions = new ConferenceCreateOptions.Builder()
            .setConferenceAlias(conference_name.getText().toString())
            .setParamsHolder(paramsHolder)
            .build();

    VoxeetSDK.conference().create(conferenceCreateOptions)
            .then((ThenPromise<Conference, Conference>) conference -> {
                ConferenceJoinOptions conferenceJoinOptions = new ConferenceJoinOptions.Builder(conference)
                        .build();

                return VoxeetSDK.conference().join(conferenceJoinOptions);
            })
            .then(conference -> {
                Toast.makeText(MainActivity.this, "started...", Toast.LENGTH_SHORT).show();
                updateViews();
            })
            .error((error_in) -> {
                Toast.makeText(MainActivity.this, "Could not create conference", Toast.LENGTH_SHORT).show();
            });
}
  • In updateViews, enable and disable buttons based on the conference state.
private void updateViews() {
    ...

    ConferenceInformation current = VoxeetSDK.conference().getCurrentConference();
    //we can now add the logic to manage our basic state
    if (null != current && VoxeetSDK.conference().isLive()) {
        setEnabled(buttonsInConference, true);
    } else {
        setEnabled(buttonsNotInConference, true);
    }
}

Step 5: Add a leaving option

1. To modify the layout, edit the main_activity.xml file, adding the following content for Step 2.2:

<LinearLayout ...>
    ...
    <LinearLayout ...>

        <!-- Step 2.2. The layout will be upgraded in the leave conference step -->
        <Button
            android:id="@+id/leave"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="leave" />

    </LinearLayout>

    <!-- Step 3. ...

</LinearLayout>

2. Modify the interface linking in the MainActivity class in MainActivity.java:

  • New method for MainActivity:
@OnClick(R.id.leave)
public void onLeave() {

}
  • Add the following code to the onCreate method:
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    // Add the leave button and enable it only while in a conference
    add(views, R.id.leave);
    add(buttonsInConference, R.id.leave);
}

3. Add the following logic to the application:

  • Use the following implementation for onLeave:
public void onLeave() {
    VoxeetSDK.conference().leave()
            .then((result, solver) -> {
                updateViews();
                Toast.makeText(MainActivity.this, "left...", Toast.LENGTH_SHORT).show();
            }).error(error());
}

Step 6: Run your application

On Android Studio, click on run. Make sure that you have:

  • a configured Android Virtual Device (AVD) available on your machine
  • a connected Android Debug Bridge (ADB) ready to use with an Android device

Did this page help you?