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

Quickstart

This page provides a step-by-step guide on how to create a basic Video Calling app using the Agora Video SDK.

Understand the tech

To start a Video Calling session, implement the following steps in your app:

  • Initialize the Agora Engine: Before calling other APIs, create and initialize an Agora 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.

Video calling workflow

Prerequisites

  • Unity Hub and Unity Editor 2018.4.0 or higher

  • A suitable operating system and compiler for your development platform:

    Development platformOperating system versionCompiler version
    AndroidAndroid 4.1 or laterAndroid Studio 4.1 or later
    iOSiOS 10.15 or laterXcode 9.0 or later
    macOSmacOS 10.15 or laterXcode 9.0 or later
    WindowsWindows 7 or laterMicrosoft Visual Studio 2017 or later
  • A camera and a microphone

Set up your project

This section shows you how to set up your Unity project and install the Agora Video SDK.

Refer to the following steps or the Official Unity documentation to create a Unity project.

  1. Open Unity and click New.

  2. Enter the following details:

    • Project name : The name of the project.
    • Location : Project storage path.
    • Template : The project type. Select 3D.
  3. Click Create project.

Install the SDK

  1. Go to the Download SDKs page and download the latest version of the Unity SDK.

  2. 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 game.

The following figure illustrates the essential steps:

Quick start sequence

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
  1. Create a new script and import the UI library.

    1. 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.cs appears in your Assets.

    2. Rename the file to JoinChannel.cs and open it.

    3. Import the Unity namespaces to access UI components by adding the following code at the top of the file:

      using UnityEngine;
      using UnityEngine.UI;
      Copy
  2. Bind the script to the canvas.

    In Assets/Agora-Unity-RTC-SDK/Code/Rtc , select the JoinChannel.cs file, 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;
Copy

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);
}
Copy

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 0 when joining a channel, the SDK generates a random number for the user ID and returns the value in the OnJoinChannelSuccess callback.

  • Channel media options: Configure ChannelMediaOptions to 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);
}
Copy

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);
}
}
Copy

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);
}
Copy
info

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);
}
Copy

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");
}
Copy

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);
}
Copy

Handle permissions

To access the camera and microphone, 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.

  1. Include the UnityEngine.Android namespace, which contains Android-specific classes for interacting with Android devices from Unity:

    #if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID)
    using UnityEngine.Android;
    #endif
    Copy
  2. 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
    Copy
  3. 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
    }
    Copy

