直播场景最佳实践
场景概述
实时音视频场景下的直播,主要分为三种,它们分别是单路流直播、多路流合流直播以及两者相结合可切换的直播场景。
以下将对上述三种场景的使用姿势做相应的使用说明,其中有关注意事项的部分请仔细阅读。
实现分析
单路流直播场景
单路流直播场景,就是将一路音视频流通过 RTN 服务器直接转推到直播服务器,适用于不包含连麦的秀场直播
、连麦时需要将某路流单独转推落存储
等场景。
该场景的流程示意图大致如下:
注意:若主播有一路以上视频流(采集/外部导入),需要做合流转推,可参考多路流合流直播场景的实现。
单路流转推场景主要实现步骤如下:
创建单路转推任务
QNForwardStreamConfiguration
用于配置单路转推的相关信息,包括推流地址、jobId 以及音视频 track,详细的接口设置可参考 QNForwardStreamConfiguration
创建转推任务的示例代码如下:
// 初始化单路转推配置
QNForwardStreamConfiguration *forwardConfig = [[QNForwardStreamConfiguration alloc] init];
// 设置 jobId
forwardConfig.jobId = self.roomName;
// 设置推流地址
forwardConfig.publishUrl = [NSString stringWithFormat:@"rtmp://xxx.com/%@", self.roomName];
// 仅支持一路音频 track、一路视频 track
forwardConfig.audioTrackInfo = self.audioTrackInfo;
forwardConfig.videoTrackInfo = self.cameraTrackInfo;
// 创建单路转推任务
[self.engine createForwardJobWithConfiguration:forwardConfig];
单路转推任务创建成功后,会回调以下接口:
/*!
* @abstract 成功创建单路转推任务的回调。
*
* @since v2.5.0
*/
- (void)RTCEngine:(QNRTCEngine *)engine didCreateForwardJobWithJobId:(NSString *)jobId {
// 此处回调的 jobId 就是创建单路的 jobId
}
创建成功即开启了单路流转推,可以通过相应的播放链接拉取直播流进行观看。
停止单路转推任务
可以通过调用如下 API 传入对应的 jobId,实现单路转推任务的停止
/*!
* @abstract 停止单路转推任务。
*
* @param jobId 单路转推任务 id
*
* @since v2.5.0
*/
- (void)stopForwardJobWithJobId:(NSString *)jobId;
多路流合流直播场景
多路流合流直播场景,适用于连麦互动直播
、PK 直播
以及单主播需两路以上视频合流转推
等场景。
简单来说,就是将连麦各方的音视频进行合流,然后进行转推。相对于单路转推会更复杂些。
该场景的流程示意图大致如下:
实现该场景,需要先了解下相关配置类及其作用:
QNMergeStreamConfiguration
用于配置合流的基本参数,包括任务 id、推流地址、合流的宽高、码率等信息。具体接口可参考 QNMergeStreamConfigurationQNMergeStreamLayout
用于配置合流的布局参数,包括 trackId、frame 以及层级。具体接口可参考 QNMergeStreamLayout
实现步骤大致如下:
开启合流直播
创建 QNMergeStreamConfiguration
// 初始化合流配置
QNMergeStreamConfiguration *mergeStreamConfiguration = [QNMergeStreamConfiguration defaultConfiguration];
// 配置合流任务 id
mergeStreamConfiguration.jobId = roomName;
// 设置推流地址
mergeStreamConfiguration.publishUrl = [NSString stringWithFormat:@"rtmp://pili-publish.qnsdk.com/sdk-live/%@", _roomName];
// 设置最小码率
mergeStreamConfiguration.minBitrateBps = 1000*1000;
// 设置最大码率
mergeStreamConfiguration.maxBitrateBps = 1000*1000;
// 创建合流任务
[self.engine createMergeStreamJobWithConfiguration:mergeStreamConfiguration];
合流任务创建成功后会回调如下接口:
/*!
* @abstract 成功创建合流任务的回调。
*
* @since v2.0.0
*/
- (void)RTCEngine:(QNRTCEngine *)engine didCreateMergeStreamWithJobId:(NSString *)jobId {
// 这里回调的 jobId 就是创建合流成功的任务 id
}
设置合流布局
合流任务创建成功之后,就可以对房间内已发布的 track 进行合流布局的配置。
QNMergeStreamLayout *layout = [[QNMergeStreamLayout alloc] init];
layout.frame = firstTrackFrame;
layout.zIndex = firstTrackZValue;
layout.trackId = trackId;
其中,trackId 可以通过 SDK 提供的相关回调返回的QNTrackInfo
获取:
/*!
* @abstract 本地音/视频 Track 成功发布的回调。
*
* @since v2.0.0
*/
- (void)RTCEngine:(QNRTCEngine *)engine didPublishLocalTracks:(NSArray<QNTrackInfo *> *)tracks;
/*!
* @abstract 远端用户发布音/视频的回调。
*
* @since v2.0.0
*/
- (void)RTCEngine:(QNRTCEngine *)engine didPublishTracks:(NSArray<QNTrackInfo *> *)tracks ofRemoteUserId:(NSString *)userId;
成功创建合流任务之后,调用以下 API 进行布局配置,更新布局也通过如下 API 设置
/*!
* @abstract 将对应的音视频 Track 加入合流。
*
* @discussion 需要更新合流布局时,重新调用该接口即可。若使用默认的合流任务,则 jobId 传入 nil 即可。
*
* @since v2.0.0
*/
- (void)setMergeStreamLayouts:(NSArray <QNMergeStreamLayout *> *)layouts
jobId:(nullable NSString *)jobId;
当期望取消某路合流布局时,可通过调用如下 API 实现:
/*!
* @abstract 将对应的音视频 Track 从合流中移除。
*
* @discussion 此处 QNMergeStreamLayout 中只需要设置 trackId 即可,其它参数可忽略。若使用默认的合流任务,则 jobId 传入 nil 即可。
*
* @since v2.0.0
*/
- (void)removeMergeStreamLayouts:(NSArray <QNMergeStreamLayout *> *)layouts
jobId:(nullable NSString *)jobId;
停止合流直播
通过调用如下 API 传入对应的 jobId,实现合流转推任务的停止
/*!
* @abstract 停止合流任务。
*
* @param jobId 合流任务 id,如果使用的是默认的合流任务,则传入 nil 即可。
*
* @since v2.0.0
*/
- (void)stopMergeStreamWithJobId:(nullable NSString *)jobId;
单路流转推、多路流合流两者的切换
单路流转推与多路流合流的切换,适用于存在连麦需求的秀场直播
等场景,能够满足主播在直播过程中的切换需求。
该场景的实现,需要注意如何在切换过程中,保证观看端不会出现断流黑屏。
这里,为避免切换过程中的断流黑屏问题,我们引入 serialnum
的概念来实现两路流的平滑切换。
需要注意以下几点:
QNForwardStreamConfiguration
和QNMergeStreamConfiguration
两种任务场景的推流地址需要保持一致,以避免播放端多余的切流操作- 由于以上提到的完全一致的推流地址,可能会出现抢流的现象出现,所以需要在推流地址上加上
serialnum
的参数,如"rtmp://xxx.com/app/roomName?serialnum=xxx" - serialnum 决定流的优先级,值越大,优先级越高,不会出现抢流的现象。
- 由于需要自定义推流地址,故合流任务必须使用自定义合流任务。
综上所述,单路流转推、多路流合流切换的场景的实现步骤大致如下:
- 创建单路转推任务,同时开启单路流直播
- 需要从单路流转推切换到多路流合流转推时,
创建自定义合流任务
后,在收到自定义合流任务创建成功的回调中,实现单路转推的停止 - 需要从合流转推任务切换到单路转推任务时,
创建单路转推任务
后,在收到单路转推任务创建成功的回调中,实现自定义合流任务的停止
注意要使用带有 serialnum
参数的推流地址,通过增大 serialnum
获取优先级。
通过上述方式,即可实现单路流直播、多路流合流直播之间的切换,具体实现也可参照 demo 中的相关实现。
注意事项
- 为保证单路流直播的质量,请务必保证配置
QNTrackInfo
为固定分辨率,即setMaintainResolutionEnabled
为 YES - 如果场景涉及到单路流直播、多路流合流直播之间的切换,那么合流务必使用自定义合流任务以指定带有
serialnum
的推流地址。其中,serialnum 决定流的优先级,值越大,优先级越高 - 单路流直播场景,一路流仅支持一路音频轨和一路视频轨的设置,多路或重复设置 track 默认会被覆盖