实现1对1呼叫(不含UI集成-V2)

更新时间: 2023/08/08 11:21:53

本文介绍如何通过集成呼叫组件(NERTCCallkit)基础包(不含 UI),实现 1 对 1 呼叫相关业务逻辑。根据业务需求,您需要自行实现相关 UI 界面。本文介绍呼叫组件 V2 版本的集成和实现方法。

注意事项

针对呼叫组件中的回调信息,开发者要做好相应回调数据的上报及存储,以便于后期上线之后排查问题。

基本概念

  • 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。

开发环境

环境要求 说明
Android Studio 版本 Android Studio 5.0 及以上版本 Android Studio 版本编号系统的变更请参考 Android Studio 版本说明
Android API 版本 Level 为 21 及以上版本。
Android SDK 版本 Android SDK 31、Android SDK Platform-Tools 31.x.x 及以上版本。
Gradle 及所需的依赖库 Gradle Services 页面下载对应版本的 Gradle 及所需的依赖库。
  • Gradle 版本:7.4.1
  • Android Gradle 插件版本: 7.1.3
    关于 Android Gradle 插件、Gradle、SDK Tool 之间的版本依赖关系,请参见 Android 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,请忽略该步骤。
  1. 若您需要创建新项目,在 Android Studio 里,在顶部菜单依次选择 File > New > New Project 新建工程,再依次选择 Phone and Tablet > Empty Activity,单击 Next
    image

    创建 Android 项目成功后,Android Studio 会自动开始同步 gradle, 您需要等同步成功后再进行下一步操作。

  2. 在项目根目录下的 “build.gradle” 文件中,配置 repositories(使用 maven)。示例代码如下:

    groovyallprojects {
        repositories {
            mavenCentral()
        }
    }
    
  3. 在 “app” 目录下的 “build.gradle” 文件中,配置支持的 SO 库架构。示例代码如下:

    groovyandroid {
    defaultConfig {
        ndk {
            //设置支持的SO库架构
            abiFilters "armeabi-v7a", "x86","arm64-v8a","x86_64"
            }
    }
    }
    
  4. 根据开发者项目的需求,添加对应的依赖。

    groovydependencies {
        implementation fileTree(dir: 'libs', include: '*.jar')
        // 添加依赖。
        
        // 基础功能 (必需)
        implementation "com.netease.nimlib:basesdk:${LATEST_VERSION}"
    }
    
  5. 添加权限。

    根据实际应用需求,在 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

ApplicationonCreate 中,调用 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 引入呼叫组件

  1. 在工程根部目录的 build.gradle 文件中添加如下代码。

    allprojects {
        repositories {
            //...
            mavenCentral()
            //...
        }
    }
    
  2. 在主工程 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 集成时请导入这个包
    
    }
    
  3. (可选)去除呼叫组件依赖的 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
    }
    
  4. 配置防代码混淆。

    代码混淆是指使用简短无意义的名称重命名类、方法、属性等,增加逆向工程的难度,保障 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
  • GLOBAL(1):全局初始化 RTC 一次
  • IN_NEED(2):按需初始化,主叫在呼叫时初始化 RTC ,被叫在收到呼叫时初始化 RTC ,通话结束销毁 RTC
  • IN_NEED_DELAY_TO_ACCEPT(3 ):**被叫接听时才初始化 RTC,通话结束销毁 RTC
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 通话被取消、拒绝或通话中挂断的回调
    

实现方法

  1. 添加呼叫监听。

在初始化呼叫组件后,调用 addCallDelegate 方法,添加回调监听。

java// 监听呼叫邀请,此处可在全局处设置,避免被意外释放导致来电丢失
NECallEngine.sharedInstance().addCallDelegate(new NECallEngineDelegateAbs() {
  @Override
  public void onReceiveInvited(NEInviteInfo info) {
    // 收到来电后可进行展示 notification,或者将 info 传入被叫页面并调起被叫页面;
  }
});
  1. 主叫发起呼叫。

