Skip to main content
Android
iOS
macOS
Web
Windows
Electron
Flutter
React Native
Python
React JS
Unity
Unreal Engine
Unreal (Blueprint)

SDK quickstart

This page provides a step-by-step guide on seamlessly integrating the Voice SDK and effortlessly building a basic, real-time interactive app from scratch using minimal code.

Understand the tech

This section explains how you can integrate Voice Calling features into your app. Following are some basic concepts about real-time audio interaction:

  • Voice SDK: An SDK developed by Agora to enable developers to add real-time audio interaction to their projects.
  • Channel: A channel is used to transmit data. Users in the same channel can interact in real time.
  • Host: A host can publish audio in a channel. The host can also subscribe to audio published by other hosts.
  • Audience: A user assigned the audience role may subscribe to audio within the channel. However, they are not authorized to publish content.

For more information, see Core Concepts.

The following figure shows the basic workflow you implement to integrate this feature into your app.

Voice Calling

Prerequisites

  • Android Studio 4.2 or higher.
  • Android SDK API Level 21 or higher.
  • Two mobile devices running Android 5.0 or higher.
  • A microphone
  • The following information from Agora Console:
    • App ID: A unique string generated by Agora that identifies your project.

    • A temporary token: A dynamic key that authenticates a user when the client joins a channel. Note down the channel name you use to generate the token.

      information
      The maximum validity period of a temporary token is 24 hours.
    Please refer to Agora account management for details.

Set up your project

This section shows you how to set up a new Android project and integrate the Agora Voice SDK.

Create a project

  1. Create a new project (Optional)

    1. Open Android Studio and select File > New > New Project....
    2. Select Phone and Tablet > Empty Activity and click Next.
    3. Set the project name and storage path.
    4. Select the language as Java, and click Finish to create the Android project.

    Note
    After you create a project, Android Studio automatically starts gradle sync. Ensure that the synchronization is successful before proceeding to the next step.
  2. Add network and device permissions

    Open the /app/src/main/AndroidManifest.xml file and add the following permissions after </application>:


    _14
    <!--Required permissions-->
    _14
    <uses-permission android:name="android.permission.INTERNET"/>
    _14
    _14
    <!--Optional permissions-->
    _14
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    _14
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
    _14
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    _14
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    _14
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    _14
    <!-- For devices running Android 12 (API level 32) or higher and integrating Agora Video SDK version v4.1.0 or lower, you also need to add the following permissions -->
    _14
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
    _14
    <!-- For Android 12 or higher, the following permissions are also required -->
    _14
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    _14
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>

  3. Prevent code obfuscation

    Open the /app/proguard-rules.pro file and add the following lines to prevent the Voice SDK code from being obfuscated:


    _2
    -keep class io.agora.**{*;}
    _2
    -dontwarn io.agora.**

Integrate the SDK

Choose either of the following methods to integrate Voice SDK into your project.

  1. Open the settings.gradle file in the project's root directory and add the Maven Central dependency, if it doesn't already exist:


    _3
    repositories {
    _3
    mavenCentral()
    _3
    }

    Note

    If your Android project uses dependencyResolutionManagement, the method of adding the Maven Central dependency may differ.

  2. Open the /app/build.gradle file and add the Voice SDK under dependencies. Check the latest version of the SDK from the release notes and replace x.y.z with the specific version number.


    _4
    dependencies {
    _4
    // Replace x.y.z with a specific SDK version number. For example, 4.3.2
    _4
    implementation 'io.agora.rtc:voice-sdk:x.y.z'
    _4
    }

    Obtain the latest version number from the release notes.

Create a user interface

Set up a FrameLayout element to add a TextView. Use the following code to generate the essential user interface. Paste the code into the /app/src/main/res/layout/activity_main.xml file, replacing the existing content.

Sample code to create the user interface
<?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_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity">      <FrameLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="@android:color/darker_gray">        <TextView            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_marginBottom="40dp"            android:layout_marginLeft="16dp"            android:layout_marginStart="16dp"            android:layout_gravity="center_vertical|start"            android:text="Welcome to the Agora Voice Call channel."/>      </FrameLayout></RelativeLayout>

