实现互动直播

更新时间: 2022/09/08 14:59:04

网易云信互动直播产品的基本功能包括音视频通话和连麦直播,当您成功初始化 SDK 之后,您可以简单体验本产品的基本业务流程,例如主播加入房间、观众CDN拉流、连麦者上下麦、结束直播等。本文档为您展示互动直播提供的基本业务流程。

前提条件

请确认您已完成以下操作:

主播加入房间

步骤一 导入类

在项目中导入 NERtcSDK 类:

objc  #import <NERtcSDK/NERtcSDK.h>

步骤二 初始化

调用 setupEngineWithContext 方法完成初始化。

自 V4.4.0 版本起,初始化之前无需通过 setParameters 方法的 kNERtcKeyPublishSelfStreamEnabled 字段打开推流开关。加入房间并创建推流任务后,房间中所有成员的音视频流均可以进行混流并推流至 CDN。

示例代码如下:

objc  //初始化
  @interface Myapp ()<NERtcEngineDelegateEx>
  ...
  NERtcEngine *coreEngine = [NERtcEngine sharedEngine];
  NERtcEngineContext *context = [[NERtcEngineContext alloc] init];
  //设置通话相关信息的回调
  context.engineDelegate = self;
  //设置当前应用的 App Key
  context.appKey = AppKey;
  [coreEngine setupEngineWithContext:context];
  ...

步骤三 设置本地视图

初始化成功后,可以设置本地视图,来预览本地图像。您可以在加入房间之前预览,或在加入房间后预览。

  • 加入房间前预览。

    1. 调用 setupLocalVideoCanvasstartPreview(streamType),在加入房间前设置本地视图,预览本地图像。

    示例代码如下:

    objc// 示例
    NERtcVideoCanvas *canvas = [[NERtcVideoCanvas alloc] init];
    canvas.container = self.localUserView;
    // 设置本地视频画布
    [NERtcEngine.sharedEngine setupLocalVideoCanvas:canvas];
    // 以开启本地视频主流预览为例
    [NERtcEngine.sharedEngine startPreview:kNERtcStreamChannelTypeMainStream];
    
    1. 若要结束预览,或者准备加入房间时,调用 stopPreview(streamType) 方法停止预览。

stopPreview(streamType)streamType 参数请与 startPreview(streamType) 的保持一致,即同为主流或辅流的开启和停止预览。

  • 加入房间后预览。

    在成功加入房间后,调用 enableLocalVideo 方法进行视频的采集发送与预览。

    示例代码如下:

    objc//以开启本地视频主流采集并发送为例
    [NERtcEngine.sharedEngine enableLocalVideo:YES,kNERtcStreamChannelTypeMainStream];
    //设置本地预览画布
    NERtcVideoCanvas *canvas = [[NERtcVideoCanvas alloc] init];
    canvas.container = self.localUserView;
    [NERtcEngine.sharedEngine setupLocalVideoCanvas:canvas];
    

步骤四 设置直播模式

在互动直播的场景中,建议在加入房间前,调用 setChannelProfile 方法设置房间模式为直播模式。当前默认为通信模式。

示例代码如下:

objc  // kNERtcChannelProfileCommunication-通信模式
  // kNERtcChannelProfileLiveBroadcasting-直播模式
  [NERtcEngine.sharedEngine setChannelProfile:kNERtcChannelProfileLiveBroadcasting];

步骤五 加入房间

加入房间前,请确保已完成初始化相关事项。若您的业务中涉及呼叫邀请等机制,建议通过 信令 实现。

调用 joinChannelWithToken:channelName:myUid:completion: 方法加入房间。

示例代码如下:

objc  // 示例
  [NERtcEngine.sharedEngine joinChannelWithToken:@""
                                     channelName:roomId
                                           myUid:userId
                                      completion:^(NSError * _Nullable error, uint64_t channelId, uint64_t elapesd) {
                                                          if (error) {
                                                              //加入失败
                                                          } else {
                                                              //加入成功
                                                          }
                                        }];

参数说明

参数 说明
Token 安全认证签名(NERTC Token)。
  • 调试模式下:可设置为 null。产品默认为安全模式,您可以在网易云信控制台将鉴权模式修改为调试模式,具体请参见Token 鉴权
    调试模式的安全性不高,请在产品正式上线前修改为安全模式。
  • 产品正式上线后:请设置为已获取的NERTC Token。安全模式下必须设置为获取到的 Token 。若未传入正确的 Token 将无法进入房间。

    推荐使用安全模式

