Unity Quick Start
This tutorial provides a straightforward approach to integrating VideoSDK into a Unity game, enabling real-time audio and video conferencing capabilities. By incorporating VideoSDK, developers can enhance their games with live communication features that foster collaboration and create a more engaging experience for users. Imagine players not just interacting through text, but actually seeing and hearing each other, transforming the way they connect and interact within the game. Letโs explore how to bring this vision to life!
Prerequisitesโ
Before getting started, make sure you have the following:
- Unity Setup: Unity Hub and Unity Editor (version 2018.4.0 or later)
- Development Environment:
- Android: Android 4.1+ with Android Studio 4.1+
- iOS: iOS 10.15+ with Xcode 9.0+
- Accounts:
- A VideoSDK account to generate a token.
Install VideoSDK packageโ
-
Open Unityโs Package Manager by selecting from the top bar: Window -> Package Manager.
-
Click the + button in the top left corner and select Add package from git URL...
-
Paste the following URL and click Add:
https://github.com/videosdk-live/videosdk-rtc-unity-sdk.git
- Add the
com.unity.nuget.newtonsoft-json
package by following the instructions provided here.
Setup Instructionsโ
Android Setupโ
To integrate the VideoSDK into your Android project, follow these steps:
- Add the following repository configuration to your
settingsTemplate.gradle
file:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
**ARTIFACTORYREPOSITORY**
google()
mavenCentral()
jcenter()
maven {
url = uri("https://maven.aliyun.com/repository/jcenter")
}
flatDir {
dirs "${project(':unityLibrary').projectDir}/libs"
}
}
}
- Install Android SDK in
mainTemplate.gradle
dependencies {
implementation 'live.videosdk:rtc-android-sdk:0.3.0'
}
- If your project has set
android.useAndroidX=true
, then setandroid.enableJetifier=true
in thegradleTemplate.properties
file to migrate your project to AndroidX and avoid duplicate class conflict.
android.enableJetifier = true;
android.useAndroidX = true;
android.suppressUnsupportedCompileSdk = 34;
Setting Up for iOSโ
- Build for iOS: In Unity, export the project for iOS.
- Open in Xcode: Navigate to the generated Xcode project and open it.
- Configure Frameworks:
- Select the Unity-iPhone target.
- Go to the General tab.
- Under Frameworks, Libraries, and Embedded Content, add VideoSDK and its required frameworks.
Steps for Setting Up a Conference in Unityโ
VideoSDK helps you add audio/video calling capabilities to your Unity app in minutes. This quick start shows you how to request camera/mic permissions, create or join a meeting, and display participant video feeds inside Unityโs RawImage
components, all while handling toggles for microphone, camera, and leaving the meeting.
User Interfacesโ
When you start a new Unity project, a default scene named "Sample" is created for you. We will use this scene to set up the user interface for our audio/video calling feature. As shown in the image above, follow these steps to create the required UI elements:
Create a Basic UIโ
In this step, we will create a user interface in Unity for a video meeting system. The UI will have two main panels:
-
Joining Panel โ where users can either create or join a meeting.
-
Meeting Panel โ where participants interact during a meeting.
1. Creating the Joining Panelโ
The Joining Panel allows users to create or join a meeting by entering a unique meeting code.
-
In your Unity project, right-click the Sample Scene and select GameObject > UI > Panel.
-
Rename the panel to MettingJoinPanel in the Inspector window.
-
Right-click MettingJoinPanel and select UI > Button - TextMeshPro. Rename this button to CreateMeeting.
- Set position: X: 0px, Y: 150px.
- Set size: Width: 250px, Height: 100px.
-
Repeat the previous step to create another button named JoinMeeting.
- Set position: X: 0px, Y: -150px.
- Set size: Width: 250px, Height: 100px.
-
Create an InputField:
- Right-click MettingJoinPanel and select UI > InputField - TextMeshPro. Rename it MeetingIdInput.
- Set position: X: 0px, Y: 0px.
- Set size: Width: 450px, Height: 120px.
2. Creating the Meeting Panelโ
The Meeting Panel is where participants interact during an ongoing meeting. It includes video frames for participants and control buttons for managing the meeting.
-
Right-click Canvas and select UI > Panel. Rename it MeetingPanel.
-
Create a controls section:
- Right-click MeetingPanel, select Create Empty, and rename it Controls.
- Set Controls to stretch to the bottom of the panel.
- Set position: Y: 38px.
- Set size: Height: 100px.
-
Add control buttons:
- Right-click Controls and select UI > Button - TextMeshPro.
- Rename it Mic and set:
- Position: X: -315px, Y: 0px.
- Size: Width: 200px, Height: 100px.
- Duplicate Mic and rename the new buttons LeaveMeeting and WebCam.
- Set LeaveMeeting position: X: 0px, Y: 0px.
- Set WebCam position: X: 315px, Y: 0px.
- Keep size: Width: 200px, Height: 100px.
-
Create a video frames container:
- Right-click MeetingPanel, select Create Empty, and rename it Participants.
- Set Participants to stretch to the top of the panel.
- Set position: Y: -185px.
- Set size: Height: 900px.
- Add a Grid Layout Group component:
- Set Cell Size: X: 350px, Y: 400px.
- Set Spacing: X: 20px, Y: 20px.
-
Add a Meeting ID text label:
- Right-click MeetingPanel and select UI > Text - TextMeshPro.
- Rename it MeetingId.
- Set it to stretch to the top of the panel.
- Set size: Height: 150px.
- This will display the current meeting's unique ID.
3. Creating Video View Prefabsโ
Each participant's video feed will be represented by a Participant prefab.
-
Create an empty GameObject and rename it Participant.
- Set size: Width: 350px, Height: 450px.
-
Add a Raw Image:
- Right-click Participant and select UI > Raw Image.
- Set it to stretch fully.
-
Attach the VideoSurface.cs script:
- Navigate to Packages > VideoSDK > Runtime.
- Drag and drop VideoSurface.cs onto the Raw Image.
UI Elements & Permissionsโ
To enable camera and microphone access on Android, you must declare the required permissions in your AndroidManifest.xml
. Add the following lines inside the <manifest>
tag and before the <application>
tag:
<manifest>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<application>
<...>
</application>
</manifest>
Next, Configure the UI fields and request camera/mic access. In your GameManager.cs
, define the serialized fields for UI references and the method that checks permissions on Android. The code snippet below covers:
- Declaring
_meetingJoinPanel
,_meetingPanel
to show/hide panels. - Requesting
Permission.Camera
andPermission.Microphone
.
using System.Collections.Generic;
using UnityEngine;
using live.videosdk;
using UnityEngine.Android;
using TMPro; // For TextMeshPro references
using EasyUI.Toast; // For quick notifications (optional)
public class GameManager : MonoBehaviour
{
[SerializeField] GameObject _meetingJoinPanel;
[SerializeField] GameObject _meetingPanel;
private void Awake()
{
// Hide UI sections initially
_meetingJoinPanel.SetActive(false);
_meetingPanel.SetActive(false);
// Request for Camera and Mic Permission
RequestForPermission();
}
private void RequestForPermission()
{
if (Application.platform == RuntimePlatform.Android)
{
if (Permission.HasUserAuthorizedPermission(Permission.Microphone) &&
Permission.HasUserAuthorizedPermission(Permission.Camera))
{
// The user authorized use of the microphone and camera.
OnPermissionGranted(string.Empty);
}
else
{
var callbacks = new PermissionCallbacks();
callbacks.PermissionDenied += OnPermissionDenied;
callbacks.PermissionGranted += OnPermissionGranted;
callbacks.PermissionDeniedAndDontAskAgain += OnPermissionDeniedAndDontAskAgain;
Permission.RequestUserPermissions(new string[] { Permission.Microphone, Permission.Camera }, callbacks);
}
}
}
private void OnPermissionGranted(string permissionName)
{
// Debug.Log($"{permissionName} allowed by the user.");
}
// Called if permission denied
private void OnPermissionDenied(string permissionName) { }
// Called if permission denied with 'Don't Ask Again'
private void OnPermissionDeniedAndDontAskAgain(string permissionName) { }
}
Creating or Joining a Meetingโ
Next, let's hook up the VideoSDK meeting object. Weโll add these code blocks to Start()
and define two simple methods: CreateMeeting()
and JoinMeeting()
. This sets up meeting creation (to get a new Meeting ID) or direct joining (when the user has an existing ID).
public class GameManager : MonoBehaviour
{
[SerializeField] TMP_Text _meetingIdTxt;
[SerializeField] TMP_InputField _meetingIdInputField;
private Meeting meeting;
// Replace with your actual token from the VideoSDK dashboard
private readonly string _token = "YOUR_TOKEN";
void Start()
{
// Get the meeting object from the VideoSDK library
meeting= Meeting.GetMeetingObject();
// Show UI panels to create or join
_meetingJoinPanel.SetActive(true);
}
public void CreateMeeting()
{
Debug.Log("User requested to create a meeting ID...");
// Alert the user if microphone or camera permission is not granted.
AlertNoPermission();
_meetingJoinPanel.SetActive(false);
// This calls the SDK to generate a new Meeting ID
meeting.CreateMeetingId(_token);
}
public void JoinMeeting()
{
// If user typed a Meeting ID, we try to join
if (string.IsNullOrEmpty(_meetingIdInputField.text)) return;
// Alert the user if microphone or camera permission is not granted.
AlertNoPermission();
try
{
meeting.Join(_token, _meetingIdInputField.text, "User", true, true);
}
catch (System.Exception ex)
{
Debug.LogError("Join Meet Failed: " + ex.Message);
}
}
private void AlertNoPermission()
{
if (Application.platform == RuntimePlatform.Android)
{
if (!(Permission.HasUserAuthorizedPermission(Permission.Microphone) && Permission.HasUserAuthorizedPermission(Permission.Camera)))
{
Toast.Show($"You have not granted microphone or camera permission.", 3f, Color.red, ToastPosition.TopCenter);
}
}
}
}
- Assign
CreateMeeting()
to the CreateMeeting button through inspector. - Assign
JoinMeeting()
to the JoinMeeting button through inspector. - The
AlertNoPermission()
method is alert the user if microphone or camera permission is not granted. - The
CreateMeeting()
method callsmeeting.CreateMeetingId(_token)
. - Once thatโs successful,
OnCreateMeetingIdCallback
callback will provide the new Meeting ID. JoinMeeting()
directly callsmeeting.Join(...)
if the user typed in an existing ID.
The Join
method allows developers to define custom values for meetingId
and participantId
:
Join(string token, string meetingId, string name, bool micEnabled, bool camEnabled, string participantId = null)
meetingId
can be structured in any preferred format by the developer, e.g.,aaaa-bbbb
orxxxx-yyyy
, instead of following a predefined pattern.participantId
can also be set by the developer, but it must be unique for each participant in a meeting.
Callbacks for Create Meetingโ
To know when a new meeting has been created, we register callback methods in Start()
.
void Start()
{
meeting = Meeting.GetMeetingObject();
// --- Register Callbacks ---
meeting.OnCreateMeetingIdCallback += OnCreateMeeting;
meeting.OnCreateMeetingIdFailedCallback += OnCreateMeetingFailed;
//...
}
private void OnCreateMeeting(string meetingId)
{
// Once a new meeting ID is generated, join automatically
_meetingIdTxt.text = meetingId; // Display on screen
meeting.Join(_token, meetingId, "User", true, true);
}
private void OnCreateMeetingFailed(string errorMsg)
{
Debug.LogError(errorMsg);
// Show create/join UI again
_meetingJoinPanel.SetActive(true);
}
OnCreateMeeting()
โ success callback forCreateMeetingId(...)
.OnCreateMeetingFailed()
โ reverts to the UI on failure.
Managing Participants & Video Renderingโ
Now for the fun part: showing participant streams. The OnParticipantJoined
callback will fire each time someone (including your local user) joins the meeting. Above we created a prefab with a VideoSurface
component to map their stream onto a RawImage
.
[SerializeField] GameObject _videoSurfacePrefab;
[SerializeField] Transform _parent;
private List<VideoSurface> _participantList = new List<VideoSurface>();
private VideoSurface _localParticipant;
void Start()
{
meeting= Meeting.GetMeetingObject();
meeting.OnCreateMeetingIdCallback += OnCreateMeeting;
meeting.OnParticipantJoinedCallback += OnParticipantJoined;
meeting.OnParticipantLeftCallback += OnParticipantLeft;
// ... (other callbacks)
_meetingJoinPanel.SetActive(true);
}
private void OnParticipantJoined(IParticipant participant)
{
Debug.Log($"OnParticipantJoined: {participant.ToString()}");
// Instantiate a prefab that has a VideoSurface.
VideoSurface surface = Instantiate(_videoSurfacePrefab, _parent.transform).GetComponentInChildren<VideoSurface>();
surface.SetVideoSurfaceType(VideoSurfaceType.RawImage);
surface.SetParticipant(participant);
surface.SetEnable(true);
// Add to our tracking list
_participantList.Add(surface);
if (participant.IsLocal)
{
// Store the local participant separately
_localParticipant = surface;
// Show the meeting controls UI once we join
_meetingPanel.SetActive(true);
_meetingJoinPanel.SetActive(false);
_meetIdTxt.text = meeting.MeetingID;
}
}
private void OnParticipantLeft(IParticipant participant)
{
Debug.Log($"OnParticipantLeft: {participant.ToString()}");
if (participant.IsLocal)
{
// If the local user leaves, do a cleanup
OnLeave();
}
else
{
// For remote participants, find the VideoSurface object and destroy it
VideoSurface surfaceToRemove = null;
for (int i = 0; i < _participantList.Count; i++)
{
if (participant.ParticipantId == _participantList[i].Id)
{
surfaceToRemove = _participantList[i];
_participantList.RemoveAt(i);
break;
}
}
if (surfaceToRemove != null)
{
Destroy(surfaceToRemove.transform.parent.gameObject);
}
}
}
private void OnLeave(){
// We'll implement this method in the next step.
}
- Create a prefab with a
RawImage
child that has aVideoSurface
component - Drag that prefab into
_videoSurfacePrefab
in the Inspector _parent
is a Transform where participant video windows appear.
Controls - Toggling Camera, Mic & Leavingโ
To provide users with essential meeting controls, the following functions handle toggling the camera, microphone, and exiting the session:
-
Toggle Camera โ
CamToggle()
enables or disables the participant's video feed. -
Toggle Mic โ
AudioToggle()
allows participants to mute or unmute their microphone. -
Leave Meeting โ
LeaveMeeting()
gracefully exits the session by callingmeeting.Leave()
, ensuring proper cleanup. -
Assign
AudioToggle()
to the Mic button through inspector. -
Assign
CamToggle()
to the WebCam button through inspector. -
Assign
LeaveMeeting()
to the LeaveMeeting button through inspector.
private bool camToggle = true;
private bool micToggle = true;
public void CamToggle()
{
camToggle = !camToggle;
Debug.Log("Cam Toggle: " + camToggle);
_localParticipant?.SetVideo(camToggle);
}
public void AudioToggle()
{
micToggle = !micToggle;
Debug.Log("Mic Toggle: " + micToggle);
_localParticipant?.SetAudio(micToggle);
}
public void LeaveMeeting()
{
meeting?.Leave();
}
private void OnLeave()
{
// Clean up local UI
_meetingJoinPanel.SetActive(true);
_meetingPanel.SetActive(false);
// Reset toggles
camToggle = true;
micToggle = true;
// Destroy all participant surfaces
for (int i = 0; i < _participantList.Count; i++)
{
Destroy(_participantList[i].transform.parent.gameObject);
}
_participantList.Clear();
// Reset text
_meetingIdTxt.text = "VideoSDK Unity Demo";
}
Callbacks releated to streamโ
- When a participant joins, if they are the local participant,
OnStreamEnable
andOnStreamDisable
are added to the callbacksOnStreamEnableCallback
andOnStreamDisableCallback
.
These functions handle the enabling and disabling of the local participant's camera and microphone:
-
OnStreamEnable
: Triggered when the camera or microphone is enabled, updating the toggle states. -
OnStreamDisable
: Triggered when the camera or microphone is disabled, updating the toggle states.
private void OnParticipantJoined(IParticipant participant)
{
//...
if (participant.IsLocal)
{
//...
// Store the local participant separately
_localParticipant = surface;
//Subscribed callback function to delegate
_localParticipant.OnStreamEnableCallback += OnStreamEnable;
_localParticipant.OnStreamDisableCallback += OnStreamDisable;
//...
}
}
private void OnStreamEnable(string kind)
{
// Called when camera or mic is enabled
camToggle = _localParticipant.CamEnabled;
micToggle = _localParticipant.MicEnabled;
}
private void OnStreamDisable(string kind)
{
// Called when camera or mic is disabled
camToggle = _localParticipant.CamEnabled;
micToggle = _localParticipant.MicEnabled;
}
Done! Full Example Codeโ
Following the steps above, youโll end up with a GameManager.cs that handles requesting permissions, creating/joining a meeting, showing participant video streams, and managing toggles. To see the complete code in one place, visit:
GameManager.cs
on GitHub
You can copy it into your project, ensure your UI references are wired up in the Inspector, and youโre set!
Final Outputโ
Got a Question? Ask us on discord