对于一个音视频通话,你可以将其中的多路音视频流合为一路,并将合并得到的音视频流推送到指定的推流地址(通常是 CDN 地址)。你可以在应用服务端和应用客户端启动转推直播,本文介绍如何通过调用客户端 API,在 RTC 服务端发起和完成转推直播任务。
关于如何调用 Open API,在服务端完成转推直播,参见 通过 OpenAPI 使用转推直播功能。
你已经集成 RTC SDK,实现了基本的音视频通话。
开启合流方法,需要在收到 onRoomStateChanged 回调,进入 RTC 房间成功后执行。
- (void)startLiveTranscoding {
// 获取合流转推视频流布局
NSArray *regions = [self getRegionWithUserId:rtcUid
rtcRoomId:rtcRoomId];
// 设置转推直播参数
self.mixedStreamConfig = [ByteRTCMixedStreamConfig defaultMixedStreamConfig];
// 设置参与合流的单路流
self.mixedStreamConfig.layoutConfig.regions = regions;
// 设置房间id
self.mixedStreamConfig.roomID = rtcRoomId;
// 参与合流的媒体流所属用户的 ID
self.mixedStreamConfig.userID = [LocalUserComponents userModel].uid;
// rtmp 推流地址
self.mixedStreamConfig.pushURL = pushUrl;
// 设置为服务器合流
self.mixedStreamConfig.expectedMixingType = ByteRTCMixedStreamByServer;
// 示例参数,具体参数可以根据业务修改。
// 合流音频采样率,单位 Hz
self.mixedStreamConfig.audioConfig.sampleRate = 44100;
// 合流音频声道数
self.mixedStreamConfig.audioConfig.channels = 2;
// 合流视频帧率
self.mixedStreamConfig.videoConfig.fps = frameRate;
// 合流视频码率
self.mixedStreamConfig.videoConfig.bitrate = maxKbps;
// 合流视频分辨率
self.mixedStreamConfig.videoConfig.width = videoSize.width;
self.mixedStreamConfig.videoConfig.height = videoSize.height;
// 设置合流SEI
self.mixedStreamConfig.layoutConfig.userConfigExtraInfo = @"json";
// 开始合流转推
[self.rtcEngineKit startPushMixedStreamToCDN:@""
mixedConfig:self.mixedStreamConfig
observer:self];
}
// 设置参与合流的单路流
- (NSArray *)getRegionWithUserId:(NSString *)userId
rtcRoomId:(NSString *)rtcRoomId {
NSInteger audienceIndex = 0;
NSMutableArray *list = [[NSMutableArray alloc] init];
ByteRTCMixedStreamLayoutRegionConfig *region = [[ByteRTCMixedStreamLayoutRegionConfig alloc] init];
region.userID = userId;
region.roomID = rtcRoomId;
region.isLocalUser = [userModel.uid isEqualToString:[LocalUserComponents userModel].uid] ? YES : NO;
region.renderMode = ByteRTCMixedStreamRenderModeHidden;
region.locationX = 0.0;
region.locationY = 0.0;
region.widthProportion = 1.0;
region.heightProportion = 1.0;
region.zOrder = 1;
region.alpha = 1.0;
[list addObject:region];
return [list copy];
}
}objectivec/**
* 开启合流转推
* @param roomId 房间id
* @param userId 用户id
* @param liveUrl rtmp 推流地址
*/
private void startLiveTranscoding(String roomId, String userId, String liveUrl,String taskId) {
MixedStreamConfig config = MixedStreamConfig.defaultMixedStreamConfig();
// 设置房间id
config.setRoomID(roomId);
// 设置用户id
config.setUserID(userId);
// 设置推流的直播地址
config.setPushURL(liveUrl);
// 设置合流模式,0 代表服务端合流
config.setExpectedMixingType(ByteRTCStreamMixingType.STREAM_MIXING_BY_SERVER);
//设置合流视频参数,具体参数根据情况而定
MixedStreamVideoConfig videoConfig = config.getVideoConfig();
videoConfig.setWidth(mHostConfig.width);
videoConfig.setHeight(mHostConfig.height);
videoConfig.setFps(mHostConfig.frameRate);
videoConfig.setBitrate(mHostConfig.bitRate);
config.setVideoConfig(videoConfig);
//设置合流音频参数,具体参数根据情况而定
MixedStreamAudioConfig audioConfig = config.getAudioConfig();
audioConfig.setSampleRate(44100);
audioConfig.setChannels(2);
config.setAudioConfig(audioConfig);
//设置合流视频布局参数
MixedStreamLayoutRegionConfig localRegionConfig = new MixedStreamLayoutRegionConfig();
localRegionConfig.setUserID(userId);
localRegionConfig.setIsLocalUser(true);
localRegionConfig.setRoomID(roomId);
localRegionConfig.setLocationX(0);
localRegionConfig.setLocationY(0);
localRegionConfig.setWidthProportion(1);
localRegionConfig.setHeightProportion(1);
localRegionConfig.setAlpha(1);
localRegionConfig.setZOrder(0);
localRegionConfig.setRenderMode(MixedStreamRenderMode.MIXED_STREAM_RENDER_MODE_HIDDEN);
MixedStreamLayoutRegionConfig[] regions = new MixedStreamLayoutRegionConfig[]{localRegionConfig};
MixedStreamLayoutConfig layoutConfig = new MixedStreamLayoutConfig();
layoutConfig.setRegions(regions);
JsonObject json = new JsonObject();
json.addProperty(KEY_SEI_KEY_SOURCE, KEY_SEI_VALUE_SOURCE_NONE);
//设置SEI信息
layoutConfig.setUserConfigExtraInfo(json.toString());
config.setLayout(layoutConfig);
//开始合流任务
mRTCVideo.startPushMixedStreamToCDN(taskId, config, mMixedStreamObserver);
}java在收到远端用户视频流后,才可以更新合流布局。
在转推直播进行时,部分设置可以更新,详见 API 文档。
在音视频互动中,你可以随时启动或停止转推直播。
/**
* 停止合流转推或者退出房间的时候调用
*/
- (void)stopPushStreamToCDN {
[self.rtcEngineKit stopPushStreamToCDN:@""];
self.transcodingSetting = nil;
}objectivec
/**
* 停止合流转推或者退出房间的时候调用
*/
public void stopPushStreamToCDN() {
if (mRTCVideo != null) {
mRTCVideo.stopPushStreamToCDN("");
}
mLiveTranscoding = null;
}javaSEI 是视频编码格式中的补充增强信息,用于传输一些用户自定义的信息。
使用场景:SEI 和视频编码帧一起打包发送,因此可以达到和视频帧发送和解析同步的效果。比如在直播答题场景中,在 SEI 中打包题目信息,每个人听到主播讲题时,同时看到对应的题目,不会因为不同延时导致题目出现的时间与讲解不匹配。
当 APP 需要开启多个视频合流时,可以通过 task_id 来区分多个合流 ID。如果同时只有一个合流视频数据可以使用空字符串代替。startPushMixedStreamToCDN 和 stopPushStreamToCDN 的 task_id 需要成对出现。 如果 task_id 不同,会导致合流不会关闭。
在开启转推任务后,如果因为进行刷新页面等操作,造成应用端进程异常终止,则转推任务会在空闲时间超过设定值后自动停止,默认空闲超时时间为180s。
重启客户端重新登录后,需先调用 stopPushStreamToCDN 结束上一个任务,再开启新的转推任务,以免造成多个任务同时操作一个推流地址,导致新的转推任务失败。
转推直播过程中返回的错误码详见各端 API 文档。
| Android | iOS | Mac | Windows | Electron | Web | |
|---|---|---|---|---|---|---|
| 错误码 | ByteRTCTranscoderErrorCode | ByteRTCStreamMixingErrorCode | ByteRTCStreamMixingErrorCode | StreamMixingErrorCode | StreamMixingErrorCode | StreamMixingEventErrorCode |
startPushMixedStreamToCDN 开启转推。其中,任务参数为 MixedStreamConfig 结构体,使用 defaultMixedStreamConfig 进行参数初始化。updatePushMixedStreamToCDN 更改音视频参数和视频布局。stopPushStreamToCDN 停止转推直播。startPushMixedStreamToCDN:mixedConfig:observer: 开启转推。其中,任务参数为 ByteRTCMixedStreamConfig 结构体,使用 defaultMixedStreamConfig 进行参数初始化。updatePushMixedStreamToCDN:mixedConfig: 更改音视频参数和视频布局。stopPushStreamToCDN: 停止转推直播。startPushMixedStreamToCDN:mixedConfig:observer: 开启转推。其中,任务参数为 ByteRTCMixedStreamConfig 结构体,使用 defaultMixedStreamConfig 进行参数初始化。updatePushMixedStreamToCDN:mixedConfig: 更改音视频参数和视频布局。stopPushStreamToCDN: 停止转推直播。startPushMixedStreamToCDN 开启转推直播。其中,任务参数为 IMixedStreamConfig 结构体,使用 defaultMixedStreamConfig 进行参数初始化。updatePushMixedStreamToCDN 更改音视频参数和视频布局。stopPushStreamToCDN 停止转推直播。startLiveTranscoding 开启转推直播。updateLiveTranscoding 更改音视频参数和视频布局。stopLiveTranscoding 停止转推直播。