直播
更新时间: 2023/06/02 02:47:10
NERoom 的直播基于专业的跨平台视频编解码技术和大规模视频内容分发网络,提供稳定流畅、高可靠、高并发的直播服务,助力轻松打造企业级在线直播平台。
功能介绍
直播的应用场景包括:
- 娱乐直播:面向秀场、游戏等直播场景,提供直播秒开、色彩滤镜、主播观众直播连麦等功能,提高直播人气,活跃直播气氛。
- 电商直播:电商直播方案实现用户在看直播中边看边卖,支持时移商品介绍、用户互动等,实现快速变现。
- 教育直播:教育直播加密、动态 URL 防盗链等安全保障防止教学内容泄露,更有高可用服务链路保障教育直播的稳定性。
- 大型直播:提供海量 CDN 网络和强大的云端媒体处理能力,保障了直播的高并发和高可用。
- 方案一(推荐):使用更简单,提供常用的布局模板。移动客户端互动直播受限于网络状况,为保证直播的稳定性,推荐选择本方案。
- 方案二:更灵活、更丰富。您可以自定义画面布局、设置音视频流的相关参数。
前提条件
创建房间时,已在NECreateRoomOptions
方法中,设置enableLive
的值为 true,具体操作方法请参见创建房间。
功能原理
服务端推流和客户端推流的底层实现逻辑如下图所示。
方案一
-
调用
getRoomContext
接口获取房间上下文。调用此方法时,您需要将 roomUuid 设置为您所加入房间的 ID。
-
调用
startLive
接口开启直播。func startLive(request: NERoomLiveRequest, callback: NECallback<NERoomLiveInfo>? = nil)
-
NERoomLiveRequest
相关参数说明如下表所示。参数 说明 title 直播主题 password 直播密码。如果密码为空,用户无需密码即可进入直播 liveLayout 直播布局,包括: - 0:无布局
- 1:画廊布局
- 2:聚焦布局
- 4:共享屏幕布局
userUuidList [String] 推流用户的 uid 集合 extensionConfig 扩展配置,透传返回 - 0:无布局
-
NERoomLiveInfo
相关参数说明如下表所示。参数 说明 title 直播主题 password 直播密码。如果密码为空,用户无需密码即可进入直播 liveLayout 直播布局,包括: - 0:无布局
- 1:画廊布局
- 2:聚焦布局
- 4:共享屏幕布局
userUuidList [String] 推流用户的 Uuid 集合 extensionConfig 扩展配置,跟 NERoomLiveRequest
中的扩展配置保持一致taskId 直播任务编号 pushUrl 推流地址 pullHttpUrl HTTP 拉流地址 pullRtmpUrl RTMP 拉流地址 pullHlsUrl HLS 拉流地址 pullRtsUrl RTS 拉流地址 chatRoomId 直播聊天室房间号 state 直播状态。包括: - init: 直播未开始
- started: 直播已开始
- ended: 直播已结束
- 0:无布局
示例代码如下:
let roomContext = NERoomKit.shared().roomService.getRoomContext(roomUuid: "xxxxx") let liveRequest = NERoomLiveRequest() liveRequest.userUuidList = ["111", "222", "333"] liveRequest.title = "start" liveRequest.liveLayout = NERoomLiveLayout.gallery liveRequest.password = "123456" liveRequest.extensionConfig = "extensionConfig" roomContext?.liveController.startLive(request: liveRequest) { code, str, liveInfo in if code == 0 { print("直播开启成功") } else { print("直播开启失败") } }
-
-
调用
updateLive
接口更新直播。参数说明请参见
startLive
中的参数说明。示例代码如下:
let roomContext = NERoomKit.shared().roomService.getRoomContext(roomUuid: "xxxxx") let liveRequest = NERoomLiveRequest() liveRequest.userUuidList = ["111", "222", "333"] liveRequest.title = "start" liveRequest.liveLayout = NERoomLiveLayout.gallery liveRequest.password = "123456" liveRequest.extensionConfig = "extensionConfig" roomContext?.liveController.updateLive(request: liveRequest) { code, str, liveInfo in if code == 0 { print("更新成功") } else { print("更新失败") } }
-
调用
stopLive
接口停止直播。示例代码如下:
let roomContext = NERoomKit.shared().roomService.getRoomContext(roomUuid: "xxxxx") roomContext?.liveController.stopLive { code, str, _ in if code == 0 { print("成功") } else { print("失败") } }
-
调用
getLiveInfo
接口获取直播信息。参数说明请参见
startLive
中的参数说明。示例代码如下:
let roomContext = NERoomKit.shared().roomService.getRoomContext(roomUuid: "xxxxx") let liveInfo = roomContext?.liveController.getLiveInfo()
-
当直播状态变更,会触发
onRoomLiveStateChanged
回调,通知房间内成员直播状态变更。监听直播状态变更的示例代码如下:
let roomContext = NERoomKit.shared().roomService.getRoomContext(roomUuid: "xxxxx") roomContext?.addRoomListener(xx) ## 遵循NERoomListener的类,实现 onRoomLiveStateChanged方法 func onRoomLiveStateChanged(state: NERoomLiveState) { ... }
方案二
注意事项
一个房间最多创建3个旁路推流任务。
配置步骤
-
调用
getRoomContext
接口获取房间上下文。调用此方法时,您需要将 roomUuid 设置为您所加入房间的 ID。
-
调用
addLiveStreamTask
接口添加旁路推流任务。每次只能增加一路旁路推流地址。如需推送多路流,则需多次调用该方法。
NERoomLiveStreamTaskInfo
的参数说明如下表所示。参数 说明 config 配置音视频流编码参数。具体参数说明请参见下表。 extraInfo 预留参数,用户自定义的发送到旁路推流客户端的信息,用于填充视频中 SEI 帧内容。
长度不能超过 4096 字节。layout 自定义房间画面的各路视频布局方式。具体参数说明请参见下表。 mode 直播推流模式。可设置为: - audio:推流纯音频。
- video:推流音视频。
serverRecordEnabled 旁路推流是否需要进行音视频录制。可设置为: - true:启动录制。
- false:关闭录制。
taskId 自定义的推流任务 ID。请保证此 ID 唯一。
taskId 由字母、数字、下划线(_)组成,最大 64 个字符。url 推流地址。例如 rtmp://example.url。 config
的参数说明如下表所示。参数 说明 singleVideoPassThrough - true:表示开启视频透传。开启后,如果房间中只有一路视频流输入,则不对输入视频流进行转码,不遵循转码布局,直接推流 CDN。
- false:表示关闭视频透传。关闭后,无论房间中是否只有一路视频流,都按照
layout
设置的布局进行转码推流。
audioBitrate 音频推流码率。单位为 kbps,取值范围为 10~192。语音场景建议设置为 64 及以上码率,音乐场景建议设置为 128 及以上码率。 sampleRate 音频推流采样率。默认值为 NERtcLiveStreamAudioSampleRate48000 48K。 channels 音频推流声道数。 - 1:单声道。
- 2:(默认)双声道。
audioCodecProfile 音频编码规格。包括 ProfileHEAAC
和ProfileLCAAC
。layout
的参数说明如下表所示。参数 类型 是否必选 示例值 描述 height Integer 必选 640 整体画布的高度,单位为 px。
取值范围为 0~1920,若设置为奇数值,会自动向下取偶。width Integer 必选 0 整体画布的宽度,单位为 px。
取值范围为 0~1920,若设置为奇数值,会自动向下取偶。backgroundColor
String
可选
0
画面背景颜色,默认为 0,即黑色。支持以下格式的颜色码:
- 256 ✖ 256 ✖ R + 256 ✖ G + B的和。请将对应 RGB 的值分别带入此公式计算即可。
- 十六进制颜色码,即#RRGGBB 或 RRGGBB 格式。例如 #CC00FF。
backgroundImg
String
可选
0
设置混流视频中占位图片属性。相关参数说明如下:
url
:占位图片的URL。例如:www.163.com/test.jpg。height
:该占位图片在画布中的高度。
取值范围为 0~1920,若设置为奇数值,会自动向下取偶。width
:该占位图片在画布中的宽度。
取值范围为 0~1920,若设置为奇数值,会自动向下取偶。x
:设置占位图片左上角在画布的横轴坐标值。
取值范围为 0~1920,若设置为奇数值,会自动向下取偶。y
:设置占位图片左上角在画布的纵轴坐标值。
取值范围为 0~1920,若设置为奇数值,会自动向下取偶。
userTranscodingList String 可选 0 画面布局的效果展示及常用布局的配置示例请参见旁路推流画面布局。
-
(可选)调用
updateLiveStreamTask
接口更新房间内的旁路推流任务。 -
调用
removeLiveStreamTask
接口删除旁路推流任务。
示例代码
// 获取房间上下文
let roomContext = NERoomKit.shared().roomService.getRoomContext(roomUuid: "xxxxx")
guard let context = roomContext else { return }
// 添加推流任务
let task = NERoomLiveStreamTaskInfo()
task.taskId = NSString(string: UUID().uuidString).replacingOccurrences(of: "-", with: "")
task.streamUrl = self.priorityPushUrl(url: streamURL)
task.mode = .video
let width = 720, height = 640
let streamLayout = NERoomLiveStreamLayout()
streamLayout.height = height
streamLayout.width = width
let selfTranscoding = self.streamUserTranscoding(userUuid: selfUser, point: CGPoint(x: 0, y: 0), size: CGSize(width: 360, height: 640))
let peerTranscoding = self.streamUserTranscoding(userUuid: peerUser, point: CGPoint(x: 360, y: 0), size: CGSize(width: 360, height: 640))
streamLayout.userTranscodingList = [selfTranscoding, peerTranscoding]
task.layout = streamLayout
context.liveController.addLiveStreamTask(task: task) { code, str, _ in
if code == 0 {
self.currentTaskId = task.taskId
}
}
// 更新推流任务
let task = NERoomLiveStreamTaskInfo()
task.taskId = currentTaskId
task.streamUrl = currentUrl
task.mode = .video
let width = 720, height = 640
let streamLayout = NERoomLiveStreamLayout()
streamLayout.height = height
streamLayout.width = width
let selfTranscoding = streamUserTranscoding(userUuid: selfUser, point: CGPoint(x: 0, y: 0), size: CGSize(width: width/2, height: height))
let peerTranscoding = streamUserTranscoding(userUuid: peerUser, point: CGPoint(x: width/2, y: 0), size: CGSize(width: width/2, height: height), audioPush: false)
streamLayout.userTranscodingList = [selfTranscoding, peerTranscoding]
task.layout = streamLayout
context.liveController.updateLiveStreamTask(task: task) { code, str, _ in
if code == 0 {
self.currentTaskId = tasktaskID
}
}
// 删除
let currentTaskId = currentTaskId {
context.liveController.removeLiveStreamTask(taskId: currentTaskId) { code, str, _ in
if code == 0 {
// 成功
}
}
//
func streamUserTranscoding(userUuid: String, point: CGPoint, size: CGSize,
audioPush: Bool = true,
videoPush: Bool = true) -> NERoomLiveStreamUserTranscoding {
let userTranscoding = NERoomLiveStreamUserTranscoding()
userTranscoding.userUuid = userUuid
userTranscoding.audioPush = audioPush
userTranscoding.videoPush = videoPush
userTranscoding.x = Int(point.x)
userTranscoding.y = Int(point.y)
userTranscoding.width = Int(size.width)
userTranscoding.height = Int(size.height)
userTranscoding.adaption = .cropFill
return userTranscoding
}
API 参考
方法 | 功能描述 |
---|---|
startLive | 开启直播。 |
stopLive | 停止直播。 |
updateLive | 更新直播。 |
getLiveInfo | 获取直播信息。 |
addLiveStreamTask | 添加旁路推流任务。 |
updateLiveStreamTask | 更新旁路推流任务。 |
removeLiveStreamTask | 删除旁路推流任务。 |