实现低延迟直播
融云开发者账户是使用融云 SDK 产品的必要条件。在开始之前,请先前往融云官网注册开发者账户。注册后,控制台将自动为您创建一个应用,默认为开发环境应用,使用国内数据中心。请获取该应用的 App Key,在本教程中使用。
首次使用融云音视频的用户,建议参考文档运行示例项目,以完成开发者账号注册、音视频服务开通等工作。
步骤 1:服务开通
您在融云创建的应用默认不会启用音视频服务。在使用融云提供的任何音视频服务前,您需要前往控制台,为应用开通音视频服务。
具体步骤请参见文档开通音视频服务。
服务开通、关闭等设置完成后 30 分钟后生效。
步骤 2:SDK 导入
您需要导入融云音视频核心能力库 RTCLib,和 RTC 业务所依赖的即时通讯能力库 IMLib。根据您的业务需求,可选择导入美颜扩展库和 CDN 扩展库。
融云推荐使用 CocoaPods 方式导入 SDK:
-
配置 Podfile。
pod 'RongCloudRTC/RongRTCLib', '~> x.y.z'
提示x.y.z
代表具体版本,各个 SDK 的最新版本号可能不同,在融云下载页或 CocoaPods 仓库能查询到。- RTCLib 会自动依赖下载对应版本的 IMLib 库,一般不需要手动指定。
- RTCLib 必须与其依赖的 IMKit/IMLib SDK 保持版本一致。从 5.2.0 开始至 5.4.4(不含),要求前三位一致。从 5.4.4 开始,要求前两位保持一致。注意,RTCLib 5.4.4 不可匹配小于 5.4.4 的 IM SDK。
-
安装依赖项。
$ pod install
提示如果出现找不到相关版本的问题,可先执行
pod repo update
,再执行pod install
。
步骤详细说明及其他导入方式请参阅导入 SDK。
步骤 3:权限配置
- 音视频通话需要用到摄像头和麦克风权限,请在工程的 info.plist 中添加如下键值:
- Privacy - Microphone Usage Description
- Privacy - Camera Usage Description
- 请将工程中 Target -> Signing & Capabilities -> Background Modes 如下内容勾选:
- Audio, AirPlay, and Picture in Picture
- Remote notifications
SDK 5.1.1 及之前的版本,音视频通话中需要 用到 HTTP
请求,请在工程的 info.plist 中添加 App Transport Security Settings
键值,并在此键值下再添加 Allow Arbitrary Loads
并将 Value 设置为 YES
。
步骤 4:初始化
音视频 SDK 是基于即时通信 SDK 作为信令通道的,所以要先初始化 IM SDK。如果不换 AppKey,在整个应用生命周期中,初始化一次即可。建议调用位置放在应用启动位置处,或在音视频功能模块的加载位置处。
[[RCCoreClient sharedCoreClient] initWithAppKey:@"从控制台申请的 AppKey"];
- 部分 RTC 引擎必须在初始化时提供,详见引擎配置。
步骤 5:连接 IM
音视频用户之间的信令传输依赖于融云的即时通信(IM)服务,因此需要先调用 connectWithToken
与 IM 服务建立好 TCP 长连接。建议在功能模块的加载位置处调用,之后再进行音视频呼叫业务。当模块退出后调用 disconnect
或 logout
断开该连接。
[[RCCoreClient sharedCoreClient] connectWithToken:@"从您服务器端获取的 Token"
dbOpened:^(RCDBErrorCode code) {}
success:^(NSString *userId) {}
error:^(RCConnectErrorCode status) {}
tokenIncorrect:^{}];
主播端
多人之间想要发起音视频通话,需要加入同一个音视频房间。对于直播需求来讲,房间类型需选择 RCRTCRoomTypeLive
,直播类型可根据业务需要选择 RCRTCLiveTypeAudioVideo
或 RCRTCLiveTypeAudio
,即音视频直播间或纯音频直播间。加入房间的角色也分为 RCRTCLiveRoleTypeBroadcaster
和 RCRTCLiveRoleTypeAudience
,即主播和观众。下面就这两种身份,分别进行说明。
步骤 6.1:加入房间
-
构建 RCRTCRoomConfig,指定房间类型和主播身份:
// 设置房间、直播和角色类型
RCRTCRoomConfig *config = [[RCRTCRoomConfig alloc] init];
config.roomType = RCRTCRoomTypeLive;
config.liveType = RCRTCLiveTypeAudioVideo;
config.roleType = RCRTCLiveRoleTypeBroadcaster; -
调用 RCRTCEngine 下的 joinRoom 方法创建并加入一个直播房间。
[[RCRTCEngine sharedInstance] joinRoom:@"直播间 ID"
config:config
completion:^(RCRTCRoom * _Nullable room, RCRTCCode code) {
if (code != RCRTCCodeSuccess) {
// 加入房间失败处理
return;
}
// 进行发布订阅流操作
}];
客户端通过 joinRoom
传入的直播间 ID 来加入不同房间。房间不需要客户端创建或销毁,融云服务若发现该房间不存在时会自动创建。当所有主播(只有观众不算)离开持续 24 小时后,服务会自动销毁该房间。
步骤 6.2:发布音视频流
加入房间后,开始摄像头采集并发布音视频流。
// 1. 初始化本地渲染视图
RCRTCVideoView *view = [[RCRTCVideoView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
// 2. 设置视频流的渲染视图
[[RCRTCEngine sharedInstance].defaultVideoStream setVideoView:view];
// 3. 添加渲染视图
[self.view addSubview:view];
// 4. 开始摄像头采集
[[RCRTCEngine sharedInstance].defaultVideoStream startCapture];
// 5. 发布本地流到房间
[self.room.localUser publishDefaultLiveStreams:^(BOOL isSuccess, RCRTCCode desc, RCRTCLiveInfo * _Nullable liveInfo) {
if (desc == RCRTCCodeSuccess) {
// 可以用 liveInfo 配置合流信息
self.liveInfo = liveInfo;
}
}];
观众端
步骤 7.1:加入房间
-
指定房间 id 并加入房间。
// 设置房间、直播和角色类型
RCRTCRoomConfig *config = [[RCRTCRoomConfig alloc] init];
config.roomType = RCRTCRoomTypeLive;
config.liveType = RCRTCLiveTypeAudioVideo;
config.roleType = RCRTCLiveRoleTypeAudience; -
调用 RCRTCEngine 下的 joinRoom 方法创建并加入一个直播房间。
[[RCRTCEngine sharedInstance] joinRoom:@"Your_Room_ID"
config:config
completion:^(RCRTCRoom * _Nullable room, RCRTCCode code) {
if (code != RCRTCCodeSuccess) {
// 加入房间失败处理
return;
}
// 进行订阅流操作
}];
步骤 7.2:观众观看直播
观众可通过加入房间后返回的 RCRTCRoom 下 localUser 中的订阅方法订阅多路音视频流。同一个流只能填写在 avStreams 或 tinyStreams 中的一个数组中。
NSArray *tinyStream = isTiny ? streams : @[];
NSArray *ordinaryStream = isTiny ? @[] : streams;
// 订阅房间中远端用户音视频流资源
[self.room.localUser subscribeStream:ordinaryStream
tinyStreams:tinyStream
completion:^(BOOL isSuccess, RCRTCCode desc) {
if (desc != RCRTCCodeSuccess) {
return;
}
// 创建并设置远端视频预览视图
NSInteger i = 0;
for (RCRTCInputStream *stream in liveStreams) {
if (stream.mediaType == RTCMediaTypeVideo) {
if (i==0) {
// 1.初始化渲染远端视频的 view
RCRTCRemoteVideoView *view = [[RCRTCRemoteVideoView alloc]initWithFrame:CGRectMake(100, 400, 100, 100)];
// 2.设置视频流的渲染视图
[(RCRTCVideoInputStream *)stream setVideoView:view];
// 3.添加渲染视图
[self.view addSubview:view];
}else{
// 其他远端视图逻辑
}
}
}
}];