音视频通话 2.0
Android

CDN推流

更新时间: 2023/12/26 17:14:45

NERTC SDK 融合了 CDN 推流能力,您只要集成一个 SDK 即可实现单人直播、PK 直播和连麦,且三个场景之间能无缝切换,提升 PK 直播体验。

  flowchart LR

    
    A("创建应用并获取 App Key") --> B(开通音视频通话 2.0 和直播服务)-->  E("获取推拉流地址")--> C("集成 RTC SDK") --> D(实现 CDN 推流)
    click A "https://doc.yunxin.163.com/console/docs/TIzMDE4NTA?platform=console"
    click B "https://doc.yunxin.163.com/nertc/docs/jY3MzMwODA?platform=android"
    click C "https://doc.yunxin.163.com/nertc/docs/DcyNDc0ODI?platform=android"
    click E "https://doc.yunxin.163.com/live-streaming/docs/DM4MjYxODY?platform=android#步骤3-获取推拉流地址"
    style D fill:#337EFF,stroke:#337EFF,stroke-width:0px,color:#FFFFFF; 
    style A fill:#9DC3E6,stroke:#9DC3E6,stroke-width:0px,color:#FFFFFF;  
    style B fill:#9DC3E6,stroke:#9DC3E6,stroke-width:0px,color:#FFFFFF;  
    style C fill:#9DC3E6,stroke:#9DC3E6,stroke-width:0px,color:#FFFFFF;   
    style E fill:#9DC3E6,stroke:#9DC3E6,stroke-width:0px,color:#FFFFFF; 

功能描述

  • 在单人直播时,SDK 将主播的音视频直接推流到 CDN 分发,观众端无需加入 RTC 房间即可通过播放器拉流观看。
  • 在 PK 直播时,通过跨频道转发,主播无须切换 SDK,也不需要退出或重新进入房间,直接将媒体流转发到主播房间和挑战者房间,实现主播跨房间与其他主播实时互动。直播间内的观众可以同时观看两个主播 PK 互动,场景无缝切换,不会出现黑屏卡顿问题。
  • 只有指定版本的 NERTC SDK 支持 CDN 推流功能。请在 SDK 下载中心直播推流区域下载对应的 SDK。
  • 为了保障您的直播体验,接入之前,请联系网易云信技术支持根据您的场景为您提供专属的 1 对 1 服务。

应用场景

该功能适用于直播间PK、游戏、在线教育等场景。

  • 秀场直播:PK 连麦是视频互动直播的主流玩法,多个主播间通过主动邀请、随机匹配等方式互相配对,连麦成功后通过斗歌等方式进行 PK 竞技,并在一定时限内决出胜负,获胜一方可获得奖励,例如粉丝礼物、打赏、积分等。
  • 游戏场景:用户可以选择与其他玩家进行 PK,通过 PK 功能实现双方的音视频流同步播放,提高游戏体验。
  • 电商直播:可通过引入 PK 连麦模式,实现价格比拼等直播形式,激起用户的购买欲望,摆脱传统电商直播缺少互动的单调形式。
  • 在线教育:老师和学生可以通过 PK 功能进行互动课堂,实现音视频流的同步播放,提高学习效果。

前提条件

完整示例代码

网易云信为您提供实现 CDN 推流的示例代码作为参考,您可以直接拷贝用于运行测试。

请单击下载CDN 推流最佳实践代码

功能原理

单人直播

单人直播的架构原理如下图所示。

单人直播.png

单人直播模式下,主播 A 和主播 B 分别加入房间 A 和 B,NERTC SDK 将主播音视频直接推流到 CDN 分发,观众端使用 RTMP/HLS/FLV 协议进行拉流观看。

PK 直播

PK 直播的架构原理如下图所示。

PK直播.png

PK 直播的业务流程说明如下:

  1. 主播 A 发出 PK 邀请,主播 B 同意。
  2. 通过跨频道转发,主播 A 和主播 B 不需要退出原房间,直接将媒体流转发到房间 A 和房间 B 中,实现主播跨房间与其他主播实时互动。
  3. 互动直播服务器将主播 A 和主播 B 的音视频进行混屏转码后,推到 CDN 分发。
  4. 观众端使用 RTMP/HLS/FLV 协议进行拉流观看。

