video sdk logo

Login

Unity Audio Rooms Tutorial

Add drop-in voice chat and audio rooms to Unity games and apps. Speaker and listener roles, mute, and moderation are driven from C#, with echo cancellation and noise suppression on by default so party chat stays clear over game audio.
Unity SDK for real-time video calls, audio rooms, and server-controlled live streaming

Trusted by 300+ global business & tech leaders

Build an Audio-Only Room in Unity with C#

Learn how to build an audio-only room in Unity using the VideoSDK Unity SDK. This tutorial covers meeting setup, speaker and listener modes, raise-hand requests, and C# controls for mute and moderation.


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:
    • A VideoSDK account to generate a token.

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:

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

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
1dependencyResolutionManagement {
2    repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
3    repositories {
4        **ARTIFACTORYREPOSITORY**
5        google()
6        mavenCentral()
7        jcenter()
8        maven {
9            url = uri("https://maven.aliyun.com/repository/jcenter")
10        }
11        flatDir {
12            dirs "${project(':unityLibrary').projectDir}/libs"
13        }
14    }
15}
16
  1. Install Android SDK in mainTemplate.gradle
mainTemplate.gradle
1dependencies {
2    implementation 'live.videosdk:rtc-android-sdk:0.3.1'
3}
4
  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
1android.enableJetifier = true;
2android.useAndroidX = true;
3android.suppressUnsupportedCompileSdk = 34;
4

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.

Step 1: Create a Basic UI

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

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.

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.

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.

Step 2: Managing 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
1<manifest>
2
3    <uses-permission android:name="android.permission.CAMERA"/>
4    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
5    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
6
7    <application>
8       <...>
9    </application>
10</manifest>
11

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.
GameManager.cs
1using System.Collections.Generic;
2using UnityEngine;
3using live.videosdk;
4using UnityEngine.Android;
5using TMPro; // For TextMeshPro references
6using EasyUI.Toast; // For quick notifications (optional)
7
8public class GameManager : MonoBehaviour
9{
10    [SerializeField] GameObject _meetingJoinPanel;
11    [SerializeField] GameObject _meetingPanel;
12
13    private void Awake()
14    {
15        // Hide UI sections initially
16        _meetingJoinPanel.SetActive(false);
17        _meetingPanel.SetActive(false);
18
19        // Request for Camera and Mic Permission
20        RequestForPermission();
21    }
22
23    private void RequestForPermission()
24    {
25        if (Application.platform == RuntimePlatform.Android)
26        {
27            if (Permission.HasUserAuthorizedPermission(Permission.Microphone) &&
28                Permission.HasUserAuthorizedPermission(Permission.Camera))
29            {
30                // The user authorized use of the microphone and camera.
31                OnPermissionGranted(string.Empty);
32            }
33            else
34            {
35                var callbacks = new PermissionCallbacks();
36                callbacks.PermissionDenied += OnPermissionDenied;
37                callbacks.PermissionGranted += OnPermissionGranted;
38                callbacks.PermissionDeniedAndDontAskAgain += OnPermissionDeniedAndDontAskAgain;
39                Permission.RequestUserPermissions(
40                    new string[] { Permission.Microphone, Permission.Camera },
41                    callbacks
42                );
43            }
44        }
45    }
46
47    private void OnPermissionGranted(string permissionName)
48    {
49        // Debug.Log($"{permissionName} allowed by the user.");
50    }
51
52    // Called if permission denied
53    private void OnPermissionDenied(string permissionName) { }
54
55    // Called if permission denied with 'Don't Ask Again'
56    private void OnPermissionDeniedAndDontAskAgain(string permissionName) { }
57}
58

Step 3: 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).