Implement Voice Calling

This section shows you how to implement basic real-time audio interaction in your app.

The following figure illustrates the essential steps:

A complete code sample that implements the basic process of real-time interaction is presented here for your reference. Copy the sample code into your project to quickly implement the basic functions of real-time interaction.

To use the sample code, copy the following lines into the /app/src/main/java/com/example/<projectname>/MainActivity.java file and replace <projectname> in package com.example.<projectname> with the name of your project.

Complete sample code for real-time Voice Calling
import android.Manifest;import android.content.pm.PackageManager;import android.os.Bundle;import android.widget.Toast;import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.ActivityCompat;import androidx.core.content.ContextCompat;import io.agora.rtc2.ChannelMediaOptions;import io.agora.rtc2.Constants;import io.agora.rtc2.IRtcEngineEventHandler;import io.agora.rtc2.RtcEngine;import io.agora.rtc2.RtcEngineConfig;public class MainActivity extends AppCompatActivity {    // Fill in your App ID, which can be generated in the Agora console    private String appId = "<Your App ID>";    // Fill in the channel name    private String channelName = "<Your channel name>";    // Fill in the temporary Token generated in the Agora console    private String token = "<Your Token>";    private RtcEngine mRtcEngine;    private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {        @Override        public void onJoinChannelSuccess(String channel, int uid, int elapsed) {            super.onJoinChannelSuccess(channel, uid, elapsed);            runOnUiThread(() -> {                Toast.makeText(MainActivity.this, "Join channel success", Toast.LENGTH_SHORT).show();            });        }        @Override        public void onUserJoined(int uid, int elapsed) {            super.onUserJoined(uid, elapsed);            runOnUiThread(() -> {                Toast.makeText(MainActivity.this, "User joined: " + uid, Toast.LENGTH_SHORT).show();            });        }        @Override        public void onUserOffline(int uid, int reason) {            super.onUserOffline(uid, reason);            runOnUiThread(() -> {                Toast.makeText(MainActivity.this, "User offline: " + uid, Toast.LENGTH_SHORT).show();        });    };    private void initializeAndJoinChannel() {        try {            // Create an RtcEngineConfig object and configure it            RtcEngineConfig config = new RtcEngineConfig();            config.mContext = getBaseContext();            config.mAppId = appId;            config.mEventHandler = mRtcEventHandler;            // Create and initialize the RtcEngine            mRtcEngine = RtcEngine.create(config);        } catch (Exception e) {            throw new RuntimeException("Check the error.");        }        // Create a ChannelMediaOptions object and configure it        ChannelMediaOptions options = new ChannelMediaOptions();        // Set the user role to BROADCASTER (host) or AUDIENCE (audience)        options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;        // Set the channel profile         options.channelProfile = Constants.CHANNEL_PROFILE_COMMUNICATION;        // Publish the audio collected by the microphone        options.publishMicrophoneTrack = true;        // Automatically subscribe to all audio streams        options.autoSubscribeAudio = true;        // Join the channel using a uid, temporary token and channel name.        // Ensure that the uid is unique within the channel.         // If you set the uid to 0, the engine  generates a random uid.        // The onJoinChannelSuccess callback is triggered upon success.        mRtcEngine.joinChannel(token, channelName, 0, options);    }    private static final int PERMISSION_REQ_ID = 22;    // Get the permissions required for experiencing real-time audio interaction    private String[] getRequiredPermissions(){        // Determine the permissions required when targetSDKVersion is 31 or above        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {            return new String[]{                    Manifest.permission.RECORD_AUDIO, // Record audio permission                    Manifest.permission.READ_PHONE_STATE, // Read phone state permission                    Manifest.permission.BLUETOOTH_CONNECT // Bluetooth connection permission            };        } else {            return new String[]{                    Manifest.permission.RECORD_AUDIO,            };        }    }    private boolean checkPermissions() {        for (String permission : getRequiredPermissions()) {            int permissionCheck = ContextCompat.checkSelfPermission(this, permission);            if (permissionCheck != PackageManager.PERMISSION_GRANTED) {                return false;            }        }        return true;    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        // If already authorized, initialize the RtcEngine and join the channel        if (checkPermissions()) {            initializeAndJoinChannel();        } else {            ActivityCompat.requestPermissions(this, getRequiredPermissions(), PERMISSION_REQ_ID);        }    }    // System permission request callback    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        if (checkPermissions()) {            initializeAndJoinChannel();        }    }    @Override    protected void onDestroy() {        super.onDestroy();        if (mRtcEngine != null) {            // Leave the channel            mRtcEngine.leaveChannel();            mRtcEngine = null;            // Destroy the engine            RtcEngine.destroy();        }    }}
info
For the appId and token variables, replace the placeholders with the values you obtained from Agora Console. Ensure you enter the same channelName you used when generating the temporary token.

Follow the implementation steps to understand the core API calls in the sample code.

Handle permissions

This section describes how to import Android classes and obtain the camera, recording, and other permissions of Android devices.

  1. Import Android classes


    _6
    import androidx.appcompat.app.AppCompatActivity;
    _6
    import androidx.core.app.ActivityCompat;
    _6
    import androidx.core.content.ContextCompat;
    _6
    _6
    import android.Manifest;
    _6
    import android.content.pm.PackageManager;

  2. Get Android permissions

    When launching the app, check that the required permissions for real-time interaction have been granted in the app.


    _27
    private static final int PERMISSION_REQ_ID = 22;
    _27
    _27
    // Obtain the permissions required for experiencing real-time audio interaction
    _27
    private String[] getRequiredPermissions(){
    _27
    // Determine the permissions required when targetSDKVersion is 31 or above
    _27
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
    _27
    return new String[]{
    _27
    Manifest.permission.RECORD_AUDIO, // Audio recording permission
    _27
    Manifest.permission.READ_PHONE_STATE, // Read phone state permission
    _27
    Manifest.permission.BLUETOOTH_CONNECT // Bluetooth connection permission
    _27
    };
    _27
    } else {
    _27
    return new String[]{
    _27
    Manifest.permission.RECORD_AUDIO,
    _27
    };
    _27
    }
    _27
    }
    _27
    _27
    private boolean checkPermissions() {
    _27
    for (String permission : getRequiredPermissions()) {
    _27
    int permissionCheck = ContextCompat.checkSelfPermission(this, permission);
    _27
    if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
    _27
    return false;
    _27
    }
    _27
    }
    _27
    return true;
    _27
    }