连麦

连麦的架构原理如下图所示。

连麦.png

连麦的业务流程说明如下:

  1. 观众申请上麦,主播同意上麦申请后,观众加入 RTC 房间。
  2. 互动直播服务器将主播和观众的音视频进行混屏转码后,推到 CDN 分发。
  3. 观众端使用 RTMP/HLS/FLV 协议进行拉流观看。

注意事项

  • 只支持网易云信播放器 NELivePlayer 进行拉流,其他播放器暂不兼容。
  • 单人直播切换到 PK 直播时,音频采样率必须保持一致。
  • 旁路推流时请使用客户端的推流接口(addLiveStreamTask),不要使用服务端的旁路推流接口,因为客户端推流接口针对本场景做了适配处理。

集成 RTC SDK

只有指定版本的 NERTC SDK 支持 CDN 推流功能,请参考如下方法集成对应版本的 NERTC SDK。详细的集成 SDK 的步骤请参见集成 SDK

使用 maven 集成指定版本 SDK 的示例代码如下:

implementation 'com.netease.yunxin:nertc:4.6.422'

如需手动集成,请到 SDK 下载中心直播推流区域下载最新版本的 SDK。

导入类

在您的工程中对应实现音视频通话的 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;

实现单人直播

API 时序图

sequenceDiagram
    actor 主播A
    participant NERtcSDK

    
    主播A->>NERtcSDK: init 初始化引擎
  
    主播A->>NERtcSDK: enableLocalVideo(true) 开启视频的采集和发送
    主播A->>NERtcSDK: enableLocalAudio(true)

    主播A->>NERtcSDK: setAudioProfile 设置音频属性

    主播A->>NERtcSDK: setLocalVideoConfig  设置视频属性

    主播A->>NERtcSDK: setChannelProfile 设置场景属性为直播

    rect rgb(191, 223, 255)
    主播A->>NERtcSDK: startPushStreaming 开始推流
    NERtcSDK-->>主播A: onStartPushStreaming

    主播A->>NERtcSDK: stopPushStreaming 停止推流
    NERtcSDK-->>主播A: onStopPushStreaming
    end

实现方法

  1. 初始化引擎。

    调用 init 方法完成初始化。

    您还需要在初始化时注册相关必要回调,建议您请在初始化方法中传入原型为 NERtcCallbackEx 的回调,并增加相应必要的处理。直播推流相关回调请参见常用的回调

  2. 设置本地视频画布。 初始化成功后,可以设置本地视图,来预览本地图像。您可以根据业务需要实现加入房间之前预览或加入房间后预览。

    • 若您想设置画布渲染参数,可以调用 setScalingType 方法设置渲染缩放模式或调用 setMirror 方法设置镜像模式。
    • 若您想调整摄像头的相关参数,请参考视频设备管理进行设置。
    • 在加入房间前,默认预览分辨率为 640*480,您可以通过 setLocalVideoConfig 接口的 width height 参数调整采集分辨率。
    • 实现加入房间前预览。
    1. 调用 setupLocalVideoCanvasstartVideoPreview(streamType) 方法,在加入房间前设置本地视图,预览本地图像。

    2. 若要结束预览,或者准备加入房间时,调用 stopVideoPreview(streamType) 方法停止预览。

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

  3. 调用 enableLocalVideo(streamType)enableLocalAudio方法进行视频和音频的采集发送。

  4. 开始直播前,调用 setChannelProfile 接口,设置房间的场景属性为直播场景(kNERtcChannelProfileLiveBroadcasting)。

  5. 直播前或直播中,调用 setAudioProfilesetLocalVideoConfig 接口,分别设置音频属性和视频属性。 本场景中相关参数的推荐配置如下表所示。

属性
推荐配置
推荐原因

