This tutorial enables you to quickly get started with using a sample app to develop requests to the Agora Gaming SDK in Unity 3D.
This sample app demonstrates the basic Agora SDK feature:
- Agora.io Developer Account
- Unity 3D 5.5+
This section shows you how to prepare and build the Agora React Native wrapper for the sample app.
To build and run the sample application you must obtain an App ID:
- Create a developer account at agora.io. Once you finish the signup process, you will be redirected to the Dashboard.
- Navigate in the Dashboard tree on the left to Projects > Project List.
- Copy the App ID that you obtained from the Dashboard into a text file. You will use this when you launch the app.
-
Edit the
Assets/HelloUnityVideo.cs
file. In theHelloUnityVideo
class declaration, update#YOUR APP ID#
with your App ID.private static string appId = #YOUR APP ID#;
-
Download the Agora Gaming SDK for Unity 3D.
-
Unzip the downloaded SDK package and copy the files from the following SDK folders into the associated sample application folders.
SDK Folder | Application Folder |
---|---|
libs/Android/ |
Assets/Plugins/Android/ |
libs/iOS/ |
Assets/Plugins/iOS/ |
libs/Scripts/AgoraGamingSDK/ |
Assets/Scripts/AgoraGamingSDK/ |
- Open the project in Unity and run the sample application.
The sample application is comprised of two main classes, HelloUnityVideo
and Home
.
The sample application consists of two main Unity scenes.
When you load SceneHelloVideo
in Unity, you'll see that the stage contains a cylindrical object and a cube object.
The scene also contains a Leave button.
Note: You may have to zoom out and adjust the camera view to see the Leave button in the stage.
When you load SceneHome
in Unity, you will see the stage contains:
UI object | Description |
---|---|
Text object | Explanation text for the user to read |
Text input box | Text input box for the user to enter the channel name |
Join button | Button to join the channel |
Note: You may have to zoom out and adjust the camera view to see the leave button in the stage.
The HelloUnityVideo
class is a subclass of MonoBehaviour
. The HelloUnityVideo.cs
file contains the relevant Agora SDK code for the Unity 3D sample application.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using agora_gaming_rtc;
using UnityEngine.UI;
public class HelloUnityVideo : MonoBehaviour {
...
}
The remaining code in this section is contained within the HelloUnityVideo
class declaration.
- Declare Global Variables
- Load / Unload Engine Methods
- Join / Leave Channel Methods
- Create General Event Listeners
- Create User Event Listeners
The HelloUnityVideo
class has three global variables and one method that acts as a declaration for the SDK version constant.
The appId
variable is initialized with the Agora App ID from your Agora Dashboard.
Note: #YOUR APP ID#
must be replaced with a valid Agora App ID.
// PLEASE KEEP THIS App ID IN SAFE PLACE
// Get your App ID at https://dashboard.agora.io/.
// After you entered the App ID, remove ## outside of Your App ID.
private static string appId = #YOUR APP ID#;
Declare the mRtcEngine
variable, which represents the Agora RTC engine for the application.
Initialize mRemotePeer
to 0
which will track the index of the current remove user for the application.
// instance of agora engine
public IRtcEngine mRtcEngine;
// implement engine callbacks
public uint mRemotePeer = 0; // insignificant. only record one peer
The getSdkVersion()
method returns the SDK version from the Agora RTC engine using IRtcEngine.GetSdkVersion()
.
public string getSdkVersion () {
return IRtcEngine.GetSdkVersion ();
}
The HelloUnityVideo
class has two methods for loading / unloading the Agora RTC engine.
The loadEngine()
method initializes the Agora RTC engine.
-
Set debugging logs for the method initialization and if
mRtcEngine
is notnull
. IfmRtcEngine
exists, execute areturn
as the RTC engine has already been initialized. -
Initialize the engine with the
appId
usingIRtcEngine.getEngine()
. -
Enable Agora logging by setting the following log filters using
mRtcEngine.SetLogFilter()
.
Filter | Description |
---|---|
LOG_FILTER.DEBUG |
Sets the Agora debugging logs |
LOG_FILTER.INFO |
Sets the Agora information logs |
LOG_FILTER.WARNING |
Sets the Agora warning logs |
LOG_FILTER.ERROR |
Sets the Agora error logs |
LOG_FILTER.CRITICAL |
Sets the Agora critical error logs |
// load agora engine
public void loadEngine()
{
// start sdk
Debug.Log ("initializeEngine");
if (mRtcEngine != null) {
Debug.Log ("Engine exists. Please unload it first!");
return;
}
// init engine
mRtcEngine = IRtcEngine.getEngine (appId);
// enable log
mRtcEngine.SetLogFilter (LOG_FILTER.DEBUG | LOG_FILTER.INFO | LOG_FILTER.WARNING | LOG_FILTER.ERROR | LOG_FILTER.CRITICAL);
}
The unloadEngine()
method destroys the Agora RTC engine.
-
Set debugging logs for the method initialization.
-
Ensure
mRtcEngine
is notnull
before destroying the engine usingIRtcEngine.Destroy()
and settingmRtcEngine
tonull
.
// unload agora engine
public void unloadEngine()
{
Debug.Log ("calling unloadEngine");
// delete
if (mRtcEngine != null) {
IRtcEngine.Destroy ();
mRtcEngine = null;
}
}
The HelloUnityVideo
class has two methods to manage joining and leaving a channel.
The join()
method joins the user to the specified channel
, sets event listeners, and configures the Agora RTC engine settings.
-
Set a debug log for the
channel
name usingDebug.Log()
and ensuremRtcEngine
is notnull
before executing the remaining code for the method. -
Set the following callbacks for
mRtcEngine
:Note: These callbacks are optional for the sample application, but are useful for extending the functionality of the application.
Event Listener | Method Value | Description |
---|---|---|
OnJoinChannelSuccess |
onJoinChannelSuccess |
Detects when the channel is successfully joined. |
OnUserJoined |
onUserJoined |
Detects when a user successfully joins the channel. |
OnUserOffline |
onUserOffline |
Detects when a user goes offline. |
-
Enable video and set its callback using
mRtcEngine.EnableVideo()
andmRtcEngine.EnableVideoObserver()
. -
Join the channel using
mRtcEngine.JoinChannel()
. -
Set a debug log for the method completion using
Debug.Log()
.
public void join(string channel)
{
Debug.Log ("calling join (channel = " + channel + ")");
if (mRtcEngine == null)
return;
// set callbacks (optional)
mRtcEngine.OnJoinChannelSuccess = onJoinChannelSuccess;
mRtcEngine.OnUserJoined = onUserJoined;
mRtcEngine.OnUserOffline = onUserOffline;
// enable video
mRtcEngine.EnableVideo();
// allow camera output callback
mRtcEngine.EnableVideoObserver();
// join channel
mRtcEngine.JoinChannel(channel, null, 0);
Debug.Log ("initializeEngine done");
}
The leave()
method exits the user to the current channel.
-
Set a debug log to track the method call using
Debug.Log()
and ensuremRtcEngine
is notnull
before executing the remaining code for the method. -
Leave the channel using
mRtcEngine.LeaveChannel()
. -
Unregister the frame observers using
mRtcEngine.DisableVideoObserver()
.
public void leave()
{
Debug.Log ("calling leave");
if (mRtcEngine == null)
return;
// leave channel
mRtcEngine.LeaveChannel();
// deregister video frame observers in native-c code
mRtcEngine.DisableVideoObserver();
}
The HelloUnityVideo
class has two event listeners to manage video loading and transform events.
The onSceneHelloVideoLoaded()
delegate method detects when the scene loads.
Set go
to the GameObject
with the name Cylinder
.
-
If
go
isnull
, set a debug log for the missingGameObject
usingDebug.Log()
and end the method execution. -
If
go
is notnull
- Create a new
VideoSurface
object usinggo.GetComponent<VideoSurface> ()
. - Add
onTransformDelegate
to the existingo.mAdjustTransfrom
value.
- Create a new
// accessing GameObject in Scnene1
// set video transform delegate for statically created GameObject
public void onSceneHelloVideoLoaded()
{
GameObject go = GameObject.Find ("Cylinder");
if (ReferenceEquals (go, null)) {
Debug.Log ("BBBB: failed to find Cylinder");
return;
}
VideoSurface o = go.GetComponent<VideoSurface> ();
o.mAdjustTransfrom += onTransformDelegate;
}
The onTransformDelegate()
delegate method detects transform changes for a GameObject
.
- If
uid
is equal to0
set the followingtransform
properties:
Transform Property | Value | Description |
---|---|---|
position |
new Vector3 (0f, 2f, 0f) |
Transform position. |
localScale |
new Vector3 (2.0f, 2.0f, 1.0f) |
Transform scale on the local level. |
Rotate |
0f, 1f, 0f |
Transform rotation. |
- Otherwise, set the rotate transform property to
0.0f, 1.0f, 0.0f
usingtransform.Rotate()
.
// delegate: Adjust transform for game object 'objName' connected with user 'uid'.
// You could save information for 'uid' (e.g. which GameObject is attached).
private void onTransformDelegate (uint uid, string objName, ref Transform transform)
{
if (uid == 0) {
transform.position = new Vector3 (0f, 2f, 0f);
transform.localScale = new Vector3 (2.0f, 2.0f, 1.0f);
transform.Rotate (0f, 1f, 0f);
} else {
transform.Rotate (0.0f, 1.0f, 0.0f);
}
}
The HelloUnityVideo
class has three event listeners to manage users joining and leaving a channel.
The onJoinChannelSuccess()
event listener detects when the channel is successfully joined.
-
Set a debug log for the user's
uid
that joins the channel usingDebug.Log ()
. -
Retrieve the
GameObject
with the nameVersionText
usingGameObject.Find()
. -
Set the text for
textVersionGameObject.GetComponent<Text> ()
as the SDK version specified bygetSdkVersion ()
.
private void onJoinChannelSuccess (string channelName, uint uid, int elapsed)
{
Debug.Log ("JoinChannelSuccessHandler: uid = " + uid);
GameObject textVersionGameObject = GameObject.Find ("VersionText");
textVersionGameObject.GetComponent<Text> ().text = "Version : " + getSdkVersion ();
}
The onUserJoined()
event listener detects when a remote user joins the channel.
Set a debug log for the remote user's uid
that joins the channel using Debug.Log ()
and retrieve the GameObject
with the name uid.ToString()
using GameObject.Find()
.
If go
is null
, set its name
property to uid.ToString ()
and create a new VideoSurface
object using go.AddComponent<VideoSurface> ()
. Apply the following to o
.
- Set the user ID using
o.SetForUser()
. - Add
onTransformDelegate
to themAdjustTransfrom
property. - Enable it by passing
true
intoo.SetEnable()
. - Set the
transform
property valuesRotate
,position
, andlocalScale
.
If go
is not null
, set mRemotePeer
to uid
.
// When a remote user joined, this delegate will be called. Typically
// create a GameObject to render video on it
private void onUserJoined(uint uid, int elapsed)
{
Debug.Log ("onUserJoined: uid = " + uid);
// this is called in main thread
// find a game object to render video stream from 'uid'
GameObject go = GameObject.Find (uid.ToString ());
if (!ReferenceEquals (go, null)) {
return; // reuse
}
// create a GameObject and assign to this new user
go = GameObject.CreatePrimitive (PrimitiveType.Plane);
if (!ReferenceEquals (go, null)) {
go.name = uid.ToString ();
// configure videoSurface
VideoSurface o = go.AddComponent<VideoSurface> ();
o.SetForUser (uid);
o.mAdjustTransfrom += onTransformDelegate;
o.SetEnable (true);
o.transform.Rotate (-90.0f, 0.0f, 0.0f);
float r = Random.Range (-5.0f, 5.0f);
o.transform.position = new Vector3 (0f, r, 0f);
o.transform.localScale = new Vector3 (0.5f, 0.5f, 1.0f);
}
mRemotePeer = uid;
}
The onUserOffline()
event listener detects when a user goes offline.
-
Set a debug log for the user's
uid
that goes offline usingDebug.Log ()
. -
Retrieve the
GameObject
with the nameuid.ToString()
usingGameObject.Find()
. -
If
go
isnull
, destroygo
by passing it into theDestroy()
method.
// When remote user is offline, this delegate will be called. Typically
// delete the GameObject for this user.
private void onUserOffline(uint uid, USER_OFFLINE_REASON reason)
{
// remove video stream
Debug.Log ("onUserOffline: uid = " + uid);
// this is called in main thread
GameObject go = GameObject.Find (uid.ToString());
if (!ReferenceEquals (go, null)) {
Destroy (go);
}
}
The Home
class is a subclass of MonoBehaviour
. The Home.cs
file contains the relevant UI functionality for the Unity 3D sample application created in the Create the Scenes section.
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine;
public class Home : MonoBehaviour {
...
}
The remaining code in this section is contained within the Home
class declaration.
- Declare Initialization Methods and Variables
- Create Join / Leave UI Functionality
- Create Event Listener
The Start()
and Update()
methods are empty method declarations and can be used for added initialization and update functionality.
// Use this for initialization.
void Start () {
}
// Update is called once per frame.
void Update () {
}
The Home
class declares a single HelloUnityVideo
object initialized to null
. This object is used to reference the functionality in the class discussed in the HelloUnityVideo
section.
static HelloUnityVideo app = null;
The onButtonClicked()
method is applied to the JoinButton and LeaveButton UI objects. This method determines if the user should join or leave the channel.
- If the button's
name
isJoinButton
, invokeonJoinButtonClicked()
. - If the button's
name
isLeaveButton
, invokeonLeaveButtonClicked()
Note: JoinButton
and LeaveButton
are the object names in the Unity scenes, not the actual display text shown to the user.
public void onButtonClicked() {
// which GameObject?
if (name.CompareTo ("JoinButton") == 0) {
onJoinButtonClicked ();
}
else if(name.CompareTo ("LeaveButton") == 0) {
onLeaveButtonClicked ();
}
}
The onJoinButtonClicked()
method is applied to the Join button object.
- Retrieve the
ChannelName
usingGameObject.Find()
. - Declare a new
InputField
class usinggo.GetComponent<InputField>()
. - If
app
is equal tonull
, create a newHelloUnityVideo
class and load the Agora RTC engine usingapp.loadEngine()
. - Join the channel specified by
field.text
usingapp.join()
. - Add
OnLevelFinishedLoading
to the scene loading event listenerSceneManager.sceneLoaded
. - Load
SceneHelloVideo
usingSceneManager.LoadScene()
.
private void onJoinButtonClicked() {
// get parameters (channel name, channel profile, etc.)
GameObject go = GameObject.Find ("ChannelName");
InputField field = go.GetComponent<InputField>();
// create app if nonexistent
if (ReferenceEquals (app, null)) {
app = new HelloUnityVideo (); // create app
app.loadEngine (); // load engine
}
// join channel and jump to next scene
app.join (field.text);
SceneManager.sceneLoaded += OnLevelFinishedLoading; // configure GameObject after scene is loaded
SceneManager.LoadScene ("SceneHelloVideo", LoadSceneMode.Single);
}
The onLeaveButtonClicked()
method is applied to the Leave button object.
Ensure app
is not null
and execute the following:
- Leave the channel using
app.leave()
. - Unload the Agora RTC engine using
app.unloadEngine()
. - Set
app
tonull
. - Load
SceneHome
usingSceneManager.LoadScene()
.
private void onLeaveButtonClicked() {
if (!ReferenceEquals (app, null)) {
app.leave (); // leave channel
app.unloadEngine (); // delete engine
app = null; // delete app
SceneManager.LoadScene ("SceneHome", LoadSceneMode.Single);
}
}
The Home
class declares a single event listener OnLevelFinishedLoading()
to detect when a scene has finished loading.
If the scene.name
is SceneHelloVideo
:
-
Ensure
app
is notnull
and invokeapp.onSceneHelloVideoLoaded()
to tell theHelloUnityVideo
that the scene finished loading. -
Remove the
OnLevelFinishedLoading
event listener fromSceneManager.sceneLoaded
.
public void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode) {
if (scene.name.CompareTo("SceneHelloVideo") == 0) {
if (!ReferenceEquals (app, null)) {
app.onSceneHelloVideoLoaded (); // call this after scene is loaded
}
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}
}
Q: There are only white cube and box on the demo screen after I join the channel. A: There may be definite reasons for this. First recommendation is implementing the OnError and OnWarning callbacks to check on what errors are occuring. (Added in the Demo starting from v3.2.1.71). Here are the common causes:
-
You registered an AppId with Certificate enabled, but you didn’t include a secure token in your JoinChannel call. => You should use an AppId without Certificate if you are new to the SDK. Create a new AppId with Certificate after you tested the POC and feel comfortable to enforce token security.
-
The Application did not acquire the required OS level permission for Camera. => Make sure you set those up in the PlayerSettings and Manifest if for Android.
-
The agoraCWrapper library didn’t get loaded on run-time (usually happens on Standalone, not Editor). Make sure you have the correct Platform Settings flag selected, we recommend you to select AnyCPU. See examples in MacOS section for building the App above.
Q: I press the join button but the scene doesn't change (usually happens on Editor). A: Make sure you have chosen both two scenes in Build Settings.
Q: When run the app, a pop-up window said agoraSdkCWrapper.bundle cannot be opened because the developer cannot be verified.(usually happens on MacOS). A: Choose "allow" in Settings/security and privacy, rerun the app.
- Complete API documentation is available at the Document Center.
- You can file bugs about this sample here.
This software is under the MIT License (MIT). View the license.