GameManager.cs
1public class GameManager : MonoBehaviour
2{
3    [SerializeField] TMP_Text _meetingIdTxt;
4    [SerializeField] TMP_InputField _meetingIdInputField;
5
6    private Meeting meeting;
7
8    // Replace with your actual token from the VideoSDK dashboard
9    private readonly string _token = "YOUR_TOKEN";
10
11    void Start()
12    {
13        // Get the meeting object from the VideoSDK library
14        meeting = Meeting.GetMeetingObject();
15
16        // Show UI panels to create or join
17        _meetingJoinPanel.SetActive(true);
18    }
19
20    public void CreateMeeting()
21    {
22        Debug.Log("User requested to create a meeting ID...");
23
24        // Alert the user if microphone or camera permission is not granted.
25        AlertNoPermission();
26
27        _meetingJoinPanel.SetActive(false);
28
29        // This calls the SDK to generate a new Meeting ID
30        meeting.CreateMeetingId(_token);
31    }
32
33    public void JoinMeeting()
34    {
35        // If user typed a Meeting ID, we try to join
36        if (string.IsNullOrEmpty(_meetingIdInputField.text)) return;
37
38        // Alert the user if microphone or camera permission is not granted.
39        AlertNoPermission();
40
41        try
42        {
43            meeting.Join(
44                _token,
45                _meetingIdInputField.text,
46                "User",
47                true,
48                true
49            );
50        }
51        catch (System.Exception ex)
52        {
53            Debug.LogError("Join Meet Failed: " + ex.Message);
54        }
55    }
56
57    private void AlertNoPermission()
58    {
59        if (Application.platform == RuntimePlatform.Android)
60        {
61            if (!(Permission.HasUserAuthorizedPermission(Permission.Microphone) &&
62                  Permission.HasUserAuthorizedPermission(Permission.Camera)))
63            {
64                Toast.Show(
65                    $"You have not granted microphone or camera permission.",
66                    3f,
67                    Color.red,
68                    ToastPosition.TopCenter
69                );
70            }
71        }
72    }
73}
74
  • 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:

1Join(
2    string token,
3    string meetingId,
4    string name,
5    bool micEnabled,
6    bool camEnabled,
7    string participantId = null
8)
9
  • 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().

GameManager.cs
1void Start()
2{
3    meeting = Meeting.GetMeetingObject();
4
5    // --- Register Callbacks ---
6    meeting.OnCreateMeetingIdCallback += OnCreateMeeting;
7    meeting.OnCreateMeetingIdFailedCallback += OnCreateMeetingFailed;
8
9    //...
10}
11
12private void OnCreateMeeting(string meetingId)
13{
14    // Once a new meeting ID is generated, join automatically
15    _meetingIdTxt.text = meetingId; // Display on screen
16    meeting.Join(_token, meetingId, "User", true, true);
17}
18
19private void OnCreateMeetingFailed(string errorMsg)
20{
21    Debug.LogError(errorMsg);
22
23    // Show create/join UI again
24    _meetingJoinPanel.SetActive(true);
25}
26
  • OnCreateMeeting() → success callback for CreateMeetingId(...).
  • OnCreateMeetingFailed() → reverts to the UI on failure.

Step 4: 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.

GameManager.cs
1[SerializeField] GameObject _videoSurfacePrefab;
2[SerializeField] Transform _parent;
3
4private List<VideoSurface> _participantList = new List<VideoSurface>();
5private VideoSurface _localParticipant;
6
7void Start()
8{
9    meeting = Meeting.GetMeetingObject();
10
11    meeting.OnCreateMeetingIdCallback += OnCreateMeeting;
12    meeting.OnParticipantJoinedCallback += OnParticipantJoined;
13    meeting.OnParticipantLeftCallback += OnParticipantLeft;
14
15    // ... (other callbacks)
16    _meetingJoinPanel.SetActive(true);
17}
18
19private void OnParticipantJoined(IParticipant participant)
20{
21    Debug.Log($"OnParticipantJoined: {participant.ToString()}");
22
23    // Instantiate a prefab that has a VideoSurface.
24    VideoSurface surface = Instantiate(
25        _videoSurfacePrefab,
26        _parent.transform
27    ).GetComponentInChildren<VideoSurface>();
28
29    surface.SetVideoSurfaceType(VideoSurfaceType.RawImage);
30    surface.SetParticipant(participant);
31    surface.SetEnable(true);
32
33    // Add to our tracking list
34    _participantList.Add(surface);
35
36    if (participant.IsLocal)
37    {
38        // Store the local participant separately
39        _localParticipant = surface;
40
41        // Show the meeting controls UI once we join
42        _meetingPanel.SetActive(true);
43        _meetingJoinPanel.SetActive(false);
44        _meetIdTxt.text = meeting.MeetingID;
45    }
46}
47
48private void OnParticipantLeft(IParticipant participant)
49{
50    Debug.Log($"OnParticipantLeft: {participant.ToString()}");
51
52    if (participant.IsLocal)
53    {
54        // If the local user leaves, do a cleanup
55        OnLeave();
56    }
57    else
58    {
59        // For remote participants, find the VideoSurface object and destroy it
60        VideoSurface surfaceToRemove = null;
61
62        for (int i = 0; i < _participantList.Count; i++)
63        {
64            if (obj.Id == _participantList[i].ParticipantId)
65            {
66                surfaceToRemove = _participantList[i];
67                _participantList.RemoveAt(i);
68                break;
69            }
70        }
71
72        if (surfaceToRemove != null)
73        {
74            Destroy(surfaceToRemove.transform.parent.gameObject);
75        }
76    }
77}
78
79private void OnLeave()
80{
81    // We'll implement this method in the next step.
82}
83
  • 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.