Import Agora classes

Import the relevant Agora classes and interfaces:


_5
import io.agora.rtc2.Constants;
_5
import io.agora.rtc2.IRtcEngineEventHandler;
_5
import io.agora.rtc2.RtcEngine;
_5
import io.agora.rtc2.RtcEngineConfig;
_5
import io.agora.rtc2.ChannelMediaOptions;

Declare variables

Pass in the app ID and the temporary token obtained from Agora Console. Use the channel name you filled in when generating the temporary token. You use these values to initialize the engine and join a channel.


_6
// Fill in the app ID from Agora Console
_6
private String appId = "<Your app ID>";
_6
// Fill in the channel name
_6
private String channelName = "<Your channel name>";
_6
// Fill in the temporary token generated from Agora Console
_6
private String token = "<#Your token#>";

Initialize the engine

Call create to initialize an RtcEngine instance.


_39
private RtcEngine mRtcEngine;
_39
_39
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
_39
// Callback when successfully joining the channel
_39
@Override
_39
public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
_39
super.onJoinChannelSuccess(channel, uid, elapsed);
_39
runOnUiThread(() -> {
_39
Toast.makeText(MainActivity.this, "Join channel success", Toast.LENGTH_SHORT).show();
_39
});
_39
}
_39
_39
// Callback when a remote user or host joins the current channel
_39
@Override
_39
// Listen for remote hosts in the channel to get the host's uid information
_39
public void onUserJoined(int uid, int elapsed) {
_39
super.onUserJoined(uid, elapsed);
_39
runOnUiThread(() -> {
_39
Toast.makeText(MainActivity.this, "User joined: " + uid, Toast.LENGTH_SHORT).show();
_39
});
_39
}
_39
_39
// Callback when a remote user or host leaves the current channel
_39
@Override
_39
public void onUserOffline(int uid, int reason) {
_39
super.onUserOffline(uid, reason);
_39
runOnUiThread(() -> {
_39
Toast.makeText(MainActivity.this, "User offline: " + uid, Toast.LENGTH_SHORT).show();
_39
});
_39
}
_39
};
_39
_39
// Create an RtcEngineConfig object and configure it
_39
RtcEngineConfig config = new RtcEngineConfig();
_39
config.mContext = getBaseContext();
_39
config.mAppId = appId;
_39
config.mEventHandler = mRtcEventHandler;
_39
// Create and initialize the RtcEngine
_39
mRtcEngine = RtcEngine.create(config);

