实现互动直播(iOS)
网易云信互动直播产品的基本功能包括音视频通话和连麦直播,当您成功初始化 SDK 之后,您可以简单体验本产品的基本业务流程,例如主播加入房间、观众CDN拉流、连麦者上下麦、结束直播等。本文档为您展示互动直播提供的基本业务流程。
前提条件
请确认您已完成以下操作:
主播加入房间
1. 导入类
在项目中导入 NERtcSDK 类:
#import <NERtcSDK/NERtcSDK.h>
2. 初始化
先执行 - setupEngineWithContext: 方法完成初始化。
@interface Myapp ()<NERtcEngineDelegateEx>
...
NERtcEngine *coreEngine = [NERtcEngine sharedEngine];
NERtcEngineContext *context = [[NERtcEngineContext alloc] init];
// 设置通话相关信息的回调
context.engineDelegate = self;
// 设置当前应用的appKey
context.appKey = AppKey;
[coreEngine setupEngineWithContext:context];
...
3. 设置本地视图(可选)
初始化成功后,可以设置设置本地视图,来预览本地图像。您可以在加入房间之前预览,或在加入房间后预览。
加入房间前预览。
通过 startPreview 与 setupLocalVideoCanvas方法,在加入房间前设置本地视图,预览本地图像。
// 示例 NERtcVideoCanvas *canvas = [[NERtcVideoCanvas alloc] init]; canvas.container = self.localUserView; // 设置本地视频画布 [NERtcEngine.sharedEngine setupLocalVideoCanvas:canvas]; // 开启预览 [NERtcEngine.sharedEngine startPreview];
- 若要结束预览,或者准备加入房间时,调用 stopPreview 停止预览。
加入房间后预览。
在成功加入房间后,通过 enableLocalVideo 方法进行视频的采集发送与预览。
// 示例 [NERtcEngine.sharedEngine enableLocalVideo:YES]; NERtcVideoCanvas *canvas = [[NERtcVideoCanvas alloc] init]; canvas.container = self.localUserView; [NERtcEngine.sharedEngine setupLocalVideoCanvas:canvas];
4. 设置直播模式
在互动直播的场景中,建议在加入房间前,通过 setChannelProfile 接口设置房间模式为直播模式。当前默认为通信模式。
// 示例
// kNERtcChannelProfileCommunication-通信模式
// kNERtcChannelProfileLiveBroadcasting-直播模式
[NERtcEngine.sharedEngine setChannelProfile:kNERtcChannelProfileLiveBroadcasting];
5. 设置推流开关
在加入音视频通话房间前,还需要打开推流开关,以便将多媒体流推往 CDN,这样拉流的观众可以拉取到该用户对应的音视频流。
// 示例
[NERtcEngine.sharedEngine setParameters:@{kNERtcKeyPublishSelfStreamEnabled: @YES}];
6. 加入房间
加入房间前,请确保已完成初始化相关事项。若您的业务中涉及呼叫邀请等机制,建议通过信令实现。
通过 – joinChannelWithToken:channelName:myUid:completion: 方法加入房间。
// 示例
[NERtcEngine.sharedEngine joinChannelWithToken:@""
channelName:roomId
myUid:userId
completion:^(NSError * _Nullable error, uint64_t channelId, uint64_t elapesd) {
if (error) {
//加入失败
} else {
//加入成功
}
}];
参数说明
参数 | 说明 |
---|---|
token | 安全认证签名(NERTC Token)。可设置为:
|
channelName | 房间名称,设置相同房间名称的用户会进入同一个通话房间。 注意:您也可以在加入通道前,通过创建房间接口创建房间。加入房间时,若传入的 {channelName} 未事先创建,则云信服务器内部将为其自动创建一个名为 {channelName} 的通话房间。 |
myUid | 用户的唯一标识 id,房间内每个用户的 uid 必须是唯一的。 |
7. 推流任务管理
在成功加入房间后,需要通过 NERtcLiveStreamTaskInfo 设置推流任务,将通话房间内的多媒体数据推至 CDN。典型的业务场景里是由主播进行设置推流任务。
推流任务也可以通过 服务端API 进行管理,请根据您的业务需求选择合适的方式。
注意:
- 此处的主播业务层面的角色,SDK 体系内不区分主播与连麦者。
- 推流任务中,需要设置互动直播的CDN推流地址,请在合适的时机创建直播频道,将获取到推流地址传入推流任务。
- 添加推流任务时,需要设置布局参数,您可以参考旁路推流画面布局完成设置。
- 推流任务与通话绑定,当通话结束后,推流任务也会自动随之销毁。
- 一通通话,即一个channelId同时最多对应3个不同的推流任务。
增加推流任务
音视频房间中默认没有推流任务,您需要在启动直播前通过 – addLiveStreamTask:compeltion: 方法增加推流任务。
// 示例
//先初始化推流任务
NERtcLiveStreamTaskInfo *info = [[NERtcLiveStreamTaskInfo alloc] init];
//taskID 可选字母、数字,下划线,不超过64位
info.taskID = taskID;
// 设置推互动直播推流地址,一个推流任务对应一个推流房间
info.streamURL = pushUrl;
// 设置是否进行互动直播录制,请注意与音视频通话录制区分。
info.serverRecordEnabled = NO;
// 设置推音视频流还是纯音频流
info.lsMode = enableVideo ? kNERtcLsModeVideo : kNERtcLsModeAudio;
//设置整体布局
NERtcLiveStreamLayout *layout = [[NERtcLiveStreamLayout alloc] init];
layout.width = 720; //整体布局宽度
layout.height = 1280; //整体布局高度
layout.backgroundColor = (red & 0xff) << 16 | (green & 0xff) << 8 | (blue & 0xff);
info.layout = layout;
// 设置直播成员布局
NERtcLiveStreamUserTranscoding *user1 = [[NERtcLiveStreamUserTranscoding alloc] init];
user1.uid = uid1;
user1.audioPush = true; // 推流是否发布user1的音频
user1.videoPush = enableVideo; // 推流是否发布user1的视频
if (user1.videoPush) {
// 如果发布视频,需要设置一下视频布局参数
user1.x = 10; // user1 的视频布局x偏移,相对整体布局的左上角
user1.y = 10; // user1 的视频布局y偏移,相对整体布局的左上角
user1.width = 180; // user1 的视频布局宽度
user1.height = 320; //user1 的视频布局高度
user1.adaption = kNERtcLsModeVideoScaleCropFill;
}
// 设置第n位直播成员布局
NERtcLiveStreamUserTranscoding *usern = [[NERtcLiveStreamUserTranscoding alloc]init];
usern.uid = uidn;
usern.audioPush = true;
usern.videoPush = enableVideo;
if (usern.videoPush) {
usern.adaption = kNERtcLsModeVideoScaleCropFill;
usern.x = user1.x + user1.width + 10;
usern.y = user1.y + user1.height + 10;
usern.width = 320;
usern.height = 640;
}
layout.users = @[user1,...,usern];
//配置背景占位图片,可以不配置。
NERtcLiveStreamImageInfo *imageInfo = [[NERtcLiveStreamImageInfo alloc] init];
imageInfo.url = url;
imageInfo.x = 0;
imageInfo.y = 0;
imageInfo.width = 720;
imageInfo.height = 1280;
layout.bgImage = imageInfo;
//调用 addLiveStreamTask 接口添加推流任务
int ret = [[NERtcEngine sharedEngine] addLiveStreamTask:info
compeltion:^(NSString * _Nonnull taskId, kNERtcLiveStreamError errorCode) {
NSString *toast = !errorCode ? @"添加成功" : [NSString stringWithFormat:@"添加失败 errorcode = %d",errorCode];
MakeToast(toast);
}];
if (ret != 0) {
MakeToast(@"调用添加推流任务失败");
}
更新推流任务
当音视频通话房间内有人员进出或其他情况时,可以使用 – updateLiveStreamTask:compeltion: 方法更新推流任务。更新推流任务时,会覆盖之前对于这条推流任务的所有配置。
// 示例
// 初始化新推流任务。注意:其中的taskid为原推流任务id。
NERtcLiveStreamTaskInfo *updateLiveTask1 = preLiveTask;
...
// 更新推流任务
int ret = [[NERtcEngine sharedEngine] updateLiveStreamTask:updateLiveTask1
compeltion:^(NSString * _Nonnull taskId, kNERtcLiveStreamError errorCode) {
NSString *toast = !errorCode ? @"更新成功" : [NSString stringWithFormat:@"errorcode = %d",errorCode];
MakeToast(toast);
}];
if (ret != 0) {
MakeToast(@"更新推流任务失败");
}
删除推流任务
当本场互动直播准备结束时,可以通过 – removeLiveStreamTask:compeltion: 方法主动删除推流任务。
// 示例
NSString *taskID = preLiveTask.taskID;
int ret = [[NERtcEngine sharedEngine] removeLiveStreamTask:taskID
compeltion:^(NSString * _Nonnull taskId, kNERtcLiveStreamError errorCode) {
NSString *toast = !errorCode ? @"删除成功" : [NSString stringWithFormat:@"errorcode = %d",errorCode];
MakeToast(toast);
}];
if (ret != 0) {
MakeToast(@"删除推流任务失败");
}
推流任务相关错误码
增加、更新与删除推流任务时,如果发生错误,回调接口通过错误码形式反馈错误原因。错误码 kNERtcLiveStreamError 如下:
错误码 | 含义 |
---|---|
kNERtcLiveStreamErrorRequestIsInvaild = 1301 | task请求无效,被后续操作覆盖 |
kNERtcLiveStreamErrorIsInvaild = 1400 | task参数格式错误 |
kNERtcLiveStreamErrorRoomExited = 1401 | 已经退出房间 |
kNERtcLiveStreamErrorNumLimit = 1402 | 推流任务超出上限 |
kNERtcLiveStreamErrorDuplicateId = 1403 | 推流ID重复 |
kNERtcLiveStreamErrorNotFound = 1404 | taskId任务不存在,或房间不存在 |
kNERtcLiveStreamErrorRequestErr = 1417 | 请求失败 |
kNERtcLiveStreamErrorInternalServerErr = 1500 | 服务器内部错误 |
kNERtcErrLsTaskInvalidLayout = 1501 | 布局参数错误 |
kNERtcErrLsTaskUserPicErr = 1502 | 用户图片错误 |
互动直播推流状态
主播/连麦者参与互动直播的过程中,可以通过 NERtcEngineLiveStreamObserver 的 – onNERTCEngineLiveStreamState:taskID:url: 来监听推流状态。
常见的推流状态如下:
状态码 | 含义 |
---|---|
kNERtcLsStatePushing = 505 | 推流中 |
kNERtcLsStatePushFail = 506 | 互动直播推流失败 |
kNERtcLsStatePushStopped = 511 | 推流结束 |
8. 设置远端视图
互动直播过程中,除了要显示本地的视频画面,通常也要显示参与互动的其他连麦者/主播的远端视频画面。
NERtcEngineDelegate 通过以下回调获取相关信息:
– onNERtcEngineUserDidJoinWithUserID:userName::监听远端用户加入通话房间的事件,并抛出对方的 uid。当本端加入房间后,也会通过此回调抛出通话房间内已有的其他用户。
– onNERtcEngineUserVideoDidStartWithUserID:videoProfile: :监听远端用户发布视频流的事件,回调中携带对方的 uid 与发布的视频分辨率。
在监听到远端用户加入房间或发布视频流后,本方可以通过 – setupRemoteVideoCanvas:forUserID: 方法设置远端用户视频画布,用于显示其视频画面。
// 示例 NERtcVideoCanvas *canvas = [self setupRemoteCanvasWithUid:userID]; [NERtcEngine.sharedEngine setupRemoteVideoCanvas:canvas forUserID:userID];
在监听到远端用户发布视频流后,本方可以通过 – subscribeRemoteVideo:forUserID:streamType: 方法对其发起视频流的订阅,来将对方的视频流渲染到视频画布上。
// 示例 [NERtcEngine.sharedEngine subscribeRemoteVideo:YES forUserID:userID streamType:kNERtcRemoteVideoStreamTypeHigh];
9. 音频流
本地音频的采集发布和远端音频订阅播放是默认启动的,正常情况下无需开发者主动干预。
观众进行CDN拉流
当通话房间内有主播/连麦者发布多媒体流,且正确设置了推流任务时,通话房间外的观众可以通过 CDN 直播拉流地址进行拉流播放。云信同时提供播放器SDK组件供您使用,详细内容请参见 直播 - 播放器SDK。
连麦者上下麦
1. 上麦
若正在进行 CDN 拉流播放的普通观众要上麦参与互动时,必须先停止 CDN 拉流,并释放播放器相关资源。然后按照主播加入房间流程,进行初始化、设置本地视图、设置直播模式、设置推流开关、加入通话房间、设置远端视图。
注意:
- 由于有新连麦者的加入,需要更新推流任务将新连麦者设置到推流布局中。操作步骤请参考更新推流任务。更新推流的任务操作,可以由主播执行,也可以由连麦者执行,也可以通过服务端API完成。
- NERTC SDK 支持直播场景下的用户角色管理,角色包括主播和观众,默认以主播角色加入房间。调用 setChannelProfile 将通话设置为直播场景之后,可以通过 setClientRole 切换用户角色。
2. 下麦
若连麦者互动结束,需要下麦时,可以更新推流任务,在推流布局中剔除该连麦者。同时,连麦者退出通话房间,清理相关资源,重新进行播放器拉流或直接离开直播间。
通话房间内的其他用户可以通过NERtcEngineDelegate 的– onNERtcEngineUserDidLeaveWithUserID:reason: 来监听其他连麦者下麦。
结束互动直播
需要结束该场互动直播时,可以先删除推流任务,然后主播与连麦者退出通话房间,观众结束 CDN 拉流。
1. 退出通话房间
通过 leaveChannel 接口退出通话房间。
// 示例
// 退出通话房间
[NERtcEngine.sharedEngine leaveChannel];
NERtcEngineDelegate 提供 – onNERtcEngineDidLeaveChannelWithResult: 来监听当前用户退出房间的结果。
2. 销毁实例
当确定 App 短期内不再使用音视频通话实例时,可以通过 destroyEngine 释放对应的对象资源。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NERtcEngine destroyEngine];
});


此文档对你是否有帮助

