互动直播 2.0
Android
动态与公告
更新日志(V4.6)
更新日志(V5)
活动与公告
【活动】内容安全检测限时补贴活动
新手接入指南
产品简介
产品介绍
功能特性
产品优势
应用场景
基本概念
使用限制
体验 Demo
下载 SDK 和 示例代码
升级指南
快速开始
接入流程
创建应用
开通服务
集成 SDK
实现互动直播
Token 鉴权
高级 Token 鉴权
基础功能
设置音频属性
设置视频属性
设置通话音量
屏幕共享
音频共享
监测发言者音量
通话中质量监测
进阶功能
音频管理
客户端音频录制
原始音频数据
美声变声与混响
耳返
自定义音频采集与渲染
音效与伴音
设置音频订阅优先级
音频裸流传输
视频管理
视频截图
水印
云信美颜
第三方美颜
自定义视频采集
视频图像畸变矫正
虚拟背景
视频裸流传输
设备管理
视频设备管理
音频设备管理
媒体补充增强信息
旁路推流
旁路推流
旁路推流画面布局
媒体流管理
跨房间媒体流转发
媒体流加密
视频流回退
AI 融合功能
AI 超分
AI 降噪
最佳实践
音视频参数配置推荐
客户端 API
Android API 参考
错误码
服务端 API
控制台指南
常见问题处理
FAQ
错题集
服务协议

实现互动直播

更新时间: 2022/09/08 22:54:11

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

前提条件

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

主播加入房间

步骤一 导入类

在您的工程中对应的 Activity 文件里添加如下代码先导入以下重要类:

import com.netease.lava.nertc.sdk.NERtcCallbackEx;
import com.netease.lava.nertc.sdk.NERtcConstants;
import com.netease.lava.nertc.sdk.NERtcEx;
import com.netease.lava.nertc.sdk.NERtcParameters;
import com.netease.lava.nertc.sdk.video.NERtcRemoteVideoStreamType;
import com.netease.lava.nertc.sdk.video.NERtcVideoView;

步骤二 初始化

默认情况下,请先调用 init 方法完成初始化。

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

示例代码如下:

//初始化
private void initializeSDK() {
      try {
          NERtcEx.getInstance().init(getApplicationContext(),Config.APP_KEY,callback,null);
      } catch (Exception e) {
          showToast("SDK初始化失败");
          finish();
          ...
          return;
      }
      ...
}

请在初始化方法中传入原型为 NERtcCallback / NERtcCallbackExcallback

步骤三 设置本地视图

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

  • 加入房间前预览。

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

    示例代码如下:

        //以开启本地视频主流预览为例
        NERtcVideoView localView = (NERtcVideoView)findViewById(R.id.local_view);
        NERtcEx.getInstance().setupLocalVideoCanvas(localView);
        NERtcEx.getInstance().startVideoPreview(kNERtcVideoStreamTypeMain);
    
    1. 若要结束预览,或者准备加入房间时,调用 stopVideoPreview(streamType) 停止预览。

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

  • 加入房间后预览。

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

    示例代码如下:

      //以开启本地视频主流采集并发送为例
      NERtcEx.getInstance().enableLocalVideo(true,kNERtcVideoStreamTypeMain);
      //设置本地预览画布
      NERtcVideoView localView = (NERtcVideoView)findViewById(R.id.local_view);
      NERtcEx.getInstance().setupLocalVideoCanvas(localView);
    

步骤四 设置直播模式

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

示例代码如下:

// 0 - COMMUNICATION(通信模式),  1 - LIVE_BROADCASTING(直播模式)
NERtcEx.getInstance().setChannelProfile(1);

步骤五 加入房间

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

调用 joinChannel 方法加入房间。

调用 joinChannel 之后,NERTC SDK 会通过 Android 的 AudioManager.setMode() 方法调整音频模式(audio mode),此后请勿修改 SDK 调整过的音频模式,否则会导致音频路由错误等问题。

示例代码如下:

  NERtcEx.getInstance().joinChannel(token,channelName,uid);

参数说明

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

    推荐使用安全模式

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

SDK 发起加入房间请求后,服务器会进行响应,您可以通过 NERtcCallbackonJoinChannel 回调监听加入房间的结果,同时该回调会抛出当前通话房间的 channelId 与加入房间总耗时(毫秒)。

步骤六 推流任务管理

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

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

增加推流任务

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

