SDK quickstart
This page provides a step-by-step guide on how to create a basic Video Calling app using the Agora Video SDK.
Understand the tech
The following figure shows the workflow you implement to integrate Video Calling into your app.
Key concepts
- Video SDK: An SDK developed by Agora to enable developers to add real-time audio and video 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 and video in a channel. The host can also subscribe to audio and video published by other hosts.
- Audience: A user assigned the audience role may subscribe to audio and video within the channel. However, they are not authorized to publish audio or video content.
For more information, see Core Concepts.
Basic workflow
To start a Video Calling session, you implement the following steps in your app:
-
Retrieve a token: A token is a computer-generated string that authenticates a user when your app joins a channel. In this guide, you retrieve your token from Agora Console. To see how to create an authentication server for development purposes, see Secure authentication with tokens.
-
Join a channel: Call methods to create and join a channel; apps that pass the same channel name join the same channel.
- Send and receive video and audio: All users can send to and receive video and audio streams from other users in the channel.
Prerequisites
- Android Studio 4.2 or higher.
- Android SDK API Level 21 or higher.
- Two mobile devices running Android 5.0 or higher.
- If a firewall is deployed in your network environment, refer to Connect through restricted networks with Cloud Proxy to use Agora services normally.
- A camera and a microphone
- A valid Agora account and project. Please refer to Agora account management for details.
- 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.
Set up your project
This section shows you how to set up a new Android project and install the Agora Video SDK.
Create a project
-
Create a new project (Optional)
- Open Android Studio and select File > New > New Project....
- Select Phone and Tablet > Empty Activity and click Next.
- Set the project name and storage path.
- Select Java or Kotlin as the language, and click Finish to create the Android project.
NoteAfter you create a project, Android Studio automatically starts gradle sync. Ensure that the synchronization is successful before proceeding to the next step. -
Add network and device permissions
Open the project's
AndroidManifest.xml
file and add the following permissions before<application>
: -
Prevent code obfuscation
Open the
/app/proguard-rules.pro
file and add the following lines to prevent the Video SDK code from being obfuscated:
Integrate the SDK
Choose either of the following methods to integrate Video SDK into your project.
- Maven Central
- Manual integration
-
Open the
settings.gradle
file in the project's root directory and add the Maven Central dependency, if it doesn't already exist:NoteIf your Android project uses dependencyResolutionManagement, the method of adding the Maven Central dependency may differ.
-
Open the
/app/build.gradle
file and add the Video SDK underdependencies
. Check the latest version of the SDK from the release notes and replacex.y.z
with the specific version number.Obtain the latest version number from the release notes.
-
Download the latest version of Video SDK from the the SDKs page and unzip it.
-
Open the unzipped file and copy the following files or subfolders to your project path.
File or folder Project path agora-rtc-sdk.jar
file/app/libs/
arm64-v8a
folder/app/src/main/jniLibs/
armeabi-v7a
folder/app/src/main/jniLibs/
x86
folder/app/src/main/jniLibs/
x86_64
folder/app/src/main/jniLibs/
high_level_api
ininclude
folder/app/src/main/jniLibs/
-
Select the file
/app/libs/agora-rtc-sdk.jar
in the left navigation bar of Android Studio project files, right-click, and select add as a library from the drop-down menu.
Create a user interface
Set up two FrameLayout
elements in your project to display local and remote video streams.
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"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Video Call!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <FrameLayout android:id="@+id/local_video_view_container" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" /> <FrameLayout android:id="@+id/remote_video_view_container" android:layout_width="160dp" android:layout_height="160dp" android:layout_marginEnd="16dp" android:layout_marginTop="16dp" android:background="@android:color/darker_gray" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>
Implement Video Calling
This section guides you through the implementation of basic real-time audio and video 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. To use the sample code, copy the following lines into the MainActivity
file in /app/src/main/java/com/example/<projectname>
file and replace <projectname>
in package com.example.<projectname>
with the name of your project.
Complete sample code for real-time Video Calling
- Java
- Kotlin
package com.example.<projectname>;import android.Manifest;import android.content.pm.PackageManager;import android.os.Bundle;import android.view.SurfaceView;import android.widget.FrameLayout;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;import io.agora.rtc2.video.VideoCanvas;public class MainActivity extends AppCompatActivity { // Fill in the App ID obtained from the Agora Console private String myAppId = "<Your app ID>"; // Fill in the channel name private String channelName = "<Your channel name>"; // Fill in the temporary token generated from Agora Console private String token = "<Your token>"; private RtcEngine mRtcEngine; private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() { // Callback when successfully joining the channel @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(); }); } // Callback when a remote user or host joins the current channel @Override public void onUserJoined(int uid, int elapsed) { runOnUiThread(() -> { // When a remote user joins the channel, display the remote video stream for the specified uid setupRemoteVideo(uid); }); } // Callback when a remote user or host leaves the current channel @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 instance and configure it RtcEngineConfig config = new RtcEngineConfig(); config.mContext = getBaseContext(); config.mAppId = myAppId; config.mEventHandler = mRtcEventHandler; // Create and initialize an RtcEngine instance mRtcEngine = RtcEngine.create(config); } catch (Exception e) { throw new RuntimeException("Check the error."); } // Enable the video module mRtcEngine.enableVideo(); // Enable local preview mRtcEngine.startPreview(); // Create a SurfaceView object and make it a child object of FrameLayout FrameLayout container = findViewById(R.id.local_video_view_container); SurfaceView surfaceView = new SurfaceView (getBaseContext()); container.addView(surfaceView); // Pass the SurfaceView object to the SDK and set the local view mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, 0)); // Create an instance of ChannelMediaOptions and configure it ChannelMediaOptions options = new ChannelMediaOptions(); // Set the user role to BROADCASTER or AUDIENCE according to the scenario options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER; // In the video calling scenario, set the channel profile to CHANNEL_PROFILE_COMMUNICATION options.channelProfile = Constants.CHANNEL_PROFILE_COMMUNICATION; // Join the channel using a temporary token and channel name, setting uid to 0 means the engine will randomly generate a username // The onJoinChannelSuccess callback will be triggered upon success mRtcEngine.joinChannel(token, channelName, 0, options); } private void setupRemoteVideo(int uid) { FrameLayout container = findViewById(R.id.remote_video_view_container); SurfaceView surfaceView = new SurfaceView (getBaseContext()); surfaceView.setZOrderMediaOverlay(true); container.addView(surfaceView); // Pass the SurfaceView object to the SDK and set the remote view mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, uid)); } private static final int PERMISSION_REQ_ID = 22; // Obtain recording, camera and other permissions required to implement real-time audio and video 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, // Recording permission Manifest.permission.CAMERA, // Camera permission Manifest.permission.READ_PHONE_STATE, // Permission to read phone status Manifest.permission.BLUETOOTH_CONNECT // Bluetooth connection permission }; } else { return new String[]{ Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA }; } } private boolean checkPermissions() { for (String permission : getRequiredPermissions()) { int permissionCheck = ContextCompat.checkSelfPermission(this, permission); if (permissionCheck != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } // 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 onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // If authorized, initialize 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(); // Stop local video preview mRtcEngine.stopPreview(); // Leave the channel mRtcEngine.leaveChannel(); }}
package com.example.<projectname>import android.Manifestimport android.content.pm.PackageManagerimport android.os.Bundleimport android.view.SurfaceViewimport android.widget.FrameLayoutimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport androidx.core.app.ActivityCompatimport androidx.core.content.ContextCompatimport io.agora.rtc2.ChannelMediaOptionsimport io.agora.rtc2.Constantsimport io.agora.rtc2.IRtcEngineEventHandlerimport io.agora.rtc2.RtcEngineimport io.agora.rtc2.RtcEngineConfigimport io.agora.rtc2.video.VideoCanvasclass MainActivity : AppCompatActivity() { // Fill in the App ID obtained from the Agora Console private val myAppId = "<Your app ID>" // Fill in the channel name private val channelName = "<Your channel name>" // Fill in the temporary token generated from Agora Console private val token = "<Your token>" private var mRtcEngine: RtcEngine? = null private val mRtcEventHandler = object : IRtcEngineEventHandler() { // Callback when successfully joining the channel override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) { runOnUiThread { Toast.makeText(this@MainActivity, "Join channel success", Toast.LENGTH_SHORT).show() } } // Callback when a remote user or host joins the current channel override fun onUserJoined(uid: Int, elapsed: Int) { runOnUiThread { // When a remote user joins the channel, display the remote video stream for the specified uid setupRemoteVideo(uid) } } // Callback when a remote user or host leaves the current channel override fun onUserOffline(uid: Int, reason: Int) { runOnUiThread { Toast.makeText(this@MainActivity, "User offline: $uid", Toast.LENGTH_SHORT).show() } } } private fun initializeAndJoinChannel() { try { // Create an RtcEngineConfig instance and configure it val config = RtcEngineConfig().apply { mContext = applicationContext mAppId = myAppId mEventHandler = mRtcEventHandler } // Create and initialize an RtcEngine instance mRtcEngine = RtcEngine.create(config) } catch (e: Exception) { throw RuntimeException("Check the error.") } // Enable the video module mRtcEngine?.enableVideo() // Enable local preview mRtcEngine?.startPreview() // Create a SurfaceView object and make it a child object of FrameLayout val container = findViewById<FrameLayout>(R.id.local_video_view_container) val surfaceView = SurfaceView(applicationContext) container.addView(surfaceView) // Pass the SurfaceView object to the SDK and set the local view mRtcEngine?.setupLocalVideo(VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, 0)) // Create an instance of ChannelMediaOptions and configure it val options = ChannelMediaOptions().apply { // Set the user role to BROADCASTER or AUDIENCE according to the scenario clientRoleType = Constants.CLIENT_ROLE_BROADCASTER // In the video calling scenario, set the channel profile to CHANNEL_PROFILE_COMMUNICATION channelProfile = Constants.CHANNEL_PROFILE_COMMUNICATION } // Join the channel using a temporary token and channel name, setting uid to 0 means the engine will randomly generate a username // The onJoinChannelSuccess callback will be triggered upon success mRtcEngine?.joinChannel(token, channelName, 0, options) } private fun setupRemoteVideo(uid: Int) { val container = findViewById<FrameLayout>(R.id.remote_video_view_container) val surfaceView = SurfaceView(applicationContext).apply { setZOrderMediaOverlay(true) } container.addView(surfaceView) // Pass the SurfaceView object to the SDK and set the remote view mRtcEngine?.setupRemoteVideo(VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, uid)) } private val permissionReqId = 22 // Obtain recording, camera and other permissions required to implement real-time audio and video interaction private fun getRequiredPermissions(): Array<String> { // Determine the permissions required when targetSDKVersion is 31 or above return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { arrayOf( Manifest.permission.RECORD_AUDIO, // Recording permission Manifest.permission.CAMERA, // Camera permission Manifest.permission.READ_PHONE_STATE, // Permission to read phone status Manifest.permission.BLUETOOTH_CONNECT // Bluetooth connection permission ) } else { arrayOf( Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA ) } } private fun checkPermissions(): Boolean { for (permission in getRequiredPermissions()) { val permissionCheck = ContextCompat.checkSelfPermission(this, permission) if (permissionCheck != PackageManager.PERMISSION_GRANTED) { return false } } return true } // System permission request callback override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (checkPermissions()) { initializeAndJoinChannel() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // If authorized, initialize RtcEngine and join the channel if (checkPermissions()) { initializeAndJoinChannel() } else { ActivityCompat.requestPermissions(this, getRequiredPermissions(), permissionReqId) } } override fun onDestroy() { super.onDestroy() // Stop local video preview mRtcEngine?.stopPreview() // Leave the channel mRtcEngine?.leaveChannel() }}
For the myAppId
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.
-
Import Android classes
- Java
- Kotlin
import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.ActivityCompat;import androidx.core.content.ContextCompat;import android.Manifest;import android.content.pm.PackageManager;import android.view.SurfaceView;import android.widget.FrameLayout;
import android.Manifestimport android.content.pm.PackageManagerimport android.os.Bundleimport android.view.SurfaceViewimport android.widget.FrameLayoutimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport androidx.core.app.ActivityCompatimport androidx.core.content.ContextCompat
-
Get Android permissions
When the app starts, check that the permissions necessary for real-time interaction have been granted to the app.
- Java
- Kotlin
private static final int PERMISSION_REQ_ID = 22;// Obtain recording, camera and other permissions required to implement real-time audio and video interactionprivate 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, // Recording permission Manifest.permission.CAMERA, // Camera permission Manifest.permission.READ_PHONE_STATE, // Permission to read phone status Manifest.permission.BLUETOOTH_CONNECT // Bluetooth connection permission }; } else { return new String[]{ Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA }; }}private boolean checkPermissions() { for (String permission : getRequiredPermissions()) { int permissionCheck = ContextCompat.checkSelfPermission(this, permission); if (permissionCheck != PackageManager.PERMISSION_GRANTED) { return false; } } return true;}
private val permissionReqId = 22// Obtain recording, camera and other permissions required to implement real-time audio and video interactionprivate fun getRequiredPermissions(): Array<String> { // Determine the permissions required when targetSDKVersion is 31 or above return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { arrayOf( Manifest.permission.RECORD_AUDIO, // Recording permission Manifest.permission.CAMERA, // Camera permission Manifest.permission.READ_PHONE_STATE, // Permission to read phone status Manifest.permission.BLUETOOTH_CONNECT // Bluetooth connection permission ) } else { arrayOf( Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA ) }}private fun checkPermissions(): Boolean { for (permission in getRequiredPermissions()) { val permissionCheck = ContextCompat.checkSelfPermission(this, permission) if (permissionCheck != PackageManager.PERMISSION_GRANTED) { return false } } return true}
Import Agora classes
Import the relevant Agora classes and interfaces:
- Java
- Kotlin
import io.agora.rtc2.Constants;import io.agora.rtc2.IRtcEngineEventHandler;import io.agora.rtc2.RtcEngine;import io.agora.rtc2.RtcEngineConfig;import io.agora.rtc2.video.VideoCanvas;import io.agora.rtc2.ChannelMediaOptions;
import io.agora.rtc2.ChannelMediaOptionsimport io.agora.rtc2.Constantsimport io.agora.rtc2.IRtcEngineEventHandlerimport io.agora.rtc2.RtcEngineimport io.agora.rtc2.RtcEngineConfigimport io.agora.rtc2.video.VideoCanvas
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.
- Java
- Kotlin
// Fill in the app ID from Agora Consoleprivate String myAppId = "<Your app ID>";// Fill in the channel nameprivate String channelName = "<Your channel name>";// Fill in the temporary token generated from Agora Consoleprivate String token = "<#Your token#>";
// Fill in the App ID obtained from the Agora Consoleprivate val myAppId = "<Your app ID>"// Fill in the channel nameprivate val channelName = "<Your channel name>"// Fill in the temporary token generated from Agora Consoleprivate val token = "<Your token>"
Initialize the engine
For real-time communication, initialize an RtcEngine
instance and set up event handlers to manage user interactions within the channel. Use RtcEngineConfig
to specify the application context, app ID, and custom event handler, then call RtcEngine.create(config)
to initialize the engine, enabling further channel operations.
- Java
- Kotlin
private RtcEngine mRtcEngine;private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() { // Callback when successfully joining the channel @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(); }); } // Callback when a remote user or host joins the current channel @Override public void onUserJoined(int uid, int elapsed) { runOnUiThread(() -> { // When a remote user joins the channel, display the remote video stream for the specified uid setupRemoteVideo(uid); }); } // Callback when a remote user or host leaves the current channel @Override public void onUserOffline(int uid, int reason) { super.onUserOffline(uid, reason); runOnUiThread(() -> { Toast.makeText(MainActivity.this, "User offline: " + uid, Toast.LENGTH_SHORT).show(); }); }};// Create an RtcEngineConfig instance and configure itRtcEngineConfig config = new RtcEngineConfig();config.mContext = getBaseContext();config.mAppId = myAppId;config.mEventHandler = mRtcEventHandler;// Create and initialize an RtcEngine instancemRtcEngine = RtcEngine.create(config);
private var mRtcEngine: RtcEngine? = nullprivate val mRtcEventHandler = object : IRtcEngineEventHandler() { // Callback when successfully joining the channel override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) { runOnUiThread { Toast.makeText(this@MainActivity, "Join channel success", Toast.LENGTH_SHORT).show() } } // Callback when a remote user or host joins the current channel override fun onUserJoined(uid: Int, elapsed: Int) { runOnUiThread { // When a remote user joins the channel, display the remote video stream for the specified uid setupRemoteVideo(uid) } } // Callback when a remote user or host leaves the current channel override fun onUserOffline(uid: Int, reason: Int) { runOnUiThread { Toast.makeText(this@MainActivity, "User offline: $uid", Toast.LENGTH_SHORT).show() } }}// Create an RtcEngineConfig instance and configure itval config = RtcEngineConfig().apply { mContext = applicationContext mAppId = myAppId mEventHandler = mRtcEventHandler}// Create and initialize an RtcEngine instancemRtcEngine = RtcEngine.create(config)
Before initializing the SDK, ensure that the user fully understands and agrees to the relevant privacy policy.
Enable the video module
Follow these steps to enable the video module:
- Call
enableVideo
to enable the video module. - Call
startPreview
to enable local video preview. - Call
setupLocalVideo
to initialize the local view and set the local video display properties.
- Java
- Kotlin
// Enable the video modulemRtcEngine.enableVideo();// Enable local previewmRtcEngine.startPreview();// Create a SurfaceView object and make it a child object of FrameLayoutFrameLayout container = findViewById(R.id.local_video_view_container);SurfaceView surfaceView = new SurfaceView (getBaseContext());container.addView(surfaceView);// Pass the SurfaceView object to the SDK and set the local viewmRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, 0));
// Enable the video modulemRtcEngine?.enableVideo()// Enable local previewmRtcEngine?.startPreview()// Create a SurfaceView object and make it a child object of FrameLayoutval container = findViewById<FrameLayout>(R.id.local_video_view_container)val surfaceView = SurfaceView(applicationContext)container.addView(surfaceView)// Pass the SurfaceView object to the SDK and set the local viewmRtcEngine?.setupLocalVideo(VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, 0))
Join a channel and publish audio and video streams
Instantiate and configure ChannelMediaOptions
and call joinChannel
to join a channel. In ChannelMediaOptions
, set the channel profile to COMMUNICATION
(video calling) and set the user role to BROADCASTER
(host) or AUDIENCE
.
- Java
- Kotlin
// Create an instance of ChannelMediaOptions and configure itChannelMediaOptions options = new ChannelMediaOptions();// Set the user role to BROADCASTER or AUDIENCE according to the scenariooptions.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;// In the live broadcast scenario, set the channel profile to COMMUNICATION (live broadcast scenario)options.channelProfile = Constants.CHANNEL_PROFILE_COMMUNICATION;// Use the temporary token to join the channel// Specify the user ID yourself and ensure it is unique within the channelmRtcEngine.joinChannel(token, channelName, 0, options);
// Create an instance of ChannelMediaOptions and configure itval options = ChannelMediaOptions().apply { // Set the user role to BROADCASTER or AUDIENCE according to the scenario clientRoleType = Constants.CLIENT_ROLE_BROADCASTER // In the live broadcast scenario, set the channel profile to COMMUNICATION (live broadcast scenario) channelProfile = Constants.CHANNEL_PROFILE_COMMUNICATION}// Use the temporary token to join the channel// Specify the user ID yourself and ensure it is unique within the channelmRtcEngine.joinChannel(token, channelName, 0, options)
Set up remote video
When a remote user joins the channel, call setupRemoteVideo
and pass in the remote user's uid
, obtained from the onUserJoined
callback, to display the remote video.
- Java
- Kotlin
private void setupRemoteVideo(int uid) { FrameLayout container = findViewById(R.id.remote_video_view_container); SurfaceView surfaceView = new SurfaceView (getBaseContext()); surfaceView.setZOrderMediaOverlay(true); container.addView(surfaceView); // Pass the SurfaceView object to the SDK and set the remote view mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, uid));}
private fun setupRemoteVideo(uid: Int) { val container = findViewById<FrameLayout>(R.id.remote_video_view_container) val surfaceView = SurfaceView(applicationContext).apply { setZOrderMediaOverlay(true) } container.addView(surfaceView) // Pass the SurfaceView object to the SDK and set the remote view mRtcEngine?.setupRemoteVideo(VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, uid))}
Start and close the app
When a user launches your app, start real-time interaction. When a user closes the app, stop the interaction.
-
In the
onCreate
callback, check whether the app has been granted the required permissions. If the permissions have not been granted, request the required permissions from the user. If permissions are granted, initializeRtcEngine
and join a channel.- Java
- Kotlin
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // If authorized, initialize RtcEngine and join the channel if (checkPermissions()) { initializeAndJoinChannel(); } else { ActivityCompat.requestPermissions(this, getRequiredPermissions(), PERMISSION_REQ_ID); } }
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if (checkPermissions()) { initializeAndJoinChannel() } else { ActivityCompat.requestPermissions(this, getRequiredPermissions(), permissionReqId) } }
-
When a user closes the app, or switches the app to the background, call
stopPreview
to stop the video preview and then callleaveChannel
to leave the current channel and release all session-related resources.- Java
- Kotlin
@Override protected void onDestroy() { super.onDestroy(); // Stop local video preview mRtcEngine.stopPreview(); // Leave the channel mRtcEngine.leaveChannel(); }
override fun onDestroy() { super.onDestroy() // Stop local video preview mRtcEngine.stopPreview() // Leave the channel mRtcEngine.leaveChannel() }
Test the sample code
Take the following steps to test the sample code:
-
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.
-
In Android Studio, click Sync Project with Gradle Files to resolve project dependencies and update the configuration.
-
After synchronization is successful, click Run app. Android Studio starts compilation. After a few moments, the app is installed on your Android device.
- Launch the App, grant recording and camera permissions. If you set the user role to host, you will see yourself in the local view.
-
On a second Android device, repeat the previous steps to install and launch the app. Alternatively, use the Web demo to join the same channel and test the following scenarios:
- If users on both devices join the channel as hosts, they can see and hear each other.
- If one user joins as host and the other as audience, the host can see themselves in the local video window; the audience can see the host in the remote video window and 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.
Sample project
Agora provides open source sample projects on GitHub for your reference. Download or view the JoinChannelVideo project for a more detailed example.
API reference
-
RtcEngineConfig
-
create
-
ChannelMediaOptions
-
joinChannel
-
enableVideo
-
startPreview
-
leaveChannel
-
IRtcEngineEventHandler