Step 5: Creating 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.
GameManager.cs
1private bool camToggle = false;
2private bool micToggle = true;
3
4public void CamToggle()
5{
6    camToggle = !camToggle;
7    Debug.Log("Cam Toggle: " + camToggle);
8    _localParticipant?.SetVideo(camToggle);
9}
10
11public void AudioToggle()
12{
13    micToggle = !micToggle;
14    Debug.Log("Mic Toggle: " + micToggle);
15    _localParticipant?.SetAudio(micToggle);
16}
17
18public void LeaveMeeting()
19{
20    meeting?.Leave();
21}
22
23private void OnLeave()
24{
25    // Clean up local UI
26    _meetingJoinPanel.SetActive(true);
27    _meetingPanel.SetActive(false);
28
29    // Reset toggles
30    camToggle = false;
31    micToggle = true;
32
33    // Destroy all participant surfaces
34    for (int i = 0; i < _participantList.Count; i++)
35    {
36        Destroy(_participantList[i].transform.parent.gameObject);
37    }
38
39    _participantList.Clear();
40
41    // Reset text
42    _meetingIdTxt.text = "VideoSDK Unity Demo";
43}
44

Step 6: Listening to 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.
GameManager.cs
1private void OnParticipantJoined(IParticipant participant)
2{
3    //...
4
5    if (participant.IsLocal)
6    {
7        //...
8
9        // Store the local participant separately
10        _localParticipant = surface;
11
12        // Subscribed callback function to delegate
13        _localParticipant.OnStreamEnableCallback += OnStreamEnable;
14        _localParticipant.OnStreamDisableCallback += OnStreamDisable;
15
16        //...
17    }
18}
19
20private void OnStreamEnable(StreamKind kind)
21{
22    // Called when camera or mic is enabled
23    camToggle = _localParticipant.CamEnabled;
24    micToggle = _localParticipant.MicEnabled;
25}
26
27private void OnStreamDisable(StreamKind kind)
28{
29    // Called when camera or mic is disabled
30    camToggle = _localParticipant.CamEnabled;
31    micToggle = _localParticipant.MicEnabled;
32}
33

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!

Summarize with

ChatGPTClaudePerplexityGoogleGrok
Prefer VideoSDK on Google

Table of Contents

Start Building Now With $20 Free Balance

No credit card required to start.

Documentation →Github Repo →

Share This Article

TwitterLinkedInFacebookHacker News

Get started for free today

Grab your API keys and start building with free $20 included in your account. Need enterprise-grade security or custom workloads? Talk to an expert!

Book a demo

Video SDK Logo

United States

28 Geary St, Suite 650,
San Francisco, CA 94108, United States

India flag

India

18th Floor, 1812, The Junomoneta Tower,
Adajan-Hazira Rd, Surat, Gujarat 395009, India

Video SDK Logo
Video SDK Logo
Video SDK Logo
Video SDK Logo
SOLUTIONS

Video KYC

Video Banking

Virtual Claim

Video MER

Telehealth

Astrology

Gaming

Dating

Live Commerce

Auto Proctoring

Interview-as-a-service

Virtual Events

Live Audio Streaming

Ed-Tech

PRODUCTS

AI-Agents

Real-time Audio & Video SDK

Interactive Live Streaming SDK

Real-time Transcription SDK

Character SDK

Open Source Examples

SUCCESS STORIES

Examedi

Coderschool

TYHO

ForagerOne

Immigo

DEVELOPERS

Documentation

Code Samples

Developer Updates

Developer Hub

TOP ARTICLES

What is WebRTC?

Build a React Native Video Calling App

Build a Flutter Video Calling App

RESOURCES

The Protocol by Video SDK

AI Apps

Creator Program

LEGAL

Terms Of Service

Privacy Policy

Cookie Notice

CCPA Notice

Subprocessors

DPA

RSS

COMPANY

Contact Us

Pricing

Support

Blog

Press Kit