channelName 房间名称,长度为 1 ~ 64 字节。目前支持以下 89 个字符:a-z, A-Z, 0-9, space, !#$%&()+-:;≤.,>? @[]^_{|}~"。
设置相同房间名称的用户会进入同一个通话房间。
您也可以在加入通道前,通过创建房间接口创建房间。加入房间时,若传入的 {channelName} 未事先创建,则云信服务器内部将为其自动创建一个名为 {channelName} 的通话房间。
myUid 用户的唯一标识 id,为数字串,房间内每个用户的 uid 必须是唯一的。此 uid 为用户在您应用中的 ID,请在您的业务服务器上自行管理并维护。

步骤六 推流任务管理

在成功加入房间后,需要通过 NERtcLiveStreamTaskInfo 设置推流任务,将通话房间内的多媒体数据推至 CDN。典型的业务场景里是由主播进行设置推流任务。

推流任务也可以通过服务端 API 进行管理,请根据您的业务需求选择合适的方式。

  • 此处的主播业务层面的角色,SDK 体系内不区分主播与连麦者。
  • 推流任务中,需要设置互动直播的CDN推流地址,请在合适的时机创建直播房间,将获取到的推流地址传入推流任务。
  • 添加推流任务时,需要设置布局参数,您可以参考旁路推流画面布局完成设置。
  • 推流任务与通话绑定,当通话结束后,推流任务也会自动随之销毁。
  • 一通通话,即一个channelId同时最多对应 6 个不同的推流任务。

增加推流任务

音视频房间中默认没有推流任务,您需要在启动直播前调用 addLiveStreamTask:compeltion: 方法增加推流任务。

示例代码(增加推流任务)
objc  //初始化推流任务
  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;
      user1.zOrder = 1;
      }
    
  //设置第n位推流成员布局
  NERtcLiveStreamUserTranscoding *usern = [[NERtcLiveStreamUserTranscoding alloc]init];
  usern.uid = uidn;
  usern.audioPush = true;
  usern.videoPush = enableVideo;
  if (usern.videoPush) {
      usern.x = user1.x + user1.width + 10;
      usern.y = user1.y + user1.height + 10;
      usern.width = 320;
      usern.height = 640;
      usern.adaption = kNERtcLsModeVideoScaleCropFill;
      usern.zOrder = 1;
  }
  layout.users = @[user1,...,usern];

  //设置音视频流编码参数
  NERtcLiveConfig *config = [[NERtcLiveConfig alloc] init];
  //设置是否开启推流成员离线时的占位图
  config.interruptedPlaceImage = false;
  //设置是否开启单路视频透传开关
  config.singleVideoPassthrough = false;
  //设置音频推流码率
  config.audioBitrate = 192 kbps;
  //设置音频推流采样率
  config.sampleRate = kNERtcLiveStreamAudioSampleRate48000;
  //设置音频编码规格
  config.audioCodecProfile= kNERtcLiveStreamAudioCodecProfileLCAAC;
  //设置音频推流声道数
  config.channels = 2;
  layout.config = config;

  //设置占位图片布局(可选)
  //原 bgImg 字段仍保留,仅可设置一张占位图,若您同时配置了两个字段,则以 bgImages 配置为准
  NERtcLiveStreamImageInfo *image1 = [[NERtcLiveStreamImageInfo alloc] init];
  image1.url = url; //image1的URL   
  image1.x = 10; //image1的布局x偏移,相对整体布局的左上角
  image1.y = 10; //image1的布局y偏移,相对整体布局的左上角
  image1.width = 320; //image1的宽度
  image1.height = 640; //image1的高度
  image.zOrder = 0; //image1的图层编号

  //设置第n张占位图片布局
  NERtcLiveStreamImageInfo *imagen = [[NERtcLiveStreamImageInfo alloc] init];
  imagen.url = url; //不同的占位图需要设置不同的url 
  imagen.x = image1.x + image1.width + 10; 
  imagen.y = image1.y + image1.height + 10; 
  imagen.width = 180; 
  imagen.height = 320; 
  image.zOrder = 0; //不同占位图可以设置不同的zOrder
  layout.bgImages = @[image1,...,imagen];
    
  //调用 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: 方法更新推流任务。更新推流任务时,会覆盖之前对于这条推流任务的所有配置。

