实现1对1呼叫(不含UI集成-V2)
更新时间: 2024/11/26 16:00:37
本文介绍如何通过集成呼叫组件(NERTCCallkit)基础包(不含 UI),实现 1 对 1 呼叫相关业务逻辑。根据业务需求,您需要自行实现相关 UI 界面。本文介绍呼叫组件 V2 版本 的集成和实现方法。
- 推荐使用含 UI 集成呼叫组件 V2 版本,请参见实现1对1呼叫(含UI集成-V2)。
- 如果您需要不含 UI 集成呼叫组件 V1 版本,请参见实现1对1呼叫(不含UI集成-V1)。
注意事项
针对呼叫组件中的回调信息,开发者要做好相应回调数据的上报及存储,以便于后期上线之后排查问题。
基本概念
- accid:accid 是 IM 账号,用于登录 IM。注册云信 IM 账号时, IM 服务器会返回对应的 accid 和 Token,应用客户端需要负责保存 accid 和 IM token 的映射关系。
- Token:呼叫组件中涉及的 Token 包括 IM Token 和 RTC Token。两者不是同一个 Token,请根据实际使用场景填入对应的 Token。
- IM Token:用于登录 IM 时进行 IM 账号鉴权。应用服务器调用 IM 服务器的
create.action
注册云信 IM 账号时,获取的 IM Token。 - RTC Token:用于加入 RTC 房间时进行 RTC 账号鉴权。应用服务器调用 NERTC 服务器的
getToken
,获取的 RTC Token。
- IM Token:用于登录 IM 时进行 IM 账号鉴权。应用服务器调用 IM 服务器的
开发环境
环境要求 | 说明 |
---|---|
Android Studio 版本 | Android Studio 5.0 及以上版本 |
Android API 版本 | Level 为 21 及以上版本。 |
Android SDK 版本 | Android SDK 31、Android SDK Platform-Tools 31.x.x 及以上版本。 |
Gradle 及所需的依赖库 | 在 Gradle Services 页面下载对应版本的 Gradle 及所需的依赖库。
|
kotlin | 1.6.21 及以上版本 |
CPU架构 | ARM 64、ARMV7 |
IDE | Android Studio |
其他 | 依赖 Androidx,不支持 support 库。 Android 系统 5.0 及以上版本的真机。 |
准备工作
集成呼叫组件
呼叫组件(NERTCCallkit)基于网易云信 NIM SDK 和 NERTC SDK 实现通话呼叫,呼叫组件中已集成 NERTC SDK,您只需集成指定版本的 NIM SDK 即可。
步骤 1: 集成 NIM SDK
单击查看集成 NIM SDK 的操作步骤。如果您的项目中已经集成了 NIM SDK,请忽略该步骤。
-
若您需要创建新项目,在 Android Studio 里,在顶部菜单依次选择 File > New > New Project 新建工程,再依次选择 Phone and Tablet > Empty Activity,单击 Next。
创建 Android 项目成功后,Android Studio 会自动开始同步 gradle, 您需要等同步成功后再进行下一步操作。
-
在项目根目录下的 “build.gradle” 文件中,配置
repositories
(使用 maven)。示例代码如下:groovy
allprojects { repositories { mavenCentral() } }
-
在 “app” 目录下的 “build.gradle” 文件中,配置支持的 SO 库架构。示例代码如下:
groovy
android { defaultConfig { ndk { //设置支持的SO库架构 abiFilters "armeabi-v7a", "x86","arm64-v8a","x86_64" } } }
-
根据开发者项目的需求,添加对应的依赖。
groovy
dependencies { implementation fileTree(dir: 'libs', include: '*.jar') // 添加依赖。 // 基础功能 (必需) implementation "com.netease.nimlib:basesdk:${LATEST_VERSION}" }
-
添加权限。
根据实际应用需求,在
AndroidManifest.xml
设置权限(请将com.netease.nim.demo
替换为自己的包名)。<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.netease.nim.demo"> <!-- 权限声明 --> <!-- 访问网络状态--> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 音视频呼叫--> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <application ...> <!-- APP Key, 可以在这里设置,也可以在 SDKOptions 中提供。 如果 SDKOptions 中提供了,则取 SDKOptions 中的值。 --> <meta-data android:name="com.netease.nim.appKey" android:value="key_of_your_app" /> </application> </manifest>
SDK 版本限制:
-
呼叫组件与 NIM SDK、NERTC SDK 之间存在映射关系,使用呼叫组件时,必须使用指定版本的 NIM SDK 和 NERTC SDK。当前最新版本 V2.1.0 适配 NIM SDK V9.12.0 和 NERTC SDK V5.4.0,其他版本的适配关系请参考更新日志。
-
如果您已经集成了 NIM SDK 和 NERTC SDK,或因业务需求等原因无法使用指定版本 SDK,请联系网易云信技术支持确认是否能替换 SDK 版本,并参考 Gradle 引入呼叫组件中的步骤 3 去除呼叫组件依赖的版本。
步骤 2:初始化 NIM SDK
在 Application
的 onCreate
中,调用 init
方法 初始化 NIM SDK。
示例代码如下:
public class NimApplication extends Application {
public void onCreate() {
NIMClient.init(this, loginInfo(), options());
// 如果提供用户信息,将同时进行自动登录。如果当前还没有登录用户,请传入null。
private LoginInfo loginInfo() {
return null;
}
// 设置初始化配置参数,如果返回值为 null,则全部使用默认参数。
private SDKOptions options() {
SDKOptions options = new SDKOptions();
return options;
}// 可在 SDKOptions 中配置 App Key
}
}
以上提供了一个简化的初始化示例,更多初始化信息请参见初始化 SDK。
步骤 3:实现登录 IM
调用login
方法登录 IM。
本文以实现静态 Token 登录为例,动态 Token 登录以及自动登录的实现方法请参见登录 IM。
示例代码如下:
public class LoginActivity extends Activity {
public void doLogin() {
LoginInfo info = new LoginInfo(); //传入accid和token
RequestCallback<LoginInfo> callback =
new RequestCallback<LoginInfo>() {
@Override
public void onSuccess(LoginInfo param) {
LogUtil.i(TAG, "login success");
// your code
}
@Override
public void onFailed(int code) {
if (code == 302) {
LogUtil.i(TAG, "账号密码错误");
// your code
} else {
// your code
}
}
@Override
public void onException(Throwable exception) {
// your code
}
};
NIMClient.getService(AuthService.class).login(info).setCallback(callback);
}
}
步骤 4: Gradle 引入呼叫组件
-
在工程根部目录的
build.gradle
文件中添加如下代码。allprojects { repositories { //... mavenCentral() //... } }
-
在主工程
build.gradle
文件中添加如下代码,引入呼叫组件。// 若出现 More than one file was found with OS independent path 'lib/arm64-v8a/libc++_shared.so'. // 可以在主 module 的 build.gradle 文件中 android 闭包内追加如下 packageOptions 配置 android{ //...... packagingOptions { pickFirst 'lib/arm64-v8a/libc++_shared.so' pickFirst 'lib/armeabi-v7a/libc++_shared.so' } } // 引入呼叫组件安装包,导入以下其中一个 dependencies { implementation 'com.netease.yunxin.kit.call:call:2.1.0' // 基础组件包,不含UI 集成时请导入这个包 }
-
(可选)去除呼叫组件依赖的 SDK。
如果因业务需求或其他原因无法使用指定版本 SDK,您可以参考如下步骤去除呼叫组件依赖的 IM 和 RTC 的 SDK。
implementation('com.netease.yunxin.kit.call:call:2.1.0') { exclude group: 'com.netease.nimlib'// 去除组件依赖的 IM sdk exclude group: 'com.netease.yunxin', module: 'nertc-base' // 去除组件依赖的 NERTC sdk }
-
配置防代码混淆。
代码混淆是指使用简短无意义的名称重命名类、方法、属性等,增加逆向工程的难度,保障 Android 程序源码的安全性。为了避免因重命名类,导致调用呼叫组件异常,您需要配置防代码混淆。
请在
proguard-rules.pro
配置文件中加入以下代码防止混淆:# NIM SDK的类,如果集成IM时已经添加,请忽略 -dontwarn com.netease.nim.** -keep class com.netease.nim.** {*;} -dontwarn com.netease.nimlib.** -keep class com.netease.nimlib.** {*;} -dontwarn com.netease.share.** -keep class com.netease.share.** {*;} -dontwarn com.netease.mobsec.** -keep class com.netease.mobsec.** {*;} # NERTC SDK的类 -keep class com.netease.lava.** {*;} -keep class com.netease.yunxin.** {*;} # 呼叫组件的类 -dontwarn com.netease.yunxin.kit.** -keep class com.netease.yunxin.kit.** {*;} -keep public class * extends com.netease.yunxin.kit.corekit.XKitInitOptions -keep class * implements com.netease.yunxin.kit.corekit.XKitService {*;}
步骤 5: 初始化呼叫组件
IM 登录成功之后,需要调用 setup
接口进行呼叫组件的初始化。
App 用户在本端完成初始化后才可以正常接收其他人的的呼叫,或主动发起呼叫。若未完成初始化,组件可能会提示应用进行初始化,或被叫方 App 在被呼叫时无提示。若 App 重复调用初始化接口,受内部依赖的 RTC SDK 以及 IM SDK 限制,会出现崩溃,需要重新初始化需要先完成组件的销毁。
呼叫组件初始化相关代码内容可以放在工程的 MainActivity
中执行,尽量避免在 MainActivity#onDestroy()
方法中做组件的释放。建议在 App 用户登出时释放,登入时进行初始化。
-
初始化呼叫组件相关步骤需要在 IM 登录成功之后进行。
-
核心功能参数说明请参见初始化参数配置。
NESetupConfig
参数说明如下表所示。
参数 | 类型 | 是否必选 | 描述 |
---|---|---|---|
appKey | String | 必选 | appKey,在云信控制后台获取 |
currentUserAccId | String | 必选 | 设置当前用户登录 IM SDK 的 accId,字符串类型 |
currentUserRtcUid | Long | 可选 | 设置对应 RTC SDK uid 长整形,默认为 0L 时组件会自动生成 |
rtcConfig | NERtcOption | 可选 | NERTC SDK 初始化配置 |
enableAutoJoinSignalChannel | Boolean | 可选 | 是否允许被叫用户收到呼叫邀请后自动加入 IM 信令通道,默认 false 注意,此功能和多端登录功能互斥 |
enableJoinRtcWhenCall | Boolean | 可选 | 主叫呼叫时是否直接加入rtc房间,默认 false |
initRtcMode | Integer | 可选 | RTC SDK 初始化模式,默认为GLOBAL
|
rtcCallExtension | CallExtension | 可选 | 主要用于设置分辨率,或者修改组件使用rtc的行为 |
具体初始化代码如下,可通过 NESetupConfig.Builder
实现参数设置。
java// NERTC SDK 初始化配置
NERtcOption rtcOption = new NERtcOption();
NESetupConfig config = new NESetupConfig.Builder(appKey, "currentUserAccId")
.rtcOption(rtcOption)
.build();
// 在 IM sdk 初始化并完成登录后,调用呼叫组件初始化
NECallEngine.sharedInstance().setup(this,config);
实现 1 对 1 呼叫(点对点呼叫)
API 时序图
sequenceDiagram
autonumber
participant 应用层
participant NERTCCallkit
应用层->>NERTCCallkit: addCallDelegate 添加监听
应用层->>NERTCCallkit: call 发起呼叫
NERTCCallkit-->>应用层: onReceiveInvited 收到呼叫邀请
应用层->>NERTCCallkit: accept 接听呼叫
NERTCCallkit-->>应用层: onCallConnected 通话建立
应用层->>NERTCCallkit: hangup 挂断通话、取消通话、拒接来电
NERTCCallkit-->>应用层: onCallEnd 通话被取消、拒绝或通话中挂断的回调
实现方法
- 添加呼叫监听。
在初始化呼叫组件后,调用 addCallDelegate
方法,添加回调监听。
java// 监听呼叫邀请,此处可在全局处设置,避免被意外释放导致来电丢失
NECallEngine.sharedInstance().addCallDelegate(new NECallEngineDelegateAbs() {
@Override
public void onReceiveInvited(NEInviteInfo info) {
// 收到来电后可进行展示 notification,或者将 info 传入被叫页面并调起被叫页面;
}
});
- 主叫发起呼叫。
进入自己的呼叫页面,调用 addCallDelegate
方法添加通话中监听,页面销毁时调用 removeCallDelegate
避免内存泄漏,并调用 call
接口发起呼叫。
NECallParam
相关参数说明如下表所示。
参数 | 类型 | 是否必选 | 示例 | 描述 |
---|---|---|---|---|
accId | String | 必选 | "12345" | 被叫用户的 IM accId。注册云信 IM 账号时, IM 服务器会返回对应的 accid 和 Token。 |
callType | ChannelType | 必选 | NECallType.VIDEO | 呼叫类型,包括:
|
extraInfo | String | 可选 | - | 扩展信息,透传到到被叫 onReceiveInvited |
globalExtraCopy | String | 可选 | - | 自定义的呼叫全局抄送信息,用户服务端接收抄送时设置自己的业务标识 |
rtcChannelName | String | 可选 | - | 自定义channelName,不传会默认生成 |
pushConfig | NECallPushConfig | 可选 | - | 用户推送自定义内容,为空时使用内部默认推送配置 |
NECallPushConfig
相关参数说明如下表所示。
参数 | 类型 | 是否必选 | 描述 |
---|---|---|---|
needPush | String | 可选 | 是否需要推送,默认 true |
pushTitle | ChannelType | 必选 | 推送标题 |
pushContent | String | 必选 | 推送内容 |
pushPayload | String | 可选 | 推送 payload 内容,自行添加键值对 |
示例代码如下:
java// 构建视频呼叫参数
NECallParam param = new NECallParam.Builder("calledUserAccId")
.callType(NECallType.VIDEO)
.build();
NEResultObserver<CommonResult<NECallInfo>> observer = new NEResultObserver<CommonResult<NECallInfo>>() {
@Override
public void onResult(CommonResult<NECallInfo> result) {
// 呼叫成功
if (result.isSuccessful()) {
// 返回通话详情
NECallInfo callInfo = result.data;
} else {
// 呼叫失败,错误码
int code = result.code;
// 呼叫失败,错误信息
String message = result.msg;
}
}
};
// 发起呼叫,可在此时做呼叫提示音
NECallEngine.sharedInstance().call(param, observer);
- 被叫收到呼叫邀请。
当收到呼叫邀请时,被叫会收到 onReceiveInvited
回调,并在回调中告知主叫的相关信息,包括主叫的accid、呼叫类型、信令通道的 ID、自定义信息。
详细的回调参数 NEInviteInfo
如下:
参数 | 类型 | 描述 |
---|---|---|
callerAccId | String | 主叫用户的 IM accId。注册云信 IM 账号时, IM 服务器会返回对应的 accid 和 Token。 |
callType | String | 呼叫类型,包括:
|
extraInfo | Integer | 扩展信息,透传到到被叫 onReceiveInvited |
channelId | String | IM 信令通道 ID |
被叫用户在收到邀请信息时可根据呼叫类型(VIDEO/AUDIO)来调用不同的方法直接启动被叫页面的 Activity。
若被叫方系统在 Android Q 及以上时,系统限制不允许后台弹出页面,此时会弹出对应的 Notification,被叫方可通过点击 Notification 跳转至对应的被叫页面。若用户通过 launcher 或其他方式唤起 app 时,通话仍有效则同样会展示被叫页面,进入被叫页面后同样可以调用 addCallDelegate
方法用于监听通话中相关回调,页面销毁时调用 removeCallDelegate
避免内存泄漏。
- 被叫接听。
被叫调用 NECallEngine#accept 接口,接听当前的呼叫邀请,此时会触发onUserEnter
回调,对方加入 rtc 成功,认为此时通话建立成功。
当被叫用户点击呼叫页面的接听按钮时,若此时通话仍在呼叫中,则可接通此次通话并加入对应的音视频房间内,和主叫方进行音视频通话。
javaNEResultObserver<CommonResult<NECallInfo>> observer = new NEResultObserver<CommonResult<NECallInfo>>() {
@Override
public void onResult(CommonResult<NECallInfo> result) {
// 接听成功
if (result.isSuccessful()) {
// 返回通话详情
NECallInfo callInfo = result.data;
} else {
// 接听失败,可做被叫页面销毁等动作,错误码,错误信息等
int code = result.code;
String message = result.msg;
}
}
};
// 执行通话接听动作
NECallEngine.sharedInstance().accept(observer);
- 通话挂断。
主叫取消/被叫拒绝/通话中挂断均可调用hangup
接口实现通话终止,此时另外一端用户会收到 onCallEnd
回调,收到详细的终止信息。
NECallEndInfo
详细参数如下表。
参数 | 类型 | 描述 |
---|---|---|
reasonCode | Integer | 通话终止的错误码,具体请参见呼叫结束错误码 |
message | String | 通话终止原因 |
extraString | String | 挂断时传入的扩展信息 |
挂断参数 NEHangupParam
,详细参数如下表。
参数 | 类型 | 是否可选 | 描述 |
---|---|---|---|
channelId | String | 可选 | 主叫通过呼叫回调结果获取 channelId 的值,被叫通过 onInvited 回调获取 channelId 的值。 若填入 null 则直接挂断当前通话,若填入特定值,则内部校验当前通话和传入的 channelId 是否为同一通话,若不同则挂断失败,否则挂断成功 |
extraString | String | 可选 | 挂断时传入的扩展信息,另外一端用户在 onCallEnd 回调的NECallEndInfo#extraString 中可获取到 |
java// 构建挂断参数
NEHangupParam param = new NEHangupParam("channelId","extraString");
NEResultObserver<CommonResult<Void>> observer = new NEResultObserver<CommonResult<Void>>() {
@Override
public void onResult(CommonResult<Void> result) {
if (result.isSuccessful()) {
// 挂断成功
} else {
// 挂断失败
}
}
};
// 执行挂断动作
NECallEngine.sharedInstance().hangup(param, observer);
- 忙线。
当被叫用户不在 STATE_IDLE
状态下接收到其他主叫用户的呼叫邀请时,被叫方内部会自动执行 NECallEngine.sharedInstance().hangup
动作,主叫方接收到对方的 reject
信令消息后会回调 NECallEngineDelegate.onCallEnd
,其中错误码为 NEHangupReasonCode.BUSY
,用于 UI 展示,主叫方本地发送忙线话单消息。
进阶功能
多端登录
云信 IM SDK 支持多端或单端登录,若此时正在通过呼叫组件进行音视频通话时,其他端登录相同账号:
- IM 关闭多端登录:此时由于关闭多端登录,导致信令通道同时被踢出,无法通过信令完成消息通知。此时会直接做离开音视频房间操作,对端用户感知到本端离开动作后,会做挂断挂断操作。
- IM 开启多端登录:其他端的用户登录不会影响当前通过组件发起的音视频通话。但若多端同时在线时,收到呼叫邀请时会同时展示被邀请页面,如果其中一端接听或拒绝,则其他端会收到相应错误回调。错误码为
2001
或2002
。
呼叫/被叫超时
主叫方发起呼叫被叫方时,若主叫方不取消,被叫方既不接听也不挂断,此时会触发超时限制。触发超时限制后主叫方和被叫方都会触发 onCallEnd
,其中 NECallEndInfo
中错误码为NEHangupReasonCode#TIME_OUT
回调,同时主叫方会做取消动作,被叫方会做挂断操作。用户可通过如下接口实现更改超时时间。发生呼叫或收到呼叫邀请前对本次通话生效,否则对下次通话生效。
javaNECallEngine.sharedInstance().setTimeout(long time);// 单位为毫秒
视频通话设置本地预览与订阅远端画面
用户发起呼叫后可以调用如下接口设置本地预览画面:
javaNERtcVideoView videoView;// 用于展示本端画面的布局UI
NECallEngine.sharedInstance().setupLocalView(videoView);
调用如下接口设置远端画面,此方法可在 onCallConnected
回调中调用。
javaNERtcVideoView videoView;// 用于展示远端画面的布局UI
NECallEngine.sharedInstance().setupRemoteView(videoView);
设置通话分辨率及相关参数
通过在初始化设置中 rtcCallExtension
的参数
javaNESetupConfig config = new NESetupConfig.Builder(appKey, "currentUserAccId")
.rtcCallExtension(new NERtcCallExtension(){
@Override
protected void configAudioProfileBeforeJoin() {
// 音频设置standard + speech
NERtcEx.getInstance().setAudioProfile(NERtcConstants.AudioProfile.STANDARD,
NERtcConstants.AudioScenario.SPEECH);
}
@Override
protected void configVideoConfigBeforeJoin(){
// 设置一个默认的videoConfig
NERtcVideoConfig videoConfig = new NERtcVideoConfig();
// 帧率:15
videoConfig.frameRate = NERtcEncodeConfig.NERtcVideoFrameRate.FRAME_RATE_FPS_15;
// 用户修改分辨率不要使用 profile,应该使用width/height修改,两种方式都存在时,profile 方式失效。
//分辨率:360*640(注意此处需要设置宽大于高不用考虑具体角度旋转)
videoConfig.width = 640;
videoConfig.height = 360;
NERtcEx.getInstance().setLocalVideoConfig(videoConfig);
}
@Override
protected void configChannelProfileBeforeJoin(){
// 设置channel profile
NERtcEx.getInstance().setChannelProfile(NERtcConstants.RTCChannelProfile.COMMUNICATION);
}
})
.build();
// 在 IM sdk 初始化并完成登录后,调用呼叫组件初始化
NECallEngine.sharedInstance().setup(this,config);
呼叫结束错误码
NEHangupReasonCode
列举通话终止错误码。
错误信息 | 错误码 | 说明 |
---|---|---|
NORMAL |
0 | 通话挂断 |
TOKEN_ERROR |
1 | RTC Token 错误 |
TIME_OUT |
2 | 通话超时 |
BUSY |
3 | 被叫用户占线 |
RTC_INIT_ERROR |
4 | RTC 初始化失败 |
JOIN_RTC_ERROR |
5 | 加入 RTC channel 失败 |
CANCEL_ERROR_PARAM |
6 | 取消参数错误 |
CALL_FAILED |
7 | 呼叫失败 |
KICKED |
8 | 用户被踢出 |
UID_EMPTY |
9 | accId 对应的 RTC uid 为空 |
SELF_RTC_DISCONNECTED |
10 | 呼叫的用户为本端 RTC 用户 |
CALLER_CANCEL |
11 | 主动取消呼叫 |
CALLEE_CANCELED |
12 | 呼叫被取消 |
CALLEE_REJECT |
13 | 主动拒绝呼叫 |
CALLER_REJECTED |
14 | 呼叫被拒绝 |
HANG_UP |
15 | 通话中主动挂断通话 |
BE_HUNG_UP |
16 | 通话中被挂断 |
OTHER_REJECTED |
17 | 多端登录下被其他端拒绝 |
OTHER_ACCEPTED |
18 | 多端登录下被其他端接听 |
USER_RTC_DISCONNECTED |
19 | 本端用户 RTC 房间长链接断开 |
USER_RTC_LEAVE |
20 | 对端用户离开 RTC 房间 |
ACCEPT_FAIL |
21 | 接听失败 |