音频属性
setAudioProfile

  • Profile:kNERtcAudioProfileHighQuality 或 kNERtcAudioProfileHighQualityStereo(双声道,伴音场景可以选择该模式)
  • Scenario:kNERtcAudioScenarioMusic

高清音质。满足娱乐场景中主播对高音质的需求。

视频属性
setLocalVideoConfig

以整体画布比例为 16:9 为例:

  • 分辨率:1280 x 720
  • 帧率:15 fps

    或者
  • 分辨率: 960 x 540
  • 帧率:15 fps
    或者
  • 分辨率: 640 x 360
  • 帧率:24 fps

保证画质清晰度。

  1. 主播调用 startPushStreaming 接口,将房间中的音视频流推流到 CDN 上,NERtcPushStreamingConfig 相关参数说明如下表所示。

    参数 描述
    streamingUrl 指定该音视频流的 CDN 推流地址。推流地址的获取方法请参见获取推拉流地址
    NERtcStreamingRoomInfo 推流的房间信息。
  2. 推流成功后,房间内的用户会收到 onStartPushStreaming 的回调。

  3. 直播结束后,调用 stopPushStreaming 接口停止推流。

  4. 停止推流后,房间内的用户会收到 onStopPushStreaming 回调。

示例代码

实现单人直播主流程的示例代码如下:

public int startLive(NERtcPushStreamingConfig config) {
    //step1 基础设置

    //初始化引擎(具体初始化方法参见初始化接口init相关)
    NERtcEx.getInstance().init(context, appkey, callback, option);

    ////打开音视频
    NERtcEx.getInstance().enableLocalVideo(true);
    NERtcEx.getInstance().enableLocalAudio(true);

    //以下设置为了保证直播效果,建议开启
    //建议audioprofile设置为kNERtcAudioProfileHighQuality和kNERtcAudioScenarioMusic
    NERtcEx.getInstance().setAudioProfile(NERtcConstants.AudioProfile.HIGH_QUALITY, NERtcConstants.AudioScenario.MUSIC);

    //建议设置为直播模式
    NERtcEx.getInstance().setChannelProfile(NERtcConstants.RTCChannelProfile.LIVE_BROADCASTING);
    //其他设置

    //step2 调用开始推流接口
    //(如果接口未返回错误, 监听onStartPushStreaming回调处理推流结果;如果接口报错,直接处理相关错误)
    return NERtcEx.getInstance().startPushStreaming(config);
}

实现加入房间前预览的示例代码如下:

//以开启本地视频主流预览为例
NERtcVideoView localView = (NERtcVideoView)findViewById(R.id.render_view_local);
NERtcEx.getInstance().setupLocalVideoCanvas(localView);
NERtcEx.getInstance().startVideoPreview(kNERtcVideoStreamTypeMain);

//设置本地视频画面的渲染模式:以保证原始视频尺寸比例为例(可选)
NERtcEx.getInstance().setScalingType(NERtcConstants.VideoScalingType.SCALE_ASPECT_FIT);

//设置本地视频画面的镜像模式:以开启镜像为例(可选)
NERtcEx.getInstance().setMirror(true);

实现加入房间后预览的示例代码如下:

//设置本地预览画布
NERtcVideoView localView = (NERtcVideoView)findViewById(R.id.render_view_local);
NERtcEx.getInstance().setupLocalVideoCanvas(localView);

//以开启本地视频主流采集并发送为例
NERtcEx.getInstance().enableLocalVideo(true,kNERtcVideoStreamTypeMain);

//设置本地视频画面的渲染模式:以保证原始视频尺寸比例为例(可选)
NERtcEx.getInstance().setScalingType(NERtcConstants.VideoScalingType.SCALE_ASPECT_FIT);

//设置本地视频画面的镜像模式:以开启镜像为例(可选)
NERtcEx.getInstance().setMirror(true);

实现 PK 直播

下文介绍在单人直播的过程中,主播 A 邀请主播 B 进行PK直播实现流程。

API 时序图

