文档反馈
文档反馈

实现互动直播(Windows)

重要通知

网易云信新版文档中心现已正式上线!

音视频通话2.0互动直播2.0多人语音聊天室PK 直播等产品和场景方案已迁移至新版文档中心维护,欢迎体验!

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

前提条件

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

主播加入房间

1. 引用头文件

在您的工程中对应的文件里添加如下代码引入头文件:

  #include "nrtc_engine.h"

2. 初始化

在操作 SDK 接口前,需要完成初始化。

  1. 调用 createNERtcEngine 方法创建一个 NERtcEngine 实例。
  2. 调用 initialize 方法完成初始化。
    // 创建 RTC 引擎对象并返回指针。
    nertc::IRtcEngineEx *rtc_engine_ = (IRtcEngineEx *)createNERtcEngine();
    // 设置已开通音视频功能的云信应用的AppKey。
    rtc_engine_context_.app_key = app_key_.c_str();
    // 设置日志目录的完整路径,采用UTF-8 编码。可选。
    rtc_engine_context_.log_dir_path = log_dir_path_.c_str();
    // 设置日志级别,默认级别为 kNERtcLogLevelInfo。
    rtc_engine_context_.log_level = log_level;
    // 指定 SDK 输出日志文件的大小上限,单位为 KB。如果设置为 0,则默认为 20 M。
    rtc_engine_context_.log_file_max_size_KBytes = log_file_max_size_KBytes;
    // 设置SDK向应用发送回调事件的通知。
    rtc_engine_context_.event_handler = this;
    // 初始化 NERTC SDK 服务。
    if (kNERtcNoError != rtc_engine_->initialize(rtc_engine_context_))
    {
      //TODO
    }

3. 设置本地视图

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

4. 设置直播模式

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

  //kNERtcChannelProfileCommunication为通话模式,
  // kNERtcChannelProfileLiveBroadcasting为直播模式
  NERtcChannelProfileType channelProfileType = kNERtcChannelProfileLiveBroadcasting;
  rtc_engine_->setChannelProfile(channelProfileType);

5. 设置推流开关

在加入音视频通话房间前,还需要打开推流开关,以便将多媒体流推往CDN,这样拉流的观众可以拉取到该用户对应的音视频流。

  // 示例
  rtc_engine_->setParameters("{\"publish_self_stream_enabled\":true}");

6. 加入房间

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

通过 joinChannel 方法加入房间。

  // 示例
  rtc_engine_->joinChannel(token, channel_name, uid);

重要参数说明

参数 说明
token 安全认证签名(NERTC Token)。可设置为:
  • null。非安全模式下可设置为 null。安全性不高,建议在产品正式上线前联系对应商务经理转为安全模式。
  • 已获取的NERTC Token。安全模式下必须设置为获取到的 Token 。若未传入正确的 Token 将无法进入房间。

    推荐使用安全模式。

channel_name 房间名称,设置相同房间名称的用户会进入同一个通话房间。
注意:您也可以在加入通道前,通过创建房间接口创建房间。若通过 joinChannel 接口加入房间时,传入的 {channel_name} 未事先创建,则云信服务器内部将为其自动创建一个名为 {channel_name} 的通话房间。
uid 用户的唯一标识 id,房间内每个用户的 uid 必须是唯一的。

SDK 发起加入房间请求后,服务器会进行响应,开发者可以通过初始化时设置的 rtc_engine_context_.event_handleronJoinChannel 回调监听加入房间的结果,同时该回调会抛出当前通话房间的 channelId 与加入房间总耗时(毫秒)。

7. 推流任务管理

在成功加入房间后,需要通过 NERtcLiveStreamTaskInfo 设置推流任务,将通话房间内的多媒体数据推至 CDN。典型的业务场景里是由主播进行设置推流任务。推流任务也可以通过 服务端API 进行管理,请根据您的业务需求选择合适的方式。

注意

增加推流任务

