human: 如何处理七牛云的实时音视频跨房媒体转发

gpt: [实时音视频](https://developer.qiniu.com/rtc) > 使用指南 > iOS >跨房媒体转发

#  跨房媒体转发

最近更新时间: 2022-06-30 17:17:56

本部分介绍跨房媒体转发的使用以及使用场景

跨房媒体转发允许主播不离开自己的所在的房间，仅通过信令的操作，转发自己的音视频到其他的房间。七牛 RTC SDK
支持同时转发多路至多个房间（具体按照设备状况以及网络状况决定）。依赖此功能，可以很方便的实现直播过程中的连麦，小班课等业务。

# 名词解释

场景：

  * [QNClientModeLive](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNClientMode)：用于互动直播场景，可以通过设置角色来控制权限。主播可以发布和订阅音视频，观众仅能订阅音视频。
  * [QNClientModeRTC](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNClientMode)：用于通信场景，所有人都可以发布自己的音视频，不可设置角色。

角色：

  * [QNClientRoleBroadcaster](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNClientRole)：主播角色，拥有发布和订阅音视频的权限。
  * [QNClientRoleAudience](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNClientRole)：观众角色，仅有订阅音视频的权限。

# 使用前注意事项

**请注意当前跨房功能仅对使用场景为直播，且角色为主播的场景下才能使用。请确保加入房间前调用以下接口：**

    
    
    // 使用直播场景和主播角色来创建 QNRTCClient
    QNClientConfig *clientConfig = [[QNClientConfig alloc] initWithMode:QNClientModeLive role:QNClientRoleBroadcaster];
    QNRTCClient *rtcClient = [QNRTC createRTCClient:clientConfig];
    // 创建 client 后依然可以修改角色，但是无法修改场景
    [rtcClient setClientRole:QNClientRoleBroadcaster completeCallback:nil];
    

对于以下几种情况：

  * 场景为 [QNClientModeRTC](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNClientMode)，则必须使用 [QNClientModeLive](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNClientMode) 重新创建房间
  * 已加入房间，且使用场景为 [QNClientModeLive](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNClientMode) ，但是角色为 [QNClientRoleAudience](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNClientRole)，则不需要退出房间，执行以下步骤即可： 
    1. 调用 `[rtcClient setClientRole:QNClientRoleBroadcaster completeCallback:callback]`
    2. 等待 `QNClientRoleResultCallback` 返回结果 `QNClientRole` 成功切换为 [QNClientRoleBroadcaster](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNClientRole)。
    3. 调用跨房媒体转发 API。

# 开启跨房媒体转发

通过
[QNRTCClient.startRoomMediaRelay](https://developer.qiniu.com/rtc/api/8836/QNRTCClient-
iOS#startRoomMediaRelay) 接口开启跨房媒体转发，在
[QNMediaRelayResultCallback](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNMediaRelayResultCallback)
中通过字典 `state` 对应房间名 `key` 获取处理结果，具体的 `value` 值参见
[QNMediaRelayState](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNMediaRelayState)。

    
    
    - (void)startRoomMediaRelay:(QNRoomMediaRelayConfiguration *_Nonnull)config completeCallback:(QNMediaRelayResultCallback)callback;
    

其中，[QNRoomMediaRelayConfiguration](https://developer.qiniu.com/rtc/api/10143/QNRoomMediaRelayConfiguration-
iOS) 为跨房媒体转发的配置类，主要包含如下配置方法：

    
    
    // 源房间信息
    @property (strong, nonatomic) QNRoomMediaRelayInfo *srcRoomInfo;    
    // 设置目标房间信息          
    - (BOOL)setDestRoomInfo:(QNRoomMediaRelayInfo *_Nonnull)destRoomInfo forRoomName:(NSString *_Nonnull)roomName;
    

由跨房媒体转发操作触发的结果，通过如下 block 回调：

    
    
    /*!
     * @typedef QNMediaRelayResultCallback
     *
     * @abstract 跨房间媒体转发操作的回调
     *
     * @warning 此接口回调的是所有跨房目标房间的状态。具体每个目标房间转发状态，需要参考回调参数中目标房间对应的 QNMediaRelayState
     *
     * @param state 目标房间状态， key 为房间名， value 为状态
     *
     * @param error 操作失败的错误信息
     */
    typedef void (^QNMediaRelayResultCallback)(NSDictionary *state, NSError *error);
    

**注意：跨房媒体转发操作过程中，发生错误的信息，可参见[QNMediaRelayErrorDomain](https://developer.qiniu.com/rtc/10718/media-
relay-iOS/rtc/9254)**

示例代码如下：

    
    
    QNRoomMediaRelayConfiguration *config = [QNRoomMediaRelayConfiguration new];
    QNRoomMediaRelayInfo *srcRoomInfo = [QNRoomMediaRelayInfo new];
    srcRoomInfo.roomName = roomName;
    srcRoomInfo.token = token;
    // 目标房间 1
    QNRoomMediaRelayInfo *destInfo1 = [QNRoomMediaRelayInfo new];
    destInfo1.roomName = roomName1;
    destInfo1.token = token1;
    // 目标房间 2
    QNRoomMediaRelayInfo *destInfo2 = [QNRoomMediaRelayInfo new];
    destInfo2.roomName = roomName2;
    destInfo2.token = token2;
    // 源房间
    config.srcRoomInfo = srcRoomInfo;
    // 设置目标房间
    [config setdestRoomInfo:destInfo1 forRoomName:roomName1];
    [config setdestRoomInfo:destInfo2 forRoomName:roomName2];
    // 开启跨房
    [rtcClient startRoomMediaRelay:config completeCallback:^(NSDictionary *state, NSError *error) {
        if (!error) {
            NSString *str = @"开始跨房媒体转发成功";
        }
    }];
    

# 更新跨房媒体转发

通过
[QNRTCClient.updateRoomMediaRelay](https://developer.qiniu.com/rtc/api/8836/QNRTCClient-
iOS#updateRoomMediaRelay) 接口更新跨房媒体转发，在
[QNMediaRelayResultCallback](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNMediaRelayResultCallback)
中通过字典 `state` 对应房间名 `key` 获取处理结果，具体的 `value` 值参见
[QNMediaRelayState](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNMediaRelayState)。

> **注意：此接口中的`config` 为全量更新，如已经开启的跨房的目标房间未被包含，则会被停止**
    
    
    - (void)updateRoomMediaRelay:(QNRoomMediaRelayConfiguration *_Nonnull)config completeCallback:(QNMediaRelayResultCallback)callback;
    

示例代码如下：

    
    
    QNRoomMediaRelayConfiguration *config = [QNRoomMediaRelayConfiguration new];
    QNRoomMediaRelayInfo *srcRoomInfo = [QNRoomMediaRelayInfo new];
    srcRoomInfo.roomName = roomName;
    srcRoomInfo.token = token;
    // 目标房间 1
    QNRoomMediaRelayInfo *destInfo1 = [QNRoomMediaRelayInfo new];
    destInfo1.roomName = roomName1;
    destInfo1.token = token1;
    // 目标房间 2
    QNRoomMediaRelayInfo *destInfo2 = [QNRoomMediaRelayInfo new];
    destInfo2.roomName = roomName2;
    destInfo2.token = token2;
    // 设置源房间
    config.srcRoomInfo = srcRoomInfo;
    // 设置目标房间
    [config setdestRoomInfo:destInfo1 forRoomName:roomName1];
    [config setdestRoomInfo:destInfo2 forRoomName:roomName2];
    // 更新跨房
    [rtcClient updateRoomMediaRelay:config completeCallback:^(NSDictionary *state, NSError *error) {
        if (!error) {
            NSString *str = @"开始跨房媒体转发成功";
        }
    }];
    

# 停止跨房媒体转发

通过
[QNRTCClient.stopRoomMediaRelay](https://developer.qiniu.com/rtc/api/8836/QNRTCClient-
iOS#stopRoomMediaRelay) 接口停止跨房媒体转发，所有已开启的跨房行为将被停止， 在
[QNMediaRelayResultCallback](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNMediaRelayResultCallback)
中通过字典 `state` 对应房间名 `key` 获取处理结果，具体的 `value` 值参见
[QNMediaRelayState](https://developer.qiniu.com/rtc/api/9254/QNTypeDefines#QNMediaRelayState)。

    
    
    - (void)stopRoomMediaRelay:(QNMediaRelayResultCallback)callback;
    

# 事件通知

  * 主动跨房的主播 A，可在 [QNRTCClientDelegate.didMediaRelayStateChanged](https://developer.qiniu.com/rtc/api/9248/QNRTCClientDelegate#didMediaRelayStateChanged) 当前跨房请求的状态更新，具体状态参见 [QNMediaRelayState](https://developer.qiniu.com/rtc/9254/QNTypeDefines#QNMediaRelayState)
  * 被跨房的主播 B，当主播 A 跨房成功之后，会触发 [QNRTCClientDelegate.didJoinOfUserID](https://developer.qiniu.com/rtc/api/9248/QNRTCClientDelegate#didJoinOfUserID)、[QNRTCClientDelegate.didLeaveOfUserId](https://developer.qiniu.com/rtc/api/9248/QNRTCClientDelegate#didLeaveOfUserId) 等用户加入、离开、发布音视频等回调。

# 直播连麦 pk

使用跨房媒体转发方案，可以很方便的解决连麦 pk 这类场景的需求。主播 A 不再需要离开自己的房间，只需通过以下步骤即可：

  1. 业务协商，主播 A 通过 `QNRTC` 自定义消息或者业务服务器长连接向主播 B 发送连麦请求，如果请求通过，则进行下一步
  2. 主播 A 调用 [QNRTCClient.startRoomMediaRelay](https://developer.qiniu.com/rtc/api/8836/QNRTCClient-iOS#startRoomMediaRelay)，主播 B 收到主播 A 加入房间和发布音视频等一系列消息后，再使用 [QNRTCClient.setTranscodingLiveStreamingID](https://developer.qiniu.com/rtc/api/8836/QNRTCClient-iOS#setTranscodingLiveStreamingID) 方法更新合流布局即可。
  3. 主播 B 操作同主播 A。
  4. 连麦结束后，各自调用 [QNRTCClient.stopRoomMediaRelay](https://developer.qiniu.com/rtc/api/8836/QNRTCClient-iOS#stopRoomMediaRelay) 停止跨房，并调用 [QNRTCClient.removeTranscodingLiveStreamingID](https://developer.qiniu.com/rtc/api/8836/QNRTCClient-iOS#removeTranscodingLiveStreamingID) 移除连麦布局。
  5. 结束

以上内容是否对您有帮助？