Skip to main content

Live streaming over multiple channels

Some special scenarios require streaming over two or more separate channels. Depending on the scenario, the game joins both channels as host, both channels as audience, or one channel as host and the other as audience. For example, consider the case of an online singing contest, where hosts of different channels interact with each other. The audience receives streams from two channels while the contestants broadcast to both channels.

Agora Video SDK multi-channel streaming allows you to join multiple channels at the same time and broadcast or receive audio and video over them. This page shows you how to implement two different multi-channel methods into your game using Video SDK. Choose the method that best fits your particular scenario.

Understand the tech

Agora Video SDK provides the following approaches to implementing multi-channel streaming:

  • Channel media relay

    In channel media relay, one channel is used as the source channel from which audio and video is relayed to a second channel called the destination channel. The audience on the destination channel subscribes to the relayed media stream. A host can relay media stream to a maximum of four destination channels. Relaying media streams provides the following benefits:

    • All hosts in the channels can see and hear each other.
    • The audience in the channels can see and hear all hosts.
  • Join multiple channels

    To join multiple channels, a host first sets up a primary channel and starts an event. The host then joins a second channel and publishes to the new channel. The audience joins either channel and subscribes to the host channel. The two channels are independent and users on one channels don't see users on the other channel. You can extend this functionality to join as many channels as required.

The following figure shows the workflow you need to implement to add multi-channel streaming to your game:

stream over multiple channels

Prerequisites

To follow this procedure you must have implemented the SDK quickstart for Interactive Live Streaming project.

Project setup

In order to create the environment necessary to implement Agora multi-channel streaming into your game, do the following:

Implement multi-channel streaming

This section shows you how to implement the following methods of multi-channel streaming:

Choose the method that best suits your scenario and follow the step by step procedure.

Channel media relay

In this example, you use a single Button to start and stop channel media relay.

Implement the user interface

To enable your users to start and stop relaying to another channel, add a Button to the user interface by taking the following steps:

  1. Right-click Sample Scene, then click GameObject > UI > Button - TextMeshPro. A button appears in the Scene Canvas.

  2. In Inspector, rename Button to StartChannelMediaRelay, then change the following coordinates:

  • Pos X - 350
  • Pos Y - 172

Handle the system logic

In your project, import the relevant libraries and declare the required variables.

  1. Declare the variables you need

    To store source and destination channel settings and manage channel relay, in your script file, add the following declarations to NewBehaviourScript:

    private string destChannelName = "<name of the destination channel>";
    private string destChannelToken = "<access token for the destination channel>";
    private uint destUid = 100; // User ID that the user uses in the destination channel.
    private string sourceChannelToken = "<access token for the source channel>"; // Generate with the _channelName and remoteUid = 0.
    private bool mediaRelaying = false;
    private TMP_Text channelRelayBtnText;
    Copy
  2. Add the required UI namespace

    To import the required Unity UI namespace, in your script file, add the following to the list of namespace declarations:

    using TMPro;
    Copy
  3. Access the channel relay button

    To programmatically access the channel media relay button, add the following at the end of SetupUI:

    // Access the channel relay button.
    go = GameObject.Find("StartChannelMediaRelay");
    go.GetComponent<Button>().onClick.AddListener(channelRelay);
    // Access the label of the channel relay button.
    channelRelayBtnText = go.GetComponentInChildren<TMP_Text>(true);
    // Change the button text and font size.
    channelRelayBtnText.text = "Relay Media";
    channelRelayBtnText.fontSize = 14;
    Copy

Implement channel media relay

To enable game users to relay channel media to a destination channel, take the following steps:

  1. Start or stop channel media relay

When a user presses the button, the game starts relaying media from the source channel to the destination channel. If channel media relay is already running, the game stops it. To integrate this workflow, add the following method to NewBehaviourScript.

public void channelRelay() {
if (mediaRelaying) {
RtcEngine.StopChannelMediaRelay();
mediaRelaying = false;
} else {
// Configure the source channel information.
ChannelMediaRelayConfiguration mediaRelayConfiguration = new ChannelMediaRelayConfiguration();
// Setup the source channel information.
mediaRelayConfiguration.srcInfo = new ChannelMediaInfo
{
channelName = _channelName,
uid = 0,
token = sourceChannelToken
};
// Setup the destination channel information.
mediaRelayConfiguration.destInfos = new ChannelMediaInfo[1];
mediaRelayConfiguration.destInfos[0] = new ChannelMediaInfo
{
channelName = destChannelName,
uid = 0,
token = destChannelToken
};
mediaRelayConfiguration.destCount = 1;
// Start relaying media streams across channels
RtcEngine.StartChannelMediaRelay(mediaRelayConfiguration);
mediaRelaying = true;
}
}
Copy
  1. Monitor the channel media relay state

To receive the state change notifications sent during media relay, you add a method to UserEventHandler. Your game responds to connection and failure events in the onChannelMediaRelayStateChanged event handler. In your script file, add the following method after the OnUserOffline:

public override void OnChannelMediaRelayStateChanged(int state, int code) {
// This example shows messages in the debug console when the relay state changes,
// a production level app needs to handle state change properly.
switch (state) {
case 1: // RELAY_STATE_CONNECTING:
Debug.Log("Channel media relay connecting.");
_videoSample.channelRelayBtnText.text = "Connecting...";
break;
case 2: // RELAY_STATE_RUNNING:
_videoSample.mediaRelaying = true;
Debug.Log("Channel media relay running.");
_videoSample.channelRelayBtnText.text = "Stop Channel Media Relay";
break;
case 3: // RELAY_STATE_FAILURE:
_videoSample.mediaRelaying = false;
Debug.Log("Channel media relay failure. Error code: " + code);
_videoSample.channelRelayBtnText.text = "Start Channel Media Relay";
break;
}
_videoSample.channelRelayBtnText.fontSize = 14;
}
Copy
  1. Monitor channel media relay events

To receive notifications of important channel relay events such as network disconnection, reconnection, and users joining channels, you add the onChannelMediaRelayEvent method to UserEventHandler. To implement this callback in your game, add the following method after OnChannelMediaRelayStateChanged:

public override void OnChannelMediaRelayEvent(int code)
{
switch (code)
{
case 0: // RELAY_EVENT_NETWORK_DISCONNECTED
Debug.Log("User disconnected from the server due to a poor network connection.");
break;
case 1: // RELAY_EVENT_NETWORK_CONNECTED
Debug.Log("Network reconnected");
break;
case 2: // RELAY_EVENT_PACKET_JOINED_SRC_CHANNEL
Debug.Log("User joined the source channel");
break;
}
}
Copy

Join multiple channels

The alternate approach to multi-channel live streaming is joining multiple channels. In this section, you learn how to implement joining a second channel in your game.

Implement the user interface

In this example, you use a single Button to join and leave a second channel. Add a Button to the user interface by taking the following steps:

  1. Right-click Sample Scene, then click UI > Button - TextMeshPro. A button appears in the Scene Canvas.

  2. In Inspector, rename Button to multiChannel, then change the following coordinates:

  • Pos X - -350
  • Pos Y - 172

Handle the system logic

In your project, import the relevant libraries, declare the required variables, and acces the UI elements.

  1. Declare the variables you need

    To join and manage a second channel, in your script file, add the following declarations to NewBehaviourScript:

    private RtcConnection rtcSecondConnection;
    private string secondChannelName = "<name of the second channel>";
    private uint secondChannelUid = 100; // Uid for the second channel
    private string secondChannelToken = "<access token for the second channel>";
    private bool isSecondChannelJoined = false; // Track connection state of the second channel
    private TMP_Text multiChannelBtnText;
    Copy
  2. Add the required UI namespace

    To import the required Uinty UI namespace, in your script file, add the following to the list of namespace declarations:

    using TMPro;
    Copy
  3. Access the multiple channel button in your code

    To programmatically access the button, add the following at the end of SetupUI:

    // Access the multi-channel button to change the button text.
    go = GameObject.Find("multiChannel");
    // Call joinSecondChannel method when the user presses the button.
    go.GetComponent<Button>().onClick.AddListener(joinSecondChannel);
    // Access the Text(TMP) sub-item of multi-channel to change the button text.
    multiChannelBtnText = go.GetComponentInChildren<TMP_Text>(true);
    // Change the button text and font size.
    multiChannelBtnText.text = "Join Second Channel";
    multiChannelBtnText.fontSize = 14;
    Copy

Implement joining multiple channels