示例代码(增加推流任务)
    //初始化推流任务
    NERtcLiveStreamTaskInfo liveTask1 = new NERtcLiveStreamTaskInfo();
    //taskID 可选字母、数字,下划线,不超过64位
    liveTask1.taskId = String.valueOf(Math.abs(pushUlr.hashCode()));
    //设置推互动直播推流地址,一个推流任务对应一个推流房间
    liveTask1.url = pushUlr;
    //设置是否进行互动直播录制,请注意与音视频通话录制区分。
    liveTask1.serverRecordEnabled = false;
    //设置推音视频流还是纯音频流
    liveTask1.liveMode = enableVideo? NERtcLiveStreamTaskInfo.NERtcLiveStreamMode.kNERtcLsModeVideo : NERtcLiveStreamTaskInfo.NERtcLiveStreamMode.kNERtcLsModeAudio;

    //设置整体布局
    NERtcLiveStreamLayout layout = new NERtcLiveStreamLayout();
    layout.userTranscodingList = new ArrayList<>();//设置成员数组
    layout.backgroundImgList = new ArrayList<>();//设置占位图数组
    layout.width = 720;//整体布局宽度
    layout.height = 1280;//整体布局高度
    layout.backgroundColor = Color.parseColor("#3399ff"); //整体背景色
    liveTask1.layout = layout;

    //设置直播成员布局
    NERtcLiveStreamUserTranscoding user1 = new NERtcLiveStreamUserTranscoding();
    user1.uid = uid1; // 用户id
    user1.audioPush = true; // 推流是否发布user1 的音频
    user1.videoPush = enableVideo; // 推流是否发布user1的视频
    if (user1.videoPush) {// 如果发布视频,需要设置一下视频布局参数
        // user1 视频的缩放模式, 详情参考NERtcLiveStreamUserTranscoding 的API 文档
        user1.adaption = NERtcLiveStreamUserTranscoding.NERtcLiveStreamVideoScaleMode.kNERtcLsModeVideoScaleCropFill;
        user1.x = 10; // user1 的视频布局x偏移,相对整体布局的左上角
        user1.y = 10; // user1 的视频布局y偏移,相对整体布局的左上角
        user1.width = 180; // user1 的视频布局宽度
        user1.height = 320; //user1 的视频布局高度
        user1.zOrder = 1;//user1 的视频帧的图层编号
    }
    layout.userTranscodingList.add(user1);

    ...
    //设置第n位直播成员布局
    NERtcLiveStreamUserTranscoding usern = new NERtcLiveStreamUserTranscoding();
    usern.uid = uidn;
    usern.audioPush = true;
    usern.videoPush = enableVideo;
    if (usern.videoPush) {
            usern.adaption = NERtcLiveStreamUserTranscoding.NERtcLiveStreamVideoScaleMode.kNERtcLsModeVideoScaleCropFill;
            usern.x = user1.x + user1.width + 10;
            usern.y = user1.y + user1.height + 10;
            usern.width = 320;
            usern.height = 640;
            usern.zOrder = 1;
        }
    layout.userTranscodingList.add(usern);
      
    //设置音视频流编码参数
    NERtcLiveConfig config = new NERtcLiveConfig();
    //设置是否开启推流成员离线时的占位图
    config.interruptedPlaceImage = false;
    //设置是否开启单路视频透传开关
    config.singleVideoPassThrough = false;
    //设置音频推流码率
    config.audioBitrate = 192 kbps;
    //设置音频推流采样率
    config.sampleRate = NERtcLiveStreamAudioSampleRate48000;
    //设置音频编码规格
    config.audioCodecProfile= NERtcLiveStreamAudioCodecProfileLCAAC;
    //设置音频推流声道数
    config.channels = 2;
    layout.config = config;

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

    ...
    //设置第n张占位图片布局
    NERtcLiveStreamImageInfo imagen = new NERtcLiveStreamImageInfo();
    imagen.url = url;//不同的占位图需要设置不同的url
    imagen.x = image1.x + image1.width + 10; 
    imagen.y = image1.y + image1.height + 10;
    imagen.width = 320;
    imagen.height = 640;
    imagen.zOrder = 0;//不同占位图可以设置不同的zOrder
    layout.backgroundImgList.add(imagen);

    //调用 addLiveStreamTask 接口添加推流任务
    int ret = NERtcEx.getInstance().addLiveStreamTask(liveTask1, addLiveTaskCallback);
    if (ret != 0) {
            showToast("调用添加推流任务接口执行失败 , ret : " + ret);
        }

    // 添加推流任务的异步callback
    private AddLiveTaskCallback addLiveTaskCallback = new AddLiveTaskCallback(){
      void onAddLiveStreamTask(String taskId, int errCode){
        if (code == RtcCode.LiveCode.OK) {
                showToast("添加推流任务成功 : taskId " + taskId);
            } else {
                showToast("添加推流任务失败 : taskId " + taskId + " , code : " + code);
            }
        }
    };

更新推流任务