Start and stop your game

  1. When the game starts, ensure that device permissions have been granted.

    void Update() {
    CheckPermissions();
    }
    Copy
  2. To start Video Calling, initialize the engine and set up the event handler.

    void Start()
    {
    SetupVideoSDKEngine();
    InitEventHandler();
    PreviewSelf();
    }
    Copy
  3. To clean up all session-related resources when a user exits the game, call the Dispose method of the IRtcEngine.

    void OnApplicationQuit() {
    if (RtcEngine != null) {
    Leave();
    // Destroy IRtcEngine
    RtcEngine.Dispose();
    RtcEngine = null;
    }
    }
    Copy
    info

    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 game
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using Agora.Rtc;#if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID)using UnityEngine.Android;#endifpublic class JoinChannelVideo : MonoBehaviour{    // Fill in your app ID    private string _appID= "";    // Fill in your channel name    private string _channelName = "";    // Fill in your Token    private string _token = "";    internal VideoSurface LocalView;    internal VideoSurface RemoteView;    internal IRtcEngine RtcEngine;    #if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID)    private ArrayList permissionList = new ArrayList() { Permission.Camera, Permission.Microphone };    #endif    void Start()    {        SetupVideoSDKEngine();        InitEventHandler();        SetupUI();        PreviewSelf();    }    void Update()    {        CheckPermissions();    }    void OnApplicationQuit()    {        if (RtcEngine != null)        {            Leave();            // Destroy IRtcEngine            RtcEngine.Dispose();            RtcEngine = null;        }    }    private void CheckPermissions() {    #if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID)            foreach (string permission in permissionList)            {                if (!Permission.HasUserAuthorizedPermission(permission))                {                    Permission.RequestUserPermission(permission);                }            }    #endif    }    private void PreviewSelf()    {        // Enable video module        RtcEngine.EnableVideo();        // Start local video preview        RtcEngine.StartPreview();        // Set local video display        LocalView.SetForUser(0, "");        // Start rendering video        LocalView.SetEnable(true);    }    private void SetupUI()    {        GameObject go = GameObject.Find("LocalView");        LocalView = go.AddComponent<VideoSurface>();        go.transform.Rotate(0.0f, 0.0f, -180.0f);        go = GameObject.Find("RemoteView");        RemoteView = go.AddComponent<VideoSurface>();        go.transform.Rotate(0.0f, 0.0f, -180.0f);        go = GameObject.Find("Leave");        go.GetComponent<Button>().onClick.AddListener(Leave);        go = GameObject.Find("Join");        go.GetComponent<Button>().onClick.AddListener(Join);    }    private void SetupVideoSDKEngine()    {        // Create IRtcEngine instance        RtcEngine = Agora.Rtc.RtcEngine.CreateAgoraRtcEngine();        RtcEngineContext context = new RtcEngineContext();            context.appId = _appID;            context.channelProfile = CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING;            context.audioScenario = AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_DEFAULT;        // Initialize IRtcEngine        RtcEngine.Initialize(context);    }    // Create an instance of the user callback class and set the callback    private void InitEventHandler()    {        UserEventHandler handler = new UserEventHandler(this);        RtcEngine.InitEventHandler(handler);    }    public void Join()    {        // Set channel media options        ChannelMediaOptions options = new ChannelMediaOptions();        // Start video rendering        LocalView.SetEnable(true);        // Publish microphone audio stream        options.publishMicrophoneTrack.SetValue(true);        // Publish camera video stream        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_LIVE_BROADCASTING);        // Set the user role to broadcaster        options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);        // Join the channel        RtcEngine.JoinChannel(_token, _channelName, 0, options);    }    public void Leave()    {        Debug.Log("Leaving _channelName");        // Disable video module        RtcEngine.StopPreview();        // Leave the channel        RtcEngine.LeaveChannel();        // Stop remote video rendering        RemoteView.SetEnable(false);    }    // Implement your own callback class by inheriting from the IRtcEngineEventHandler interface class    internal class UserEventHandler : IRtcEngineEventHandler    {        private readonly JoinChannelVideo _videoSample;        internal UserEventHandler(JoinChannelVideo videoSample)        {            _videoSample = videoSample;        }        // Callback triggered when an error occurs        public override void OnError(int err, string msg)        {        }        // Callback triggered when the local user successfully joins the channel        public override void OnJoinChannelSuccess(RtcConnection connection, int elapsed)        {        }        // OnUserJoined callback is triggered when the SDK receives and successfully decodes the first frame of remote video        public override void OnUserJoined(RtcConnection connection, uint uid, int elapsed)        {            // Set 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");        }        // Callback triggered when a remote user leaves the current channel        public override void OnUserOffline(RtcConnection connection, uint uid, USER_OFFLINE_REASON_TYPE reason)        {            _videoSample.RemoteView.SetEnable(false);            Debug.Log("Remote user offline");        }    }}

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
  1. Create buttons to join and leave channel

    1. In your Unity project, right-click the Sample Scene and select Game Object > UI > Button. You see a button on the scene canvas.

    2. In the Inspector panel, rename the button to Join and adjust the position coordinates as needed. For example:

      • Pos X-329
      • Pos Y: -172
    3. Select the Text control of the Join button , and change the text to Join in the Inspector panel.

    4. Repeat the steps to create a Leave button, using the following positions:

      • Pos X329
      • Pos Y: -172
  1. Create local and remote view windows

    1. Right-click the Canvas and select UI > Raw Image.

    2. In the Inspector panel, rename Raw Image to LocalView and adjust its size and position on the canvas. For example:

      • PosX-250
      • Pos Y: 0
      • Width: 250
      • Height: 250
    3. Repeat the above steps to create a remote view window, name it RemoteView , and adjust its position on the canvas:

      • PosX250
      • Pos Y: 0
      • Width: 250
      • Height: 250

      Save the changes.

At this point your UI looks similar to the following:

Test the sample code

Take the following steps to test the sample code:

  1. Obtain a temporary token from Agora Console.

  2. In JoinChannel.cs, update _appID, _channelName, and _token with the app ID, channel name, and temporary token for your project.

  3. In Unity Editor, click Play to run your project.

  4. Click Join to join a channel.

  5. Invite a friend to run the demo game on a second device. Use the same _appID_, _token, and _channelName to 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 to 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.

Video Calling