音视频房间中默认没有推流任务,您需要在启动直播前通过 addLiveStreamTask 方法增加推流任务。增加推流任务的结果将通过 onAddLiveStreamTask 回调。

    // 添加推流任务的异步callback , 更多错误码请参考onAddLiveStreamTask API文档
    void onAddLiveStreamTask(const char* task_id, const char* url, int error_code){
        if (code == kNERtcNoError) {
            showToast("添加推流任务成功 : taskId " + taskId);
        } else {
            showToast("添加推流任务失败 : taskId " + taskId + " , code : " + code);
        }
    };

    //推流任务数据结构
    NERtcLiveStreamTaskInfo ls_task_info_;
    //保证一个url 只能设置一个task , 要不然会有问题的,使用上层自己维护的task_id、url
    strncpy(ls_task_info_.task_id, task_id.c_str(), kNERtcMaxTaskIDLength);
    strncpy(ls_task_info_.stream_url, url.c_str(), kNERtcMaxURILength);
    ls_task_info_.ls_mode = kNERtcLsModeVideo;
    ls_task_info_.server_record_enabled = false;

    //设置整体布局
    ls_task_info_.layout.background_color = 0x3399ff; // 整体背景色
    ls_task_info_.layout.width = 1280;//整体布局宽度
    ls_task_info_.layout.height = 640;//整体布局高度

    ls_task_info_.layout.user_count = 2;
    ls_task_info_.layout.users = new NERtcLiveStreamUserTranscoding[2];
    ls_task_info_.layout.users[0].uid = uid;
    ls_task_info_.layout.users[1].uid = remote_uid;
    for (int i = 0; i < ls_task_info_.layout.user_count; i++)
    {
        ls_task_info_.layout.users[i].adaption = kNERtcLsModeVideoScaleFit;
        ls_task_info_.layout.users[i].video_push = true;// 推流是否发布user的视频
        ls_task_info_.layout.users[i].x = 640 * i;      // user 的视频布局x偏移,相对整体布局的左上角
        ls_task_info_.layout.users[i].y = 0;            // user 的视频布局y偏移,相对整体布局的左上角
        ls_task_info_.layout.users[i].width = 640;      // user 的视频布局宽度
        ls_task_info_.layout.users[i].height = 640;     //user1 的视频布局高度
        ls_task_info_.layout.users[i].audio_push = true;// 推流是否发布user的音频
    }
    if (0)
    {
        ls_task_info_.layout.bg_image = new NERtcLiveStreamImageInfo;
        ls_task_info_.layout.bg_image->x = 0;
        ls_task_info_.layout.bg_image->y = 0;
        ls_task_info_.layout.bg_image->width = 640;
        ls_task_info_.layout.bg_image->height = 480;
        strncpy(ls_task_info_.layout.bg_image->url, url2.c_str(), kNERtcMaxURILength);
    }
    else
    {
        ls_task_info_.layout.bg_image = nullptr;
    }

    // 如果需要,可以配置多个用户,配置的用户不用已经在房间中,如果用户不在房间中,那么会有相应的视频占位
    // 之后用户以配置了的uid进入房间,开启推流开关即可推流
    int ret = addLiveStreamTask(ls_task_info_);
    if (ret != 0) {
        showToast("调用添加推流任务失败 , ret : " + ret);
    }

更新推流任务

当音视频通话房间内有人员进出或其他情况时,可以使用 updateLiveStreamTask 方法更新推流任务。更新推流任务的结果将通过onUpdateLiveStreamTask回调。

更新推流任务时,会覆盖之前对于这条推流任务的所有配置。

    // 更新推流任务的异步callback , 更多错误码请参考onUpdateLiveStreamTask API文档
    void onUpdateLiveStreamTask(const char* task_id, const char* url, int error_code) {
        if (code == kNERtcNoError) {
        showToast("更新推流任务成功 : taskId " + taskId);
        } else {
        showToast("更新推流任务失败 : taskId " + taskId + " , code : " + code);
        }
    };

    NERtcLiveStreamTaskInfo updateLiveTask1 = preLiveTask;
    // todo 重新配置相关配置 , 具体的配置与添加推流任务时一模一样 ,唯一不能修改的就是 taskId

    int ret = updateLiveStreamTask(taskInfo);
    if (ret != 0) {
        showToast("调用更新推流任务失败 , ret : " + ret);
    }

删除推流任务