进入自己的呼叫页面,调用 addCallDelegate 方法添加通话中监听,页面销毁时调用 removeCallDelegate避免内存泄漏,并调用 call 接口发起呼叫。

NECallParam 相关参数说明如下表所示。

参数 类型 是否必选 示例 描述
accId String 必选 "12345" 被叫用户的 IM accId。注册云信 IM 账号时, IM 服务器会返回对应的 accid 和 Token。
callType ChannelType 必选 NECallType.VIDEO 呼叫类型,包括:
  • NECallType.AUDIO: 音频
  • 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);
  1. 被叫收到呼叫邀请。

当收到呼叫邀请时,被叫会收到 onReceiveInvited 回调,并在回调中告知主叫的相关信息,包括主叫的accid、呼叫类型、信令通道的 ID、自定义信息。

详细的回调参数 NEInviteInfo 如下:

参数 类型 描述
callerAccId String 主叫用户的 IM accId。注册云信 IM 账号时, IM 服务器会返回对应的 accid 和 Token。
callType String 呼叫类型,包括:
  • NECallType.AUDIO: 音频
  • NECallType.VIDEO:视频
extraInfo Integer 扩展信息,透传到到被叫 onReceiveInvited
channelId String IM 信令通道 ID

被叫用户在收到邀请信息时可根据呼叫类型(VIDEO/AUDIO)来调用不同的方法直接启动被叫页面的 Activity。

若被叫方系统在 Android Q 及以上时,系统限制不允许后台弹出页面,此时会弹出对应的 Notification,被叫方可通过点击 Notification 跳转至对应的被叫页面。若用户通过 launcher 或其他方式唤起 app 时,通话仍有效则同样会展示被叫页面,进入被叫页面后同样可以调用 addCallDelegate 方法用于监听通话中相关回调,页面销毁时调用 removeCallDelegate避免内存泄漏。

  1. 被叫接听。

被叫调用 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);
  1. 通话挂断。

主叫取消/被叫拒绝/通话中挂断均可调用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);
  1. 忙线。

当被叫用户不在 STATE_IDLE 状态下接收到其他主叫用户的呼叫邀请时,被叫方内部会自动执行 NECallEngine.sharedInstance().hangup 动作,主叫方接收到对方的 reject 信令消息后会回调 NECallEngineDelegate.onCallEnd ,其中错误码为 NEHangupReasonCode.BUSY,用于 UI 展示,主叫方本地发送忙线话单消息。

进阶功能

多端登录

云信 IM SDK 支持多端或单端登录,若此时正在通过呼叫组件进行音视频通话时,其他端登录相同账号:

  1. IM 关闭多端登录:此时由于关闭多端登录,导致信令通道同时被踢出,无法通过信令完成消息通知。此时会直接做离开音视频房间操作,对端用户感知到本端离开动作后,会做挂断挂断操作。
  2. IM 开启多端登录:其他端的用户登录不会影响当前通过组件发起的音视频通话。但若多端同时在线时,收到呼叫邀请时会同时展示被邀请页面,如果其中一端接听或拒绝,则其他端会收到相应错误回调。错误码为 20012002

呼叫/被叫超时

主叫方发起呼叫被叫方时,若主叫方不取消,被叫方既不接听也不挂断,此时会触发超时限制。触发超时限制后主叫方和被叫方都会触发 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 接听失败
此文档是否对你有帮助?
有帮助
去反馈
  • 注意事项
  • 基本概念
  • 开发环境
  • 准备工作
  • 集成呼叫组件
  • 步骤 1: 集成 NIM SDK
  • 步骤 2:初始化 NIM SDK
  • 步骤 3:实现登录 IM
  • 步骤 4: Gradle 引入呼叫组件
  • 步骤 5: 初始化呼叫组件
  • 实现 1 对 1 呼叫(点对点呼叫)
  • API 时序图
  • 实现方法
  • 进阶功能
  • 多端登录
  • 呼叫/被叫超时
  • 视频通话设置本地预览与订阅远端画面
  • 设置通话分辨率及相关参数
  • 呼叫结束错误码