客户端实现
更新时间: 2023/06/29 11:28:26
本文档为您展示通过 SDK 实现 PK 连麦场景的相关步骤,帮助您在业务中实时音视频通话、互动直播、连麦 PK、文字聊天、收发礼物等 IM、音视频通话 2.0 和互动直播 2.0 在 PK 连麦场景下的相关能力。
前提条件
-
已在控制台创建应用,并获取了应用对应的 App Key。
详细操作请参考创建应用。
-
已成功开通 IM 即时通讯产品的聊天室功能、开通信令、音视频通话 2.0 产品。
详细操作请参考开通服务。聊天室功能需单独开通,若有需要,请联系商务经理或技术支持。
集成 SDK
请参考下表,将相应的 SDK 或服务集成到您的项目中。
产品 | SDK 下载 | 集成文档 |
---|---|---|
IM 即时通讯(含信令) | IM SDK(含信令) | 集成 SDK |
音视频通话 2.0 | NERTC SDK | 集成 SDK |
实现 PK 连麦
步骤1 初始化配置
-
业务应用服务器配置。
正式开始业务流程之前,您需要通过业务应用服务器完成以下步骤。
- 调用创建房间服务端接口,在返回参数中获取推拉流地址。详细操作请参考直播管理相关 API。
- 创建音视频房间。详细操作请参考创建房间。
- 创建聊天室。业务服务器维护聊天室列表及礼物信息。详细操作请参考创建聊天室。
-
初始化并登陆 IM。
初始化的详细说明请参考初始化 IM SDK。
-
加入聊天室。
加入聊天室后可以参与文字聊天。Demo 中的逻辑规定,只有加入聊天室后才能开启直播。
-
设置音频参数和属性。
您可以根据对音质、声道、场景等的不同需求,通过 setAudioProfile 方法灵活设置音频属性,获得最佳实时互动效果。也可以通过 setLocalVideoConfig 设置视频发送配置。
示例代码:
obic//1. 初始化并登陆 IM。
//2. 加入聊天室。
// 进入聊天室
- (void)enterChatroom:(NIMChatroomEnterRequest *)request
completion:(nullable NIMChatroomEnterHandler)completion;
//3. 设置音频参数和属性。
// 设置视频发送配置(帧率/分辨率)
[[NERtcEngine sharedEngine] setLocalVideoConfig:config];
// 设置音频质量
[[NERtcEngine sharedEngine] setAudioProfile:profile scenario:scenario];
步骤2 主播端开播
经过一系列初始化配置之后,主播端可以开启单人直播。
-
设置直播模式。
在互动直播的场景中,建议在加入房间前,通过 setChannelProfile 接口设置房间模式为直播模式。
-
启动音视频流,并打开推流开关。
调用 enableLocalVideo 开启本地视频采集和发送,并通过 setParameters 打开推流开关。
注意:开启推流开关之后,主播或管理员创建推流任务之后才正式启动旁路推流。
-
设置本地视频画布。
通过 setupLocalVideoCanvas 设置本地视频画布,确定本地采集的视频画面。
-
初始化 NERTC SDK 并注册监听。 初始化的详细说明请参考初始化 NERTC SDK。
-
设置角色为主播。
NERTC SDK V3.9.0 及后续版本支持直播场景下的用户角色管理,角色包括主播和观众。加入房间前可以通过 setClientRole 设置用户角色为主播。
-
加入音视频房间。
- 由于您已在步骤 1 中创建了音视频房间,客户端可以直接通过参数 ChannelName 加入指定房间。若未提前创建房间,客户端也可以直接通过 joinChannel 直接加入房间,SDK 会在加入时自动创建一个房间。
- 安全模式下加入房间需要填写获取到的 Token;调试模式下,Token 请设置为 null。
-
配置推流状态监听。
主播或连麦者参与互动直播的过程中,可以通过 NERtcCallback 的 onNERTCEngineLiveStreamState 来监听推流状态。
-
新增并维护推流任务。
在成功加入房间后,通过 addLiveStreamTask 创建推流任务,将通话房间内的多媒体数据推至 CDN。常见的推流状态请参考互动直播推流状态。
您也可以通过服务端 API 创建推流任务。
示例代码:
//1. 设置直播模式。
// 设置房间场景(直播)
[[NERtcEngine sharedEngine] setChannelProfile:kNERtcChannelProfileLiveBroadcasting];
//2. 启动音视频流,并打开推流开关。
//启动音视频流
[[NERtcEngine sharedEngine] enableLocalAudio:YES];
[[NERtcEngine sharedEngine] enableLocalVideo:YES];
// 打开推流,回调摄像头采集数据
NSDictionary *params = @{
kNERtcKeyPublishSelfStreamEnabled: @YES, // 打开推流
kNERtcKeyVideoCaptureObserverEnabled: @YES // 将摄像头采集的数据回调给用户
};
[[NERtcEngine sharedEngine] setParameters:params];
//3. 设置本地视频画布。
- (int)setupLocalVideoCanvas:(NERtcVideoCanvas *)canvas;
//4. 初始化 NERTC SDK 并注册监听。
NERtcEngineContext *context = [[NERtcEngineContext alloc] init];
context.engineDelegate = self;
context.appKey = appkey;
[[NERtcEngine sharedEngine] setupEngineWithContext:context];
//5. 加入音视频房间。
// 加入房间
- (int)joinChannelWithToken:(NSString *)token
channelName:(NSString *)channelName
myUid:(uint64_t)uId
completion:(NERtcJoinChannelCompletion)completion;
//6. 配置推流状态监听。
- (void)onNERTCEngineLiveStreamState:(NERtcLiveStreamStateCode)state
taskID:(NSString *)taskID
url:(NSString *)url;
//7. 新增并维护推流任务。
// 示例
//先初始化推流任务
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(@"调用添加推流任务失败");
}
步骤3 观众端观看
-
观众端加入聊天室。
观众端加入聊天室之后可以进行文字互动、打赏等操作。
-
观众端通过拉流地址拉流观看直播。
观众端通过播放器实现拉流收听,您可以使用网易云信提供的播放器 SDK 实现,详细操作请参考播放器 SDK 快速入门。
步骤4 主播连麦 PK
在 PK 连麦场景 Demo 中,主播 A 邀请主播 B 进行连麦 PK,主播 B 同意 PK 申请后,主播 A 和 B 删除推流任务、退出原有互动直播房间,并且请求服务器创建一个新的互动直播房间用于连麦 PK。主播 A 和 B 重新加入新房间之后,使用原有的推流地址重新推流,在新的互动直播房间中进行连麦 PK 即可。
注意:
- 主播退出原直播房间之前,需要先删除推流任务,并在加入新房间后使用原推拉流地址重新推流,否则会因为重复推流造成推流失败。
- 观众端不需要切换推拉流地址,拉流出现断流时可以重新拉流解决问题。
操作步骤:
-
主播 A 通过信令发起 PK 邀请,并创建信令房间。
通过信令可以直接呼叫并创建信令房间,用于邀请其他主播进行 PK。
-
主播 B 接受 PK 邀请,并自动加入信令房间。
其中,参数 NIMSignalingAcceptRequest 中的 autoJoin 表示接受邀请后是否自动加入房间,请配置为 YES。主播 B 也可以拒绝邀请,详细操作请查看示例代码。
-
主播 A 和主播 B 删除推流任务、退出原房间并加入新的直播房间。
-
主播端设置远端画布。
- 监听远端用户加入房间与监听远端视频流发布。
- 设置远端画布、订阅远端视频流。
-
新增推流任务,观众端重新拉流。
新的推流任务中需要添加两个主播的原推流地址,观众端拉流时无需切换拉流地址。
示例代码:
//1. 主播 A 通过信令发起 PK 邀请,并创建信令房间。
// 呼叫
- (void)signalingCall:(NIMSignalingCallRequest *)request
completion:(nullable NIMSignalingCallBlock)completion;
//2. 主播 B 接受 PK 邀请,并自动加入信令房间。
// 接受对方邀请并自动加入房间,参数 NIMSignalingAcceptRequest 中的 autoJoin 表示接受邀请后是否自动加入房间,请配置为 YES。
- (void)signalingAccept:(NIMSignalingAcceptRequest *)request
completion:(nullable NIMSignalingAcceptBlock)completion;
// 拒绝邀请
- (void)signalingReject:(NIMSignalingRejectRequest *)request
completion:(nullable NIMSignalingOperationBlock)completion;
//3. 主播 A 和主播 B 删除推流任务、退出原房间并加入新的直播房间。
// 先退出当前房间
[NERtcEngine.sharedEngine leaveChannel];; 离开房间
// 在退出成功的代理方法里,加入新房间
- (int)joinChannelWithToken:(NSString *)token
channelName:(NSString *)channelName
myUid:(uint64_t)uId
completion:(NERtcJoinChannelCompletion)completion;
//4. 主播端设置远端画布。
//监听远端用户加入房间与监听远端视频流发布。
- (void)onNERtcEngineUserDidJoinWithUserID:(uint64_t)userID
userName:(NSString *)userName;
- (void)onNERtcEngineUserVideoDidStartWithUserID:(uint64_t)userID videoProfile:(NERtcVideoProfileType)profile;
//设置远端画布、订阅远端视频流。
- (int)setupRemoteVideoCanvas:(NERtcVideoCanvas *)canvas forUserID:(uint64_t)userID;
- (int)subscribeRemoteVideo:(BOOL)subscribe
forUserID:(uint64_t)userID
streamType:(NERtcRemoteVideoStreamType)streamType;
//5. 新增推流任务,观众端重新拉流。
步骤5 结束直播
-
调用接口 leaveChannel 离开房间。
-
调用接口 destroyEngine 销毁音视频实例。
在收到
onNERtcEngineDidLeaveChannelWithResult
之后执行 destroyEngine 销毁实例。
示例代码:
//1. 离开房间。
//UI 挂断按钮事件- (IBAction)onHungupAction:(UIButton *)sender {
[NERtcEngine.sharedEngine leaveChannel];
[self dismiss];
}
//2. 销毁音视频实例。
- (void)dealloc {
[NERtcEngine destroyEngine]; //销毁实例
}
常见问题
如何实现在 PK 直播过程中,一方异常退出后,自动停止 PK?
可以开通实时音视频抄送,获取用户离开房间回调,或者开通 IM 登出事件消息抄送。您的业务层可以根据抄送,判断退出的一方失败,并结束 PK、删除推流任务。