Skip to main content
Version: 2.x.x

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!

Unity Quick Start Demo Interface

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:

Install VideoSDK packageโ€‹

  1. Open Unityโ€™s Package Manager by selecting from the top bar: Window -> Package Manager.

  2. Click the + button in the top left corner and select Add package from git URL...

  3. Paste the following URL and click Add:

https://github.com/videosdk-live/videosdk-rtc-unity-sdk.git

Install VideoSDK Package

  1. 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:

  1. Add the following repository configuration to your settingsTemplate.gradle file:
settingsTemplate.gradle
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"
}
}
}
  1. Install Android SDK in mainTemplate.gradle
mainTemplate.gradle
dependencies {
implementation 'live.videosdk:rtc-android-sdk:0.3.0'
}
  1. If your project has set android.useAndroidX=true, then set android.enableJetifier=true in the gradleTemplate.properties file to migrate your project to AndroidX and avoid duplicate class conflict.
gradleTemplate.properties
android.enableJetifier = true;
android.useAndroidX = true;
android.suppressUnsupportedCompileSdk = 34;

Setting Up for iOSโ€‹

  1. Build for iOS: In Unity, export the project for iOS.
  2. Open in Xcode: Navigate to the generated Xcode project and open it.
  3. Configure Frameworks:
    • Select the Unity-iPhone target.
    • Go to the General tab.
    • Under Frameworks, Libraries, and Embedded Content, add VideoSDK and its required frameworks.

Unity iPhone Frameworks, Libraries, and Embedded Content

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:

  1. Joining Panel โ€“ where users can either create or join a meeting.

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

  1. In your Unity project, right-click the Sample Scene and select GameObject > UI > Panel.

  2. Rename the panel to MettingJoinPanel in the Inspector window.

  3. 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.
  4. Repeat the previous step to create another button named JoinMeeting.

    • Set position: X: 0px, Y: -150px.
    • Set size: Width: 250px, Height: 100px.
  5. 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.

  1. Right-click Canvas and select UI > Panel. Rename it MeetingPanel.

  2. 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.
  3. 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.
  4. 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.
  5. 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.

  1. Create an empty GameObject and rename it Participant.

    • Set size: Width: 350px, Height: 450px.
  2. Add a Raw Image:

    • Right-click Participant and select UI > Raw Image.
    • Set it to stretch fully.
  3. 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:

AndroidManifest.xml
<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 and Permission.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 calls meeting.CreateMeetingId(_token).
  • Once thatโ€™s successful, OnCreateMeetingIdCallback callback will provide the new Meeting ID.
  • JoinMeeting() directly calls meeting.Join(...) if the user typed in an existing ID.
Customizing Meeting and Participant IDs

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 or xxxx-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 for CreateMeetingId(...).
  • 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 a VideoSurface 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 calling meeting.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 and OnStreamDisable are added to the callbacks OnStreamEnableCallback and OnStreamDisableCallback.

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