sequenceDiagram
    actor 主播A
    participant NERtcSDK
    participant 业务服务器
    actor 主播B
    %% 开始PK 
   
    主播A->>业务服务器: 邀请PK
    Note right of 主播A: 邀请主播B进行PK(带上自己的uidcnameToken等信息)
    Note left of 主播B: 请自行实现邀请PK的相关业务逻辑
    业务服务器->>主播B: 邀请PK(带上主播AuidcnameToken等信息)

    主播B-->>业务服务器: 同意PK
    业务服务器-->>主播A: 对端同意PK(带上主播BuidcnameToken等信息)

    rect rgb(191, 223, 255)
    主播A ->> NERtcSDK: startChannelMediaRelay   开启媒体转发
    主播A ->> NERtcSDK: addLiveStream 开始旁路推流
    NERtcSDK -->> 主播A: onLiveStreamState  监听旁路推流状态

    主播A ->> NERtcSDK: stopPushStreaming   旁路推流成功后,停止推流
    Note right of 主播A: 当主播B开始MediaRelay后,更新旁路推流,具体请根据实际业务进行调整
    主播A ->> NERtcSDK: updateLiveStreamTask  更新旁路推流
    Note right of 主播A:  根据回调确认mediaRelay是否成功
    NERtcSDK -->> 主播A: onMediaRelayStatesChangeonMediaRelayReceiveEvent 
    
    end
    NERtcSDK -->> 主播A: 监听房间中人员进入和音视频打开的回调
    NERtcSDK -->> 主播B: 监听房间中人员进入和音视频打开的回调
    

    主播A ->> 业务服务器: 结束PK
    业务服务器 ->> 主播B: 结束PK
    主播A ->> NERtcSDK: startPushStreaming  重新开始单人直播推流

    NERtcSDK -->> 主播A: onStartPushStreaming
    主播A ->> NERtcSDK: stopChannelMediaRelay  停止媒体转发
    主播A ->> NERtcSDK: removeLiveStreamTask  移除旁路推流任务
    主播B ->> NERtcSDK: stopChannelMediaRelay
    主播B ->> NERtcSDK: removeLiveStreamTask  移除旁路推流任务

实现方法

  1. 已实现单人直播

开始 PK

  1. 开始 mediaRelay。

    主播 A 调用 startChannelMediaRelay 方法开启媒体转发功能,将主播 A 的视频流推送到主播 B 房间。

  2. 开启旁路推流任务。

    主播 A 调用 addLiveStreamTask 方法添加旁路推流任务,将主播 A 和 主播 B 房间的音视频流推送到 CDN 上进行合流。

  3. 等待旁路推流结果。

    通过 onLiveStreamState 回调监听旁路推流状态,如果状态为 STATE_PUSHING, 表示旁路推流成功。

    如果旁路推流失败,则根据实际情况进行失败回退,例如调用 stopChannelMediaRelay 方法停止媒体转发功能。

  4. 停止单人直播推流。

    主播 A 调用 stopPushStreaming 方法停止单人直播推流。

  5. 等待主播 B 加入房间后更新旁路推流任务。

    主播 A 调用 updateLiveStreamTask 方法更新旁路推流任务,保证主播房间和挑战者房间的音视频流能够同步播放。

  6. 确认 mediaRelay 是否成功。

    通过 onMediaRelayStatesChangeonMediaRelayReceiveEvent 回调监听媒体转发状态,确认媒体转发是否成功。

    如果媒体转发失败,则根据实际情况进行失败回退,例如调用 stopChannelMediaRelayremoveLiveStreamTask 方法结束 PK。

结束PK

  1. 开始单人直播推流。

    主播 A 调用 startPushStreaming 方法开始单人直播推流。

  2. 等待单人直播推流结果。

    主播 A 通过 onStartPushStreaming 回调监听单人直播推流状态,如果推流成功,则执行下一步操作。

  3. 停止mediaRelay。

    主播 A 和 主播 B 分别调用 stopChannelMediaRelay 方法停止媒体转发功能。

  4. 移除旁路推流任务。

    主播 A 和 主播 B 分别调用 removeLiveStreamTask 方法移除旁路推流任务。

示例代码

