快速实现 PK 直播

更新时间: 2023/12/26 09:24:15

通过跨房间媒体流转发,主播无须退出/加入原房间,即可将媒体流同时转发到多个房间中,实现PK 直播。

下文介绍在单人直播的过程中,主播 A 邀请主播 B 进行 PK 直播的实现流程。

功能原理

PK 直播的架构原理如下图所示。

PK直播.png

PK 直播的业务流程说明如下:

  1. 主播 A 发出 PK 邀请,主播 B 同意。
  2. 通过跨频道转发,主播 A 和主播 B 不需要退出原房间,直接将媒体流转发到房间 A 和房间 B 中,实现主播跨房间与其他主播实时互动。
  3. 互动直播服务器将主播 A 和主播 B 的音视频进行混屏转码后,推到 CDN 分发。
  4. 观众端使用 RTMP/HLS/FLV 协议进行拉流观看。

注意事项

  • 只支持网易云信播放器 NELivePlayer 进行拉流,其他播放器暂不兼容。
  • 单人直播切换到 PK 直播时,音频采样率必须保持一致。

API 时序图

sequenceDiagram
    actor 主播A
    participant NERtcSDK
    participant 业务服务器
    actor 主播B
    %% 开始PK 
   
    主播A->>业务服务器: 邀请PK
    Note right of 主播A: 邀请主播B进行PK(带上自己的uid、cname、Token等信息)
    Note left of 主播B: 请自行实现麦位管理相关业务逻辑
    业务服务器->>主播B: 邀请PK(带上主播A的uid、cname、Token等信息)

    主播B-->>业务服务器: 同意PK
    业务服务器-->>主播A: 对端同意PK(带上主播B的uid、cname、Token等信息)

    rect rgb(191, 223, 255)
    主播A ->> NERtcSDK: startChannelMediaRelay   开启媒体转发
    主播A ->> NERtcSDK: addLiveStream 开始旁路推流
    NERtcSDK -->> 主播A: onNERTCEngineLiveStreamState  监听旁路推流状态

    主播A ->> NERtcSDK: stopPushStreaming   旁路推流成功后,停止单人直播推流

    Note right of 主播A: 当主播B开始MediaRelay后,更新旁路推流,具体请根据实际业务进行调整
    主播A ->> NERtcSDK: updateLiveStreamTask  更新旁路推流
    Note right of 主播A:  根据回调确认mediaRelay是否成功,如果失败,则进行失败回退,<br>例如调用stopChannelMediaRelay和removeLiveStreamTask 方法结束 PK
    NERtcSDK -->> 主播A: onNERtcEngineChannelMediaRelayStateDidChange:channelName: <br>和onNERtcEngineDidReceiveChannelMediaRelayEvent: channelName: error:
    
    end
    NERtcSDK -->> 主播A: 监听房间中人员进入和音视频打开的回调
    NERtcSDK -->> 主播B: 监听房间中人员进入和音视频打开的回调

    主播A ->> 业务服务器: 结束PK
    业务服务器 ->> 主播B: 结束PK
    主播A ->> NERtcSDK: startPushStreaming  重新开始单人直播推流

    NERtcSDK -->> 主播A: onNERtcEngineStartPushStreaming
    主播A ->> NERtcSDK: stopChannelMediaRelay  停止媒体转发
    主播A ->> NERtcSDK: removeLiveStreamTask  移除旁路推流任务
    主播B ->> NERtcSDK: stopChannelMediaRelay
    主播B ->> NERtcSDK: removeLiveStreamTask  移除旁路推流任务

实现方法

  1. 已实现单人直播

开始 PK

  1. 开始 mediaRelay。

    主播 A 调用 startChannelMediaRelay 方法开启媒体转发功能,将主播 A 的视频流推送到主播 B 房间。

  2. 开启旁路推流任务。

    主播 A 调用 addLiveStreamTask 方法添加旁路推流任务,将主播 A 和主播 B 房间的音视频流推送到 CDN 上进行合流。

    旁路推流时的音频采样率和声道数请保持和单人直播时的一致,采样率设置为 44100,声道数设置为 2 。

  3. 等待旁路推流结果。

    通过 onNERTCEngineLiveStreamState 回调监听旁路推流状态,如果状态为 kNERtcLsStatePushing, 表示旁路推流成功。

    如果旁路推流失败,则根据业务实际情况进行失败回退,例如调用 stopChannelMediaRelay 方法停止媒体转发功能。

  4. 停止单人直播推流。

    主播 A 调用 stopPushStreaming 方法停止单人直播推流。

  5. 等待主播 B 加入房间后更新旁路推流任务。

    主播 A 调用 updateLiveStreamTask 方法更新旁路推流任务,保证主播房间和挑战者房间的音视频流能够同步播放。

  6. 确认 mediaRelay 是否成功。

    通过 onNERtcEngineChannelMediaRelayStateDidChangeonNERtcEngineDidReceiveChannelMediaRelayEvent: channelName: error: 回调监听媒体转发状态,确认媒体转发是否成功。

    如果媒体转发失败,则根据业务实际情况进行失败回退,例如调用 stopChannelMediaRelayremoveLiveStreamTask 方法结束 PK。

