# Cross-channel media stream relay (/en/realtime-media/rtc/build/join-and-manage-channels/cross-channel-media-relay/windows)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

Some special use-cases require cross-channel media stream forwarding functionality. RTC SDK enables you to relay the media stream of a host, from a source channel, to multiple target channels simultaneously. This functionality allows you to realize the following interactions:

* The hosts publish and receive each other's audio and video streams while engaging in *cross-channel* real-time interaction.

* The audience receive all audio and video streams from hosts and watch multiple hosts interact at the same time.

Due to its real-time and interactive nature, this feature enriches live broadcasts and game-play, It is especially suitable for live scenes such as co-hosting PK and online choir. It provides the audience with a better viewing experience, while bringing more traffic and revenue to the hosts.

      
  
      
  
      
  
      
  
      
<CalloutContainer type="info">
  <CalloutDescription>
    Cross-channel media stream relay is included in Agora's policy of [10,000 free minutes](/en/api-reference/faq/account/billing_free) every month. For usage beyond the free quota, please refer to [Pricing](/en/realtime-media/rtc/reference/pricing).
  </CalloutDescription>
</CalloutContainer>

## Prerequisites

* Ensure that you have implemented the [SDK quickstart](/en/realtime-media/rtc/get-started-sdk) in your project.
* Contact [support@agora.io](mailto\:support@agora.io) to activate the cross-channel media stream relay feature.

## Implement cross-channel media stream relay

The following figure shows the workflow you implement to facilitate cross-channel media stream relay:

<Accordions>
  <Accordion title="Cross-channel media stream relay workflow">
    ![Cross-channel media stream relay workflow](https://assets-docs.agora.io/images/video-sdk/cross-channel-forwarding.svg)
  </Accordion>
</Accordions>

To implement cross-channel media stream relay in your app, take the following steps:

1. Start cross-channel media stream relay

   After joining a channel, call `startOrUpdateChannelMediaRelay` to configure the source and target channel information and start forwarding a media stream. Calling this method before joining a channel fails. In live broadcasting, only hosts can call this method.

   ```cpp
   // Configure source channel information
   ChannelMediaInfo *m_srcInfo = new ChannelMediaInfo;
   m_srcInfo->channelName = new char[szChannelId.size() + 1];
   strcpy_s(const_cast<char *>(m_srcInfo->channelName), szChannelId.size() + 1,
   		szChannelId.data());
   // Note: The token for source channel is different from the token used when joining the source channel.
   // It needs to be regenerated using the source channel name and uid = 0
   m_srcInfo->token = APP_TOKEN;
   // It is recommended to set the uid of the source channel to 0, allowing the SDK to assign a random uid.
   m_srcInfo->uid = 0;

   // Configure destination channel information
   int nDestCount = m_vecChannelMedias.size();
   ChannelMediaInfo *lpDestInfos = new ChannelMediaInfo[nDestCount];
   for (int nIndex = 0; nIndex < nDestCount; nIndex++) {
   	lpDestInfos[nIndex].channelName = m_vecChannelMedias[nIndex].channelName;
   	lpDestInfos[nIndex].token = m_vecChannelMedias[nIndex].token;
   	// Set the uid to 0, allowing the SDK to assign a random uid, or specify your own uid
   	// Ensure that it is different from all uids in the target channels
   	lpDestInfos[nIndex].uid = m_vecChannelMedias[nIndex].uid;
   }

   ChannelMediaRelayConfiguration cmrc;
   cmrc.srcInfo = m_srcInfo;
   cmrc.destInfos = lpDestInfos;
   cmrc.destCount = nDestCount;
   int ret = 0;
   // Start or update the cross-channel media stream relay
   ret = m_rtcEngine->startOrUpdateChannelMediaRelay(cmrc);
   ```

   <CalloutContainer type="info">
     <CalloutDescription>
       * Best practice is to set the UID of the source channel to `0`, allowing the SDK to assign a random UID.
       * The source channel token in `srcChannelInfo` should be different from the one used when joining the source channel. Generate a new token using the source channel name and `uid = 0`.
       * For the destination channel, set the uid to `0`, to allow the SDK to assign a random `uid`, or specify a `uid`, ensuring that it is different from all uids in the target channel.
       * Cross-channel media stream relay doesn't support String-type user IDs. Join the channel with an int-type `uid`.
     </CalloutDescription>
   </CalloutContainer>

2. Update media stream relay channels

   To forward the stream to multiple target channels or exit the current forwarding channel after starting channel media relay, call `startOrUpdateChannelMediaRelay` again to add or remove target channels for forwarding. Multiple hosts in a channel can forward media streams, and each host can forward to up to six target channels.

   <CalloutContainer type="info">
     <CalloutDescription>
       The updated configuration completely **replaces** the previous configuration.
     </CalloutDescription>
   </CalloutContainer>

3. Pause or resume media stream relay

   To pause forwarding the media stream to all target channels, call `pauseAllChannelMediaRelay`.

   ```cpp
   m_rtcEngine->pauseAllChannelMediaRelay();
   ```

   To resume forwarding the media stream to all target channels, call `resumeAllChannelMediaRelay`.

   ```cpp
   m_rtcEngine->resumeAllChannelMediaRelay();
   ```

4. Stop cross-channel media stream relay

   To stop forwarding the media stream, call `stopChannelMediaRelay` . When forwarding stops, the host exits all target channels.

   ```cpp
   m_rtcEngine->stopChannelMediaRelay();
   m_lstInfo.AddString(_T("stopChannelMediaRelay"));
   m_btnStartMediaRelay.SetWindowText(CrossChannelStartMediaRelay);
   ```

   <CalloutContainer type="info">
     <CalloutDescription>
       If this method fails, you can call `leaveChannel` to leave the channel, and cross-channel media stream relay will automatically stop.
     </CalloutDescription>
   </CalloutContainer>

5. Listen for cross-channel media stream status changes

   During cross-channel media stream relay, the SDK reports changes in the status of media stream relay through the `onChannelMediaRelayStateChanged` callback. Implement relevant business logic based on the [status codes](#status-codes).

   ```cpp
   class CAgoraCrossChannelEventHandler : public IRtcEngineEventHandler {
       virtual void onChannelMediaRelayStateChanged(
           CHANNEL_MEDIA_RELAY_STATE state,
           CHANNEL_MEDIA_RELAY_ERROR code) override {
           if (m_hMsgHanlder)
               ::PostMessage(m_hMsgHanlder,
                   WM_MSGID(EID_CHANNEL_MEDIA_RELAY_STATE_CHNAGENED),
                   state, code);
       }
   };
   ```

## Reference

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

### Status codes

The main media stream forwarding states and their corresponding status codes are as follows:

| Media stream forwarding status                                                                                                                                                                     | status code                                |
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------- |
| The source channel starts transmitting data to the target channel.                                                                                                                                 | `RELAY_STATE_RUNNING`(2) and `RELAY_OK`(0) |
| Cross-channel media stream forwarding encounters an exception. You can troubleshoot based on the [error code](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/enum_channelmediarelayerror.html). | `RELAY_STATE_FAILURE`(3)                   |
| Media stream forwarding has stopped.                                                                                                                                                               | `RELAY_STATE_IDLE`(0) and `RELAY_OK`(0)    |

### Sample project

Agora provides an open-source [CrossChannel](https://github.com/AgoraIO/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/CrossChannel) sample project for your reference. Download the project or view the source code for a more detailed example.

### API reference

* [`startOrUpdateChannelMediaRelay`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/api_irtcengine_startorupdatechannelmediarelay.html)
* [`stopChannelMediaRelay`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_irtcengine.html#api_irtcengine_stopchannelmediarelay)
* [`pauseAllChannelMediaRelay`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_irtcengine.html#api_irtcengine_pauseallchannelmediarelay)
* [`resumeAllChannelMediaRelay`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_irtcengine.html#api_irtcengine_resumeallchannelmediarelay)
* [`onChannelMediaRelayStateChanged`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_irtcengineeventhandler.html#callback_irtcengineeventhandler_onchannelmediarelaystatechanged)
* [`ChannelMediaRelayConfiguration`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_channelmediarelayconfiguration.html)
* [`ChannelMediaInfo`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_channelmediainfo.html)

    
  
      
  
      
  
      
  
      
  