public void enterPK(String channelName, String token, long uid) {
    //step1 开始mediaRelay(startMediaRelay)
    NERtcMediaRelayParam mediaRelayParam = new NERtcMediaRelayParam();
    NERtcMediaRelayParam.ChannelMediaRelayConfiguration config = mediaRelayParam.new ChannelMediaRelayConfiguration();
    NERtcMediaRelayParam.ChannelMediaRelayInfo relayInfo = mediaRelayParam.new ChannelMediaRelayInfo(token, channelName, 0);
    config.setDestChannelInfo(channelName, relayInfo);
    NERtcEx.getInstance().startChannelMediaRelay(config);

    //step2 开启旁路推流任务(addLiveStream)
    NERtcEx.getInstance().addLiveStreamTask(taskInfo, (taskId, errCode) -> {});

    //step3 等待旁路推流结果(onLiveStreamState), 如果state为STATE_PUSHING表示添加旁路任务成功,否则停止cdn推流(stopPushStreaming)
    //step4 等待pk对方加入房间后更新旁路推流任务 updateLiveStreamTask
    //step5 确认mediaRelay是否成功,如果失败根据实际情况做相应处理
    //等待mediaRelay任务状态回调onMediaRelayStatesChange和onMediaRelayReceiveEvent确认mediaRelay是否成功
}

public void leavePK() {
    //step1 开始cdn推流(startPushStreaming)
    NERtcEx.getInstance().startPushStreaming(pushStreamingConfig);

    //step2 等待cdn推流结果回调(onStartPushStreaming)
    //成功后停止mediaRelay(stopMediaRelay)和移除旁路推流任务(removeLiveStreamTask)
    //NERtcEx.getInstance().stopChannelMediaRelay();
    //NERtcEx.getInstance().removeLiveStreamTask(taskId, (DeleteLiveTaskCallback) (taskId, errCode) -> {});
}

实现直播过程中连麦

下文介绍在单人直播的过程中,观众连麦场景下,NERTC 的实现流程。

API 时序图

sequenceDiagram
    actor 主播A
    participant NERtcSDK
    participant 业务服务器
    actor 连麦者
    
    Note over 主播A, 连麦者: 开始连麦

    连麦者->>业务服务器: 申请上麦
    Note right of 主播A: 请自行实现相关业务逻辑
    业务服务器->>主播A: 申请上麦

    主播A-->>业务服务器: 同意上麦
    业务服务器-->>连麦者: 主播同意上麦

    连麦者 ->> NERtcSDK: joinChannel  

    rect rgb(191, 223, 255)
    主播A ->> NERtcSDK: addLiveStreamTask  开始旁路推流
    NERtcSDK -->> 主播A: onLiveStreamState
   
    主播A ->> NERtcSDK: stopPushStreaming   旁路推流成功后,停止推流

    Note over 主播A, 连麦者: 连麦状态下新增连麦
    主播A ->> NERtcSDK: updateLiveStreamTask  更新旁路推流

    Note over 主播A, 连麦者: 结束连麦
    连麦者 ->> 业务服务器: 下麦
    业务服务器 ->> 主播A: 下麦

 
    主播A ->> NERtcSDK: startPushStreaming  重新开始推流
    NERtcSDK -->> 主播A: onStartPushStreaming

    主播A ->> NERtcSDK: removeLiveStreamTask 移除推流任务
    end
    连麦者 ->> NERtcSDK: leaveChannel

实现方法

  1. 已实现单人直播

开始连麦

  1. 开启旁路推流任务。

    主播 A 调用 addLiveStreamTask 方法添加旁路推流任务,将主播房间和连麦者的音视频流推送到 CDN 上进行合流。

  2. 等待旁路推流结果。

    通过 onLiveStreamState 回调监听旁路推流状态,如果状态为 STATE_PUSHING, 表示旁路推流成功。如果旁路推流失败,则调用 removeLiveStreamTask 方法移除推流任务。

  3. 旁路推流成功后,停止单人直播推流。

    主播 A 调用 stopPushStreaming 方法停止单人直播推流。