结束PK

  1. 开始单人直播推流。

    主播 A 调用 startPushStreaming 方法开始单人直播推流。

  2. 等待单人直播推流结果。

    主播 A 通过 onNERtcEngineStartPushStreamingWithResult:channelId: 回调监听单人直播推流状态,如果推流成功,则执行下一步操作。

  3. 停止mediaRelay。

    主播 A 和 主播 B 分别调用 stopChannelMediaRelay 方法停止媒体转发功能。

  4. 移除旁路推流任务。

    主播 A 和 主播 B 分别调用 removeLiveStreamTask 方法移除旁路推流任务。

示例代码

网易云信为您提供实现CDN 推流的示例代码作为参考,您可以直接拷贝用于运行测试。

请单击下载CDN 推流最佳实践代码

//发起PK
- (int)enterPK:(NSString *)channelName token:(NSString *)token uid:(uint64_t)uid {
    //step1 开始mediaRelay(startMediaRelay)
    NERtcChannelMediaRelayConfiguration *mediaRelayConfig = [[NERtcChannelMediaRelayConfiguration alloc]init];
    NERtcChannelMediaRelayInfo *info = [[NERtcChannelMediaRelayInfo alloc]init];
    info.channelName = channelName;
    info.token = token;
    info.uid = uid;
    [mediaRelayConfig setDestinationInfo:info forChannelName:info.channelName];
    [[NERtcEngine sharedEngine] startChannelMediaRelay:mediaRelayConfig]
    
    //step2 开启旁路推流任务(addLiveStream,旁路任务中的音频参数保持跟cdn下相同(采样率、声道数等等))
    [[NERtcEngine sharedEngine] addLiveStreamTask:task compeltion:^(NSString * _Nonnull taskId, kNERtcLiveStreamError errorCode) {
    }];
    
    //step3 等待旁路推流结果(onNERTCEngineLiveStreamState:taskID:url:), 如果state为kNERtcLsStatePushing表示添加旁路任务成功,则停止cdn推流(stopPushStreaming)
    [[NERtcEngine sharedEngine] stopPushStreaming];
    
    //step4 等待pk对方加入房间后更新旁路推流任务 updateLiveStreamTask
    [[NERtcEngine sharedEngine] updateLiveStreamTask:task compeltion:^(NSString * _Nonnull taskId, kNERtcLiveStreamError errorCode) {
    }];
    
    //step5 确认mediaRelay是否成功,如果失败根据实际情况做相应处理
    //等待mediaRelay任务状态回调onNERtcEngineChannelMediaRelayStateDidChange:channelName:和onNERtcEngineDidReceiveChannelMediaRelayEvent: channelName: error:确认mediaRelay是否成功
}


//结束PK
- (int)leavePK {
    //step1 开始cdn推流
    [[NERtcEngine sharedEngine] startPushStreaming:config];
    
    //step2 等待cdn推流结果回调(onNERtcEngineStartPushStreamingWithResult:channelId:),
    //成功后停止mediaRelay(stopMediaRelay)和移除旁路推流任务(removeLiveStreamTask:compeltion:)
    [[NERtcEngine sharedEngine] stopChannelMediaRelay];
    [[NERtcEngine sharedEngine] removeLiveStreamTask:task compeltion:^(NSString * _Nonnull taskId, kNERtcLiveStreamError errorCode) {
    }];
}

常用的回调

请在初始化时注册推流相关的回调,PK 场景需要关注的主要回调如下:

//开始推流startPushStreaming结果回调
- (void)onNERtcEngineStartPushStreamingWithResult:(NERtcError)result channelId:(uint64_t)channelId;

//停止推流stopPushStreaming结果回调
- (void)onNERtcEngineStopPushStreaming:(NERtcError)result;

//推流过程中断开,变为重连状态回调
- (void)onNERtcEnginePushStreamingChangeToReconnectingWithReason:(NERtcError)reason;

//推流过程中重连成功回调
- (void)onNERtcEnginePushStreamingReconnectedSuccess;

//推流状态已改变回调
- (void)onNERTCEngineLiveStreamState:(NERtcLiveStreamStateCode)state taskID:(NSString *)taskID url:(NSString *)url;

//跨房间媒体流转发状态发生改变回调
- (void)onNERtcEngineChannelMediaRelayStateDidChange:(NERtcChannelMediaRelayState)state channelName:(NSString *)channelName;

//媒体流相关转发事件回调
- (void)onNERtcEngineDidReceiveChannelMediaRelayEvent:(NERtcChannelMediaRelayEvent)event channelName:(NSString *)channelName error:(NERtcError)error;

此文档是否对你有帮助?
有帮助
去反馈
  • 功能原理
  • 注意事项
  • API 时序图
  • 实现方法
  • 示例代码
  • 常用的回调