旁路推流
更新时间: 2024/08/05 15:02:55
NERTC SDK 支持云端音视频混流和 RTMP 旁路推流,可以将实时音视频流转为标准直播流,并将其从网易云信实时音视频云推送到第三方 CDN(Content Delivery Network)或网易云信直播服务,这一过程称为旁路推流。
推流到 CDN 后,基于 CDN 的大规模内容分发,观众可通过 URL 拉流地址使用播放器或 Web 端浏览器直接在线观看直播,也可以加入音视频房间进行实时连麦。当房间中有多个主播时,需要将多个直播流组合成单流,并设置直播流的推流布局,在直播画布中显示主播们的实时画面。
您可以选择通过客户端或者服务端实现旁路推流,服务端推流方法请参考旁路推流。移动客户端受限于网络状况,为保证直播的稳定性,建议通过服务端实现旁路推流。本文档为您展示通过客户端进行旁路推流的实现方式。
功能描述
在您的项目中实现音视频通话后,可以将房间画面进行旁路推流。网易云信可以将您的媒体流在云端进行混流、转码、合图等操作,生成一路视频流,并将其推送到网易云信直播服务中进行大规模内容分发,以便观众直播观看。
- 房间内首个终端加入自动触发转码,房间内无终端时停止转码。
- 直播流支持 RTMP 协议。
前提条件
- 主播端推流之前,需要通过 setChannelProfile 设置房间模式为直播模式。
- 发起推流任务之前,请确认您已实现音视频通话的相关流程。详细信息请参考 快速入门。
注意事项
- 同一个音视频房间(即同一个 channelid)可以创建 3 个不同的推流任务。
- 客户端 SDK 添加推流任务时,默认将创建推流任务的用户 UID 设置为主播角色。互动直播场景中,仅支持解析主播端的 SEI 自定义数据。
- 自 2021年 7 月 13 日开始,加入房间时无需通过 liveEnable 打开推流开关。加入房间并创建推流任务后,房间中所有成员的音视频流均可以进行混流并推流至 CDN。
- 移动客户端互动直播受限于网络状况,为保证直播的稳定性,推荐通过服务端实现旁路推流。
实现方式
在项目中实现音视频通话后,可以通过 addTasks 接口创建推流任务,并配置推流画面布局,将房间画面进行旁路推流。
其中参数 options
用于设置推流任务信息,包括任务基本信息、推流布局、 音视频流配置等。
配置推流任务信息
创建推流任务时,需要配置任务 ID、推流地址等推流参数信息,还可以开启直播视频录制。
录制的视频默认存储在点播服务中,您可以通过点播的相关接口查看并下载视频文件。详细信息请参考点播媒资管理。
推流任务信息相关参数说明:
参数名称 | 描述 |
---|---|
taskId | 自定义的推流任务ID。请保证此 ID 唯一。字母数字下划线组成的 64 位以内的字符串。 |
streamUrl | 推流地址,例如 rtmp://test.url。 此处的推流地址可设置为网易云信直播产品中服务端 API 创建直播频道 的返回参数pushUrl。 |
record | 旁路推流是否需要进行音视频录制。 |
配置推流布局
通过 layout 参数可以设置互动直播的画面布局,即自定义房间画面的各路视频布局方式,例如调整画布(Canvas)大小和颜色、各路视频的图像大小、位置等。
当房间中只有一路视频流时,您也可以设置视频透传。
音视频流配置
config 参数用于配置音视频流编码参数等设置。
-
通过 audioParam 设置音频编码参数。
- 通过 bitRate 设置音频推流码率。单位为 kbps,取值范围为 10~192。语音场景建议设置为 64 及以上码率,音乐场景建议设置为 128 及以上码率。
- 通过 channels 设置音频推流声道数,默认为2,即双声道。
- 通过 codecProfile 设置音频编码规格,默认为 NERTC.LIVE_STREAM_AUDIO_CODEC_PROFILE.LC_AAC,即 LC-AAC 规格,表示基本音频编码规格。
- 通过 sampleRate 设置音频推流采样率。默认采样率为 48 kHz。
-
通过 singleVideoNoTrans 设置视频透传。
singleVideoNoTrans 参数设置为 true 表示开启视频透传,开启后,如果房间中只有一路视频流输入,则不对输入视频流进行转码,不遵循转码布局,直接推流 CDN。视频透传默认为关闭状态。
-
通过 subAllAudio 设置音频流订阅。
subAllAudio 设置为 true 表示互动直播中订阅所有用户的音频流,房间中所有成员的音频流均会被混流后推往 CDN。
参数名称 | 描述 |
---|---|
single_video_passthrough | 参数设置为 true 表示开启视频透传,开启后,如果房间中只有一路视频流输入,则不对输入视频流进行转码,不遵循转码布局,直接推流 CDN。视频透传默认为关闭状态。 |
audio_bitrate | 音频推流码率。单位为 kbps,取值范围为 10~192。语音场景建议设置为 64 及以上码率,音乐场景建议设置为 128 及以上码率。 |
sampleRate | 音频推流采样率。默认值为 kNERtcLiveStreamAudioSampleRate48000 48K。 |
channels | 音频推流声道数,默认为 2,即双声道。 |
audioCodecProfile | 音频编码规格,默认为 0,即 LC-AAC 规格,表示基本音频编码规格。 |
API 参考
方法 |
功能 |
---|---|
Client.addTasks | 添加房间推流任务。 |
Client.updateTasks | 更新修改房间推流任务。 |
Client.deleteTasks | 删除房间推流任务。 |
示例代码
js //加入房间前设置直播模式:
//"rtc": 通信场景,"live": 直播场景
rtc.client.setChannelProfile({mode:'live'});
//加入房间并打开推流开关
rtc.client.join({
channelName: '房间名称',
uid: uid,
token: token
}).then((obj) => {
console.info('加入房间成功...')
//初始化本地流,并且发布
initLocalStream() //后面介绍说明
})
// 添加推流任务
// 互动直播的推流任务,可以设置多个推流任务
let rtmpTasks = []
// taskID 可选字母、数字,下划线,不超过64位
let taskId = 'taskId_1'
// 设置推互动直播推流地址,一个推流任务对应一个推流房间
let streamUrl = 'rtmp://xxxxxx-1'
// 设置是否进行互动直播录制,请注意与音视频通话录制区分。
let record = true
let task1 = {
taskId,
streamUrl,
record,
// 整体布局参数
layout: {
canvas: {
//整体布局宽度
width: 1280,
//整体布局高度
height: 720,
//整体布局背景色(转为10进制的数,如:#FFFFFF 16进制转为10进制为 16777215)
color: 16777215
},
users: [{
uid: 100, //用户id
x: 0, // user1 的视频布局x偏移,相对整体布局的左上角(前提是推流发布user1的视频)
y: 0, // user1 的视频布局y偏移,相对整体布局的左上角(前提是推流发布user1的视频)
width: 640, // user1 的视频布局宽度(前提是推流发布user1的视频)
height: 360, //user1 的视频布局高度(前提是推流发布user1的视频)
adaption: 1, //自适应,值默认为1
pushAudio: true, // 推流是否发布user1 的音频
pushVideo: true // 推流是否发布user1的视频
},
{
uid: 200, //用户id
x: 0, // user2 的视频布局x偏移,相对整体布局的左上角(前提是推流发布user2的视频)
y: 0, // user2 的视频布局y偏移,相对整体布局的左上角(前提是推流发布user2的视频)
width: 640, // user2 的视频布局宽度(前提是推流发布user2的视频)
height: 360, //user2 的视频布局高度(前提是推流发布user2的视频)
adaption: 1, //自适应,值默认为1
pushAudio: true, // 推流是否发布user2 的音频
pushVideo: true // 推流是否发布user2 的视频
}],
images: [{
url: "xxxxxx", //设置背景图片
x: 0, // 背景图片x偏移,相对整体布局的左上角
y: 0, // 背景图片y偏移,相对整体布局的左上角
width: 480, // 背景图片宽度
height: 360, //背景图片高度
adaption: 1 //自适应,值默认为1
}]
}
}
rtmpTasks.push(task1)
// 添加推流任务
rtc.client.addTasks({rtmpTasks}).then(()=>{
console.log('添加推流任务接口成功')
}).catch(error=>{
console.warn('添加推流任务接口失败: ', error)
if (error == 'INVALID_PARAMETER') {
console.log('参数错误')
}
})