示例代码(更新推流任务)
objc  // 初始化新推流任务。注意:其中的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: 方法主动删除推流任务。

示例代码(删除推流任务)
objc  // 示例
  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 推流结束

步骤七 设置远端视图

互动直播过程中,除了要显示本地的视频画面,通常也要显示参与互动的其他连麦者/主播的远端视频画面。

  1. NERtcEngineDelegate 通过以下回调获取相关信息:

  2. 在监听到远端用户加入房间或发布视频流后,本方可以通过 – setupRemoteVideoCanvas:forUserID: 方法设置远端用户视频画布,用于显示其视频画面。

    示例代码如下:

    objc  NERtcVideoCanvas *canvas = [self setupRemoteCanvasWithUid:userID];
      [NERtcEngine.sharedEngine setupRemoteVideoCanvas:canvas forUserID:userID];
    
  3. 在监听到远端用户发布视频流后,本方可以通过 – subscribeRemoteVideo:forUserID:streamType: 方法对其发起视频流的订阅,来将对方的视频流渲染到视频画布上。

    示例代码如下:

    objc  [NERtcEngine.sharedEngine subscribeRemoteVideo:YES
                                          forUserID:userID
                                          streamType:kNERtcRemoteVideoStreamTypeHigh];
    

步骤八 音频流

本地音频的采集发布和远端音频订阅播放是默认启动的,正常情况下无需开发者主动干预。

观众进行CDN拉流

当通话房间内有主播/连麦者发布多媒体流,且正确设置了推流任务时,通话房间外的观众可以通过 CDN 直播拉流地址进行拉流播放。云信同时提供播放器SDK组件供您使用,详细内容请参考直播-播放器 SDK

连麦者上下麦

步骤一 上麦

若正在进行 CDN 拉流播放的普通观众要上麦参与互动时,必须先停止 CDN 拉流,并释放播放器相关资源。然后按照主播加入房间流程,进行初始化、设置本地视图、设置直播模式、设置推流开关、加入通话房间、设置远端视图。

注意

  • 由于有新连麦者的加入,需要更新推流任务将新连麦者设置到推流布局中。操作步骤请参考更新推流任务。更新推流的任务操作,可以由主播执行,也可以由连麦者执行,也可以通过服务端API完成。
  • NERTC SDK 支持直播场景下的用户角色管理,角色包括主播和观众,默认以主播角色加入房间。调用 setChannelProfile 将通话设置为直播场景之后,可以通过 setClientRole 切换用户角色。

步骤二 下麦

若连麦者互动结束,需要下麦时,可以更新推流任务,在推流布局中剔除该连麦者。同时,连麦者退出通话房间,清理相关资源,重新进行播放器拉流或直接离开直播间。

通话房间内的其他用户可以通过NERtcEngineDelegate– onNERtcEngineUserDidLeaveWithUserID:reason: 来监听其他连麦者下麦。

结束互动直播

需要结束该场互动直播时,可以先删除推流任务,然后主播与连麦者退出通话房间,观众结束 CDN 拉流。

1. 退出通话房间

通过 leaveChannel 接口退出通话房间。

示例代码如下:

objc  // 退出通话房间
  [NERtcEngine.sharedEngine leaveChannel];

NERtcEngineDelegate 提供 – onNERtcEngineDidLeaveChannelWithResult: 来监听当前用户退出房间的结果。

2. 销毁实例

当确定 App 短期内不再使用音视频通话实例时,可以通过 destroyEngine 释放对应的对象资源。

示例代码如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

     [NERtcEngine destroyEngine];

 });
此文档是否对你有帮助?
有帮助
去反馈
  • 前提条件
  • 主播加入房间
  • 步骤一 导入类
  • 步骤二 初始化
  • 步骤三 设置本地视图
  • 步骤四 设置直播模式
  • 步骤五 加入房间
  • 步骤六 推流任务管理
  • 增加推流任务
  • 更新推流任务
  • 删除推流任务
  • 推流任务相关错误码
  • 互动直播推流状态
  • 步骤七 设置远端视图
  • 步骤八 音频流
  • 观众进行CDN拉流
  • 连麦者上下麦
  • 步骤一 上麦
  • 步骤二 下麦
  • 结束互动直播
  • 1. 退出通话房间
  • 2. 销毁实例