当音视频通话房间内有人员进出或其他情况时,可以调用 updateLiveStreamTask 方法更新推流任务。更新推流任务时,会覆盖之前对于这条推流任务的所有配置。

示例代码(更新推流任务)
      // 初始化新推流任务。注意:其中的taskid为原推流任务id。
      NERtcLiveStreamTaskInfo updateLiveTask1 = preLiveTask;
      ...
      // 更新推流任务
      int ret = NERtcEx.getInstance().updateLiveStreamTask(updateLiveTask1 , updateLiveTaskCallback);
      if (ret != 0) {
          showToast("调用更新推流任务接口执行失败 , ret : " + ret);
      }
      // 更新推流任务的异步callback
      private UpdateLiveTaskCallback updateLiveTaskCallback = new UpdateLiveTaskCallback() {
          @Override
          public void onUpdateLiveStreamTask(String taskId, int errCode) {
              if (code == RtcCode.LiveCode.OK) {
                  showToast("更新推流任务成功 : taskId " + taskId);
              } else {
                  showToast("更新推流任务失败 : taskId " + taskId + " , code : " + code);
              }
          }
      };

删除推流任务

当本场互动直播准备结束时,可以调用 removeLiveStreamTask 方法主动删除推流任务。

示例代码(删除推流任务)
      int ret = NERtcEx.getInstance().removeLiveStreamTask(preLiveTask.taskId,deleteLiveTaskCallback );
      if (ret != 0) {
          showToast("调用删除推流任务接口执行失败 : ret : " + ret);
      }
      // 删除推流任务的异步callback
      private DeleteLiveTaskCallback deleteLiveTaskCallback = new DeleteLiveTaskCallback() {
          @Override
          public void onDeleteLiveStreamTask(String taskId, int errCode) {
              if (code == RtcCode.LiveCode.OK) {
                  showToast("删除推流任务成功 : taskId " + taskId);
              } else {
                  showToast("删除推流任务失败 : taskId " + taskId + " , code : " + code);
              }
          }
      };

推流任务相关错误码

增加、更新与删除推流任务时,如果发生错误,callback 回调通过错误码形式反馈错误原因。错误码 RtcCode.LiveCode 如下:

错误码 含义
OK = 0 成功
TASK_REQUEST_INVALID = 1301 task请求无效,被后续操作覆盖
TASK_IS_INVALID = 1400 task参数格式错误
TASK_ROOM_EXITED = 1401 已经退出房间
TASK_NUM_LIMIT = 1402 推流任务超出上限
TASK_DUPLICATE_ID = 1403 推流ID重复
TASK_NOT_FOUND = 1404 taskId任务不存在,或房间不存在
TASK_REQUEST_ERR = 1417 请求失败
TASK_INTERNAL_SERVER_ERR = 1500 服务器内部错误
TASK_INVALID_LAYOUT = 1501 布局参数错误
TASK_USER_PIC_ERR = 1502 用户图片错误

互动直播推流状态

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

常见的推流状态如下:

状态码 含义
NERtcConstants.LiveStreamState.STATE_PUSHING = 505 推流中
NERtcConstants.LiveStreamState.STATE_PUSH_FAIL = 506 互动直播推流失败
NERtcConstants.LiveStreamState.STATE_PUSH_STOPPED = 511 推流结束
NERtcConstants.LiveStreamState.STATE_IMAGE_ERROR = 512 背景图片设置出错

步骤七 设置远端视图

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

  1. 监听远端用户进出频道。

    NERtcCallback 通过以下回调获取相关信息:

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

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

  2. 设置远端视频画布。

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

    示例代码如下:

      NERtcVideoView remoteView = (NERtcVideoView)findViewById(R.id.remote_view);
      NERtcEx.getInstance().setupRemoteVideoCanvas(remoteView,uid);
    
  3. 监听远端视频流发布。

    当房间中的其他用户发布视频流时,本端会触发 onUserVideoStart 回调。

  4. 订阅远端视频流。

    在监听到远端用户发布视频流后,本端可以调用 subscribeRemoteVideoStream 方法对其发起视频流的订阅,来将对方的视频流渲染到视频画布上。

    示例代码如下:

    NERtcEx.getInstance().subscribeRemoteVideoStream(uid, streamType, subscribe);
    
  5. 监听远端用户离开房间或关闭视频功能。

步骤八 音频流

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

观众进行 CDN 拉流

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

连麦者上下麦

步骤一 上麦

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

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

步骤二 下麦

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

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

结束互动直播

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

步骤一 退出通话房间

调用 leaveChannel 方法退出通话房间。

示例代码如下:

NERtcEx.getInstance().leaveChannel();

NERtcCallback 提供 onLeaveChannel 回调来监听当前用户退出房间的结果。

步骤二 销毁实例

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

示例代码如下:

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