实现音视频通话
更新时间: 2024/09/18 16:26:13
网易云信音视频通话产品的基本功能包括高质量的实时音视频通话。当您成功初始化 SDK 之后,您可以简单体验本产品的基本业务流程。本文档为您展示音视频通话提供的基本业务流程。
前提条件
请确认您已完成以下操作:
- 创建应用并获取 App Key。
- 开通音视频通话 2.0 服务。
- 集成 SDK(Android),其中需要添加必要的设备权限。
示例代码
网易云信为您提供完整的创建界面及实现基础音视频通话的示例代码作为参考,您可以直接拷贝用于运行测试。
xml 界面的完整示例代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_channel_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_margin="12dp"
android:text="频道名称:xxx"
android:textSize="16sp" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/tv_channel_name">
<com.netease.lava.nertc.sdk.video.NERtcVideoView
android:id="@+id/render_remote_user"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/tv_remote_uid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_margin="12dp"
android:text="对端uid:xxx"
android:textSize="16sp" />
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_channel_name"
android:layout_alignParentEnd="true"
android:layout_margin="12dp">
<com.netease.lava.nertc.sdk.video.NERtcVideoView
android:id="@+id/render_local_user"
android:layout_width="135dp"
android:layout_height="240dp" />
<TextView
android:id="@+id/tv_local_uid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_margin="12dp"
android:text="本地uid:xxx"
android:textSize="16sp" />
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:orientation="horizontal">
<Button
android:id="@+id/btn_enable_video"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:text="关闭视频"
android:textColor="@color/black" />
<Button
android:id="@+id/btn_enable_audio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:text="关闭语音"
android:textColor="@color/black" />
<Button
android:id="@+id/btn_leave_channel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:text="结束通话"
android:textColor="@color/black" />
</LinearLayout>
</RelativeLayout>
实现音视频通话的完整示例代码
NERtcVideoView localRenderView = findViewById(R.id.render_view_local);
//小画布置于大画布上面
localRenderView.setZOrderMediaOverlay(true);
NERtcVideoView remoteRenderView = findViewById(R.id.render_view_remote);
NERtcCallback neRtcCallback = new NERtcCallbackEx() {
@Override
public void onJoinChannel(int result, long channelId, long elapsed, long uid) {
if (result == NERtcConstants.ErrorCode.OK) {
// 加入房间成功
} else {
// 加入房间失败 ,退出页面
finish();
}
}
@Override
public void onLeaveChannel(int result) {
}
@Override
public void onUserJoined(long uid) {
}
@Override
public void onUserLeave (long uid,int reason) {
}
@Override
public void onUserAudioStart(long uid) {
}
@Override
public void onUserAudioStop(long uid) {
}
@Override
public void onUserVideoStart(long uid,int maxProfile) {
//对方开启视频,按需设置画布及订阅视频
NERtcEx.getInstance().setupRemoteVideoCanvas(remoteRenderView,uid);
NERtcEx.getInstance().subscribeRemoteVideoStream(uid, NERtcRemoteVideoStreamType.kNERtcRemoteVideoStreamTypeHigh,true);
}
@Override
public void onUserVideoStop(long uid) {
//释放之前绑定的画布
NERtcEx.getInstance().setupRemoteVideoCanvas(null,uid);
}
@Override
public void onDisconnect(int reason) {
// 与服务器断连 ,退出页面
finish();
}
//*******其他一些回调******
};
//初始化SDK
try {
NERtc.getInstance().init(getApplicationContext(), "your_app_key", neRtcCallback, null);
} catch (Exception e) {
e.printStackTrace();
showToast("SDK初始化失败");
finish();
return;
}
//设置本地视频参数
NERtcVideoConfig videoConfig = new NERtcVideoConfig();
videoConfig.width = 1080;
videoConfig.height = 720;
videoConfig.frameRate = NERtcEncodeConfig.NERtcVideoFrameRate.FRAME_RATE_FPS_30;
NERtcEx.getInstance().setLocalVideoConfig(videoConfig);
//加入房间前提前设置好视频开启状态
NERtcEx.getInstance().enableLocalVideo(true,kNERtcVideoStreamTypeMain);
//设置本地画布
NERtcEx.getInstance().setupLocalVideoCanvas(localRenderView);
//加入房间
long yourUid = 1234567;//同一个房间不允许相同uid
NERtcEx.getInstance().joinChannel("your_token", "your_channel_name", yourUid,null);
//结束通话
NERtcEx.getInstance().leaveChannel();
//释放SDK
NERtcEx.getInstance().release();
实现流程
实现音频通话的 API 调用时序如下图所示。
sequenceDiagram
autonumber
participant App
participant NERtcSDK
participant 云信服务端
App->>NERtcSDK: initialize 初始化 NERtcEngine
App->>NERtcSDK: joinChannel 加入房间
NERtcSDK->>云信服务端: 请求加入房间
NERtcSDK-->>App: onJoinChannel
App->>NERtcSDK: leaveChannel 离开房间
NERtcSDK->>云信服务端: 请求离开房间
App->>NERtcSDK: release 销毁实例
实现视频通话的 API 调用时序如下图所示。
sequenceDiagram
autonumber
participant App
participant NERtcSDK
participant 云信服务端
App->>NERtcSDK: initialize 初始化 NERtcEngine
Note over App, NERtcSDK: 设置本地视图
App->>NERtcSDK: setupLocalVideoCanvas
App->>NERtcSDK: enableLocalVideo
Note over App, NERtcSDK: 加入房间
App->>NERtcSDK: joinChannel
NERtcSDK->>云信服务端: 请求加入房间
NERtcSDK-->>App: onJoinChannel
Note over App, NERtcSDK: 设置远端视图
Note right of NERtcSDK: 远端用户加入房间
NERtcSDK-->>App: onUserJoined 远端用户加入房间的回调
NERtcSDK-->>App: onUserVideoStart 远端用户发布视频流的回调
App->>NERtcSDK: setupRemoteVideoCanvas 设置远端视频画布
App->>NERtcSDK: subscribeRemoteVideoStream 订阅远端视频流
云信服务端-->>App : onFirstVideoFrameDecoded 已接收到远端视频首帧并完成解码的回调
Note over App, NERtcSDK: 离开房间
App->>NERtcSDK: leaveChannel
NERtcSDK->>云信服务端: 请求离开房间
App->>NERtcSDK: release 销毁实例
实现音视频通话
步骤一 (可选)创建音视频通话界面
您可以参考此步骤根据业务场景创建相应的音视频通话界面,若您已实现相应界面,请忽略该步骤。
实现基础的音视频通话,建议您参考 xml 界面的示例代码在界面上添加以下控件。
- 房间 ID
- 用户昵称
- 本端视频窗口
- 远端视频窗口
- 麦克风按钮
- 摄像头按钮
- 结束通话按钮
效果图如下图所示。
步骤二 导入类
在您的工程中对应实现音视频通话的 Activity 文件里添加如下代码先导入以下重要类:
javaimport 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;
步骤三 初始化
默认情况下,请在导入后的 nertc-sdk-4.x.xx.jar
文件中先执行 init
方法完成初始化。
您需要将 App_Key
替换为您的应用对应的 App Key。
示例代码如下:
javaprivate void initializeSDK() {
try {
NERtcEx.getInstance().init(getApplicationContext(),Config.APP_KEY,callback,null);
} catch (Exception e) {
showToast("SDK初始化失败");
finish();
...
return;
}
...
}
为了实现标准音视频通话业务,您还需要在初始化时注册相关必要回调,建议您请在初始化方法中传入原型为 NERtcCallbackEx 的以下回调,并增加相应必要的处理。
//NERtcCallbackEx 重要回调
//本端用户加入房间结果回调
@Override
public void onJoinChannel(int result, long channelId, long elapsed, long uid) {
if (result == NERtcConstants.ErrorCode.OK) {
// 加入房间成功
} else {
// 加入房间失败 ,退出页面
}
}
//本端用户离开房间回调
@Override
public void onLeaveChannel(int result) {
}
//远端用户加入房间
@Override
public void onUserJoined(long uid) {
}
//远端用户离开房间
@Override
public void onUserLeave (long uid,int reason) {
}
//远端用户打开音频
@Override
public void onUserAudioStart(long uid) {
}
//远端用户关闭音频
@Override
public void onUserAudioStop(long uid) {
}
//远端用户打开视频,建议在此按需设置画布及订阅视频
@Override
public void onUserVideoStart(long uid,int maxProfile) {
}
//远端用户关闭视频,可释放之前绑定的画布
@Override
public void onUserVideoStop(long uid) {
}
//与服务器断连,退出页面
@Override
public void onDisconnect(int reason) {
}
步骤四 设置本地视图
初始化成功后,可以设置本地视图,来预览本地图像。您可以根据业务需要实现加入房间之前预览或加入房间后预览。
- 若您想设置画布渲染参数,可以调用
setScalingType
方法设置渲染缩放模式或调用setMirror
方法设置镜像模式。 - 若您想调整摄像头的相关参数,请参考视频设备管理进行设置。
- 在加入房间前,默认预览分辨率为 640*480,您可以通过
setLocalVideoConfig
接口的width
和height
参数调整采集分辨率。
-
实现加入房间前预览。
-
调用
setupLocalVideoCanvas
与startVideoPreview(streamType)
方法,在加入房间前设置本地视图,预览本地图像。示例代码如下:
java
//以开启本地视频主流预览为例 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);
-
若要结束预览,或者准备加入房间时,调用
stopVideoPreview(streamType)
方法停止预览。stopVideoPreview(streamType)
的streamType
参数请与startVideoPreview(streamType)
的保持一致,即同为主流或辅流的开启和停止预览。
-
-
实现加入房间后预览。
调用
setupLocalVideoCanvas
设置本地视图,再调用enableLocalVideo(streamType)
方法进行视频的采集发送与预览。成功加入房间后,即可预览本地图像。示例代码如下:
java
//设置本地预览画布 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);
步骤五 加入房间
加入房间前,请确保已完成初始化相关事项。若您的业务中涉及呼叫邀请等机制,建议通过信令实现,总体实现流程请参见一对一会话操作流程,具体呼叫邀请机制的实现请参见邀请机制。
调用 joinChannel
方法加入房间。
调用 joinChannel
之后,NERTC SDK 会通过 Android 的 AudioManager.setMode()
方法调整音频模式(audio mode),此后请勿修改 SDK 调整过的音频模式,否则会导致音频路由错误等问题。
示例代码如下:
javaNERtcEx.getInstance().joinChannel(token,channelName,uid,channelOptions);
参数说明:
参数 | 说明 |
---|---|
token | 安全认证签名(NERTC Token)。
|
channelName | 房间名称,长度为 1 ~ 64 字节。目前支持以下 89 个字符:a-z, A-Z, 0-9, space, !#$%&()+-:;≤.,>? @[]^_{|}~"。 设置相同房间名称的用户会进入同一个通话房间。 |
uid | 用户的唯一标识 id,为数字串,房间内每个用户的 uid 必须是唯一的。 |
channelOptions | 加入房间时可以设置携带一些特定信息,包括高级权限密钥。默认值为 NULL,具体请参考 NERtcJoinChannelOptions。 |
-
SDK 发起加入房间请求后,服务器会进行响应,您可以通过
NERtcCallback
的onJoinChannel
回调监听加入房间的结果,同时该回调会抛出当前通话房间的 channelId 与加入房间总耗时(毫秒);其中 channelId 即音视频通话的 ID,建议您在业务层保存该数据,以便于后续问题排查。 -
成功加入房间之后,您可以通过监听
onConnectionStateChanged
回调实时监控自己在本房间内的连接状态。
步骤六 设置远端视图并发起订阅
音视频通话过程中,除了要显示本地的视频画面,通常也要显示参与互动的其他连麦者/主播的远端视频画面。
设置远端视图并订阅的完整示例代码
//对方开启视频,按需设置画布及订阅视频
NERtcVideoView remoteRenderView = findViewById(R.id.render_view_remote);
NERtcEx.getInstance().setupRemoteVideoCanvas(remoteRenderView,uid);
NERtcEx.getInstance().subscribeRemoteVideoStream(uid, NERtcRemoteVideoStreamType.kNERtcRemoteVideoStreamTypeHigh,true);
-
监听远端用户进出房间。
当远端用户加入房间时,本端会触发
onUserJoined
回调,并抛出对方的 uid。当本端加入房间后,也会通过此回调抛出通话房间内已有的其他用户。
-
设置远端视频画布。
在监听到远端用户加入房间或发布视频流后,本端可以调用
setupRemoteVideoCanvas
方法设置远端用户视频画布,用于显示其视频画面。示例代码如下:
java
NERtcVideoView remoteRenderView = findViewById(R.id.render_view_remote); NERtcEx.getInstance().setupRemoteVideoCanvas(remoteRenderView,uid);
-
监听远端视频流发布。
当房间中的其他用户发布视频流时,本端会触发
onUserVideoStart
回调。 -
订阅远端视频流。
在监听到远端用户发布视频流后,本端可以调用
subscribeRemoteVideoStream
方法对其发起视频流的订阅,来将对方的视频流渲染到视频画布上。示例代码如下:
java
NERtcEx.getInstance().subscribeRemoteVideoStream(uid, streamType, subscribe);
-
监听远端用户离开房间或关闭视频功能。
-
onUserLeave
:用户离开房间回调。 -
onUserVideoStop
:远端用户关闭视频功能回调。
步骤七 音频流
在 NERTC SDK 中,本地音频的采集发布和远端音频订阅播放是默认启动的,正常情况下无需开发者主动干预。
步骤八 退出通话房间
调用 leaveChannel
方法退出通话房间。
示例代码如下:
javaNERtcEx.getInstance().leaveChannel();
NERtcCallback 提供 onLeaveChannel
回调来监听当前用户退出房间的结果。
步骤九 销毁实例
当确定 App 短期内不再使用音视频通话实例时,可以调用 release
方法释放对应的对象资源。
示例代码如下:
java// 销毁实例
NERtcEx.getInstance().release();