Note

Before initializing the SDK, ensure that the user fully understands and agrees to the relevant privacy policy.

Join a channel and publish audio stream

Call joinChannel to join the channel. Configure the ChannelMediaOptions as follows:

  • Set the channel profile to BROADCASTING (live broadcast scene) and set the user role to BROADCASTER (host) or AUDIENCE (audience).
  • Set publishMicrophoneTrack to true to publish the audio captured by the microphone.
  • Set autoSubscribeAudio to true to automatically subscribe to all audio streams.

_13
// Create an instance of ChannelMediaOptions and configure it
_13
ChannelMediaOptions options = new ChannelMediaOptions();
_13
// Set the user role to BROADCASTER or AUDIENCE according to the scenario
_13
options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
_13
// In the live broadcast scenario, set the channel profile to BROADCASTING (live broadcast scenario)
_13
options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
_13
// Publish the audio collected by the microphone
_13
options.publishMicrophoneTrack = true;
_13
// Automatically subscribe to all audio streams
_13
options.autoSubscribeAudio = true;
_13
// Use the temporary token to join the channel
_13
// Specify the user ID yourself and ensure it is unique within the channel
_13
mRtcEngine.joinChannel(token, channelName, 0, options);

Start and close the app

When a user launches your app, start real-time interaction. When a user closes the app, stop the interaction.

  1. In the onCreate callback, check whether the app has obtained the required permissions. If the permissions have not been granted, request the required permissions from the user. If permissions have been granted, initialize RtcEngine and join a channel.


    _11
    @Override
    _11
    protected void onCreate(Bundle savedInstanceState) {
    _11
    super.onCreate(savedInstanceState);
    _11
    setContentView(R.layout.activity_main);
    _11
    // If authorized, initialize RtcEngine and join the channel
    _11
    if (checkPermissions()) {
    _11
    initializeAndJoinChannel();
    _11
    } else {
    _11
    ActivityCompat.requestPermissions(this, getRequiredPermissions(), PERMISSION_REQ_ID);
    _11
    }
    _11
    }

  1. When a user closes the app, or switches the app to the background, call leaveChannel to leave the current channel and release all session-related resources.


    _11
    @Override
    _11
    protected void onDestroy() {
    _11
    super.onDestroy();
    _11
    if (mRtcEngine != null) {
    _11
    // Leave the channel
    _11
    mRtcEngine.leaveChannel();
    _11
    mRtcEngine = null;
    _11
    // Destroy the engine
    _11
    RtcEngine.destroy();
    _11
    }
    _11
    }

Test the sample code

Take the following steps to test the sample code:

  1. Enable developer options on your Android test device. Turn on USB debugging, connect the Android device to your development machine through a USB cable, and check that your device appears in the Android device options.

  2. In Android Studio, click Sync Project with Gradle Files to resolve project dependencies and update the configuration.

  3. After synchronization is successful, click Run app. Android Studio starts compilation. After a few moments, the app is installed on your Android device.

  1. Launch the App, grant the recording permission.
  1. On a second Android device, repeat the previous steps to install and launch the app. Test the following scenarios:
    • If users on both devices join the channel as hosts, they can hear each other.
    • If one user joins as host and the other as audience, the audience can hear the host.

Reference

This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

Next steps

After implementing the quickstart sample, read the following documents to learn more:

  • To ensure communication security in a test or production environment, best practice is to obtain and use a token from an authentication server. For details, see Secure authentication with tokens.

Voice Calling