For AI agents: see the complete documentation index at /llms.txt.
Quickstart
Updated
Build a basic Video Calling app with the Agora Video SDK.
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
Prerequisites
- A camera and a microphone.
- A valid Agora account and project. See Agora account management for details.
- Android Studio 4.2 or higher.
- Android SDK API Level 21 or higher.
- Two mobile devices running Android 5.0 or higher.
Set up your project
-
Create a new project.
-
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.
Note
After you create a project, Android Studio automatically starts gradle sync. Ensure that the synchronization is successful before proceeding to the next step.
-
-
Add a new activity to your project.
- Open your project in Android Studio.
- Right-click on the
app/src/main/java/<your.package.name>folder. - Select New → Activity → Empty Activity.
- Enter an activity name and click Finish.
This guide uses
MainActivityas the activity name in the sample code. Replace it with your activity name where required.
-
Add a layout file for your activity.
Set up two container elements in your activity to display local and remote video streams. Refer to Create a user interface to get a bare bones sample layout.
Install the SDK
Use either of the following methods to add Video SDK to your project.
-
Open the
settings.gradlefile in the project's root directory and add the Maven Central dependency, if it doesn't already exist:repositories { mavenCentral() }If your Android project uses dependencyResolutionManagement, the method of adding the Maven Central dependency may differ.
-
To integrate the Video SDK into your Android project, add the following to the
dependenciesblock in your project modulebuild.gradlefile:-
Groovy
build.gradleimplementation 'io.agora.rtc:full-sdk:x.y.z' -
Kotlin
build.gradle.ktsimplementation("io.agora.rtc:full-sdk:x.y.z")
Replace
x.y.zwith the specific SDK version number, such as4.5.0.To get the latest version number, check the Release notes. To integrate the Lite SDK, use
io.agora.rtc:lite-sdkinstead. -
-
Prevent code obfuscation
Open the
/app/proguard-rules.profile and add the following lines to prevent the Video SDK code from being obfuscated:-keep class io.agora.** { *; } -dontwarn io.agora.**
-
Download the latest version of Video SDK from 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.jarfile/app/libs/arm64-v8afolder/app/src/main/jniLibs/armeabi-v7afolder/app/src/main/jniLibs/x86folder/app/src/main/jniLibs/x86_64folder/app/src/main/jniLibs/high_level_apiinincludefolder/app/src/main/jniLibs/ -
Select the file
/app/libs/agora-rtc-sdk.jarin the left navigation bar of Android Studio project files, right-click, and select add as a library from the drop-down menu. -
Prevent code obfuscation
Open the
/app/proguard-rules.profile and add the following lines to prevent the Video SDK code from being obfuscated:-keep class io.agora.** { *; } -dontwarn io.agora.**
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:
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps and use the code in your MainActivity file.
Import Agora classes
Import the relevant Agora classes and interfaces:
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.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.ChannelMediaOptionsInitialize 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. In your MainActivity file, add the following code:
// Fill in the app ID from Agora Console
private String myAppId = "<Your app ID>";
private RtcEngine mRtcEngine;
private void initializeAgoraVideoSDK() {
try {
RtcEngineConfig config = new RtcEngineConfig();
config.mContext = getBaseContext();
config.mAppId = myAppId;
config.mEventHandler = mRtcEventHandler;
mRtcEngine = RtcEngine.create(config);
} catch (Exception e) {
throw new RuntimeException("Error initializing RTC engine: " + e.getMessage());
}
}// Fill in the App ID obtained from the Agora Console
private val myAppId = "<Your app ID>"
private var mRtcEngine: RtcEngine? = null
private fun initializeRtcEngine() {
try {
val config = RtcEngineConfig().apply {
mContext = applicationContext
mAppId = myAppId
mEventHandler = mRtcEventHandler
}
mRtcEngine = RtcEngine.create(config)
} catch (e: Exception) {
throw RuntimeException("Error initializing RTC engine: ${e.message}")
}
}Join a channel
To join a channel, call joinChannel with the following parameters:
-
Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.
-
Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.
-
User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to
0when joining a channel, the SDK generates a random number for the user ID and returns the value in theonJoinChannelSuccesscallback. -
Channel media options: Configure
ChannelMediaOptionsto define publishing and subscription settings, optimize performance for your specific use-case, and set optional parameters.
For Video Calling, set the channelProfile to CHANNEL_PROFILE_COMMUNICATION and the clientRoleType to CLIENT_ROLE_BROADCASTER.
// 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 void joinChannel() {
ChannelMediaOptions options = new ChannelMediaOptions();
options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
options.channelProfile = Constants.CHANNEL_PROFILE_COMMUNICATION;
options.publishCameraTrack = true;
options.publishMicrophoneTrack = true;
mRtcEngine.joinChannel(token, channelName, 0, options);
}// 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 fun joinChannel() {
val options = ChannelMediaOptions().apply {
clientRoleType = Constants.CLIENT_ROLE_BROADCASTER
channelProfile = Constants.CHANNEL_PROFILE_COMMUNICATION
publishMicrophoneTrack = true
publishCameraTrack = true
}
mRtcEngine.joinChannel(token, channelName, 0, options)
}Subscribe to Video SDK events
The Video SDK provides an interface for subscribing to channel events. To use it, create an instance of IRtcEngineEventHandler and implement the event methods you want to handle.
To ensure that you receive all Video SDK events, set the engine event handler before joining a channel.
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
// Triggered when the local user successfully joins the specified channel.
@Override
public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
super.onJoinChannelSuccess(channel, uid, elapsed);
showToast("Joined channel " + channel);
}
// Triggered when a remote user/host joins the channel.
@Override
public void onUserJoined(int uid, int elapsed) {
super.onUserJoined(uid, elapsed);
runOnUiThread(() -> {
// Initialize and display remote video view for the new user.
setupRemoteVideo(uid);
showToast("User joined: " + uid);
});
}
// Triggered when a remote user/host leaves the channel.
@Override
public void onUserOffline(int uid, int reason) {
super.onUserOffline(uid, reason);
runOnUiThread(() -> {
showToast("User offline: " + uid);
});
}
};private val mRtcEventHandler = object : IRtcEngineEventHandler() {
override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {
super.onJoinChannelSuccess(channel, uid, elapsed)
runOnUiThread {
showToast("Joined channel $channel")
}
}
override fun onUserJoined(uid: Int, elapsed: Int) {
runOnUiThread {
showToast("User joined: $uid")
}
}
override fun onUserOffline(uid: Int, reason: Int) {
super.onUserOffline(uid, reason)
runOnUiThread {
showToast("User offline: $uid")
}
}
}Enable the video module
Follow these steps to enable the video module:
- Call
enableVideoto enable the video module. - Call
startPreviewto enable local video preview.
private void enableVideo() {
mRtcEngine.enableVideo();
mRtcEngine.startPreview();
}private fun enableVideo() {
mRtcEngine?.apply {
enableVideo()
startPreview()
}
}Display the local video
Call setupLocalVideo to initialize the local view and set the local video display properties.
private void setupLocalVideo() {
FrameLayout container = findViewById(R.id.local_video_view_container);
SurfaceView surfaceView = new SurfaceView(getBaseContext());
container.addView(surfaceView);
mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, 0));
}/**
* Initializes the local video view and sets the display properties.
* This method adds a SurfaceView to the local video container and configures it.
*/
private fun setupLocalVideo() {
val container: FrameLayout = findViewById(R.id.local_video_view_container)
val surfaceView = SurfaceView(baseContext)
container.addView(surfaceView)
mRtcEngine.setupLocalVideo(VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, 0))
}Display 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.
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);
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(baseContext).apply {
setZOrderMediaOverlay(true)
}
container.addView(surfaceView)
mRtcEngine.setupRemoteVideo(VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, uid))
}Handle permissions
To access the media devices on Android devices, declare the necessary permissions in the app's manifest and ensure that the user grants these permissions when the client starts.
-
Open your project's
AndroidManifest.xmlfile and add the following permissions before<application>:<uses-feature android:name="android.hardware.camera" android:required="false" /> <!--Required permissions--> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <!--Optional permissions--> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.BLUETOOTH"/> <!-- 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 --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/> <!-- For Android 12.0 or higher, the following permissions are also required --> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/> -
Use the following code to handle runtime permissions in your Android app. The logic ensures that the necessary permissions are granted before starting Video Calling. In your
MainActivityfile, add the following code:
private static final int PERMISSION_REQ_ID = 22;
private void requestPermissions() {
ActivityCompat.requestPermissions(this, getRequiredPermissions(), PERMISSION_REQ_ID);
}
private boolean checkPermissions() {
for (String permission : getRequiredPermissions()) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
private String[] getRequiredPermissions() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
return new String[]{
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.BLUETOOTH_CONNECT
};
} else {
return new String[]{
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA
};
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQ_ID && checkPermissions()) {
startVideoCalling();
}
}private val PERMISSION_REQ_ID = 22
private fun requestPermissions() {
ActivityCompat.requestPermissions(this, getRequiredPermissions(), PERMISSION_REQ_ID)
}
private fun checkPermissions(): Boolean {
for (permission in getRequiredPermissions()) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false
}
}
return true
}
private fun getRequiredPermissions(): Array<String> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
arrayOf(
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.BLUETOOTH_CONNECT
)
} else {
arrayOf(
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_REQ_ID && checkPermissions()) {
startVideoCalling()
}
}Start and close the app
When a user launches your client, start real-time interaction. When a user closes the app, stop the interaction.
- In the
onCreatecallback, check whether the client has been granted the required permissions. If the permissions have not been granted, request the required permissions from the user. If permissions are granted, initializeRtcEngineand join a channel.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkPermissions()) {
startVideoCalling();
} else {
requestPermissions();
}
}override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (checkPermissions()) {
startVideoCalling()
} else {
requestPermissions()
}
}- When a user closes the client, or switches the client to the background, call
stopPreviewto stop the video preview and then callleaveChannelto leave the current channel and release all session-related resources.
private void cleanupAgoraEngine() {
if (mRtcEngine != null) {
mRtcEngine.stopPreview();
mRtcEngine.leaveChannel();
mRtcEngine = null;
}
}private fun cleanupAgoraEngine() {
mRtcEngine?.apply {
stopPreview()
leaveChannel()
}
mRtcEngine = null
}Complete sample code
A complete code sample demonstrating the basic process of real-time interaction is provided for your reference. To use the sample code, copy the following lines into the MainActivity file in your project. Then, replace <projectname> in package com.example.<projectname> with your project's name.
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.
Create a user interface
To connect the sample code to your existing UI, ensure that your XML layout includes the container UI element IDs used to Display the local video and Display remote video.
Alternatively, use the following sample code to generate a basic user interface. Replace the existing content in /app/src/main/res/layout/activity_main.xml with this code.
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">
<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>Test the sample code
Take the following steps to test the sample code:
-
In
MainActivityupdate the values formyAppId, andtokenwith values from Agora Console. Fill in the samechannelNameyou used to generate the token. -
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 client. Alternatively, use the Web demo to join the same channel and test the following use-cases:
- 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 of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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
Frequently asked questions
See also
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
Prerequisites
- A camera and a microphone.
- A valid Agora account and project. See Agora account management for details.
- Xcode 13.0 or higher.
- An Apple developer account.
- If you use CocoaPods to integrate the SDK, make sure CocoaPods is installed.
- Two devices running iOS 14.0 or higher.
Set up your project
Follow these steps to create a project in Xcode:
-
Refer to Create a project. Under Application, select App. Use Storyboard for the user interface and choose Swift as the programming language.
Information
If you have not added the development team information, you see the Add account... button. Click the button and follow the on-screen prompts to log in to your Apple ID. Once login is complete, click Next, and choose your Apple account as the development team.
-
Set up automatic signing for your project.
-
Set the target devices where your app will be deployed.
-
Create a user interface for your app. Refer to Create a user interface to create a bare-bones UI.
Follow these steps to add Video Calling to your Xcode project:
- Open your project in Xcode.
- Set the target devices where your app will be deployed.
- Create a user interface for your app. Refer to Create a user interface to create a bare-bones UI.
Install the SDK
Use one of the following methods to install the Video SDK.
-
In Xcode, go to File > Add Package Dependencies.
-
In the search bar, paste the following URL:
https://github.com/AgoraIO/AgoraRtcEngine_iOS.git -
Click Add Package, select the latest version, and click Next.
-
For basic Video Calling, select RtcBasic.
If needed, also select:
SpatialAudiofor spatial audio effects.VirtualBackgroundfor virtual background.
-
Under Add to Target, select your project and click Add Package.
For more information, see Apple's official documentation.
-
Go to the project root directory in Terminal and run
pod init. A text file namedPodfileis generated in the project folder. -
Open
Podfileand modify the content as follows. ReplaceYour Appwith your target name.platform :ios, '9.0' target 'Your App' do # Replace x.y.z with the specific SDK version number, such as 4.4.0. # Integrate the Full SDK pod 'AgoraRtcEngine_iOS', 'x.y.z' # To integrate the Lite SDK, use the following line instead # pod 'AgoraLite_iOS', '4.4.0' endGet the latest version number from the release notes.
-
Run
pod installin Terminal to install the Video SDK. After successful installation, Terminal shows Pod installation complete!. -
After successful installation, a file with the suffix
.xcworkspaceis generated in the project folder. Open the file in Xcode for subsequent operations.
-
Download the latest version of the SDK from SDKs download and extract the contents.
-
Copy the files in the
libsfolder of the SDK package to your project directory. -
Open Xcode and add the corresponding dynamic library. Make sure the Embed property of the added dynamic library is set to Embed & Sign.
Information
Agora SDK uses
libc++(LLVM) by default. If you need to uselibstdc++(GNU), contactsupport@agora.io. The library provided by the SDK is a FAT image that includes simulator and device builds.
Note
The privacy updates for App Store submissions released by Apple require developers to declare approved reasons for using a set of APIs in their app's privacy manifest. Agora provides a PrivacyInfo.xcprivacy file that you can include in your project.
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:
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps.
Import Agora framework
Add the following import to your swift file:
import UIKit
import AgoraRtcKitInitialize the engine
Call sharedEngine(withAppId:delegate:) to create and initialize an AgoraRtcEngineKit instance. Provide your App ID and an AgoraRtcEngineDelegate implementation to handle SDK events.
var agoraKit: AgoraRtcEngineKit!
let appId = "YOUR_AGORA_APP_ID"
// Initialize the Agora engine
func initializeAgoraVideoSDK() {
agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId: appId, delegate: self)
}Join a channel
To join a channel, call joinChannel with the following parameters:
-
Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.
-
Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.
-
User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to
0when joining a channel, the SDK generates a random number for the user ID and returns the value in thedidJoinChannelcallback. -
Channel media options: Configure
AgoraRtcChannelMediaOptionsto define publishing and subscription settings, optimize performance for your specific use-case, and set optional parameters.
For Video Calling, set the channelProfile to .communication and the clientRoleType to .broadcaster.
let channelName = "demo" // Replace with your actual channel name
let token = "<Authentication token>" // Replace with your token
// Join the channel with specified options
func joinChannel() {
let options = AgoraRtcChannelMediaOptions()
// In video calling, set the channel use-case to communication
options.channelProfile = .communication
// Set the user role as broadcaster (default is audience)
options.clientRoleType = .broadcaster
// Publish audio captured by microphone
options.publishMicrophoneTrack = true
// Publish video captured by camera
options.publishCameraTrack = true
// Auto subscribe to all audio streams
options.autoSubscribeAudio = true
// Auto subscribe to all video streams
options.autoSubscribeVideo = true
// Use a temporary Token to join the channel
agoraKit.joinChannel(
byToken: token,
channelId: channelName,
uid: 0,
mediaOptions: options
)
}Subscribe to Video SDK events
The Video SDK provides a delegate for handling channel events. To use it, conform to the AgoraRtcEngineDelegate protocol in your class and implement the event methods you want to handle. The following code implements the didJoinChannel, didOfflineOfUid, and didJoinedOfUid callbacks:
To ensure that you receive all Video SDK events, set the engine event handler before joining a channel.
// Extension for handling Agora SDK callbacks
extension ViewController: AgoraRtcEngineDelegate {
// Triggered when the local user successfully joins a channel
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) {
print("Successfully joined channel: \(channel) with UID: \(uid)")
}
// Triggered when a remote user joins the channel
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
setupRemoteVideo(uid: uid, view: remoteView)
}
// Triggered when a remote user leaves the channel
func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) {
setupRemoteVideo(uid: uid, view: nil)
}
}To learn about the other SDK events, see AgoraRtcEngineDelegate.
Enable the video module
Follow the steps below to set up the video module.
-
To enable the video module, call
enableVideo. -
To enable local video preview, call
startPreview.// Enable video functionality (audio is enabled by default) agoraKit.enableVideo() // Enable local video preview agoraKit.startPreview()
Display the local video
Call setupLocalVideo to initialize the local view and set the local video display properties.
// Configures and starts displaying the local video feed
func setupLocalVideo() {
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.view = localView
videoCanvas.uid = 0 // UID 0 is assigned to the local user
videoCanvas.renderMode = .hidden
agoraKit.setupLocalVideo(videoCanvas)
}Display remote video
To initialize the remote user view, call setupRemoteVideo and set the local display properties for the remote user. Use the didJoinedOfUid callback to get the UID of the remote user.
func setupRemoteVideo(uid: UInt, view: UIView?) {
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = uid
videoCanvas.view = view // Assign view for joining, set to nil for leaving
videoCanvas.renderMode = .hidden
agoraKit.setupRemoteVideo(videoCanvas)
}Handle permissions
To access the camera and microphone on Video Calling devices, add the required permissions for real-time interaction. Open the info.plist file from the project navigation bar, edit the property list, to add the required permissions. These permissions are optional. However, if you do not add these permissions, you will not be able to use the corresponding devices.
| Key | Type | Value |
|---|---|---|
| Privacy - Microphone Usage Description | String | For the purpose of using the microphone. For example, for a call or live interactive streaming session. |
| Privacy - Camera Usage Description | String | For the purpose of using the camera. For example, for a call or live interactive streaming session. |
- If your project depends on third-party plugins or libraries, such as a third-party camera library, and the signature of the plug-in or library is inconsistent with the signature of the project, check the Hardened Runtime settings. Specifically, review and potentially disable Runtime Exceptions and Library Validation in the project configuration.
- For further information, refer to Preparing your app for distribution.
Start and close the app
When the user launches the app, it joins the channel and starts Video Calling. When the user closes the app, it leaves the channel and ends Video Calling.
-
To start Video Calling, call the following methods:
// Initialize the Agora engine initializeAgoraVideoSDK() // Start the local video preview setupLocalVideo() // Join an Agora channel joinChannel() -
To leave the channel and release SDK resources when the app is closed, call the following methods:
// Stop local video preview agoraKit.stopPreview() // Leave the channel and release session-related resources agoraKit.leaveChannel(nil) // Release all resources used by the Agora SDK AgoraRtcEngineKit.destroy()
caution
After destroying the engine, you can no longer use SDK methods and callbacks. To use the real-time interaction functions again, create a new engine. See Initialize the engine for details.
Complete sample code
A complete code sample demonstrating the basic process of real-time interaction is provided for your reference. Copy the following code into your ViewController.swift file:
Create a user interface
To connect the sample code to your existing UI, ensure that your ViewController.swift file includes the UIViews used to Display the local video and Display remote video.
Alternatively, use the following sample code to generate a basic user interface. To use this interface, replace the contents of the ViewController.swift file with the following code:
Sample code to create the user interface
// ViewController.swift
import UIKit
class ViewController: UIViewController {
// UI view for displaying the local video stream
var localView: UIView!
// UI view for displaying the remote video stream
var remoteView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Set up the user interface
setupUI()
}
// Sets up the UI layout for local and remote video views
func setupUI() {
// Create the local video view covering the full screen
localView = UIView(frame: UIScreen.main.bounds)
// Create the remote video view positioned in the top-right corner
remoteView = UIView(frame: CGRect(x: self.view.bounds.width - 135, y: 50, width: 135, height: 240))
// Add video views to the main view
self.view.addSubview(localView)
self.view.addSubview(remoteView)
}
}Test the sample code
Take the following steps to test the sample code:
-
In your code update the
appIdandtoken, with the app ID and temporary token you obtained from Agora Console. Use the samechannelNameyou filled in when generating the temporary token. -
Connect your iOS device to your computer.
-
Click Build to run your project and wait a few seconds for the app installation to complete.
-
Allow the app to access the device's microphone and camera.
-
If an untrusted developer prompt pops up on the device, click Cancel to close the prompt, then open Settings > General > VPN and Device Management on the iOS device, and choose to trust the developer in the Developer APP.
-
On a second Video Calling device, repeat the previous steps to install and launch the client. Alternatively, use the Web demo to join the same channel and test the following use-cases:
- 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 of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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 an open source sample project on GitHub for your reference. Download it or view the source code for a more detailed example.
Add a privacy manifest file
The Agora Video SDK for Video Calling provides the PrivacyInfo.xcprivacy file that contains the required reasons for the APIs used by the SDK. To add the privacy manifest to your app in Xcode, follow these steps:
-
Create a privacy manifest in your app project:
- Choose File > New File.
- Scroll down to the Resource section and select App Privacy File type.
- Click Next.
- Check your app in the Targets list.
- Click Create.
The default file name is
PrivacyInfo.xcprivacy, which is also the required file name for bundled privacy manifests. -
Add the items in the SDK
PrivacyInfo.xcprivacyfile to your appPrivacyInfo.xcprivacyfile using the following source code:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>NSPrivacyTracking</key> <false/> <key>NSPrivacyCollectedDataTypes</key> <array/> <key>NSPrivacyAccessedAPITypes</key> <array> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategorySystemBootTime</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>35F9.1</string> </array> </dict> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategoryFileTimestamp</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>DDA9.1</string> </array> </dict> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategoryDiskSpace</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>E174.1</string> </array> </dict> </array> </dict> </plist>
API reference
sharedEnginejoinChannelenableVideostartPreviewleaveChannelenableMultiCameraAgoraRtcEngineDelegate
Frequently asked questions
- How can I fix black screen issues?
- Why can't I turn on the camera?
- How can I listen for audience joining or leaving a channel?
- How can I solve channel-related issues?
- How can I set the log file?
- How can I troubleshoot the issue of no sound?
- How can I add a privacy manifest to my iOS app?
See also
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
Prerequisites
- A camera and a microphone.
- A valid Agora account and project. See Agora account management for details.
- Xcode 13.0 or higher.
- An Apple developer account.
- If you use CocoaPods to integrate the SDK, make sure CocoaPods is installed.
- Two devices running macOS 10.10 or higher.
Set up your project
Follow these steps to create a project in Xcode:
-
Refer to Create a project. Under Application, select App. Use Storyboard for the user interface and choose Swift as the programming language.
Information
If you have not added the development team information, you see the Add account... button. Click the button and follow the on-screen prompts to log in to your Apple ID. Once login is complete, click Next, and choose your Apple account as the development team.
-
Set up automatic signing for your project.
-
Set the target devices where your app will be deployed.
-
Create a user interface for your app. Refer to Create a user interface to create a bare-bones UI.
Follow these steps to add Video Calling to your Xcode project:
- Open your project in Xcode.
- Set the target devices where your app will be deployed.
- Create a user interface for your app. Refer to Create a user interface to create a bare-bones UI.
Install the SDK
Use one of the following methods to install the Video SDK.
-
In Xcode, go to File > Add Package Dependencies.
-
In the search bar, paste the following URL:
https://github.com/AgoraIO/AgoraRtcEngine_macOS.git -
Click Add Package, select the latest version, and click Next.
-
For basic Video Calling, select RtcBasic.
If needed, also select:
SpatialAudiofor spatial audio effects.VirtualBackgroundfor virtual background.
-
Under Add to Target, select your project and click Add Package.
For more information, see Apple's official documentation.
-
Go to the project root directory in Terminal and run
pod init. A text file namedPodfileis generated in the project folder. -
Open
Podfileand modify the content as follows. ReplaceYour Appwith your target name.platform :macos, '10.11' target 'Your App' do # Replace x.y.z with the specific SDK version number, such as 4.4.0. pod 'AgoraRtcEngine_macOS', 'x.y.z' endGet the latest version number from the release notes.
-
Run
pod installin Terminal to install the Video SDK. After successful installation, Terminal shows Pod installation complete!. -
After successful installation, a file with the suffix
.xcworkspaceis generated in the project folder. Open the file in Xcode for subsequent operations.
-
Download the latest version of the SDK from SDKs download and extract the contents.
-
Copy the files in the
libsfolder of the SDK package to your project directory. -
Open Xcode and add the corresponding dynamic library. Make sure the Embed property of the added dynamic library is set to Embed & Sign.
Information
Agora SDK uses
libc++(LLVM) by default. If you need to uselibstdc++(GNU), contactsupport@agora.io. The library provided by the SDK is a FAT image that includes simulator and device builds.
Note
The privacy updates for App Store submissions released by Apple require developers to declare approved reasons for using a set of APIs in their app's privacy manifest. Agora provides a PrivacyInfo.xcprivacy file that you can include in your project.
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:
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps.
Import Agora framework
Add the following import to your swift file:
import Cocoa
import AgoraRtcKitInitialize the engine
Call sharedEngine(withAppId:delegate:) to create and initialize an AgoraRtcEngineKit instance. Provide your App ID and an AgoraRtcEngineDelegate implementation to handle SDK events.
var agoraKit: AgoraRtcEngineKit!
let appId = "YOUR_AGORA_APP_ID"
// Initialize the Agora engine
func initializeAgoraVideoSDK() {
agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId: appId, delegate: self)
}Join a channel
To join a channel, call joinChannel with the following parameters:
-
Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.
-
Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.
-
User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to
0when joining a channel, the SDK generates a random number for the user ID and returns the value in thedidJoinChannelcallback. -
Channel media options: Configure
AgoraRtcChannelMediaOptionsto define publishing and subscription settings, optimize performance for your specific use-case, and set optional parameters.
For Video Calling, set the channelProfile to .communication and the clientRoleType to .broadcaster.
let channelName = "demo" // Replace with your actual channel name
let token = "<Authentication token>" // Replace with your token
// Join the channel with specified options
func joinChannel() {
let options = AgoraRtcChannelMediaOptions()
// In video calling, set the channel use-case to communication
options.channelProfile = .communication
// Set the user role as broadcaster (default is audience)
options.clientRoleType = .broadcaster
// Publish audio captured by microphone
options.publishMicrophoneTrack = true
// Publish video captured by camera
options.publishCameraTrack = true
// Auto subscribe to all audio streams
options.autoSubscribeAudio = true
// Auto subscribe to all video streams
options.autoSubscribeVideo = true
// Use a temporary Token to join the channel
agoraKit.joinChannel(
byToken: token,
channelId: channelName,
uid: 0,
mediaOptions: options
)
}Subscribe to Video SDK events
The Video SDK provides a delegate for handling channel events. To use it, conform to the AgoraRtcEngineDelegate protocol in your class and implement the event methods you want to handle. The following code implements the didJoinChannel, didOfflineOfUid, and didJoinedOfUid callbacks:
To ensure that you receive all Video SDK events, set the engine event handler before joining a channel.
// Extension for handling Agora SDK callbacks
extension ViewController: AgoraRtcEngineDelegate {
// Triggered when the local user successfully joins a channel
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) {
print("Successfully joined channel: \(channel) with UID: \(uid)")
}
// Triggered when a remote user joins the channel
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
setupRemoteVideo(uid: uid, view: remoteView)
}
// Triggered when a remote user leaves the channel
func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) {
setupRemoteVideo(uid: uid, view: nil)
}
}To learn about the other SDK events, see AgoraRtcEngineDelegate.
Enable the video module
Follow the steps below to set up the video module.
-
To enable the video module, call
enableVideo. -
To enable local video preview, call
startPreview.// Enable video functionality (audio is enabled by default) agoraKit.enableVideo() // Enable local video preview agoraKit.startPreview()
Display the local video
Call setupLocalVideo to initialize the local view and set the local video display properties.
// Configures and starts displaying the local video feed
func setupLocalVideo() {
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.view = localView
videoCanvas.uid = 0 // UID 0 is assigned to the local user
videoCanvas.renderMode = .hidden
agoraKit.setupLocalVideo(videoCanvas)
}Display remote video
To initialize the remote user view, call setupRemoteVideo and set the local display properties for the remote user. Use the didJoinedOfUid callback to get the UID of the remote user.
func setupRemoteVideo(uid: UInt, view: UIView?) {
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = uid
videoCanvas.view = view // Assign view for joining, set to nil for leaving
videoCanvas.renderMode = .hidden
agoraKit.setupRemoteVideo(videoCanvas)
}Handle permissions
To access the camera and microphone on Video Calling devices, add the required permissions for real-time interaction. Open the info.plist file from the project navigation bar, edit the property list, to add the required permissions. These permissions are optional. However, if you do not add these permissions, you will not be able to use the corresponding devices.
| Key | Type | Value |
|---|---|---|
| Privacy - Microphone Usage Description | String | For the purpose of using the microphone. For example, for a call or live interactive streaming session. |
| Privacy - Camera Usage Description | String | For the purpose of using the camera. For example, for a call or live interactive streaming session. |
- If your project depends on third-party plugins or libraries, such as a third-party camera library, and the signature of the plug-in or library is inconsistent with the signature of the project, check the Hardened Runtime settings. Specifically, review and potentially disable Runtime Exceptions and Library Validation in the project configuration.
- For further information, refer to Preparing your app for distribution.
Configure your macOS project settings by navigating to TARGETS > Project Name > Signing & Capabilities. Enable App Sandbox and Hardened Runtime, and add the necessary permissions as follows:
| Capability | Category | Permission |
|---|---|---|
| App Sandbox | Network |
|
| App Sandbox | Hardware |
|
| Hardened Runtime | Resource Access |
|
Start and close the app
When the user launches the app, it joins the channel and starts Video Calling. When the user closes the app, it leaves the channel and ends Video Calling.
-
To start Video Calling, call the following methods:
// Initialize the Agora engine initializeAgoraVideoSDK() // Start the local video preview setupLocalVideo() // Join an Agora channel joinChannel() -
To leave the channel and release SDK resources when the app is closed, call the following methods:
// Stop local video preview agoraKit.stopPreview() // Leave the channel and release session-related resources agoraKit.leaveChannel(nil) // Release all resources used by the Agora SDK AgoraRtcEngineKit.destroy()
caution
After destroying the engine, you can no longer use SDK methods and callbacks. To use the real-time interaction functions again, create a new engine. See Initialize the engine for details.
Complete sample code
A complete code sample demonstrating the basic process of real-time interaction is provided for your reference. Copy the following code into your ViewController.swift file:
Create a user interface
To connect the sample code to your existing UI, ensure that your ViewController.swift file includes the UIViews used to Display the local video and Display remote video.
Alternatively, use the following sample code to generate a basic user interface. To use this interface, replace the contents of the ViewController.swift file with the following code:
Sample code to create the user interface
import Cocoa
import AgoraRtcKit
// ViewController.swift
class ViewController: NSViewController {
// UI view for displaying the local video stream
var localView: NSView!
// UI view for displaying the remote video stream
var remoteView: NSView!
override func viewDidLoad() {
super.viewDidLoad()
// Set up the user interface
setupUI()
}
func setupUI() {
guard let screenFrame = NSScreen.main?.frame else { return } // Ensure screen is available
// Create the local video view covering the full screen
localView = NSView(frame: screenFrame)
// Create the remote video view positioned in the top-right corner
remoteView = NSView(frame: CGRect(x: self.view.bounds.width - 135, y: 50, width: 250, height: 250))
// Add video views to the main view
self.view.addSubview(localView)
self.view.addSubview(remoteView)
}
}Test the sample code
Take the following steps to test the sample code:
-
In your code update the
appIdandtoken, with the app ID and temporary token you obtained from Agora Console. Use the samechannelNameyou filled in when generating the temporary token. -
Click Build to run your project and wait a few seconds for the app installation to complete.
-
Allow the app to access the device's microphone and camera.
-
On a second Video Calling device, repeat the previous steps to install and launch the client. Alternatively, use the Web demo to join the same channel and test the following use-cases:
- 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 of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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
Frequently asked questions
- How can I fix black screen issues?
- Why can't I turn on the camera?
- How can I listen for audience joining or leaving a channel?
- How can I solve channel-related issues?
- How can I set the log file?
- How can I troubleshoot the issue of no sound?
See also
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
Prerequisites
- A camera and a microphone.
- A valid Agora account and project. See Agora account management for details.
- A supported browser. Agora strongly recommends using the latest stable version of Google Chrome.
- Node.js and npm
Set up your project
To initialize a new Vite project, take the following steps:
-
Open a terminal and run the following command:
npm create vite@latest agora_web_quickstart -- --template vanillaThis creates a new folder named
agora_web_quickstartand initializes a Vite project inside it using thevanillaJavaScript template. -
Navigate to the newly created folder. Download and set up dependencies for your project:
cd agora_web_quickstart npm install -
Create a user interface for your project. The UI consists of buttons to join and leave a channel. Refer to Create a user interface to get a bare bones html layout.
To add Video Calling to your existing project, take the following steps:
-
Create a JavaScript file in your project's
srcfolder to addAgoraRTCClientcode that implements specific application logic. -
Add an HTML file to your project to create a user interface. The UI consists of buttons to join and leave a channel. Refer to Create a user interface to get a bare bones HTML layout.
-
Include the JavaScript file in your HTML file.
<script type="module" src="/src/main.js"></script>
Install the SDK
Add the Video SDK to your project:
npm install agora-rtc-sdk-ngImplement 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:
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps.
Import the AgoraRTC SDK
import AgoraRTC from "agora-rtc-sdk-ng";Initialize an instance of AgoraRTCClient
Call createClient to initialize an AgoraRTCClient object.
Set the Channel mode and Video encoding format based on your use case.
For Video Calling Set mode to rtc.
// RTC client instance
let client = null;
// Initialize the AgoraRTC client
function initializeClient() {
client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
setupEventListeners();
}Join a channel
To join a channel, call join with the following parameters:
-
App ID: The App ID for your project.
-
Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.
-
Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.
-
User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to
0when joining a channel, the SDK generates a random number for the user ID.
// Join a channel and publish local media
async function joinChannel() {
await client.join(appId, channel, token, uid);
await createLocalMediaTracks();
displayLocalVideo();
publishLocalTracks();
}Create local media tracks
To set up the necessary local media tracks:
- Call
createMicrophoneAudioTrackto create a local audio track. - Call
createCameraVideoTrackto create a local Video track.
// Declare variables for local tracks
let localAudioTrack = null;
let localVideoTrack = null;
// Create local audio and video tracks
async function createLocalMediaTracks() {
localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
localVideoTrack = await AgoraRTC.createCameraVideoTrack();
}Publish local media tracks
To make the created audio and video tracks available for other users in the channel, use the publish method.
async function publishLocalTracks() {
await client.publish([localAudioTrack, localVideoTrack]);
}See Local audio and video tracks to learn more about local tracks.
Set up event listeners
Use the on method to register event listeners for SDK events. The SDK triggers the user-published event when a user publishes an audio track in the channel. Similarly, it triggers the user-unpublished event when a user leaves the channel, goes offline, or unpublishes a media track.
// Handle client events
function setupEventListeners() {
// Declare event handler for "user-published"
client.on("user-published", async (user, mediaType) => {
// Subscribe to media streams
await client.subscribe(user, mediaType);
if (mediaType === "video") {
// Specify the ID of the DOM element or pass a DOM object.
user.videoTrack.play("<Specify a DOM element>");
}
if (mediaType === "audio") {
user.audioTrack.play();
}
});
// Handle the "user-unpublished" event to unsubscribe from the user's media tracks
client.on("user-unpublished", async (user) => {
const remotePlayerContainer = document.getElementById(user.uid);
remotePlayerContainer && remotePlayerContainer.remove();
});
}- After successfully unsubscribing, the SDK releases the corresponding
RemoteTrackobject. This automatically removes the video playback element and stops audio playback. - If a remote user actively stops publishing, the local user receives the
user-unpublishedcallback. Upon receiving this callback, the SDK automatically releases the correspondingRemoteTrackobject, so you do not need to callunsubscribeagain. - The
unsubscribemethod is asynchronous and should be used withPromiseorasync/await.
To ensure that you receive all Video SDK events, set up event listeners before joining a channel.
For more information about other AgoraRTCClient events, refer to the API reference.
Display the local video
To play the local video, use the play method of the local video track. Pass an element ID or a DOM element from your UI where you want to render the video.
// Display local video
function displayLocalVideo() {
const localPlayerContainer = document.createElement("div");
localPlayerContainer.id = uid;
localPlayerContainer.textContent = `Local user ${uid}`;
localPlayerContainer.style.width = "640px";
localPlayerContainer.style.height = "480px";
document.body.append(localPlayerContainer);
localVideoTrack.play(localPlayerContainer);
}Display remote video
To display the remote video, call the play method of the remote user's videoTrack and pass in either the element ID or a DOM element from your UI where you want to render the video.
// Display remote user's video
function displayRemoteVideo(user) {
const remotePlayerContainer = document.createElement("div");
remotePlayerContainer.id = user.uid.toString();
remotePlayerContainer.textContent = `Remote user ${user.uid}`;
remotePlayerContainer.style.width = "640px";
remotePlayerContainer.style.height = "480px";
document.body.append(remotePlayerContainer);
user.videoTrack.play(remotePlayerContainer);
}Leave the channel
To exit the channel, close local audio and video tracks and call leave.
// Leave the channel and clean up
async function leaveChannel() {
// Stop the local media tracks to release the microphone and camera resources
if (localAudioTrack) {
localAudioTrack.close();
localAudioTrack = null;
}
if (localVideoTrack) {
localVideoTrack.close();
localVideoTrack = null;
}
// Leave the channel
await client.leave();
}Complete sample code
A complete code sample demonstrating the basic process of real-time interaction is provided here for your reference. To use the sample, copy the following code to the JavaScript file in the project's src folder.
Create a user interface
Open index.html in the project's root folder and replace the contents with the following code to implement a basic client user interface:
Sample code to create the user interface
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Web SDK Video Quickstart</title>
</head>
<body>
<h2 class="left-align">Web SDK Video Quickstart</h2>
<div class="row">
<div>
<button type="button" id="join">Join</button>
<button type="button" id="leave">Leave</button>
</div>
</div>
<!-- Include the JavaScript file -->
<script type="module" src="/src/main.js"></script>
</body>
</html>Test the sample code
Take the following steps to run and test the sample code:
-
In your
.jsfile, update the values forappId, andtokenwith values from Agora Console. Use the samechannelname you used to generate the token. -
To start the development server, use the following command:
npm run dev -
Open your browser and navigate to the URL displayed in your terminal, for example,
http://localhost:5173.You see the following page:
-
On a second device, repeat the previous steps to install and launch the client. Alternatively, use the Web demo or clone the sample project on Github to join the same channel and test the following use-cases:
-
Click Join to join the channel.
-
Enter the same app ID, channel name, and temporary token.
Information
- Run the web app on a local server (localhost) for testing purposes only. When deploying to a production environment, use the HTTPS protocol.
- Due to browser security policies that restrict HTTP addresses to 127.0.0.1, the Agora Web SDK only supports HTTPS protocol and
http://localhost(http://127.0.0.1). Please do not use the HTTP protocol to access your project, except forhttp://localhost(http://127.0.0.1).
-
Reference
This section contains content that completes the information on this page, or points you to documentation that explains other aspects of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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 basicVideoCall project for a more detailed example.
API reference
AgoraRTC.createClientIAgoraRTCRemoteUserplayjoincreateMicrophoneAudioTrackcreateCameraVideoTrackpublish- AgoraRTCClient events
Channel modes
The Video SDK supports the following channel modes:
rtc: Communication use-caselive: Live broadcast use-case
Communication use-case
It is suitable for use-cases where all users in the channel need to communicate with each other and the total number of users is not too large, such as multi-person conferences and online chats.
Live broadcast use-case
It is suitable for use-cases where there are few publishers but many subscribers. In this use-case, the SDK defines two user roles: audience (default) and host. Hosts can send and receive audio and video, but audience cannot send and may only receive audio and video. You can specify user roles by setting the parameters createClient of role, or you can call setClientRole to dynamically modify user roles.
Video encoding formats
You can set the codec parameter in the createClient method to the following video encoding formats:
vp8(VP8)h264(H.264)vp9(VP9)
This setting only affects the video encoding format of the host. For the audience, as long as their device and browser support the decoding of this format, the subscription can be completed normally.
Support for these formats may vary across browsers and devices. The following table lists the codec formats supported by different browsers for reference:
| Browser | VP8 | H.264 | VP9 |
|---|---|---|---|
| Desktop Chrome 58+ | ✔ | ✔ | ✔ |
| Firefox 56+ | ✔ | ✔ | ✔(Requires Firefox 69+) |
| Safari 12.1+ | ✔ | ✔ | ✔(Requires Safari 16+) |
| Safari < 12.1 | ✘ | ✔ | ✘ |
| AndroidChrome 58+ | ✔ | No clear information | ✔(Requires Chrome 68+) |
- H.264 support on Firefox depends on the
OpenH264video codec plug-in from Cisco Systems, Inc. - For Chrome, support for H.264 on Android devices varies based on device hardware compatibility with hardware codecs mandated by Chrome.
Local audio and video tracks
The SDK uses a hierarchy where all local track objects derive from the LocalTrack base class. This class defines the common behavior for all local tracks. Specific track types, such as LocalAudioTrack and LocalVideoTrack inherit from LocalTrack and extend its functionality.
To publish a local track, you call the publish method of the client with the LocalTrack object as an input parameter. This approach makes publishing a track independent of how you create your local track.
There are two main types of local tracks: LocalAudioTrack and LocalVideoTrack for publishing audio and video, respectively. Each type of LocalTrack comes with its own set of tools. For example, LocalAudioTrack lets you control the volume, while LocalVideoTrack has functions for customizing video.
The SDK includes more specific classes based on LocalAudioTrack and LocalVideoTrack. For example, the CameraVideoTrack, is a type of LocalVideoTrack that you can use to publish video from your camera. It comes with extra features for controlling the camera and adjusting video quality.
The following diagram shows the relationship between the LocalTrack classes:
Other integration methods
When you use npm to install the Web SDK, you can enable tree shaking to reduce the size of the app after integration. For details, see Using tree shaking.
In addition to using npm to install the Web SDK, you can also use the following methods:
-
In the project HTML file, add the following tag to obtain the SDK from CDN:
<script src="https://download.agora.io/sdk/release/AgoraRTC_N-4.24.5.js"></script> -
Download the Video SDK package locally, save the
.jsfiles in the SDK package to the project directory, and then add the following tag to the project HTML file:<script src="./AgoraRTC_N-4.24.5.js"></script>
Visit the Download page to obtain the link for the latest SDK version.
Frequently asked questions
Why do I get a digital envelope routines::unsupported error when running the quickstart project locally?
This issue arises in projects configured with webpack for local execution due to changes in Node.js 16 and above. The modifications in Node.js, particularly its dependency on OpenSSL (detailed in the node issue), impact the local development environment dependencies of the project. Refer to the webpack issue for details.
Use one of the following solutions to resolve the issue:
-
Run the following command to set a temporary environment variable (Recommended):
export NODE_OPTIONS=--openssl-legacy-provider -
Temporarily switch to a lower version of Node.js.
See also
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
Prerequisites
- A camera and a microphone.
- A valid Agora account and project. See Agora account management for details.
- A device running Windows 7 or higher.
- Microsoft Visual Studio 2017 or higher with C++ desktop development support and C++ 11 or above.
- If you use C# for development, you also need the .NET Framework.
Set up your project
The following steps outline the process to set up a new Visual Studio 2022 project on Windows 11 for implementing real-time audio and video interaction functions.
-
In Visual Studio, select File > New > Project to create a new project. In the pop-up window, select MFC application as the project template, click Next, update the project name to
AgoraQuickStart, set the project storage location, and then click Create. -
In the pop-up MFC application window, set the application type to Dialog-based , and set Use MFC to Use MFC in a shared DLL. Enter the generated class, set the generated class to Dlg, set the base class to CDialog, and click Finish.
To integrate real-time audio and video interaction into your project:
-
Launch Visual Studio 2022 and open your existing project by selecting File > Open > Project/Solution.
-
Navigate to your project directory and open the
.slnfile.
-
Create a user-interface for your app based on your application use-case.
A basic UI consists of the following controls:
- A Picture Control for displaying local video
- A Picture Control for displaying remote video
- An Edit Control for entering a channel name
- Buttons to join and leave a channel
Refer to Create a user interface to get a bare bones sample layout.
Install the SDK
Install the Agora Video SDK:
-
Download the latest Windows SDK.
-
Unzip and open the downloaded SDK. Copy all subfolders in
sdk/to your solution folder. Make sure these subfolders are in the same directory as your.slnfile.
Configure the project
In the Solution Explorer window, right-click the project name and click Properties to configure the following:
- Go to the C/C++ > General > Additional Include Directory menu, click Edit, and in the pop-up window enter
$(SolutionDir)sdk\high_level_api\include. - Go to the Linker > General > Additional Library Directory menu, click Edit, and in the pop-up window:
- for 64 bit Windows, enter
$(SolutionDir)sdk\x86_64. - for x86 Windows, enter
$(SolutionDir)sdk\x86.
- for 64 bit Windows, enter
- Go to the Linker > Input > Additional Dependencies menu, click Edit, and in the pop-up window:
- for 64 bit Windows, enter
$(SolutionDir)sdk\x86_64\agora_rtc_sdk.dll.lib. - for x86 Windows, enter
$(SolutionDir)sdk\x86\agora_rtc_sdk.dll.lib.
- for 64 bit Windows, enter
- Enter the Advanced menu, and in Advanced Properties, set Copy contents to OutDir and Copy C++ runtime to output directory to
Yes. - Go to the Build Events > Post-Build Events > Command Line menu and enter
copy $(SolutionDir)sdk\x86_64\*.dll $(SolutionDir)$(Platform)\$(Configuration). - Click Apply to save the configuration.
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:
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps.
Initialize the engine
For real-time communication, initialize an IRtcEngine instance and set up event handlers to manage user interactions within the channel. Use RtcEngineContext to specify the App ID, and custom event handler, then call initialize to initialize the engine, enabling further channel operations. Add the following code to your header and .cpp files:
// Declare the required variables
IRtcEngine* m_rtcEngine = nullptr; // RTC engine instance
CAgoraQuickStartRtcEngineEventHandler m_eventHandler; // IRtcEngineEventHandlervoid CAgoraQuickStartDlg::initializeAgoraEngine() {
// Create IRtcEngine object
m_rtcEngine = createAgoraRtcEngine();
// Create IRtcEngine context object
RtcEngineContext context;
// Input your App ID. You can obtain your project's App ID from the Agora Console
context.appId = APP_ID;
// Add event handler for callbacks and events
context.eventHandler = &m_eventHandler;
// Initialize
int ret = m_rtcEngine->initialize(context);
m_initialize = (ret == 0);
if (m_initialize) {
// Enable the video module
m_rtcEngine->enableVideo();
} else {
AfxMessageBox(_T("Failed to initialize Agora RTC engine"));
}
}Join a channel
To join a channel, call joinChannel[2/2] with the following parameters:
-
Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.
-
Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.
-
User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to
0when joining a channel, the SDK generates a random number for the user ID and returns the value in theonJoinChannelSuccesscallback. -
Channel media options: Configure
ChannelMediaOptionsto define publishing and subscription settings, optimize performance for your specific use-case, and set optional parameters.
For Video Calling, set the channelProfile to CHANNEL_PROFILE_COMMUNICATION and the clientRoleType to CLIENT_ROLE_BROADCASTER.
void CAgoraQuickStartDlg::joinChannel(const char* token, const char* channelName) {
ChannelMediaOptions options;
// Set the channel profile to live broadcasting
options.channelProfile = CHANNEL_PROFILE_COMMUNICATION;
// Set the user role to broadcaster; to set the user role as audience, keep the default value
options.clientRoleType = CLIENT_ROLE_BROADCASTER;
// Publish the audio stream captured by the microphone
options.publishMicrophoneTrack = true;
// Publish the camera track
options.publishCameraTrack = true;
// Automatically subscribe to all audio streams
options.autoSubscribeAudio = true;
// Automatically subscribe to all video streams
options.autoSubscribeVideo = true;
// Join the channel using the temporary token obtained from the console
m_rtcEngine->joinChannel(token, channelName, 0, options);
}Subscribe to Video SDK events
The Video SDK provides an interface for subscribing to channel events. To use it, create a custom event handler class by inheriting from IRtcEngineEventHandler and override its methods to handle real-time interaction events. Add callbacks to receive notification of users joining and leaving the channel.
To ensure that you receive all Video SDK events, set the engine event handler before joining a channel.
// Define the CAgoraQuickStartRtcEngineEventHandler class to handle callback events such as users joining and leaving the channel
class CAgoraQuickStartRtcEngineEventHandler
: public IRtcEngineEventHandler {
public:
CAgoraQuickStartRtcEngineEventHandler()
: m_hMsgHandler(nullptr) {
}
// Set the handle of the message receiving window
void SetMsgReceiver(HWND hWnd) {
m_hMsgHandler = hWnd;
}
// Register onJoinChannelSuccess callback
// This callback is triggered when a local user successfully joins a channel
virtual void onJoinChannelSuccess(const char* channel, uid_t uid, int elapsed) {
if (m_hMsgHandler) {
::PostMessage(m_hMsgHandler, WM_MSGID(EID_JOIN_CHANNEL_SUCCESS), uid, 0);
}
}
// Register onUserJoined callback
// This callback is triggered when the remote host successfully joins the channel
virtual void onUserJoined(uid_t uid, int elapsed) {
if (m_hMsgHandler) {
::PostMessage(m_hMsgHandler, WM_MSGID(EID_USER_JOINED), uid, 0);
}
}
// Register onUserOffline callback
// This callback is triggered when the remote host leaves the channel or is offline
virtual void onUserOffline(uid_t uid, USER_OFFLINE_REASON_TYPE reason) {
if (m_hMsgHandler) {
::PostMessage(m_hMsgHandler, WM_MSGID(EID_USER_OFFLINE), uid, 0);
}
}
private:
HWND m_hMsgHandler;
};Implement the callback functions.
LRESULT CAgoraQuickStartDlg::OnEIDJoinChannelSuccess(WPARAM wParam, LPARAM lParam) {
// Join channel success callback
uid_t localUid = wParam;
return 0;
}
LRESULT CAgoraQuickStartDlg::OnEIDUserJoined(WPARAM wParam, LPARAM lParam) {
// Remote user joined callback
uid_t remoteUid = wParam;
if (m_remoteRender) {
return 0;
}
// Render remote view
VideoCanvas canvas;
canvas.renderMode = RENDER_MODE_TYPE::RENDER_MODE_HIDDEN;
canvas.uid = remoteUid;
canvas.view = m_staRemote.GetSafeHwnd();
m_rtcEngine->setupRemoteVideo(canvas);
m_remoteRender = true;
return 0;
}
LRESULT CAgoraQuickStartDlg::OnEIDUserOffline(WPARAM wParam, LPARAM lParam) {
// Remote user left callback
uid_t remoteUid = wParam;
if (!m_remoteRender) {
return 0;
}
// Clear remote view
VideoCanvas canvas;
canvas.uid = remoteUid;
m_rtcEngine->setupRemoteVideo(canvas);
m_remoteRender = false;
return 0;
}Enable the video module
Call the enableVideo method to enable the video module.
// Enable the video module
m_rtcEngine->enableVideo();Display the local video
Follow these steps to set up and start the local video preview:
-
Create a
VideoCanvasinstance and configure its properties:- Set the video rendering mode.
- Specify the user ID (
uid). - Define the display window.
-
Call the
setupLocalVideomethod to apply theVideoCanvasconfiguration. -
Call the
startPreviewmethod to start the local video preview.void CAgoraQuickStartDlg::setupLocalVideo() { // Set local video display properties VideoCanvas canvas; // Set video to be scaled proportionally canvas.renderMode = RENDER_MODE_TYPE::RENDER_MODE_HIDDEN; // User ID canvas.uid = 0; // Video display window canvas.view = m_staLocal.GetSafeHwnd(); m_rtcEngine->setupLocalVideo(canvas); // Preview the local video m_rtcEngine->startPreview(); }
Display remote video
To display the remote user's video:
-
Define the video display properties using
VideoCanvas. -
Call
setupRemoteVideoto render the video.void CAgoraQuickStartDlg::setupRemoteVideo(uid_t remoteUid) { // Set remote video display properties VideoCanvas canvas; // Set video size to be proportionally scaled canvas.renderMode = RENDER_MODE_TYPE::RENDER_MODE_HIDDEN; // Remote user ID canvas.uid = remoteUid; // You can only choose to set either view or surfaceTexture. If both are set, only the settings in view take effect. canvas.view = m_staRemote.GetSafeHwnd(); m_rtcEngine->setupRemoteVideo(canvas); m_remoteRender = true; return 0; }
Leave the channel
When a user ends a call, or closes the client call leaveChannel to exit the current channel.
To stop the local video preview and clear the view:
-
Call
stopPreviewto stop playing the local video. -
Call
setupLocalVideo, passing an emptyVideoCanvasto reset the view.void CAgoraQuickStartDlg::LeaveChannel() { if (m_rtcEngine) { // Stop local video preview m_rtcEngine->stopPreview(); // Leave the channel m_rtcEngine->leaveChannel(); // Clear local view VideoCanvas canvas; canvas.uid = 0; m_rtcEngine->setupLocalVideo(canvas); m_remoteRender = false; } }
Release resources
To destroy the engine instance, call release :
// Release resources when the object is destroyed
m_rtcEngine->release(true);
m_rtcEngine = NULL;Caution
After you call Dispose, you can no longer use any SDK methods or callbacks. To use real-time Video Calling again, you must create a new engine. For more information, see Initialize the Engine.
Complete sample code
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.
AgoraQuickStartDlg.h
Create a user interface
To connect the sample code to your existing user interface, ensure that your UI includes the controls used to Display the local video and Display remote video.
Alternatively, follow these steps to create a bare-bones UI for your project.
Steps to create a minimalistic UI
-
Switch the project to resource view in the right menu bar, and then open the
.Dialogfile. -
From View > Toolbox, select Add Picture Control, and in Properties > Miscellaneous, set the ID of the control to
IDC_STATIC_REMOTE. -
From View > Toolbox , select Add Picture Control , and in Properties > Miscellaneous , set the control's ID to
IDC_STATIC_LOCAL. -
To set up an input box for entering the channel name, from View > Toolbox , select add Static Text control, and change the description text to
Channel namein the properties. Add an Edit Control as an input box, and in Properties > Miscellaneous, set the control's ID toIDC_EDIT_CHANNEL. -
To add join and leave channel buttons, open View > Toolbox and add two Button controls. In Properties > Miscellaneous , set the IDs to
ID_BTN_JOINandID_BTN_LEAVE, and set the description text to Join and Leave respectively. Your user interface looks similar to the following:
Follow these steps to create a bare-bones UI for your project.
Test the sample code
To test your app, follow these steps:
-
In Visual Studio, select local Windows debugger to start compiling the application.
-
Enter the name of the channel you want to join in the input box and click the Join button to join the channel.
You see yourself in the local view.
-
Use the Web demo to join the same channel and test the following use-cases:
- 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 of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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 sample project for a more detailed example.
- For a Windows C# implementation, see this sample project.
API Reference
Frequently asked questions
See also
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
Prerequisites
- A camera and a microphone.
- A valid Agora account and project. See Agora account management for details.
- Node.js 14 or higher.
Set up your project
-
Create a new directory for your Electron project in a local folder. Add the following files to the root of the project directory:
package.json: Manages project dependencies and scripts.index.html: Defines the app's user interface.main.js: The main process entry point.renderer.js: The renderer process script, responsible for interacting with the Agora Electron SDK.
-
Create a user interface for your app based on your use-case.
A basic user interface consists of an element for local video and an element for remote video. Refer to Create a user interface to get a bare bones sample layout.
Install the SDK
Add the Video SDK to your project using npm:
-
Configure
package.json-
macOS
{ "name": "electron-demo-app", "version": "0.1.0", "author": "your name", "description": "My Electron app", "main": "main.js", "scripts": { "start": "electron ." }, "agora_electron": { "platform": "darwin", "prebuilt": true }, "dependencies": { "agora-electron-sdk": "latest" }, "devDependencies": { "electron": "latest" } } -
Windows
{ "name": "electron-demo-app", "version": "0.1.0", "author": "your name", "description": "My Electron app", "main": "main.js", "scripts": { "start": "electron ." }, "agora_electron": { "platform": "win32", "prebuilt": true, "arch": "ia32" }, "dependencies": { "agora-electron-sdk": "latest" }, "devDependencies": {"electron": "latest" } }Configuration parameters
agora-electron-sdk: Version number of the Agora Electron SDK. Set to latest for the most recent version, or specify a version number. Seeagora-electron-sdkon npm for available versions.electron: Electron version number. Versions 5.0.0 and above are supported. For macOS devices with M1 chips, use version 11.0.0 or higher.platform(Optional): Target platform. Set todarwinfor macOS orwin32for Windows.prebuilt(Optional): Set totrueby default to prevent compatibility issues between Electron, Node.js, and the SDK.arch(Optional): Target architecture. Defaults to your system architecture.
Different versions of Electron have different environment requirements. If you see errors due to a mismatched environment when running the project, refer to the official Electron documentation to choose the appropriate Electron and Node.js versions.
-
-
To install the dependencies, open a terminal in your project root directory and run the following commands::
-
macOS
npm install -
Windows
npm install -D --arch=ia32 electron npm install
-
-
On Windows, you must first install the 32-bit version of Electron by running
npm install -D --arch=ia32 electron, and then runnpm install. Otherwise, you may encounter the error: “Not a valid Win32 application.” -
If a
node_modulesfolder exists in the project root directory, delete it before runningnpm installto avoid potential errors.
Compile the latest SDK from the Electron SDK repository and integrate it into your application.
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:
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps.
Set up the main process
The main.js file is the entry point for your Electron application. It defines the main process, which is responsible for creating and managing browser windows. This script initializes the app, loads the UI from index.html, and ensures proper behavior across platforms.
const { app, BrowserWindow } = require("electron");
const path = require("path");
// If using Electron 9.x or later, set allowRendererProcessReuse to false
app.allowRendererProcessReuse = false;
function createWindow() {
// Create the browser window
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// preload: path.join(__dirname, "renderer.js"),
// Enable Node integration and disable context isolation
nodeIntegration: true,
contextIsolation: false,
},
});
// Load the contents of the index.html file
mainWindow.loadFile("./index.html");
// Open the Developer Tools
mainWindow.webContents.openDevTools();
}
// Manage the browser window for the Electron app
app.whenReady().then(() => {
createWindow();
// On macOS, create a new window if none are open
app.on("activate", function () {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
// Quit the Electron app when all windows are closed (except on macOS)
app.on("window-all-closed", function () {
if (process.platform !== "darwin") app.quit();
});Handle permissions
Perform this step only when the target platform is macOS. Starting with macOS v10.14, you must check and obtain permission before accessing the camera or microphone. Use Electron’s askForMediaAccess method to request these permissions from the user.
Add the following code to the main.js file:
// Check and request device permissions
async function checkAndApplyDeviceAccessPrivilege() {
// Check and request camera permission
const cameraPrivilege = systemPreferences.getMediaAccessStatus('camera');
console.log(`Camera privilege before applying: ${cameraPrivilege}`);
if (cameraPrivilege !== 'granted') {
await systemPreferences.askForMediaAccess('camera');
console.log('Requested camera access from user');
}
// Check and request microphone permission
const micPrivilege = systemPreferences.getMediaAccessStatus('microphone');
console.log(`Microphone privilege before applying: ${micPrivilege}`);
if (micPrivilege !== 'granted') {
await systemPreferences.askForMediaAccess('microphone');
console.log('Requested microphone access from user');
}
}
checkAndApplyDeviceAccessPrivilege();Import dependencies
Import the modules and functions required to build the app using Video SDK. Add the following code to renderer.js:
const {
createAgoraRtcEngine,
ChannelProfileType,
ClientRoleType,
VideoSourceType,
VideoViewSetupMode
} = require("agora-electron-sdk");Specify connection parameters
Provide the App ID, temporary token, and the channel name you used when generating the token. The engine uses these values to initialize and join the channel.
// Enter your App ID
const APPID = "<-- Insert App Id -->";
// Enter your temporary token
let token = "<-- Insert Token -->";
// Enter the channel name used when generating the token
const channel = "<-- Insert Channel Name -->";
// Specify a unique user ID for this session
let uid = 123;Initialize the engine
For real-time communication, create an IRtcEngine object by calling createAgoraRtcEngine and then call initialize with RtcEngineContext to specify the App ID. Call registerEventHandler to register a custom event handler for managing user interactions within the channel.
let rtcEngine;
const os = require("os");
const path = require("path");
const sdkLogPath = path.resolve(os.homedir(), "./test.log");
// Create RtcEngine instance
rtcEngine = createAgoraRtcEngine();
// Initialize RtcEngine instance
rtcEngine.initialize({
appId: APPID,
logConfig: { filePath: sdkLogPath }
});Enable the video module
Call the enableVideo method to enable the video module, and then call startPreview to start the local video preview.
// Enable the video module
rtcEngine.enableVideo();
// Start the local video preview
rtcEngine.startPreview();Join a channel
To join a channel, call joinChannel with the following parameters:
-
Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.
-
Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.
-
User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to
0when joining a channel, the SDK generates a random number for the user ID and returns the value in theonJoinChannelSuccesscallback. -
Channel media options: Configure
ChannelMediaOptionsto define publishing and subscription settings, optimize performance for your specific use-case, and set optional parameters.
For Video Calling, set the channelProfile to ChannelProfileCommunication and the clientRoleType to ClientRoleBroadcaster.
// Join the channel using a temporary token
rtcEngine.joinChannel(token, channel, uid, {
// Set the channel profile to communication
channelProfile: ChannelProfileType.ChannelProfileCommunication,
// Set the user role to broadcaster; keep the default value for audience role
clientRoleType: ClientRoleType.ClientRoleBroadcaster,
// Publish audio collected from the microphone
publishMicrophoneTrack: true,
// Publish video collected from the camera
publishCameraTrack: true,
// Automatically subscribe to all audio streams
autoSubscribeAudio: true,
// Automatically subscribe to all video streams
autoSubscribeVideo: true,
});Register event handlers
Call the registerEventHandler method to register the following callback events:
onJoinChannelSuccess: Triggered when the local user successfully joins a channel. After joining, callsetupLocalVideoto configure the local video window.onUserJoined: Triggered when a remote user joins the current channel. After the remote user joins, callsetupRemoteVideoto configure the remote video window.onUserOffline: Triggered when a remote user leaves the current channel. After the remote user leaves, callsetupRemoteVideoto close the remote video window.
const EventHandles = {
// Listen for the local user joining the channel
onJoinChannelSuccess: ({ channelId, localUid }, elapsed) => {
console.log('Successfully joined channel: ' + channelId);
// After the local user joins the channel, set up the local video view
rtcEngine.setupLocalVideo({
sourceType: VideoSourceType.VideoSourceCameraPrimary,
uid: uid,
view: localVideoContainer,
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
});
},
// Listen for remote users joining the channel
onUserJoined: ({ channelId, localUid }, remoteUid, elapsed) => {
console.log('Remote user ' + remoteUid + ' joined');
// After a remote user joins the channel, set up the remote video view
rtcEngine.setupRemoteVideo(
{
sourceType: VideoSourceType.VideoSourceRemote,
uid: remoteUid,
view: remoteVideoContainer,
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
},
{ channelId },
);
},
// Listen for users leaving the channel
onUserOffline: ( { channelId, localUid }, remoteUid, reason ) => {
console.log('Remote user ' + remoteUid + ' left the channel');
// After a remote user leaves the channel, remove the remote video view
rtcEngine.setupRemoteVideo(
{
sourceType: VideoSourceType.VideoSourceRemote,
uid: remoteUid,
view: remoteVideoContainer,
setupMode: VideoViewSetupMode.VideoViewSetupRemove,
},
);
},
};
// Register the event handler
rtcEngine.registerEventHandler(EventHandles);To ensure that you receive all Video SDK events, set the engine event handler before joining a channel.
Display the local video
To display the local video:
// Set up the local video view
rtcEngine.setupLocalVideo({
sourceType: VideoSourceType.VideoSourceCameraPrimary,
uid: uid,
view: localVideoContainer,
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
});Display remote video
To display the remote video, call setupRemoteVideo to configure the remote video feed.
// Set up the remote video view
rtcEngine.setupRemoteVideo(
{
sourceType: VideoSourceType.VideoSourceRemote,
uid: remoteUid,
view: remoteVideoContainer,
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
},
{ channelId },
);
// Remove the remote video view
rtcEngine.setupRemoteVideo(
{
sourceType: VideoSourceType.VideoSourceRemote,
uid: remoteUid,
view: remoteVideoContainer,
setupMode: VideoViewSetupMode.VideoViewSetupRemove,
},
);Call this method when the client receives the onUserJoined callback.
Start and close the app
When a user launches your app, start Video Calling. When a user closes the app, stop Video Calling and release resources.
-
To start Video Calling, initialize the engine, display the local video and join a channel.
-
When Video Calling ends, leave the channel and clean up resources:
// Stop the preview rtcEngine.stopPreview(); // Leave the channel rtcEngine.leaveChannel();When you no longer need to interact, unregister the event handler and call
releaseto release engine resources.// Unregister the event handler rtcEngine.unregisterEventHandler(EventHandles); // Release the engine rtcEngine.release();caution
After destroying the engine, you can no longer use SDK methods and callbacks. To use the real-time interaction functions again, create a new engine instance. See Initialize the engine for details.
Complete sample code
A complete code sample demonstrating the basic process of real-time interaction is provided for your reference. Replace the entire contents of the main.js and renderer.js with the following code samples:
main.js
Information
- In
renderer.js, replace the values forAPPID,token, andchannelwith your App ID, the temporary token from Agora Console, and the channel name you used to generate the token. - If you're targeting macOS v10.14 or later, add the device permission code to
main.js. For more details, see Get device permissions.
To test the complete code, see Test the sample code.
Create a user interface
To connect the sample code to your existing UI, ensure that your index.html file includes the HTML elements used to Display the local video and Display remote video.
Alternatively, use the following sample to create a minimal interface. Add the following code to index.html:
Sample code to create the user interface
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Electron Quickstart</title>
</head>
<body>
<h1>Electron Quickstart</h1>
<!-- Add the local video view to the interface -->
<div
id="join-channel-local-video"
style="width: 300px; height: 300px; float: left"
></div>
<!-- Add the remote video view to the interface -->
<div
id="join-channel-remote-video"
style="width: 300px; height: 300px; float: left"
></div>
</body>
<script src="./renderer.js"></script>
</html>Test the sample code
Take the following steps to test the sample code:
-
Update the
APPID,token, andchannelparameter values in your code. -
To run the app, execute the following command in the project root directory:
npm startYou see a window pop up showing the local video.
-
Invite a friend to run the demo app on a second device. Alternatively, use the Web demo to join the same channel.
- 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 of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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
Frequently asked questions
See also
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
Prerequisites
-
A camera and a microphone.
-
A valid Agora account and project. See Agora account management for details.
-
Flutter 2.10.5 or higher with Dart 2.14.0 or higher.
-
Android Studio, IntelliJ, VS Code, or another IDE that supports Flutter. See Set up an editor.
-
Prepare your development and testing environment according to your target platform.
Run
flutter doctorto confirm that your development environment is set up correctly for Flutter development.
Set up your project
From the Terminal, run the following commands to create a new project named agora_project, or follow the steps for your IDE:
flutter create agora_project
cd agora_projectTo add Video Calling to your existing project:
- Open your Flutter project and navigate to the
libfolder. - Add a new file to the
libfolder and name itagora_logic.dart.
Install the SDK
Install the Agora Video SDK and other dependencies.
-
Add the latest version of Agora Video SDK to your Flutter project:
flutter pub add agora_rtc_engine -
Add the permission processing package:
flutter pub add permission_handlerThe
dependenciesin yourpubspec.yamlfile should look like the following:dependencies: flutter: sdk: flutter agora_rtc_engine: ^6.5.0 # Agora Flutter SDK, please use the latest version permission_handler: ^11.3.1 # Package for managing runtime permissions cupertino_icons: ^1.0.8 -
Install the dependencies.
Execute the following command in the project path:
flutter pub get
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:
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps.
Import packages
Import the following packages in your dart file.
import 'dart:async';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';Initialize the engine
For real-time communication, initialize an RtcEngine instance. Use RtcEngineContext to specify the App ID, and other configuration parameters. In your dart file, add the following code:
// Set up the Agora RTC engine instance
Future<void> _initializeAgoraVoiceSDK() async {
_engine = createAgoraRtcEngine();
await _engine.initialize(const RtcEngineContext(
appId: "<-- Insert app Id -->",
channelProfile: ChannelProfileType.channelProfileCommunication,
));
}Join a channel
To join a channel, call joinChannel with the following parameters:
-
Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.
-
Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.
-
User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to
0when joining a channel, the SDK generates a random number for the user ID and returns the value in theonJoinChannelSuccesscallback. -
Channel media options: Configure
ChannelMediaOptionsto define publishing and subscription settings, optimize performance for your specific use-case, and set optional parameters.
For Video Calling, set the clientRoleType to clientRoleBroadcaster.
// Join a channel
Future<void> _joinChannel() async {
await _engine.joinChannel(
token: token,
channelId: channel,
options: const ChannelMediaOptions(
autoSubscribeVideo: true, // Automatically subscribe to all video streams
autoSubscribeAudio: true, // Automatically subscribe to all audio streams
publishCameraTrack: true, // Publish camera-captured video
publishMicrophoneTrack: true, // Publish microphone-captured audio
// Use clientRoleBroadcaster to act as a host or clientRoleAudience for audience
clientRoleType: ClientRoleType.clientRoleBroadcaster,
),
uid: 0,
);
}Subscribe to Video SDK events
The SDK provides the RtcEngineEventHandler for subscribing to channel events. To use it, pass an instance of RtcEngineEventHandler to registerEventHandler and implement the event methods you want to handle.
Call registerEventHandler to bind the event handler to the SDK.
// Register an event handler for Agora RTC
void _setupEventHandlers() {
_engine.registerEventHandler(
RtcEngineEventHandler(
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
debugPrint("Local user ${connection.localUid} joined");
setState(() => _localUserJoined = true);
},
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
debugPrint("Remote user $remoteUid joined");
setState(() => _remoteUid = remoteUid);
},
onUserOffline: (RtcConnection connection, int remoteUid, UserOfflineReasonType reason) {
debugPrint("Remote user $remoteUid left");
setState(() => _remoteUid = null);
},
),
);
}When a remote user joins the channel, the onUserJoined callback is triggered. Use the remote user's uid returned in the callback, to create an AgoraVideoView control for displaying the video stream from the remote user.
To ensure that you receive all Video SDK events, register the event handler before joining a channel.
Display the local video
To display the local video, enable the video module by calling enableVideo, then start the local video preview with startPreview.
Future<void> _setupLocalVideo() async {
// The video module and preview are disabled by default.
await _engine.enableVideo();
await _engine.startPreview();
}To render the local video, add the following widget inside your UI’s widget tree, such as in the build method of your StatefulWidget:
// Displays the local user's video view using the Agora engine.
Widget _localVideo() {
return AgoraVideoView(
controller: VideoViewController(
rtcEngine: _engine, // Uses the Agora engine instance
canvas: const VideoCanvas(
uid: 0, // Specifies the local user
renderMode: RenderModeType.renderModeHidden, // Sets the video rendering mode
),
),
);
}Display remote video
To render a remote video, add the following widget inside your UI’s widget tree, such as in the build method of your StatefulWidget:
// If a remote user has joined, render their video, else display a waiting message
Widget _remoteVideo() {
if (_remoteUid != null) {
return AgoraVideoView(
controller: VideoViewController.remote(
rtcEngine: _engine, // Uses the Agora engine instance
canvas: VideoCanvas(uid: _remoteUid), // Binds the remote user's video
connection: const RtcConnection(channelId: channel), // Specifies the channel
),
);
} else {
return const Text(
'Waiting for remote user to join...',
textAlign: TextAlign.center,
);
}
}Handle permissions
Request microphone and camera permissions for Video Calling.
Future<void> _requestPermissions() async {
await [Permission.microphone, Permission.camera].request();
}Information
If your target platform is iOS or macOS, add the microphone and camera permission declarations required for real-time interaction to Info.plist.
| Device | Key | Value |
|---|---|---|
| Microphone | Privacy - Microphone Usage Description | for audio calls |
| Camera | Privacy - Camera Usage Description | for video calls |
Start and close the app
To start Video Calling, request microphone and camera permissions, initialize the Agora SDK instance, set up event handlers, join a channel, and display the local video.
await _requestPermissions();
await _initializeAgoraVideoSDK();
await _setupLocalVideo();
_setupEventHandlers();
await _joinChannel();To stop Video Calling, leave the channel and release the engine instance.
// Leaves the channel and releases resources
Future<void> _cleanupAgoraEngine() async {
await _engine.leaveChannel();
await _engine.release();
}Warning
After you call release, you no longer have access to the methods and callbacks of the SDK. To use Video Calling features again, create a new engine instance.
Complete sample code
A complete code sample demonstrating the basic process of real-time interaction is provided for your reference. To use the sample code, copy the following code to replace the entire contents of the .dart file in your project.
Information
In the appId and token fields, enter the corresponding values you obtained from Agora Console. Use the same channel name you filled in when generating the temporary token.
Create a user interface
To connect the sample code to your existing UI, ensure that your widget tree includes the _remoteVideo and _localVideo widgets used to Display the local video and Display remote video.
Alternatively, use the following sample code to generate a basic user interface:
Sample code to create the user interface
// Build UI to display local video and remote video
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Agora Video Call')),
body: Stack(
children: [
Center(child: _remoteVideo()),
Align(
alignment: Alignment.topLeft,
child: SizedBox(
width: 100,
height: 150,
child: Center(
child: _localUserJoined
? _localVideo()
: const CircularProgressIndicator(),
),
),
),
],
),
);
}Test the sample code
Take the following steps to test the sample code:
-
In
main.dartupdate the values forappId, andtokenwith values from Agora Console. Fill in the samechannelname you used to generate the token. -
Connect a target device to your development computer.
-
Open Terminal and execute the following command in the project folder to run the sample project:
flutter run -
Launch the App, grant microphone and camera permissions. If you set the user role to host, you see yourself in the local view.
-
On a second target device, repeat the previous steps to install and launch the client. Alternatively, use the Web demo to join the same channel and test the following use-cases:
- 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.
On an Android device, the app UI appears similar to the following:
Reference
This section contains content that completes the information on this page, or points you to documentation that explains other aspects of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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 join_channel_video.dart for a more detailed example.
API reference
Frequently asked questions
See also
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
Prerequisites
- A camera and a microphone.
- A valid Agora account and project. See Agora account management for details.
- React Native 0.60 or later. See Get Started with React Native.
- Node.js 16 or later.
- Depending on your target platform:
- Android: a machine running macOS, Windows, or Linux; JDK 11 or later; the latest version of Android Studio; and a physical or virtual Android device running Android 5.0 or later.
- iOS: a machine running macOS; Xcode 10 or later; CocoaPods; and a physical or virtual iOS device running iOS 9.0 or later. If you use React Native 0.63 or later, ensure your iOS version is 10.0 or later.
Set up your project
Create a project
To create a new application using React Native Community CLI, see Get Started Without a Framework.
Install the SDK
Download and add the Agora Video SDK to your React Native project. Choose either of the following methods:
In your project folder, execute the following command:
npm i --save react-native-agoraIn your project folder, execute the following commands:
# Install yarn
npm install -g yarn
# Use yarn to download Agora React Native SDK
yarn add react-native-agorainformation
React Native 0.60.0 and later support automatic linking of native modules. Manual linking is not recommended. See Autolinking for details
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:
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps and use the code in your App.tsx file.
Import dependencies
Add the required Agora dependencies to your app.
import {
createAgoraRtcEngine,
ChannelProfileType,
ClientRoleType,
IRtcEngine,
RtcSurfaceView,
RtcConnection,
IRtcEngineEventHandler,
} from 'react-native-agora';Initialize the engine
For real-time communication, call createAgoraRtcEngine to create an RtcEngine instance, and then initialize the engine using RtcEngineContext to specify the App ID.
const appId = '<-- Insert app ID -->';
const setupVideoSDKEngine = async () => {
if (Platform.OS === 'android') { await getPermission(); }
agoraEngineRef.current = createAgoraRtcEngine();
const agoraEngine = agoraEngineRef.current;
await agoraEngine.initialize({ appId: appId });
};Join a channel
To join a channel, call joinChannel with the following parameters:
-
Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.
-
Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.
-
User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to
0when joining a channel, the SDK generates a random number for the user ID and returns the value in theonJoinChannelSuccesscallback. -
Channel media options: Configure
ChannelMediaOptionsto define publishing and subscription settings, optimize performance for your specific use-case, and set optional parameters.
For Video Calling, set the channelProfile to ChannelProfileCommunication and the clientRoleType to ClientRoleBroadcaster.
const token = '<-- Insert token -->';
const channelName = '<-- Insert channel name -->';
const localUid = 0; // Local user UID, no need to modify
// Define the join method called after clicking the join channel button
const join = async () => {
if (isJoined) {
return;
}
if (isHost) {
// Join the channel as a broadcaster
agoraEngineRef.current?.joinChannel(token, channelName, localUid, {
// Set channel profile to live broadcast
channelProfile: ChannelProfileType.ChannelProfileCommunication,
// Set user role to broadcaster
clientRoleType: ClientRoleType.ClientRoleBroadcaster,
// Publish audio collected by the microphone
publishMicrophoneTrack: true,
// Publish video collected by the camera
publishCameraTrack: true,
// Automatically subscribe to all audio streams
autoSubscribeAudio: true,
// Automatically subscribe to all video streams
autoSubscribeVideo: true,
});
} else {
// Join the channel as an audience
agoraEngineRef.current?.joinChannel(token, channelName, localUid, {
// Set channel profile to live broadcast
channelProfile: ChannelProfileType.ChannelProfileCommunication,
// Set user role to audience
clientRoleType: ClientRoleType.ClientRoleAudience,
// Do not publish audio collected by the microphone
publishMicrophoneTrack: false,
// Do not publish video collected by the camera
publishCameraTrack: false,
// Automatically subscribe to all audio streams
autoSubscribeAudio: true,
// Automatically subscribe to all video streams
autoSubscribeVideo: true,',
});
}
};Since the engine runs locally, reloading the app using the Metro bundler may cause the engine reference to be lost, preventing channel joining. To resolve this issue, restart the app.
Subscribe to Video SDK events
The Video SDK provides an interface for subscribing to channel events. To use it, create an instance of IRtcEngineEventHandler and implement the event methods you want to handle. Call registerEventHandler to register your custom event handler.
const [remoteUid, setRsemoteUid] = useState(0); // Uid of the remote user
const setupEventHandler = () => {
eventHandler.current = {
// Triggered when the local user successfully joins a channel
onJoinChannelSuccess: () => {
setMessage('Successfully joined channel: ' + channelName);
setupLocalVideo();
setIsJoined(true);
},
// Triggered when a remote user joins the channel
onUserJoined: (_connection: RtcConnection, uid: number) => {
setMessage('Remote user ' + uid + ' joined');
setRemoteUid(uid);
},
// Triggered when a remote user leaves the channel
onUserOffline: (_connection: RtcConnection, uid: number) => {
setMessage('Remote user ' + uid + ' left the channel');
setRemoteUid(uid);
},
};
// Register the event handler
agoraEngineRef.current?.registerEventHandler(eventHandler.current);
};To ensure that you receive all Video SDK events, register the event handler before joining a channel.
Enable the video module
Call enableVideo to activate the video module, and use startPreview to enable the local video preview.
const setupLocalVideo = () => {
agoraEngineRef.current?.enableVideo();
agoraEngineRef.current?.startPreview();
};Display the local video
To display the local user's video stream, use the RtcSurfaceView component. Set the uid to 0 and style the video container.
<React.Fragment key={0}>
<RtcSurfaceView canvas={{ uid: 0 }} style={ width: '90%', height: 200 } />
</React.Fragment>Display remote video
To display the remote user's video, use the RtcSurfaceView component. Pass the remoteUid of the remote user to the component and set the desired style for the video container.
<React.Fragment key={remoteUid}>
<RtcSurfaceView
canvas={{ uid: remoteUid }}
style={ width: '90%', height: 200 }
/>
</React.Fragment>Handle permissions
To access the camera and microphone, ensure that the user grants the necessary permissions when the app starts.
On Android devices, pop up a prompt box to obtain permission to use the microphone and camera.
// Import components related to Android device permissions
const getPermission = async () => {
if (Platform.OS === 'android') {
await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
PermissionsAndroid.PERMISSIONS.CAMERA,
]);
}
};In Xcode, open the info.plist file and add the following content to the list on the right to obtain the corresponding device permissions:
| Key | Type | Value |
|---|---|---|
| Privacy - Microphone Usage Description | String | The purpose of using the microphone, for example, for a call or live interactive streaming. |
| Privacy - Camera Usage Description | String | The purpose of using the camera, for example, for a call or live interactive streaming. |
Leave the channel
To exit a Video Calling channel, call leaveChannel.
const leave = () => {
// Leave the channel
agoraEngineRef.current?.leaveChannel();
setIsJoined(false);
};Clean up resources
Before closing your client, unregister the event handler and call release to free up resources.
const cleanupAgoraEngine = () => {
return () => {
agoraEngineRef.current?.unregisterEventHandler(eventHandler.current!);
agoraEngineRef.current?.release();
};
};After calling release, methods and callbacks of the SDK are no longer available. To use the SDK functions again, create a new engine instance.
Complete sample code
A complete code sample demonstrating the basic process of real-time interaction is provided for your reference. To use the sample code, copy the code into ProjectName/App.tsx to quickly implement the basic functionality.
Create a user interface
Design a user interface for your project based on your application use-case. A basic interface consists of two view frames to display local and remote videos. Add Join channel and Leave channel buttons to enable the user to join and leave a channel. To create such an interface, refer to the following code:
Sample code to create the user interface
import React, { useState } from 'react';
// Import user interface elements
import {
SafeAreaView,
ScrollView,
StyleSheet,
Text,
View,
Switch,
} from 'react-native';
const localUid = 0; // Local user Uid, no need to modify
const App = () => {
const [isJoined, setIsJoined] = useState(false); // Whether the local user has joined the channel
const [isHost, setIsHost] = useState(true); // User role
const [remoteUid, setRemoteUid] = useState(0); // Uid of the remote user
const [message, setMessage] = useState(''); // User prompt message
// Render user interface
return (
<SafeAreaView style={styles.main}>
<Text style={styles.head}>Agora Video SDK Quickstart</Text>
<View style={styles.btnContainer}>
<Text onPress={join} style={styles.button}>
Join Channel
</Text>
<Text onPress={leave} style={styles.button}>
Leave Channel
</Text>
</View>
<View style={styles.btnContainer}>
<Text>Audience</Text>
<Switch
onValueChange={switchValue => {
setIsHost(switchValue);
if (isJoined) {
leave();
}
}}
value={isHost}
/>
<Text>Host</Text>
</View>
<ScrollView
style={styles.scroll}
contentContainerStyle={styles.scrollContainer}>
{isJoined && isHost ? (
<React.Fragment key={localUid}>
<Text>Local user uid: {localUid}</Text>
</React.Fragment>
) : (
<Text>Join a channel</Text>
)}
{isJoined && remoteUid !== 0 ? (
<React.Fragment key={remoteUid}>
<Text>Remote user uid: {remoteUid}</Text>
</React.Fragment>
) : (
<Text>{isJoined && !isHost ? 'Waiting for remote user to join' : ''}</Text>
)}
<Text style={styles.info}>{message}</Text>
</ScrollView>
</SafeAreaView>
);
};
// Define user interface styles
const styles = StyleSheet.create({
button: {
paddingHorizontal: 25,
paddingVertical: 4,
fontWeight: 'bold',
color: '#ffffff',
backgroundColor: '#0055cc',
margin: 5,
},
main: { flex: 1, alignItems: 'center' },
scroll: { flex: 1, backgroundColor: '#ddeeff', width: '100%' },
scrollContainer: { alignItems: 'center' },
videoView: { width: '90%', height: 200 },
btnContainer: { flexDirection: 'row', justifyContent: 'center' },
head: { fontSize: 20 },
info: { backgroundColor: '#ffffe0', paddingHorizontal: 8, color: '#0000ff' },
});
export default App;Test the sample code
Take the following steps to test the sample code:
-
Update the values for
appId,token, andchannelNamein your code. -
Run the app.
Caution
Some simulators may not support all the functions of this project. Best practice is to run the project on a physical device.
To run the client on an Android device:
-
Turn on the developer options of the Android device and connect the Android device to the computer through a USB cable.
-
In the project root directory, execute
npx react-native run-android.
To run the client on an iOS device:
-
Open the
ProjectName/ios/ProjectName.xcworkspacefolder using Xcode. -
Connect the iOS device to your computer through a USB cable.
-
In Xcode, click the Build and Run button.
Information
For detailed steps on running the app on a real Android or iOS device, refer to Running On Device.
-
Launch the app and click the Join channel button to join a channel.
-
Invite a friend to install and run the client on a second device. Alternatively, use the Web demo to join the same channel. Once your friend joins the channel, you can see and hear each other.
Reference
This section contains content that completes the information on this page, or points you to documentation that explains other aspects of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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
Frequently asked questions
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
React SDK and Web SDK relationship
The React SDK is built on Web SDK 4.x and includes its APIs. For example, useLocalMicrophoneTrack calls the Web SDK createMicrophoneAudioTrack method.
Use the React SDK for basic real-time audio and video features. For advanced or complex scenarios, use the Web SDK. When a feature requires the Web SDK, the React SDK documentation links to the relevant Web SDK API pages.
Prerequisites
- A camera and a microphone.
- A valid Agora account and project. See Agora account management for details.
- A supported browser.
- A JavaScript package manager such as npm.
Set up your project
Create a project
To create a new ReactJS project with the necessary dependencies:
-
Ensure that you have installed Node.js LTS and
npm. -
Open a terminal and execute:
npm create vite@latest agora-sdk-quickstart -- --template react-tsThis creates a new project folder named
agora-sdk-quickstart. Open the folder in your preferred IDE.
Install the SDK
Use one of the following methods to install the project dependencies:
Navigate to the project folder and run the following command to install the Video SDK:
npm i agora-rtc-reactTo integrate React JS dependencies and the Agora SDK using CDN, add the following code to your HTML file:
<!-- Include the React development libraries (must be introduced in this order) -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- If the above React libraries have already been integrated through npm, skip them and include only the Agora RTC React SDK -->
<script src="https://download.agora.io/sdk/release/agora-rtc-react.2.3.0.js"></script>Implement Video Calling
This section guides you through the implementation of basic real-time audio and video interaction in your app.
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps.
Import Agora hooks and components
To use Video SDK in your component, include the following imports:
import {
LocalUser, // Plays the microphone audio track and the camera video track
RemoteUser, // Plays the remote user audio and video tracks
useIsConnected, // Returns whether the SDK is connected to Agora's server
useJoin, // Automatically join and leave a channel on mount and unmount
useLocalMicrophoneTrack, // Create a local microphone audio track
useLocalCameraTrack, // Create a local camera video track
usePublish, // Publish the local tracks
useRemoteUsers, // Retrieve the list of remote users
} from "agora-rtc-react";
import AgoraRTC, { AgoraRTCProvider } from "agora-rtc-react";
import { useState } from "react";Initialize the client
Use the createClient method provided by the SDK to create a client object for the <AgoraRTCProvider /> component. Wrap the <Basics /> component with <AgoraRTCProvider /> to enable state management and access operation-related hooks.
For Video Calling, set the mode property of ClientConfig to "rtc".
export const VideoCalling = () => {
const client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
return(
<AgoraRTCProvider client={client}>
</AgoraRTCProvider>
);
}Join a channel
To join a channel, use the useJoin hook. You can specify the following joinOptions:
-
App ID:
appididentifies the project you created in Agora Console. -
Channel name: The name of the
channelto join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins. -
Authentication token: A
tokenis a dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token. -
User ID:
uidis a 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you do not set a user ID or set it to0when joining a channel, the SDK generates a random number for the user ID and returns the value.
Add the following to Basics:
const [appId, setAppId] = useState("<-- Insert App ID -->");
const [channel, setChannel] = useState("<-- Insert Channel Name -->");
const [token, setToken] = useState("<-- Insert Token -->");
const [calling, setCalling] = useState(false);
useJoin({appid: appId, channel: channel, token: token ? token : null}, calling);Create local audio and video tracks
To create local audio and video tracks, use the useLocalMicrophoneTrack and useLocalCameraTrack hooks. Add the following to Basics:
const { localMicrophoneTrack } = useLocalMicrophoneTrack(micOn);
const { localCameraTrack } = useLocalCameraTrack(cameraOn);Publish tracks in the channel
After joining a channel, publish the local audio and video tracks using the usePublish hook. Add the following to Basics:
const [micOn, setMic] = useState(true);
const [cameraOn, setCamera] = useState(true);
const { localMicrophoneTrack } = useLocalMicrophoneTrack(micOn);
const { localCameraTrack } = useLocalCameraTrack(cameraOn);
usePublish([localMicrophoneTrack, localCameraTrack]);Display the local video
To display the local video, use the LocalUser hook, which provides properties to manage local audio and video tracks. Assign the local video track to videoTrack and the audio track to audioTrack. Use the micOn and cameraOn parameters to toggle audio and video. Include the following code in the markup of your Basics component:
<LocalUser
audioTrack={localMicrophoneTrack}
cameraOn={cameraOn}
micOn={micOn}
videoTrack={localCameraTrack}
style={{width: '50%', height: 300 }}
>Display remote video
To manage and display the list of remote users connected to a channel, use the useRemoteUsers hook. To show each user's video, pass the user object to the RemoteUser component along with the required properties. Follow these steps to implement the logic:
-
Retrieve the list of remote users
Use the
useRemoteUsershook to get the current list of remote users:const remoteUsers = useRemoteUsers(); -
Render the remoteUser component
Loop through the
remoteUserslist and nest theRemoteUsercomponent where you want to display each user's video. Include the following code in the markup of yourBasicscomponent:{remoteUsers.map((user) => ( <div key={user.uid}> <RemoteUser user={user} style={{ width: '50%', height: 300 }}> <samp>{user.uid}</samp> </RemoteUser> </div> ))}
Leave the channel
To leave a channel, destroy the component, close the browser window, or refresh the browser tab. The useJoin hook automatically handles the destruction of the React component.
Complete sample code
A complete code sample demonstrating the basic process of real-time interaction is provided for your reference. To use the complete sample, add the following to your src/App.tsx file.
Test the sample code
Use CodeSandbox, to swiftly run the complete demo code and experience the Video Calling Video SDK functionality in just a few simple steps.
To run the demo code in CodeSandbox:
- Fill in the app ID and the temporary token you obtained from Agora Console. Use the same channel name you used to generate the token.
- Click the Join Channel button. You see yourself in the video.
- Ask a friend to open the same demo link in their browser and join the channel using the same app ID, channel name, and temporary token as yours. After successfully joining the channel, you can see and hear each other.
- Click the microphone and camera buttons at the bottom to switch on, or turn off the corresponding devices.
- Click the hang-up button to end the call.
To experiment and learn more, modify the code directly in the editor on the left, and preview the runtime effect on the right.
If CodeSandbox access is slow, try adjusting your network configuration.
Reference
This section contains content that completes the information on this page, or points you to documentation that explains other aspects of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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 an open source sample project on GitHub for your reference. The project demonstrates the use of each component and hook provided by the React SDK, as well as some advanced functions.
API reference
LocalUserRemoteUseruseIsConnected()useJoin()useLocalMicrophoneTrack()usePublish()useRemoteUsers()
See also
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
Prerequisites
-
A camera and a microphone.
-
A valid Agora account and project. See Agora account management for details.
-
Unity Hub and Unity Editor 2018.4.0 or higher.
-
A suitable operating system and compiler for your development platform:
Development platform Operating system version Compiler version Android Android 4.1 or later Android Studio 4.1 or later iOS iOS 10.15 or later Xcode 9.0 or later macOS macOS 10.15 or later Xcode 9.0 or later Windows Windows 7 or later Microsoft Visual Studio 2017 or later
Set up your project
Refer to the following steps or the Official Unity documentation to create a Unity project.
-
Open Unity and click New.
-
Enter the following details:
- Project name : The name of the project.
- Location : Project storage path.
- Template : The project type. Select 3D.
-
Click Create project.
To open your existing project:
-
In the Projects window, click the Open button in the top-right corner.
-
Browse your file manager and select the folder of the project you want to open.
-
Confirm your selection to add the project to the Projects window and open it in the Unity Editor.
Install the SDK
-
Go to the Download SDKs page and download the latest version of the Unity SDK.
-
In Unity Editor, navigate to Assets > Import Package > Custom Package, and select the unzipped SDK.
All plugins are selected by default. Deselect any plugins you don't need, then click Import.
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:
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps.
Before proceeding, create and set up a script to implement Video Calling and bind the script to the canvas.
Steps to set up a script
-
Create a new script and import the UI library.
-
In the Project tab, navigate to Assets > Agora-Unity-RTC-SDK > Code > Rtc, right-click and select Create > C# Script. A new file named
NewBehaviourScript.csappears in your Assets. -
Rename the file to
JoinChannel.csand open it. -
Import the Unity namespaces to access UI components by adding the following code at the top of the file:
using UnityEngine; using UnityEngine.UI;
-
-
Bind the script to the canvas.
In
Assets/Agora-Unity-RTC-SDK/Code/Rtc, select theJoinChannel.csfile, and drag it to the Canvas. In the Inspector panel, ensure that the file is bound to the Canvas.
Import Agora classes
Import the Agora.Rtc namespace, which contains various classes and interfaces required to implement real-time audio and video functions.
using Agora.Rtc;Initialize the engine
For real-time communication, create an IRtcEngine instance using RtcEngine.CreateAgoraRtcEngine(). Then, configure it using Initialize(context) with an RtcEngineContext, specifying the application context, App ID, and channel profile. In your JoinChannel.cs file, add the following code:
internal IRtcEngine RtcEngine;
// Fill in your app ID
private string _appID= "";
private void SetupVideoSDKEngine()
{
// Create an IRtcEngine instance
RtcEngine = Agora.Rtc.RtcEngine.CreateAgoraRtcEngine();
RtcEngineContext context = new RtcEngineContext();
context.appId = _appID;
context.channelProfile = CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_COMMUNICATION;
context.audioScenario = AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_DEFAULT;
// Initialize the instance
RtcEngine.Initialize(context);
}Join a channel
To join a channel, call JoinChannel with the following parameters:
-
Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.
-
Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.
-
User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to
0when joining a channel, the SDK generates a random number for the user ID and returns the value in theOnJoinChannelSuccesscallback. -
Channel media options: Configure
ChannelMediaOptionsto define publishing and subscription settings, optimize performance for your specific use-case, and set optional parameters.
For Video Calling, set the channelProfile to CHANNEL_PROFILE_COMMUNICATION and the clientRoleType to CLIENT_ROLE_BROADCASTER.
// Fill in your channel name
private string _channelName = "";
// Fill in a temporary token
private string _token = "";
public void Join()
{
// Set channel media options
ChannelMediaOptions options = new ChannelMediaOptions();
// Publish the audio stream collected from the microphone
options.publishMicrophoneTrack.SetValue(true);
// Publish the video stream collected from the camera
options.publishCameraTrack.SetValue(true);
// Automatically subscribe to all audio streams
options.autoSubscribeAudio.SetValue(true);
// Automatically subscribe to all video streams
options.autoSubscribeVideo.SetValue(true);
// Set the channel profile to live broadcasting
options.channelProfile.SetValue(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_COMMUNICATION);
// Set the user role to broadcaster
options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
// Join the channel
RtcEngine.JoinChannel(_token, _channelName, 0, options);
}Subscribe to Video SDK events
Create an instance of the UserEventHandler class and set it as the engine event handler. Override the callbacks based on your use-case.
// Implement your own callback class by inheriting from the IRtcEngineEventHandler interface
internal class UserEventHandler : IRtcEngineEventHandler
{
private readonly JoinChannelVideo _videoSample;
internal UserEventHandler(JoinChannelVideo videoSample)
{
_videoSample = videoSample;
}
// Triggered when the local user successfully joins a channel
public override void OnJoinChannelSuccess(RtcConnection connection, int elapsed)
{
}
// Triggered when the SDK receives and successfully decodes the first frame of a remote video
public override void OnUserJoined(RtcConnection connection, uint uid, int elapsed)
{
// Set the display for the remote video
_videoSample.RemoteView.SetForUser(uid, connection.channelId, VIDEO_SOURCE_TYPE.VIDEO_SOURCE_REMOTE);
// Start video rendering
_videoSample.RemoteView.SetEnable(true);
Debug.Log("Remote user joined");
}
// Triggered when the remote user leaves the channel
public override void OnUserOffline(RtcConnection connection, uint uid, USER_OFFLINE_REASON_TYPE reason)
{
// Stop displaying the remote video
_videoSample.RemoteView.SetEnable(false);
}
}Create an instance of the user callback class and call InitEventHandler to register the event handler.
private void InitEventHandler()
{
UserEventHandler handler = new UserEventHandler(this);
RtcEngine.InitEventHandler(handler);
}To ensure that you receive all Video SDK events, register the event handler before joining a channel.
Display the local video
Use the following code to set up the local video view:
internal VideoSurface LocalView;
private void PreviewSelf()
{
// Enable the video module
RtcEngine.EnableVideo();
// Enable local video preview
RtcEngine.StartPreview();
// Set up local video display
LocalView.SetForUser(0, "");
// Render the video
LocalView.SetEnable(true);
}Display remote video
When a remote user joins the channel, the OnUserJoined callback is triggered. Call SetForUser to set the remote video display and call SetEnable(true) to render the video.
internal VideoSurface RemoteView;
// When the SDK receives the first frame of a remote video stream and successfully decodes it, the OnUserJoined callback is triggered.
public override void OnUserJoined(RtcConnection connection, uint uid, int elapsed) {
// Set the remote video display
_videoSample.RemoteView.SetForUser(uid, connection.channelId, VIDEO_SOURCE_TYPE.VIDEO_SOURCE_REMOTE);
// Start video rendering
_videoSample.RemoteView.SetEnable(true);
Debug.Log("Remote user joined");
}Leave the channel
Call LeaveChannel to leave the current channel.
public void Leave() {
Debug.Log("Leaving " + _channelName);
// Leave the channel
RtcEngine.LeaveChannel();
// Disable the video module
RtcEngine.DisableVideo();
// Stop remote video rendering0
RemoteView.SetEnable(false);
// Stop local video rendering
LocalView.SetEnable(false);
}Handle permissions
To access the media devices, add device permissions to your project according to your target platform.
Since version 2018.3, Unity does not actively obtain device permissions from the user. Call CheckPermission to check for and obtain the necessary permissions.
-
Include the
UnityEngine.Androidnamespace, which contains Android-specific classes for interacting with Android devices from Unity:#if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID) using UnityEngine.Android; #endif -
Create a list of permissions to be obtained.
#if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID) private ArrayList permissionList = new ArrayList() { Permission.Camera, Permission.Microphone }; #endif -
Check if the required permissions have been granted. If not, prompt the user to grant the necessary permissions.
private void CheckPermissions() { #if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID) foreach (string permission in permissionList) { if (!Permission.HasUserAuthorizedPermission(permission)) { Permission.RequestUserPermission(permission); } } #endif }
For iOS and macOS platforms, the Video SDK includes a post-build script named BL_BuildPostProcess.cs. When you build and export your Unity project as an iOS project, this script automatically inserts camera and microphone permission entries into the Info.plist file, eliminating the need for manual updates.
Start and stop your client
-
When the client starts, ensure that device permissions have been granted.
void Update() { CheckPermissions(); } -
To start Video Calling, initialize the engine and set up the event handler.
void Start() { SetupVideoSDKEngine(); InitEventHandler(); PreviewSelf(); } -
To clean up all session-related resources when a user exits the client, call the
Disposemethod of theIRtcEngine.void OnApplicationQuit() { if (RtcEngine != null) { Leave(); // Destroy IRtcEngine RtcEngine.Dispose(); RtcEngine = null; } }After calling
Dispose, you can no longer use any methods or callbacks of the SDK. To use Video Calling features again, create a new engine instance.
Complete sample code
A complete code sample demonstrating the basic process of real-time interaction is provided for your reference. To quickly implement the basic functions of real-time Video Calling, copy the following sample code into your project:
Sample code to implement Video Calling in your client
Create a user interface
Follow these steps to set up a basic UI for your project or to integrate essential UI elements into your existing interface. A basic UI consists of the following components:
- Local view window
- Remote view window
- Buttons to join and leave the channel
Create a basic UI
-
Create buttons to join and leave channel
-
In your Unity project, right-click the Sample Scene and select Game Object > UI > Button. You see a button on the scene canvas.
-
In the Inspector panel, rename the button to
Joinand adjust the position coordinates as needed. For example:- Pos X:
-329 - Pos Y:
-172
- Pos X:
-
Select the Text control of the Join button , and change the text to
Joinin the Inspector panel. -
Repeat the steps to create a Leave button, using the following positions:
- Pos X:
329 - Pos Y:
-172
- Pos X:
-
-
Create local and remote view windows
-
Right-click the Canvas and select UI > Raw Image.
-
In the Inspector panel, rename
Raw ImagetoLocalViewand adjust its size and position on the canvas. For example:- PosX:
-250 - Pos Y:
0 - Width:
250 - Height:
250
- PosX:
-
Repeat the above steps to create a remote view window, name it
RemoteView, and adjust its position on the canvas:- PosX:
250 - Pos Y:
0 - Width:
250 - Height:
250
Save the changes.
- PosX:
-
At this point your UI looks similar to the following:
Test the sample code
Take the following steps to test the sample code:
-
Obtain a temporary token from Agora Console.
-
In
JoinChannel.cs, update_appID,_channelName, and_tokenwith the app ID, channel name, and temporary token for your project. -
In Unity Editor, click Play to run your project.
-
Click Join to join a channel.
-
Invite a friend to run the demo client on a second device. Use the same
_appID_,_token, and_channelNameto join. Alternatively, use the Web demo to join the same channel.After your friend joins successfully, you can hear and see each other.
Reference
This section contains content that completes the information on this page, or points you to documentation that explains other aspects of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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
Frequently asked questions
See also
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
Prerequisites
-
A camera and a microphone.
-
A valid Agora account and project. See Agora account management for details.
-
Unreal Engine 4.27 or higher.
-
Prepare your development environment according to your target platform and engine version:
-
Two physical devices for testing.
Set up your project
Refer to the following steps or the Unreal official guide to create a new project. If you already have an Unreal project, skip to the next section.
-
Open Unreal Engine. Select Games under New Project Categories, and click Next.
-
Configure your project as follows:
- Template: Select Blank.
- Project Defaults:
- Language: Select C++.
- Target Platform: Select Desktop.
- Project Location: Enter the project files storage path.
- Project Name: Type a suitable name for your project.
Click Create.
-
In the Unreal Project Browser, click on Browse and locate the
.uprojectfile. -
Select the project and click Open.
-
Add the Agora dependency library
In
Project/Source/Project/Project.Build.cs, add theAgoraPluginusingPublicDependencyModuleNames.AddRange().// Add the AgoraPlugin library PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "AgoraPlugin" }); -
Create a new C++ class and generate header and library files
In the Unreal Editor, select Tools > New C++ Class, then select All Classes, find UserWidget and name it
AgoraWidget. Click Create Class. A new C++ class is added to your project and you seeAgoraWidget.handAgoraWidget.cppfiles. -
Initialize custom Widget
Add the following code to your widget header file:
protected: // Initialize custom Widget void NativeConstruct() override; -
Associate C++ classes and Widgets
In Unreal Editor, click Content Drawer, select Class Settings > Graph, and set the Parent Class under Class Options to AgoraWidget.
-
Create a user interface for your app. Refer to Create a user interface to create a bare bones UI. A basic user interface consists of the following elements:
- Local user video window
- Remote user video window
- Join and leave channel buttons
Install the SDK
Take the following steps to add the Video Calling Video SDK to your project:
- Download the latest version of Agora Unreal Video SDK from Download SDKs and unzip it.
- In your project root folder, create a
Pluginsfolder. - Copy
AgoraPluginfrom the Unreal SDK folder toPlugins.
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:
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps.
Import Agora libraries
To import Agora library, add the following to AgoraWidget.h:
#include "AgoraPluginInterface.h"Initialize the engine
For real-time communication, initialize an IRtcEngine instance and set up an event handler to manage user interactions within the channel. Use RtcEngineContext to specify App ID, and custom event handler, then call RtcEngineProxy->initialize(RtcEngineContext) to initialize the engine, enabling further channel operations.
Add the SetupSDKEngine method declaration and implementation to the following files:
-
AgoraWidget.h// Fill in your app ID FString _appID = ""; // Define a global variable for IRtcEngine agora::rtc::IRtcEngine* RtcEngineProxy; private: // Create and initialize IRtcEngine void SetupSDKEngine(); -
AgoraWidget.cppvoid UAgoraWidget::SetupSDKEngine() { agora::rtc::RtcEngineContext RtcEngineContext; RtcEngineContext.appId = TCHAR_TO_ANSI(*_appID); RtcEngineContext.eventHandler = this; // Create IRtcEngine instance RtcEngineProxy = agora::rtc::ue::createAgoraRtcEngine(); // Initialize IRtcEngine RtcEngineProxy->initialize(RtcEngineContext); }
Join a channel
To join a channel, call joinChannel with the following parameters:
-
Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.
-
Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.
-
User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to
0when joining a channel, the SDK generates a random number for the user ID and returns the value in theonJoinChannelSuccesscallback. -
Channel media options: Configure
ChannelMediaOptionsto define publishing and subscription settings, optimize performance for your specific use-case, and set optional parameters.
Add the Join method declaration and implementation to the following files:
-
AgoraWidget.h// Fill in your channel name FString _channelName = ""; // Fill in a valid token FString _token = ""; UFUNCTION(BlueprintCallable) void Join(); UFUNCTION(BlueprintCallable) void Leave(); -
AgoraWidget.cppFor Video Calling, set the
channelProfiletoCHANNEL_PROFILE_COMMUNICATIONand the user role toCLIENT_ROLE_BROADCASTER.void UAgoraWidget::Join() { // Enable the video module RtcEngineProxy->enableVideo(); // Set channel media options agora::rtc::ChannelMediaOptions options; // Automatically subscribe to all audio streams options.autoSubscribeAudio = true; // Automatically subscribe to all video streams options.autoSubscribeVideo = true; // Publish video captured by the camera options.publishCameraTrack = true; // Publish audio captured by the microphone options.publishMicrophoneTrack = true; // Set the channel profile to live broadcasting options.channelProfile = agora::CHANNEL_PROFILE_TYPE::CHANNEL_PROFILE_COMMUNICATION; // Set the user role as host or audience options.clientRoleType = agora::rtc::CLIENT_ROLE_TYPE::CLIENT_ROLE_BROADCASTER; // Join a channel RtcEngineProxy->joinChannel(TCHAR_TO_ANSI(*_token), TCHAR_TO_ANSI(*_channelName), 0, options); }
Subscribe to Video SDK events
The Video SDK provides an interface for subscribing to channel events. To use it, inherit from the IRtcEngineEventHandler class and override the event handler methods for the events you want to process.
-
AgoraWidget.h// Triggered when the local user leaves a channel void onLeaveChannel(const agora::rtc::RtcStats& stats) override; // Triggered when a remote user joins a channel void onUserJoined(agora::rtc::uid_t uid, int elapsed) override; // Triggered when a remote user leaves a channel void onUserOffline(agora::rtc::uid_t uid, agora::rtc::USER_OFFLINE_REASON_TYPE reason) override; // Triggered when the local user joins a channel void onJoinChannelSuccess(const char* channel, agora::rtc::uid_t uid, int elapsed) override; -
AgoraWidget.cpp// Implement the callback triggered after a remote user joins the channel void UAgoraWidget::onUserJoined(agora::rtc::uid_t uid, int elapsed) { // Set up remote video agora::rtc::VideoCanvas videoCanvas; videoCanvas.view = RemoteVideo; videoCanvas.uid = uid; videoCanvas.sourceType = agora::rtc::VIDEO_SOURCE_TYPE::VIDEO_SOURCE_REMOTE; agora::rtc::RtcConnection connection; connection.channelId = TCHAR_TO_ANSI(*_channelName); ((agora::rtc::IRtcEngineEx*)RtcEngineProxy)->setupRemoteVideoEx(videoCanvas, connection); } // Implement the callback triggered when a remote user leaves the channel void UAgoraWidget::onUserOffline(agora::rtc::uid_t uid, agora::rtc::USER_OFFLINE_REASON_TYPE reason) { // Stop remote video agora::rtc::VideoCanvas videoCanvas; videoCanvas.view = nullptr; videoCanvas.uid = uid; videoCanvas.sourceType = agora::rtc::VIDEO_SOURCE_TYPE::VIDEO_SOURCE_REMOTE; agora::rtc::RtcConnection connection; connection.channelId = TCHAR_TO_ANSI(*_channelName); ((agora::rtc::IRtcEngineEx*)RtcEngineProxy)->setupRemoteVideoEx(videoCanvas, connection); } // Implement the callback triggered when the local user joins the channel void UAgoraWidget::onJoinChannelSuccess(const char* channel, agora::rtc::uid_t uid, int elapsed) { AsyncTask(ENamedThreads::GameThread, [=]() { UE_LOG(LogTemp, Warning, TEXT("JoinChannelSuccess uid: %u"), uid); // Set up local video agora::rtc::VideoCanvas videoCanvas; videoCanvas.view = LocalVideo; videoCanvas.uid = 0; videoCanvas.sourceType = agora::rtc::VIDEO_SOURCE_TYPE::VIDEO_SOURCE_CAMERA; RtcEngineProxy->setupLocalVideo(videoCanvas); }); } // Implement the callback triggered when the local user leaves the channel void UAgoraWidget::onLeaveChannel(const agora::rtc::RtcStats& stats) { AsyncTask(ENamedThreads::GameThread, [=]() { agora::rtc::VideoCanvas videoCanvas; videoCanvas.view = nullptr; videoCanvas.uid = 0; videoCanvas.sourceType = agora::rtc::VIDEO_SOURCE_TYPE::VIDEO_SOURCE_CAMERA; RtcEngineProxy->setupLocalVideo(videoCanvas); }); }
Handle permissions
To access the media devices, follow the steps for your target platform:
Add the AndroidPermission library to obtain device and network permissions:
-
Add the following code to your header file:
#if PLATFORM_ANDROID #include "AndroidPermission/Classes/AndroidPermissionFunctionLibrary.h" #endif -
Add the
AndroidPermissionlibrary to theProject/Source/Project/Project.Build.csfile:if (Target.Platform == UnrealTargetPlatform.Android) { PrivateDependencyModuleNames.AddRange(new string[] { "AndroidPermission" }); } -
To check whether Android permissions have been granted, add the
CheckAndroidPermissionmethod and its implementation to theAgoraWidget.handAgoraWidget.cppfiles.AgoraWidget.h
private:
// Get Android permissions
void CheckAndroidPermission();AgoraWidget.cpp
void UAgoraWidget::CheckAndroidPermission()
{
#if PLATFORM_ANDROID
FString pathfromName = UGameplayStatics::GetPlatformName();
if (pathfromName == "Android")
{
TArray<FString> AndroidPermission;
AndroidPermission.Add(FString("android.permission.CAMERA"));
AndroidPermission.Add(FString("android.permission.RECORD_AUDIO"));
AndroidPermission.Add(FString("android.permission.READ_PHONE_STATE"));
AndroidPermission.Add(FString("android.permission.WRITE_EXTERNAL_STORAGE"));
AndroidPermission.Add(FString("android.permission.ACCESS_WIFI_STATE"));
AndroidPermission.Add(FString("android.permission.ACCESS_NETWORK_STATE"));
UAndroidPermissionFunctionLibrary::AcquirePermissions(AndroidPermission);
}
#endif
}
void UAgoraWidget::NativeConstruct()
{
Super::NativeConstruct();
#if PLATFORM_ANDROID
CheckAndroidPermission()
#endif
}-
Refer to How to add the permissions required for real-time interaction to an Unreal Engine project?
-
In
Project/Source/Project.Target.cs, add the following code:public class unrealstartTarget : TargetRules { public unrealstartTarget( TargetInfo Target) : base(Target) { Type = TargetType.Game; DefaultBuildSettings = BuildSettingsVersion.V2; if (Target.Platform == UnrealTargetPlatform.IOS) { bOverrideBuildEnvironment = true; GlobalDefinitions.Add("FORCE_ANSI_ALLOCATOR=1") } ExtraModuleNames.AddRange( new string[] { "unrealstart" } ); } }
Display the local video
Display the local video.
AsyncTask(ENamedThreads::GameThread, =
{
UE_LOG(LogTemp, Warning, TEXT("JoinChannelSuccess uid: %u"), uid);
agora::rtc::VideoCanvas videoCanvas;
videoCanvas.view = LocalVideo;
videoCanvas.uid = 0;
videoCanvas.sourceType = agora::rtc::VIDEO_SOURCE_TYPE::VIDEO_SOURCE_CAMERA;
RtcEngineProxy->setupLocalVideo(videoCanvas);
});Display remote video
When a remote user joins the channel, display their video.
// Set up remote video
agora::rtc::VideoCanvas videoCanvas;
videoCanvas.view = RemoteVideo;
videoCanvas.uid = uid;
videoCanvas.sourceType = agora::rtc::VIDEO_SOURCE_TYPE::VIDEO_SOURCE_REMOTE;
agora::rtc::RtcConnection connection;
connection.channelId = TCHAR_TO_ANSI(*_channelName);
((agora::rtc::IRtcEngineEx*)RtcEngineProxy)->setupRemoteVideoEx(videoCanvas, connection);Leave a channel
To leave a channel call leaveChannel. Implement the following method:
-
AgoraWidget.hUFUNCTION(BlueprintCallable) void Leave(); -
AgoraWidget.cppvoid UAgoraWidget::Leave() { // Leave the channel RtcEngineProxy->leaveChannel(); }
Release resources
When the local user leaves the channel, or exits the client, release memory by calling the release method of IRtcEngine. Override the NativeDestruct() method and add its implementation as follows:
-
AgoraWidget.hvoid NativeDestruct() override; -
AgoraWidget.cppvoid UAgoraWidget::NativeDestruct() { Super::NativeDestruct(); if (RtcEngineProxy != nullptr) { RtcEngineProxy->unregisterEventHandler(this); RtcEngineProxy->release(); delete RtcEngineProxy; RtcEngineProxy = nullptr; } }
Complete sample code
A complete code sample demonstrating the basic process of real-time interaction is provided for your reference. To use the sample code, copy each of the following code blocks and paste it in the corresponding file.
Project/Source/Project/AgoraWidget.h
Create a user interface
Follow these steps to set up a basic UI for your project or to integrate essential UI elements into your existing interface.
Create a basic UI
-
Create a Widget Blueprint.
In Unreal Editor, click Content Drawer > Content, right-click and select User Interface > Widget Blueprint. Name the new Widget Blueprint AgoraWidget and double-click it to open.
-
Create a view canvas.
Select Palette > PANEL > Canvas Panel and drag it to AgoraWidget.
-
Create join and leave channel buttons in Widget Blueprint.
-
In AgoraWidget, select COMMON > Button, drag it to the Canvas Panel, and rename it to JoinBtn. Adjust the button's size and position on the canvas or use the following sample settings:
- Position X:
300 - Position Y:
700 - Size X:
240 - Size Y:
120
- Position X:
-
Select COMMON > Text and drag it to JoinBtn. Select the Text control of JoinBtn, and change the text content of Text to Join in the Details panel.
-
Repeat the above steps to create a LeaveBtn. Adjust the button size and position according to your layout design.
-
-
Create local and remote views in the Widget Blueprint.
-
Select COMMON > Image, drag it to the Canvas Panel, and rename it LocalVideo. Adjust its position and size on the canvas. Use the following values, or specify as per your own layout design:
- Position X:
350 - Position Y:
150 - Size X:
450 - Size Y:
450
- Position X:
-
Repeat the above steps to create a remote view and name it RemoteVideo. Adjust its position and size on the canvas. Use the following values, or specify as per your own layout design:
- Position X:
1200 - Position Y:
150 - Size X:
450 - Size Y:
450
- Position X:
-
-
Save the changes. Your user interface in Widget Blueprint looks similar to the following:
-
Create a Level Blueprint and associate it with the created Widget Blueprint.
-
In Unreal Editor, click Content Drawer, right-click to select Level, and name it agoraLevel.
-
Double-click to open agoraLevel and click Open Level Blueprint.
-
Right-click and enter Create Widget in the search box. Select the created AgoraWidget, then create Event BeginPlay and Add to Viewport in the same way. Connect them as follows:
-
Save your changes and run the project. The UI you have created looks similar to the following:
-
Test the sample code
Take the following steps to test the sample code:
-
Obtain a temporary token from Agora Console.
-
In
AgoraWidget.h, update_appID,_channelName, and_tokenwith the app ID, channel name, and temporary token for your project. -
In the Unreal Editor, click the play button to run your project, then click Join to join a channel.
-
Invite a friend to run the demo client on a second device. Alternatively, use the Web demo to join the same channel.
After your friend joins successfully, you can hear and see each other.
Reference
This section contains content that completes the information on this page, or points you to documentation that explains other aspects of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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.
To learn about Agora Unreal Blueprint development, refer to the Unreal (Blueprint) Quickstart.
API reference
Frequently asked questions
See also
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
To start a Video Calling session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Send and receive audio and video: All users can publish streams to the channel and subscribe to audio and video streams published by other users in the channel.
Prerequisites
-
A camera and a microphone.
-
A valid Agora account and project. See Agora account management for details.
-
Unreal Engine 4.27 or higher.
-
Prepare your development environment according to your target platform and engine version:
-
Two physical devices for testing.
Set up your project
Refer to the following steps or the Unreal official guide to create a new project. If you already have an Unreal project, skip to the next section.
-
Open Unreal Engine. Select Games under New Project Categories, and click Next.
-
Configure your project as follows:
- Template: Select Blank.
- Project Defaults:
- Language: Select Blueprint.
- Target Platform: Pick Desktop.
- Project Location: Enter a project files storage path.
- Project Name: Type a suitable name for your project.
Click Create.
-
In the Unreal Project Browser, click on Browse and locate the
.uprojectfile. -
Select the project and click Open.
Install the SDK
Take the following steps to add the Video Calling Video SDK to your project:
- Download the latest version of Agora Unreal Video SDK from Download SDKs and unzip it.
- In your project root folder, create a
Pluginsfolder. - Copy
AgoraPluginfrom the Unreal SDK folder toPlugins.
Implement Video Calling
This section guides you through the implementation of basic real-time audio and video interaction in your app.
Create a level
-
In the Content folder of the Content Browser, right-click and select Level to create a Level Blueprint and name it BasicVideoCallScene.
-
Double-click BasicVideoCallScene and click Blueprints > Open Level Blueprint above the editor to open the level blueprint.
Implement basic processes
In the My Blueprint panel, double-click Graphs > EventGraph to open the event graph. You see two event nodes: Event BeginPlay (game starts) and Event End Play (game ends). Create event nodes with the corresponding functions and variables, and connect them as shown in the following figure to implement the Video Calling logic:
The following table lists the main nodes:
| # | Node | Type | Description |
|---|---|---|---|
| 1 | Set Show Mouse Cursor | Native* | (Optional) Set whether to display the mouse cursor. Check to display it. Information
|
| 2 | Load Agora Config | Custom** | Loads Agora configuration. Used to verify user identity when creating and joining channels. |
| 3 | Create BP Video Widget | Native | Create user interface:
|
| 4 | Set Basic Video Call Widget | Custom | Set up the user interface:
|
| 5 | BindUIEvent | Custom | Use Bind UI events to handle event logic after clicking the Join Channel and Leave Channel buttons. |
| 6 | Add to Viewport | Native | Add user interface to the viewport. |
| 7 | Check Permission | Custom | (Optional) Check whether you have obtained the system permissions required for real-time audio and video interaction, such as access to the camera and microphone. Note If your target platform is Android, create this node to check system permissions. |
| 8 | Init Rtc Engine | Custom | Create and initialize the RTC engine. |
| 9 | Un Init Rtc Engine | Custom | Leave the channel and release resources. |
* Native nodes are nodes that come with the blueprint and can be added and called directly.
** Custom nodes are not included in the blueprint. You create a custom function before you can add the corresponding node.
Add channel-related variables
Add variables to create an engine instance and join a channel.
-
Create three variables:
Token, ChannelId, and AppId. Select the Variable Type as String.
-
In the Load Agora Config function, add the Sequence node, and then connect Set Token, Set Channel Id, and Set App Id respectively. Fill in the token, channel name, and app ID values obtained from Agora Console.
Initialize RTC engine
-
If your target platform is Android, check whether system permissions have been granted before initializing the RTC engine. Refer to the following figure to create nodes for adding permissions to access the microphone and camera in the CheckPermission function.
Information
If your target platform is macOS or iOS, please refer to How do I add the permissions needed for real-time interaction to my Unreal Engine project?
-
To initialize the RTC engine, in the InitRtcEngine function, create and connect nodes as shown in the following figure:
-
Create
IRtcEngineandIRtcEngineEventHandler.-
To store references to the engine and event-handler interface classes, create
RtcEngineandEventHandlervariables, and set the Variable Type to Agora Rtc Engine and IRtc Engine Event Handler, respectively. -
Add two Construct Object From Class nodes, set Class to Agora Rtc Engine and IRtc Engine Event Handler respectively. Connect to Set Rtc Engine and Set Event Handler, respectively.
-
-
Bind
IRtcEngineEventHandlerclass-related callback functions.-
Create
onJoinChannelSuccess,onLeaveChannel,onUserJoined, andonUserOfflinecallback functions. Refer to the following table to configure the input parameters of the callbacks:Callback Description Input parameters FOnJoinChannelSuccessThe local user successfully joined a channel. channel: (String) Channel name.uid: (Integer64) The ID of the user joining the channel.elapsed: (Integer) The time (in milliseconds) that elapsed from the local call toJoinChanneltill the occurrence of this event.
FOnLeaveChannelThe local user left the channel. - stats: Call statistics.FOnUserJoinedA remote user joined the current channel. uid: (Integer64) The user ID of the remote user joining the channel.elapsed: (Integer) The time (in milliseconds) that elapsed from the local call toJoinChanneltill the occurrence of this event.
FOnUserOfflineA remote user left the current channel. uid: (Integer64) The ID of the user going offline.reason: Offline reason. For details, seeEUSER_OFFLINE_REASON_TYPE.
-
Create a Bind Event function. In this function, add a Sequence node, and then bind the
onJoinChannelSuccess,onLeaveChannel,onUserJoined, andonUserOfflinecallback events.
-
-
IRtcEngineinitialization-
Call Initialize to initialize the RTC engine.
-
Connect to the RtcEngineContext configuration
IRtcEngineinstance and select Channel Profile asCHANNEL_PROFILE_COMMUNICATION.
-
Bind UI events
To bind UI events:
-
Create and implement the
OnJoinChannelClickedevent callback.- Call Enable Video and Enable Audio to enable the video and audio modules.
- Call Join Channel to join the channel.
- Set the following parameters in Make ChannelMediaOptions:
- Set Publish Camera Track to
AGORA TRUE VALUEto publish the video stream recorded by the camera. - Set Publish Microphone Track to
AGORA TRUE VALUEto publish the audio stream recorded by the microphone. - Set Auto Subscribe Video to
AGORA TRUE VALUEto automatically subscribe to all video streams. - Set Auto Subscribe Audio to
AGORA TRUE VALUEto automatically subscribe to all audio streams. - Check Client Role Type Set Value and set Client Role Type to
CLIENT_ROLE_BROADCASTERorCLIENT_ROLE_AUDIENCE, to set the user role to host or audience. - Check Channel Profile Set Value and set Channel Profile to
CHANNEL_PROFILE_LIVE_BROADCASTING.
- Set Publish Camera Track to
-
Create and implement the
OnLeaveChannelClickedevent callback. When the event is triggered, call Leave Channel to leave the channel. -
In the Bind UIEvent function, refer to the figure below to bind the
OnJoinChannelClickedandOnLeaveChannelClickedcallback functions to the Join Channel and Leave Channel buttons respectively. When the button is clicked, the corresponding event callback is triggered.
Information
You can also bind UI events in Unreal Motion Graphics (UMG). This document only shows binding using the Bind UIEvent Function.
Set up local and remote views
-
Create and implement the MakeVideoView function to load the view when local or remote users join the channel:
- In this function, create
SavedUID,SavedSourceType,SavedChannelIDlocal variables, set the Variable Type toInteger64,VIDEO_SOURCE_TYPE, andString, respectively. Save the variables for use when loading the view later. - Create a local view. In the local view, if the UID is 0, a value is randomly assigned by the SDK, and the video source type is
VIDEO_SOURCE_CAMERA_PRIMARY(the first camera). - Create a remote view. In the remote view, the
uidis the uid sent from the remote end, and the video source type isVIDEO_SOURCE_REMOTE(remote video obtained from the network).
- In this function, create
-
Create and implement the ReleaseVideoView function to release the view when a local or remote user leaves the channel.
- In this function, create
SavedUID,SavedSourceType, andSavedChannelIDlocal variables, set the Variable Type toInteger64,VIDEO_SOURCE_TYPE, andString, respectively. Save the variables for use when releasing the view later. - Release the local view.
- Release the remote view.
- In this function, create
Implement callback function
Configure the previously created onJoinChannelSuccess, onLeaveChannel, onUserJoined, and onUserOffline callback functions as follows:
-
After the local user successfully joins the channel, the
onJoinChannelSuccesscallback is triggered and the local view is created. Theuidis set to0by default, but it is assigned a random value by the SDK. The video source type isVIDEO_SOURCE_CAMERA_PRIMARY(first camera): -
After the local user leaves the channel, the
onLeaveChannelcallback is triggered which releases the local view: -
When a remote user joins the channel, the
onUserJoinedcallback is triggeredd to create a remote view.uidis the uid sent from the remote end, and the video source type isVIDEO_SOURCE_REMOTE(remote video obtained from the network): -
When a remote user leaves the channel, the
onUserOfflinecallback is triggered to release the remote view:
Leave the channel and release resources
To leave the channel, implement the following steps:
- Leave the channel.
- Unregister Agora backend event callback.
- Destroy
IRtcEngineObjectto release all resources used by Agora SDK.
Refer to the figure below to implement the UnInitRtcEngine function:
Test the sample code
Take the following steps to test the sample code:
-
In the Load Agora Config function, fill in the app ID, channel name, and temporary token for your project.
-
In the Unreal Editor, click Play to run your project. Click JoinChannel to join a channel.
-
Invite a friend to run the demo client on a second device. Use the same app ID, channel name, and token to join. After your friend joins successfully, you can hear and see each other.
Reference
This section contains content that completes the information on this page, or points you to documentation that explains other aspects of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
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.
Frequently asked questions
- How can I listen for audience joining or leaving a channel?
- How can I fix black screen issues?
- Why can't I turn on the camera?
- How can I solve channel-related issues?
- How can I set the log file?