当本场互动直播准备结束时,可以通过 removeLiveStreamTask 方法主动删除推流任务。删除推流任务的结果将通过onRemoveLiveStreamTask回调。

    // 删除推流任务的异步callback , 更多错误码请参考onRemoveLiveStreamTask API文档
    void onRemoveLiveStreamTask(const char* task_id, int error_code){
        if (code == kNERtcNoError) {
            showToast("删除推流任务成功 : taskId " + taskId);
        } else {
            showToast("删除推流任务失败 : taskId " + taskId + " , code : " + code);
        }
    };

    int ret = removeLiveStreamTask(preLiveTask.taskId);
    if (ret != 0) {
        showToast("调用删除推流任务失败 : ret : " + ret);
    }

推流任务相关错误码

在增加、更新与删除推流任务时当发生错误时,回调出的错误码如下:

错误码 含义
kNERtcNoError = 0 成功
kNERtcErrLsTaskRequestInvalid = 1301 task请求无效,被后续操作覆盖
kNERtcErrLsTaskIsInvaild = 1400 task参数格式错误
kNERtcErrLsTaskRoomExited = 1401 已经退出房间
kNERtcErrLsTaskNumLimit = 1402 推流任务超出上限
kNERtcErrLsTaskDuplicateId = 1403 推流ID重复
kNERtcErrLsTaskNotFound = 1404 taskId任务不存在,或房间不存在
kNERtcErrLsTaskRequestErr = 1417 请求失败
kNERtcErrLsTaskInternalServerErr = 1500 服务器内部错误
kNERtcErrLsTaskInvalidLayout = 1501 布局参数错误
kNERtcErrLsTaskUserPicErr = 1502 用户图片错误

互动直播推流状态

主播/连麦者参与互动直播的过程中,可以通过 onLiveStreamState 来监听推流状态。

状态码 含义
kNERtcLsStatePushing = 505 推流中
kNERtcLsStatePushFail = 506 互动直播推流失败
kNERtcLsStatePushStopped = 511 推流结束
kNERtcLsStateImageError = 512 背景图片设置出错

8. 设置远端视图

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

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

    • onUserJoined:监听远端用户加入通话房间的事件,并抛出对方的 uid。当本端加入房间后,也会通过此回调抛出通话房间内已有的其他用户。

    • onUserVideoStart :监听远端用户发布视频流的事件,回调中携带对方的 uid 与发布的视频分辨率。

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

     // 示例
     NERtcVideoCanvas canvas;
     canvas.cb = nullptr;
     canvas.user_data = nullptr;
     canvas.window = window;
     // 设置视频缩放模式。
     canvas.scaling_mode = mode;
     rtc_engine_->setupRemoteVideoCanvas(uid, &canvas);
  3. 在监听到远端用户发布视频流后,本方可以通过 setupRemoteVideoCanvas 方法对其发起视频流的订阅,来将对方的视频流渲染到视频画布上。

     // 示例
     // 订阅指定用户的 kNERtcRemoteVideoStreamTypeHigh 类型的视频流
     void NRTCEngine::subscribeRemoteUserVideoStream(nertc::uid_t uid) {
         int ret_temp = rtc_engine_->subscribeRemoteVideoStream(uid, kNERtcRemoteVideoStreamTypeHigh, true);
         if (ret_temp) {
             qDebug("[ERROR] can not subscribe remote video stream! ERROR CODE: %d", ret_temp);
         }
     } 

9. 音频流

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

观众进行 CDN 拉流

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

连麦者上下麦

1. 上麦

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

注意

2. 下麦

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

通话房间内的其他用户可以通过 onUserLeave 来监听其他连麦者下麦。

结束互动直播

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

退出通话房间

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

  // 示例
  rtc_engine_->leaveChannel();

真正退出房间后,SDK 会走入初始化时设置的 rtc_engine_context_.event_handler 回调事件通知中的 onLeaveChannel

销毁实例

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

  // 示例
  // 同步销毁 IRtcEngine 对象
  rtc_engine_->release(true);
  // 销毁 RTC 引擎对象
  destroyNERtcEngine((void*&)rtc_engine_);
  rtc_engine_ = nullptr;
×

反馈成功

非常感谢您的反馈,我们会继续努力做得更好。