Use this guide to quickly start a basic voice call with the Agora Voice SDK for Android.
In this section, we will create an Android project, integrate the Agora Voice SDK into the project, and add the Android device permissions to prepare the development environment.
Skip to Integrate the SDK if a project already exists.
Open Android Studio and click Start a new Android Studio project.
On the Select a Project Template panel, choose Phone and Tablet > Empty Activity, and click Next.
On the Configure Your Project panel, fill in the following contents:
Click Finish. Follow the on-screen instructions, if any, to install the plug-ins.
Choose either of the following methods to integrate the Agora Voice SDK into your project.
Method 1: Automatically integrate the SDK with JCenter
Add the following line in the /app/build.gradle file of your project:
...
dependencies {
...
// For x.y.z, please fill in a specific SDK version number, such as 3.0.0.
// Get the latest version number through the release notes.
implementation 'io.agora.rtc:voice-sdk:x.y.z'
}
Method 2: Manually copy the SDK files
File or subfolder | Path of your project |
---|---|
agora-rtc-sdk.jar file | /app/libs/ |
arm64-v8a folder | /app/src/main/jniLibs/ |
armeabi-v7a folder | /app/src/main/jniLibs/ |
include folder | /app/src/main/jniLibs/ |
x86 folder | /app/src/main/jniLibs/ |
x86_64 folder | /app/src/main/jniLibs/ |
libagora-crypto.so
file in the SDK package.Add the following permissions in the /app/src/main/AndroidManifest.xml file for device access according to your needs:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.agora.tutorials1v1acall">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
// Add the following permission if your scenario involves reading the external storage:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
// For devices running Android 10.0 or later, you also need to add the following permission:
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
...
</manifest>
If your targetSdkVersion
≥ 29, add the following line in the <application>
module in the AndroidManifest.xml file:
<application
android:requestLegacyExternalStorage="true">
</application>
Add the following line in the app/proguard-rules.pro file to prevent obfuscating the code of the Agora SDK:
-keep class io.agora.**{*;}
This section introduces how to use the Agora Voice SDK to make a call. The following figure shows the API call sequence of a basic one-to-one voice call.
Create the user interface (UI) for the one-to-one voice call in the layout file of your project. Skip to Import Classes if you already have a UI in your project.
You can also refer to the activity_voice_chat_view.xml file in the Agora-Android-Voice-Tutorial-1to1 demo project.
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_voice_chat_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="io.agora.tutorials1v1acall.VoiceChatViewActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="@dimen/activity_vertical_margin"
android:orientation="vertical">
<TextView
android:id="@+id/quick_tips_when_use_agora_sdk"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="40dp"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:gravity="center_vertical|start"
android:text="1. Default channel name is voiceDemoChannel1\n2. Waiting for remote users\n3. This demo only supports 1v1 voice calling" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="20"
android:onClick="onLocalAudioMuteClicked"
android:scaleType="centerInside"
android:src="@drawable/btn_mute" />
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="20"
android:onClick="onSwitchSpeakerphoneClicked"
android:scaleType="centerInside"
android:src="@drawable/btn_speaker" />
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="20"
android:onClick="onEncCallClicked"
android:scaleType="centerInside"
android:src="@drawable/btn_end_call" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Import the following classes in the activity file of your project:
import io.agora.rtc.IRtcEngineEventHandler;
import io.agora.rtc.RtcEngine;
Call the checkSelfPermission
method to access the microphone of the Android device when launching the activity.
// Java
private static final int PERMISSION_REQ_ID_RECORD_AUDIO = 22;
// Check the microphone access when running the app.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_voice_chat_view);
// Initialize RtcEngine and join a channel after getting the permission.
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO, PERMISSION_REQ_ID_RECORD_AUDIO)) {
initAgoraEngineAndJoinChannel();
}
}
private void initAgoraEngineAndJoinChannel() {
initializeAgoraEngine();
joinChannel();
}
public boolean checkSelfPermission(String permission, int requestCode) {
Log.i(LOG_TAG, "checkSelfPermission " + permission + " " + requestCode);
if (ContextCompat.checkSelfPermission(this,
permission)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{permission},
requestCode);
return false;
}
return true;
}
// Kotlin
// Check the microphone access when running the app.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_voice_chat_view)
// Initialize RtcEngine and join a channel after getting the permission.
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO, PERMISSION_REQ_ID_RECORD_AUDIO) ) {
initAgoraEngineAndJoinChannel()
}
}
private fun initAgoraEngineAndJoinChannel() {
initializeAgoraEngine()
joinChannel()
}
private fun checkSelfPermission(permission. String, requestCode: Int): Boolean {
Log.i(LOG_TAG, "checkSelfPermission $permission $reuqestCode")
if (ContextCompat.checkSelfPermission(this,
permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermission(this
arrayOf(permission),
requestCode)
return false
}
return true
}
Create and initialize the RtcEngine object before calling any other Agora APIs.
In the string.xml
file, replace agora_app_id
with your App ID. Call the create
method and pass in the App ID to initialize the RtcEngine object.
You can also listen for callback events, such as when the local user joins the channel, and when the first video frame of a remote user is decoded. Do not implement UI operations in these callbacks.
// Java
private RtcEngine mRtcEngine;
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
// Listen for the onUserOffline callback.
// This callback occurs when the remote user leaves the channel or drops offline.
@Override
public void onUserOffline(final int uid, final int reason) {
runOnUiThread(new Runnable() {
@Override
public void run() {
onRemoteUserLeft(uid, reason);
}
});
}
// Listen for the onUserMuterAudio callback.
// This callback occurs when a remote user stops sending the audio stream.
@Override
public void onUserMuteAudio(final int uid, final boolean muted) {
runOnUiThread(new Runnable() {
@Override
public void run() {
onRemoteUserVoiceMuted(uid, muted);
}
});
}
};
// Call the create method to initialize RtcEngine.
private void initializeAgoraEngine() {
try {
mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);
mRtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_COMMUNICATION);
} catch (Exception e) {
Log.e(LOG_TAG, Log.getStackTraceString(e));
throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e));
}
}
// Kotlin
private var mRtcEngine: RtcEngine? = null
private val mRtcEventHandler = object : IRtcEngineEventHandler() {
// Listen for the onUserOffline callback.
// This callback occurs when the remote user leaves the channel or drops offline.
override fun onUserOffline(uid: Int, reason: Int) {
runOnUiThread { onRemoteUserLeft() }
}
// Listen for the onUserMuterAudio callback.
// This callback occurs when a remote user stops sending the audio stream.
override fun onUserMuteAudio(uid: Int, muted: Boolean) {
runOnUiThread { onRemoteUserVoiceMuted(uid, muted)}
}
}
...
// Call the create method to initialize RtcEngine.
private fun initializeAgoraEngine() {
try {
mRtcEngine = RtcEngine.create(baseContext, getString(R.string.agora_app_id), mRtcEventHandler)
} catch (e: Exception) {
Log.e(LOG_TAG, Log.getStackTraceString(e))
throw RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e))
}
}
After initializing the RtcEngine object and setting the local video view (for a video call), you can call the joinChannel
method to join a channel. In this method, set the following parameters:
token
: Pass a token that identifies the role and privilege of the user. You can set it as one of the following values:
uid
is the same with those you use to generate the token.token
as "".channelName: Specify the channel name that you want to join. Users that input the same channel name join the same channel.
uid: ID of the local user that is an integer and should be unique. If you set uid as 0, the SDK assigns a user ID for the local user and returns it in the onJoinChannelSuccess
callback.
mute
methods accordingly.For more details on the parameter settings, see joinChannel
.
// Java
private void joinChannel() {
String accessToken = getString(R.string.agora_access_token);
if (TextUtils.equals(accessToken, "") || TextUtils.equals(accessToken, "#YOUR ACCESS TOKEN#")) {
accessToken = null; // default, no token
}
// Call the joinChannel method to join a channel.
// The uid is not specified. The SDK will assign one automatically.
mRtcEngine.joinChannel(accessToken, "voiceDemoChannel1", "Extra Optional Data", 0);
}
// Kotlin
private fun joinChannel() {
// Call the joinChannel method to join a channel.
// The uid is not specified. The SDK will assign one automatically.
mRtcEngine!!.joinChannel(token, "demoChannel1", "Extra Optional Data", 0)
}
Call the leaveChannel
method to leave the current call according to your scenario, for example, when the call ends, when you need to close the app, or when your app runs in the background.
// Java
private void leaveChannel() {
mRtcEngine.leaveChannel();
}
// Kotlin
private fun leaveChannel() {
mRtcEngine!!.leaveChannel()
}
You can find the complete code logic in the VoiceChatViewActivity.java file in the Agora-Android-Voice-Tutorial-1to1 demo project.
Run the project on your Android device. You can hear the remote user when you successfully start a one-to-one voice call in the app.
We provide an open-source Group-Voice-Call demo project that implements the group video call on GitHub. For scenarios involving group voice calls, you can download the demo project as a code source reference.
When integrating the Agora Voice SDK, you can also refer to the following articles: