跳到主要内容

实现低延迟直播

本教程旨在帮助开发者快速了解和掌握 RTCLib SDK(融云实时音视频能力库)的基础集成流程与直播功能。RTCLib 是融云提供的音视频通话和直播功能 SDK,支持多人音视频直播的各种场景。通过本教程,您将完成服务开通、SDK 初始化、连接服务、加入房间、发布和订阅音视频流等全流程操作。

房间人数上限

考虑移动设备的带宽和性能,建议直播房间内:主播不超过 16 人,观众无限制。超过主播上限可能影响直播效果。

环境要求

  • Xcode 需要使用 Xcode 11 及以上的版本。
  • 苹果设备的系统需要使用 iOS 9.0 及以上的版本。
  • 需要真机设备运行测试相关音视频直播功能。
  • 如果您打算通过 CocoaPods 集成 SDK,需要使用 CocoaPods 1.10.0 及以上的版本。这是因为 RTCLib SDK 5.1.1 版本后变更为 XCFramework,而 CocoaPods 是从 1.10.0 版本后才完整支持 XCFramework 的集成方式,具体请参见知识库文档
提示

如需安装 CocoaPods 环境,请参照 安装 CocoaPods

准备工作

  1. 访问融云控制台,注册您的开发者账号。注册成功后,控制台自动在开发环境中为您创建一个应用。

  2. 在控制台的基本信息页,获取您的应用在开发环境的 App Key / Secret。您可在基本信息页查看应用的信息,如 App Key / Secret、所属数据中心(默认为北京)。 alt text

    如您想自己创建应用,参考如何创建应用,并获取对应环境 App Key / Secret

    提示

    每个应用均拥有两个不同的 App Key / Secret,分别对应开发环境与生产环境,且两个环境之间数据相互隔离。在您的应用正式上线前,建议切换到生产环境的 App Key / Secret,以便完成上线前全流程测试和最终发布。

服务开通

您在融云创建的应用默认不会启用音视频服务。在使用融云提供的任何音视频服务前,您需要前往控制台,为应用开通音视频服务。

具体步骤请参阅控制台文档开通音视频服务

提示
  • 服务开通、关闭等设置完成后 15 分钟后生效。
  • 客户端配置文件更新最长 2 小时,您可以在服务生效后卸载重装来立刻获取最新配置。

导入 SDK

融云支持通过 CocoaPods 添加远程依赖和将 RTCLib 的相关 XCFramework 本地库导入应用工程两种集成方式。下文以通过 CocoaPods 添加远程依赖为示例。

  1. 如果您的项目中没有 Podfile 文件,您需要打开终端并进入到项目的根目录,在终端中运行 pod init 命令,之后系统会自动创建一个默认的 Podfile 文件,在项目中的 Podfile 文件中添加如下内容:

    ruby
    pod 'RongCloudRTC/RongRTCLib', '~> x.y.z' 
    pod 'RongCloudRTC/RongFaceBeautifier', '~> x.y.z' # 美颜(可选)
    pod 'RongCloudRTC/RongRTCPlayer', '~> x.y.z' # 混音网络资源文件(可选)
    pod 'RongCloudRTC/RongVoiceBeautifier', '~> x.y.z' # 美声特效(可选)
    提示
    • RTCLib 会自动依赖下载对应版本的 IMLibCore 库,一般不需要手动指定。注意,RTCLib 必须与其依赖的 IMLibCore SDK 保持版本一致。从 5.2.0 开始至 5.4.4(不含),要求前三位一致。从 5.4.4 开始,要求前两位保持一致。注意,RTCLib 5.4.4 不可匹配小于 5.4.4 的 IMLibCore SDK。
    • x.y.z 代表 RTCLib 具体的版本号,您可以在融云官网 SDK 下载页面或在终端中通过先执行 pod repo update,再执行 pod search RongCloudRTC 命令在 CocoaPods 仓库查询 RTCLib 最新的版本。
  2. 打开终端并进入到 Podfile 文件所在的目录,在终端中运行以下命令:

    shell
    pod install
    提示

    如果终端中出现类似 CocoaPods could not find compatible versions for 等找不到相关版本的报错,可先在终端中执行 pod repo update 命令,再执行 pod install 命令。

  3. 通过 Xcode 打开项目目录下的 xcworkspace 文件加载工程。

权限配置

  1. 音视频直播需要用到摄像头和麦克风权限,请在工程的 info.plist 中添加如下键值:
    • Privacy - Microphone Usage Description
    • Privacy - Camera Usage Description
  2. 请将工程中 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

初始化 SDK

RTCLib 基于 IMLibCore 作为信令通道,您须调用 init 方法初始化 IMLibCore SDK。初始化前,您须在融云控制台中获取 App Key / Secret,并设置好 RCInitOption(初始化配置)。

IMLibCore SDK 相关接口的调用都需要导入 SDK 的头文件:

Objective C
#import <RongIMLibCore/RongIMLibCore.h>

RCInitOption 中封装了 areaCode(数据中心的区域码)、naviServer(导航服务地址)、fileServer(文件服务地址)、statisticServer(数据统计服务地址)和 crashMonitorEnable(崩溃监控开关)。详见初始化文档

如果您使用北京数据中心,则不需设置 RCInitOption,IMLibCore SDK 默认连接北京数据中心。

Objective C
NSString *appKey = @"您的 App Key"; // 示例: bos9p5rlcm2ba
RCInitOption *initOption = nil;

[[RCCoreClient sharedCoreClient] initWithAppKey:appKey option:initOption];

如果您使用海外数据中心,则须传入海外数据中心对应的 AreaCode。

Objective C
NSString *appKey = @"您的 App Key"; // 示例: bos9p5rlcm2ba
RCInitOption *initOption = [[RCInitOption alloc] init];
initOption.areaCode = RCAreaCodeSG; // 新加坡数据中心

[[RCCoreClient sharedCoreClient] initWithAppKey:appKey option:initOption];
提示

如果您使用的开发版 RTCLib SDK 版本号小于 5.4.2,或者稳定版 RTCLib SDK 版本号小于等于 5.3.8,则您须调用 RCCoreClient 的 initWithAppKey 方法,并传入 App Key 来进行初始化。详见初始化文档

连接融云 IM 服务器

用户 Token 是与用户 ID 对应的身份验证令牌,是应用程序的用户在融云的唯一身份标识。音视频用户之间的信令传输依赖于融云的即时通信(IM)服务,与融云建立 IM 连接,连接时必须传入 Token。

在实际业务运行过程中,应用客户端需要通过应用的服务端调用 IM Server API 申请取得 Token。详见 Server API 文档注册用户

在本教程中,为了快速体验和测试 SDK,我们将使用控制台「北极星」开发者工具箱,从 API 调试页面调用获取 Token 接口,获取到 userId 为 1 的用户的 Token。提交后,可在返回正文中取得 Token 字符串。

  1. 为模拟用户通过融云 IM 服务器进行直播,您需要首先注册一个用户。在实际业务中,应用客户端通过应用服务端调用融云 IM Server API 获取 token。详见 Server API 文档注册用户。在本教程中,为了快速体验融云服务,您可在控制台「北极星」的 API 调试页面调用获取 Token 接口,获取到 userId 为 1 的用户的 Token。调用返回如下:

    HTTP
    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8

    {"code":200,"userId":"1","token":"gxld6GHx3t1eDxof1qtxxYrQcjkbhl1V@sgyu.cn.example.com;sgyu.cn.example.com"}
  2. 设置连接监听器来实时获取连接状态。您可以将连接状态通过 UI 反馈给用户(例如提示 "网络连接中断" 或 "已重新连接"),提高用户体验。建议在应用生命周期内,初始化 SDK 之后,连接 IM 之前设置 IM 连接状态监听器,并在不需要的时候移除监听器。详见设置连接状态监听

    Objective C
    @protocol RCConnectionStatusChangeDelegate <NSObject>

    // 添加代理委托
    [[RCCoreClient sharedCoreClient] addConnectionStatusChangeDelegate:self];

    /*!
    IMLib 连接状态的监听器

    @param status SDK 与融云服务器的连接状态

    @discussion 如果您设置了 IMLib 连接监听之后,当 SDK 与融云服务器的连接状态发生变化时,会回调此方法。
    */
    - (void)onConnectionStatusChanged:(RCConnectionStatus)status {
    }
    @end
  3. 调用 connectWithToken 方法,将 userId 为 1 的用户连接融云 IM 服务。

    注:IMLibCore SDK 有重连机制,因此一个应用生命周期内调用一次 connect 即可,详见连接

    Objective C
    [[RCCoreClient sharedCoreClient] connectWithToken:@"融云 token" 
    dbOpened:^(RCDBErrorCode code) {
    // 消息数据库打开,可以进入到主页面
    }
    success:^(NSString *userId) {
    // 连接成功
    }
    error:^(RCConnectErrorCode errorCode) {
    if (errorCode == RC_CONN_TOKEN_INCORRECT) {
    // 从 APP 服务获取新 token,并重连
    } else {
    // 无法连接到 IM 服务器,请根据相应的错误码作出对应处理
    }
    }];

主播端

多人之间想要发起音视频通话,需要加入同一个音视频房间。对于直播需求,房间类型需选择 RCRTCRoomTypeLive,直播类型可根据业务需要选择 RCRTCLiveTypeAudioVideoRCRTCLiveTypeAudio(即音视频直播间或纯音频直播间)。加入房间的角色分为 RCRTCLiveRoleTypeBroadcasterRCRTCLiveRoleTypeAudience(即主播和观众)。下面就这两种身份分别进行说明。

加入房间

成功连接 IM 服务后,可以指定房间 ID 并加入音视频房间。

Objective C
// 1. 配置视频参数(可选)
RCRTCVideoStreamConfig *videoConfig = [[RCRTCVideoStreamConfig alloc] init];
videoConfig.videoSizePreset = RCRTCVideoSizePreset720x480; // 设置分辨率
videoConfig.videoFps = RCRTCVideoFPS30; // 设置帧率
[[RCRTCEngine sharedInstance].defaultVideoStream setVideoConfig:videoConfig];

// 2. 配置房间参数
RCRTCRoomConfig *config = [[RCRTCRoomConfig alloc] init];
config.roomType = RCRTCRoomTypeLive; // 直播房间类型
config.liveType = RCRTCLiveTypeAudioVideo; // 音视频直播
config.roleType = RCRTCLiveRoleTypeBroadcaster; // 主播角色

// 3. 启用扬声器输出
[[RCRTCEngine sharedInstance] enableSpeaker:YES];

// 4. 加入房间
[[RCRTCEngine sharedInstance] joinRoom:@"您的房间ID"
config:config
completion:^(RCRTCRoom *_Nullable room, RCRTCCode code) {
if (code == RCRTCCodeSuccess) {
// 加入房间成功
[self afterJoinRoomAsBroadcaster:room];
} else {
// 加入房间失败,请根据相应的错误码作出对应处理
}
}];
提示

客户端通过 joinRoom 传入的直播间 ID 来加入不同房间。房间不需要客户端创建或销毁,融云服务若发现该房间不存在时会自动创建。

发布音视频流

加入成功后开始采集本地视频并发布本地视频流。

Objective C
- (void)afterJoinRoomAsBroadcaster:(RCRTCRoom *)room {
// 设置房间代理
self.room = room;
room.delegate = self;

// 开始本地视频采集
[[[RCRTCEngine sharedInstance] defaultVideoStream] setVideoView:self.localView];
[[[RCRTCEngine sharedInstance] defaultVideoStream] startCapture];

// 发布本地音视频流
[room.localUser publishDefaultLiveStreams:^(BOOL isSuccess, RCRTCCode desc, RCRTCLiveInfo * _Nullable liveInfo) {
if (isSuccess && desc == RCRTCCodeSuccess) {
NSLog(@"本地流发布成功");
self.liveInfo = liveInfo;
}
}];
}

观众端

加入房间

观众以不同的角色类型加入直播房间。

Objective C
// 1. 配置房间参数
RCRTCRoomConfig *config = [[RCRTCRoomConfig alloc] init];
config.roomType = RCRTCRoomTypeLive; // 直播房间类型
config.liveType = RCRTCLiveTypeAudioVideo; // 音视频直播
config.roleType = RCRTCLiveRoleTypeAudience; // 观众角色

// 2. 启用扬声器输出
[[RCRTCEngine sharedInstance] enableSpeaker:YES];

// 3. 加入房间
[[RCRTCEngine sharedInstance] joinRoom:@"您的房间ID"
config:config
completion:^(RCRTCRoom *_Nullable room, RCRTCCode code) {
if (code == RCRTCCodeSuccess) {
// 加入房间成功
[self afterJoinRoomAsAudience:room];
} else {
// 加入房间失败,请根据相应的错误码作出对应处理
}
}];

订阅音视频流

观众加入房间后订阅主播的音视频流。

Objective C
- (void)afterJoinRoomAsAudience:(RCRTCRoom *)room {
// 设置房间代理
self.room = room;
room.delegate = self;

// 如果已经有远端用户在房间中, 需要订阅远端流
if ([room.remoteUsers count] > 0) {
NSMutableArray *streamArray = [NSMutableArray array];
for (RCRTCRemoteUser *user in room.remoteUsers) {
[streamArray addObjectsFromArray:user.remoteStreams];
}
[self subscribeRemoteResource:streamArray];
}
}

- (void)subscribeRemoteResource:(NSArray<RCRTCInputStream *> *)streams {
[self.room.localUser subscribeStream:streams
tinyStreams:nil
completion:^(BOOL isSuccess, RCRTCCode desc) {
if (isSuccess && desc == RCRTCCodeSuccess) {
NSLog(@"远端流订阅成功");
}
}];

// 创建并设置远端视频预览视图
for (RCRTCInputStream *stream in streams) {
if (stream.mediaType == RTCMediaTypeVideo) {
[(RCRTCVideoInputStream *) stream setVideoView:self.remoteView];
[self.remoteView setHidden:NO];
}
}
}

#pragma mark - RCRTCRoomEventDelegate
// 远端用户发布资源通知
- (void)didPublishStreams:(NSArray<RCRTCInputStream *> *)streams {
[self subscribeRemoteResource:streams];
}

// 远端用户取消发布资源通知
- (void)didUnpublishStreams:(NSArray<RCRTCInputStream *> *)streams {
[self.remoteView setHidden:YES];
}

// 远端用户离开通知
- (void)didLeaveUser:(RCRTCRemoteUser *)user {
[self.remoteView setHidden:YES];
}

离开房间

当用户完成直播或需要退出时,需要调用相应的退出方法:

Objective C
// 停止本地视频采集(仅主播需要)
[[[RCRTCEngine sharedInstance] defaultVideoStream] stopCapture];

// 离开房间
[[RCRTCEngine sharedInstance] leaveRoom:^(BOOL isSuccess, RCRTCCode desc) {
if (isSuccess) {
// 成功离开房间
}
}];