To add multi-channel functionality to your game, take the following steps:

  1. Use the multi-channel enabled RtcEngineEx interface

    In the SDK quickstart code, the Agora Engine instance was declared as IRtcEngine. To implement multi-channel functionality, you use the multi-channel interface of the Agora Engine IRtcEngineEx. In order to switch to the multi-user interface, do the following:

    1. In NewBehaviourScript.cs, replace the declaration internal IRtcEngine RtcEngine; with:
    internal IRtcEngineEx RtcEngine;
    Copy
    1. In your script file, locate SetupVideoSDKEngine, replace the line RtcEngine = Agora.Rtc.RtcEngine.CreateAgoraRtcEngine(); with the following:
    RtcEngine = (IRtcEngineEx) Agora.Rtc.RtcEngine.CreateAgoraRtcEngine();
    Copy
  2. Join a second channel

    When a user presses the button, the game joins a second channel. If the game is already connected to a second channel, it leaves the channel. To implement this workflow, add the following method to NewBehaviourScript:

    public void joinSecondChannel()
    {
    if (isSecondChannelJoined)
    {
    RtcEngine.LeaveChannelEx(rtcSecondConnection);
    isSecondChannelJoined = false;
    multiChannelBtnText.text = "Join Second Channel";
    }
    else
    {
    RtcEngine.EnableVideo();
    // Preview the local video.
    LocalView.SetForUser(0, "", VIDEO_SOURCE_TYPE.VIDEO_SOURCE_CAMERA);
    LocalView.SetEnable(true);
    ChannelMediaOptions mediaOptions = new ChannelMediaOptions();
    mediaOptions.autoSubscribeAudio.SetValue(true);
    mediaOptions.autoSubscribeVideo.SetValue(true);
    mediaOptions.channelProfile.SetValue(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING);
    if (clientRole == "Audience")
    {
    mediaOptions.publishCameraTrack.SetValue(false);
    mediaOptions.publishMicrophoneTrack.SetValue(false);
    mediaOptions.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_AUDIENCE);
    }
    else if(clientRole == "Host")
    { // Host Role
    mediaOptions.publishCameraTrack.SetValue(true);
    mediaOptions.publishMicrophoneTrack.SetValue(true);
    mediaOptions.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
    }

    rtcSecondConnection = new RtcConnection();
    rtcSecondConnection.channelId = secondChannelName;
    rtcSecondConnection.localUid = secondChannelUid;

    RtcEngine.JoinChannelEx(secondChannelToken, rtcSecondConnection, mediaOptions);
    isSecondChannelJoined = true;
    multiChannelBtnText.text = "Leave Second Channel";
    }
    }
    Copy
  3. Update onUserJoined callback to render the second channel remote video

    When the user presses Join Second Channel, you join the channel and wait for the second channel remote user to join the channel. When a remote user joins the channel second, your game stops rendering the first channel remote video and starts rendering the second channel remote video. To implement this workflow, in your script file, replace onUserJoined with the following:

    public override void OnUserJoined(RtcConnection connection, uint uid, int elapsed)
    {
    // Setup remote view.
    GameObject go = GameObject.Find("RemoteView");
    _videoSample.RemoteView = go.AddComponent<VideoSurface>();
    _videoSample.RemoteView.SetForUser(uid, connection.channelId, VIDEO_SOURCE_TYPE.VIDEO_SOURCE_REMOTE);
    if(_videoSample.clientRole == "Audience")
    {
    // Start rendering remote video.
    _videoSample.RemoteView.SetEnable(true);
    }
    else
    {
    // Stop rendering remote video.
    _videoSample.RemoteView.SetEnable(false);
    }
    _videoSample.remoteUid = uid;
    }
    Copy

Test your implementation

To ensure that you have implemented multi-channel streaming into your game, follow the relevant testing procedure:

Test channel media Relay

  1. In Unity Editor, in your script file, update _appID, _channelName and destChannelName.

  2. Generate a temporary token in using _appID and _channelName. Use it to update _token in NewBehaviourScript. Use the same values to generate another token and update sourceChannelToken.

  3. Generate a third token in using _appID and destChannelName. Use it to update destChannelToken in NewBehaviourScript.

  4. In your browser, navigate to the Agora web demo and update App ID, Channel, and Token with the values for your temporary token, then click Join.

  5. Repeat the previous step on a second device, but this time use _appID, destChannelName, and destChannelToken to Join the channel.

  6. In Unity Editor, click Play. A moment later you see the game running on your development device.

  7. Select Host and press Join. You see the video from the web browser demo app connected to _channelName in the local view of your device.

  8. Press Start Channel Media Relay. You see the video from the web browser demo app connected to _channelName relayed to the web browser demo app connected to destChannelName.

  9. Press Stop Channel Media Relay. The media relaying is stopped.

Test joining multiple channels

  1. In Unity Editor, in your script file, update _appID, _channelName and destChannelName.

  2. Generate a temporary token in using _appID and _channelName. Use it to update _token in NewBehaviourScript.

  3. Generate a second token in using _appID and secondChannelName. Use it to update secondChannelToken in NewBehaviourScript.

  4. In your browser, navigate to the Agora web demo and update App ID, Channel, and Token with the values for your temporary token, then click Join.

  5. Repeat the previous step on a second device, but this time use _appID, secondChannelName, and secondChannelToken to Join the channel.

  6. In Unity Editor, click Play. A moment later you see the game running on your development device.

  7. Select Audience

    1. Press Join. You see the video from the web browser demo app connected to _channelName in the remote view of your development device.
    2. Press Join Second Channel. Now, you see the video from the web browser demo app connected to secondChannelName in the remote view of your development device.
    3. Press Leave Second Channel and then Leave to exit both channels.
  8. Select Host

    1. Press Join. You see the local video in the local view of your development device. The web browser demo app connected to channelName shows the video from your development device.

    2. Press Join Second Channel. The web browser demo app connected to secondChannelName plays only the audio stream from your development device. This is because you can publish video stream only in one channel.

    3. Press Leave Second Channel and then Leave to exit both channels.

    4. Publish video stream in the second channel:

      1. Press Join Second Channel. The web browser demo app connected to secondChannelName shows the video from your development device.
      2. Press Join. You see, the web browser demo app connected to channelName plays only the audio stream from your development device.

Reference

This section contains information that completes the information in this page, or points you to documentation that explains other aspects to this product.

  • Ensure that each RtcConnection object has a unique user ID that is not 0.
  • You can configure the publishing and subscribing options for the RtcConnection object in joinChannelEx.
  • Each RtcConnection can publish multiple audio streams and a video stream simultaneously.
  • When calls to startOrUpdateChannelMediaRelay are too frequent, they are rejected and RELAY_EVENT_PACKET_UPDATE_DEST_CHANNEL_REFUSED(8) is returned.

Interactive Live Streaming