结束连麦

  1. 开始单人直播推流。

    主播 A 调用 startPushStreaming 方法开始单人直播推流。

  2. 等待单人直播推流结果。

    主播 A 通过 onStartPushStreaming 回调监听单人直播推流状态,如果推流成功,则执行下一步操作。

  3. 移除旁路推流任务。

    主播 A 和 主播 B 分别调用 removeLiveStreamTask 方法移除旁路推流任务。

示例代码

public void enterSeat() {
    //step1 开启旁路推流任务(addLiveStream)
    NERtcEx.getInstance().addLiveStreamTask(taskInfo, (taskId, errCode) -> {});

    //step2 等待旁路推流结果(onLiveStreamState), 如果state为STATE_PUSHING表示添加旁路任务成功,否则停止cdn推流(stopPushStreaming)
}

public void leaveSeat() {
    //step1 开始cdn推流(startPushStreaming)
    NERtcEx.getInstance().startPushStreaming(pushStreamingConfig);

    //step2 等待cdn推流结果回调(onStartPushStreaming)
    //成功后移除旁路推流任务(removeLiveStreamTask)
    //NERtcEx.getInstance().removeLiveStreamTask(taskId, (DeleteLiveTaskCallback) (taskId, errCode) -> {});
}

常用的回调

请在初始化时注册推流相关的回调,以下列举推流需要关注的主要回调:

  • 单人直播场景需要关注的主要回调如下:
    //开始推流startPushStreaming结果回调
    void onStartPushStreaming(int result, long channelId);
    
    //停止推流stopPushStreaming结果回调
    void onStopPushStreaming(int result);
    
    //推流过程中断开,变为重连状态回调
    void onPushStreamingReconnecting(int reason);
    
    //推流过程中重连成功回调
    void onPushStreamingReconnectedSuccess();
    
    //推流过程重连失败,最终断开回调
    void onDisconnect(int reason);
    
    
  • PK 场景需要关注的主要回调如下:
    //开始推流startPushStreaming结果回调
    void onStartPushStreaming(int result, long channelId);
    
    //停止推流stopPushStreaming结果回调
    void onStopPushStreaming(int result);
    
    //推流过程中断开,变为重连状态回调
    void onPushStreamingReconnecting(int reason);
    
    //推流过程中重连成功回调
    void onPushStreamingReconnectedSuccess();
    
    //推流状态已改变回调
    void onLiveStreamState(String taskId, String pushUrl, int liveState);
    
    //跨房间媒体流转发状态发生改变回调
    void onMediaRelayStatesChange(int state, String channelName);
    
    //媒体流相关转发事件回调
    void onMediaRelayReceiveEvent(int event, int code, String channelName);
    
    
  • 连麦场景需要关注的主要回调如下:
    //开始推流startPushStreaming结果回调
    void onStartPushStreaming(int result, long channelId);
    
    //停止推流stopPushStreaming结果回调
    void onStopPushStreaming(int result);
    
    //推流过程中断开,变为重连状态回调
    void onPushStreamingReconnecting(int reason);
    
    //推流过程中重连成功回调
    void onPushStreamingReconnectedSuccess();
    
    //推流状态已改变回调
    void onLiveStreamState(String taskId, String pushUrl, int liveState);
    
    

播放器拉流

请使用网易云信播放器进行拉流播放,播放器的实现方法请参见实现播放功能

为了避免在播放音视频媒体流时,因网络连接不稳定或者其他问题导致播放失败,请设置自动重试参数,以提高播放成功率和用户体验。

此文档是否对你有帮助?
有帮助
去反馈
  • 功能描述
  • 应用场景
  • 前提条件
  • 完整示例代码
  • 功能原理
  • 注意事项
  • 集成 RTC SDK
  • 导入类
  • 实现单人直播
  • API 时序图
  • 实现方法
  • 示例代码
  • 实现 PK 直播
  • API 时序图
  • 实现方法
  • 示例代码
  • 实现直播过程中连麦
  • API 时序图
  • 实现方法
  • 示例代码
  • 常用的回调
  • 播放器拉流