实现首次通话
CallPlus for Android 为您的应用提供一对一和多人语音/视频通话能力。
CallPlus 支持一对一通话和多人通话。按照本指南使用 Java 或 Kotlin 从零开始实现一对一通话与多人通话。
环境要求
CallPlus SDK 的最低要求:
Android 5 (API level 21) or higherJava 8 or higher
前置条件
-
注册开发者账号。注册成功后,控制台会默认自动创建您的首个应用,默认生成开发环境下的 App Key,使用国内数据中心。
-
获取开发环境的应用 App Key。如不使用默认应用,请参考如何创建应用,并获取对应环境 App Key 和 App Secret。
注意
每个应用具有两个不同的 App Key,分别对应开发环境与生产环境,两个环境之间数据隔离。在您的应用正式上线前,可切换到使用生产环境的 App Key,以便上线前进行测试和最终发布。
-
完成开通音视频服务。您需要开通音视频通话服务。
Demo 项目
融云提供了一个 Android 端 Demo 项目,集中演示了通话、会议、直播场景下的功能。
https://github.com/rongcloud/rtc-quickdemo-android
快速上手
您可以通过安装 CallPlus for Android 进行一对一通话,或多人通话。
步骤 1 创建项目
首先,打开 Android Studio 并在 Project 窗口中创建一个新项目,如下所示:
- 在 Welcome to Android Studio 窗口中点击 Start a new Android Studio project。
- 选择 Empty Activity,接着点击 Next。
- 在 Name 字段中输入您的项目名称。
- 从语言下拉菜单中选择您的语言 Java 或 Kotlin。
- 选择最低 API 级别为 21 或更高。

步骤 2 导入 SDK
Gradle
使用 Gradle,添加融云音视频通话能力库 CallPlus 为远程依赖项。请注意使用 融云的 Maven 仓库。
-
打开根目录下的
build.gradle(Project 视图下),声明融云的 Maven 代码库。Groovyallprojects {
repositories {
...
// 融云 Maven 仓库地址
maven {url "https://maven.rongcloud.cn/repository/maven-releases/"}
}
} -
在应用的
build.gradle中,添加对 IMLibCore 和 CallPlus 的远程依赖项。融云 CallPlus 业务依赖 IM 通道,所以必须同时集成 IMLibCore SDK(最低使用 5.6.3 版本)。Groovydependencies {
// x.y.z,请填写具体的 SDK 版本号,新集成用户建议使用最新版。
implementation 'cn.rongcloud.sdk:im_libcore:x.y.z' // 即时通讯基础能力库
implementation 'cn.rongcloud.sdk:callplus_lib:x.y.z'// 音视频呼叫能力库
implementation 'cn.rongcloud.sdk:rtc_lib:x.y.z' // 音视频通话基础能力库
}
注意
各个 SDK 的最新版本号可能不相同,还可能是 x.y.z.h,可前往 融云官网 SDK 下载页面 或 融云的 Maven 代码库 查询。 自 2.1.1 版本起,callplus_lib 内不再包含 rtc_lib。在使用 callplus_lib 的同时,还需要引入 rtc_lib。
Android 本地库模块 (Module)
在导入 SDK 前,您需要前往融云官网 SDK 下载页面,将音视频通话能力-CallPlusLib及其依赖的即时通讯能力库-IMLib 和 音视频基础能力-RTCLib 下载到本地。
-
将
rong_callplus_x.y.z.aar文件复制到 Android Studio 项目的 libs 目录下,在应用的build.gradle中,添加*.aar依赖。 -
依次点击 File > New > Import Module,将
imlib和rtclib的 Module 组件导入。Groovydependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
implementation project(path: ':imlib')
implementation project(path: ':rtclib')
}
步骤 3 权限配置
-
在 AndroidManifest.xml 中声明 SDK 需要的所有权限。
xml<!-- 允许程序访问网络连接 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 允许程序获取网络信息状态,如当前的网络连接是否有效 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<!-- 允许程序获取当前 Wi‑Fi 接入的状态以及 WLAN 热点的信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 允许程序访问摄像头进行拍照 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 允许程序录制声音通过手机或耳机的麦克 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 允许程序修改声音设置信息 -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- 允许程序访问电话状态,如通话中收到来自 SIM 卡的来电时,会将 SIM 卡通话状态通知给远端用户,所以需要该权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> -
如果您的应用需要支持 Android 6.0(API 级别 23)或更高版本的设备,您还需要在 App 用户使用对应功能时(例如发起呼叫、接听)请求摄像头(
CAMERA)、麦克风(RECORD_AUDIO)权限。详见 Android 开发者官方文档运行时权限与请求权限的工作流。
步骤 4 代码混淆
当您使用 minifyEnabled true 构建 APK 时,将以下行添加到模块的 ProGuard 规则文件中。
-keepattributes Exceptions,InnerClasses
-keepattributes Signature
# imlib
-keep class io.rong.** {*;}
-keep class cn.rongcloud.** {*;}
-keep class * implements io.rong.imlib.model.MessageContent {*;}
-dontwarn io.rong.push.**
-dontnote com.xiaomi.**
-dontnote com.google.android.gms.gcm.**
-dontnote io.rong.**
# rtclib
-keep public class cn.rongcloud.rtc.** {*;}
-keep public class cn.rongcloud.rtclib.** {*;}
# callpluslib
-keep public class cn.rongcloud.calllib.** {*;}
-keep public class cn.rongcloud.callplus.** {*;}
-ignorewarnings
步骤 5 使用 App Key 初始化
CallPlus for Android 依赖融云即时通讯客户端 SDK 提供信令通道。要在您的应用程序中集成和运行,您需要先对 IMLibCore 进行初始化。
融云即时通讯客户端 SDK 核心类为 RongCoreClient 和 RongIMClient。在 Application 的 onCreate() 方法中,调用 RongCoreClient 的初始化方法,传入生产或开发环境的 App Key。
String appKey = "Your_AppKey"; // example: bos9p5rlcm2ba
InitOption initOption = new InitOption.Builder().build();
RongCoreClient.init(getApplicationContext(), appKey, initOption);
初始化配置(InitOption)中封装了区域码(AreaCode),导航服务地址(naviServer)、文件服务地址(fileServer)、数据统计服务地址(statisticServer)配置,以及是否开启推送的开关(enablePush)和主进程开关(isMainProcess)。您可以传 null,表示全部使用默认配置。SDK 默认连接北京数据中心。
如果 App Key 不属于中国(北京)数据中心,则必须传入有效的初始化配置。
步骤 6 添加通话所需监听
使用 setCallPlusEventListener 方法添加通话事件监听 IRCCallPlusEventListener。该监听提供来电事件、通话状态、通话记录等事件相关回调。通过 setCallPlusEventListener(null); 可移除监听器。
注意
如果未注册
IRCCallPlusEventListener监听器,则用户无法接收onReceivedCall回调事件。请务必在下一步与融云服务器建立连接(connect)之前使用setCallPlusEventListener注册监听,否则用户在未连接的情况下无法通过离线推送接收来电通知。
RCCallPlusClient.getInstance().setCallPlusEventListener(new IRCCallPlusEventListener() {
/**
* 本端用户通过该回调接收到通话呼叫
*
* @param callSession 通话实体信息
*/
@Override
public void onReceivedCall(RCCallPlusSession callSession, String extra) {
RCCallPlusSession currentCallSession = RCCallPlusClient.getInstance().getCurrentCallSession();
if (currentCallSession != null && !TextUtils.equals(callSession.getCallId(), currentCallSession.getCallId())) {
// 可用该判断识别:已有通话进行中,又有第二通通话呼入
// 第二通通话可直接调用 RCCallPlusClient.getInstance().accept 接听,SDK 内部会将第一通通话挂断
}
// SDK 的回调均为子线程
// showDialog() 方法中涉及 UI 操作,需要切换到主线程执行
// showDialog() 方法实现可参考附录
runOnUiThread(new Runnable() {
@Override
public void run() {
// 打开摄像头采集;请提前完成摄像头、麦克风权限的动态申请
RCCallPlusClient.getInstance().startCamera();
RCCallPlusClient.getInstance().enableMicrophone(true);
// 复用发起通话逻辑中的“设置本地视频渲染视图”方法
setLocalVideoView();
showDialog(CallPlusActivity.this, "收到通话,是否接听?", "接听", new OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
acceptCall(callSession);
}
}, "挂断", new OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
RCCallPlusClient.getInstance().hangup();
}
});
}
});
}
@Override
public void onCallEnded(RCCallPlusSession session, RCCallPlusReason reason) {
IRCCallPlusEventListener.super.onCallEnded(session, reason);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(CallPlusActivity.this, "通话结束,callId: " + session.getCallId() + " 通话结束原因:" + reason.getValue(), Toast.LENGTH_SHORT).show();
}
});
}
/**
* 远端用户状态改变监听
*
* @param callId 通话 ID
* @param userId 用户 ID
* @param status 当前状态
* @param reason 当前状态原因
*/
@Override
public void onRemoteUserStateChanged(String callId, String userId, RCCallPlusUserSessionStatus status, RCCallPlusReason reason) {
IRCCallPlusEventListener.super.onRemoteUserStateChanged(callId, userId, status, reason);
runOnUiThread(new Runnable() {
@Override
public void run() {
StringBuilder stringBuilder = new StringBuilder("通话 ");
stringBuilder.append(callId).append(" 中的远端用户 ").append(userId).append(" 当前状态为 ");
switch (status) {
case IDLE:
stringBuilder.append("空闲");
break;
case CALLING:
stringBuilder.append("呼叫中");
break;
case INVITED:
stringBuilder.append("被邀请中");
break;
case RINGING:
stringBuilder.append("响铃中");
break;
case BUSY_LINE_RINGING:
stringBuilder.append("忙线(响铃中)");
break;
case BUSY_LINE_WAIT:
stringBuilder.append("忙线(通话中)");
break;
case CONNECTING:
stringBuilder.append("已接听,连接中");
break;
case ON_CALL:
stringBuilder.append("通话中");
break;
case ENDED:
stringBuilder.append("通话已结束");
break;
case NO_ANSWER:
stringBuilder.append("未应答");
break;
case MISSED:
stringBuilder.append("未接听");
break;
case CANCELED:
stringBuilder.append("已取消");
break;
case DECLINED:
stringBuilder.append("已拒绝");
break;
case ERROR:
stringBuilder.append("错误");
break;
}
Toast.makeText(CallPlusActivity.this, stringBuilder.toString(), Toast.LENGTH_SHORT).show();
}
});
}
});
使用 setCallPlusResultListener 方法添加通 话 API 异步结果回调监听 IRCCallPlusResultListener。该监听可以接收 startCall、accept、hangup 等方法的结果回调。通过 setCallPlusResultListener(null); 可移除监听器。
RCCallPlusClient.getInstance().setCallPlusResultListener(new IRCCallPlusResultListener() {
/**
* 发起通话结果回调
*
* @param code 方法请求结果
* @param callId 通话 ID
* @param busyUserList 呼叫成功后,返回被邀请人列表中的忙线用户列表
*/
@Override
public void onStartCall(RCCallPlusCode code, String callId, List<RCCallPlusUser> busyUserList) {
IRCCallPlusResultListener.super.onStartCall(code, callId, busyUserList);
}
/**
* 接听通话结果回调
*
* @param code 方法请求结果
* @param callId 通话 ID
*/
@Override
public void onAccept(RCCallPlusCode code, String callId) {
IRCCallPlusResultListener.super.onAccept(code, callId);
}
/**
* 挂断通话结果回调
*
* @param code 方法请求结果
* @param callId 通话 ID
*/
@Override
public void onHangup(RCCallPlusCode code, String callId) {
IRCCallPlusResultListener.super.onHangup(code, callId);
}
});
步骤 7 获取用户 Token
用户身份令牌(Token)与用户 ID 对应,是应用程序用户在融云的唯一身份标识。应用客户端在使用融云服务前必须与融云建立 IM 连接,连接时必须传入 Token。
在体验和调试阶段,我们将使用控制台「北极星」开发者工具箱,从 API 调试页面调用 获取 Token 接口,获取到 userId 为 1 的用户的 Token。提交后,可在返回正文中取得 Token 字符串。
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"code":200,"userId":"1","token":"gxld6GHx3t1eDxof1qtxxYrQcjkbhl1V@sgyu.cn.example.com;sgyu.cn.example.com"}
融云的客户端 SDK 不提供获取 Token 的 API。在实际业务运行过程中,调用融云 Server API
/user/getToken.json,传入您的应用分配的用户标识(userId)申请 Token。详见 Server API 文档注册用户。
步骤 8 连接融云服务器
要拨打和接听一对一呼叫或开始多人呼叫,必须先通过 RongCoreClient 的 connect 方法连接融云服务器,传入用户身份令牌(Token),向融云服务器验证用户身份。连接成功后,使用 RCCallPlusClient.getInstance().init() 初始化并配置 CallPlus SDK。
注意
必须在连接成功之后调用
RCCallPlusClient.getInstance().init方法初始化 CallPlus SDK。反初始化使用RCCallPlusClient.getInstance().unInit();。
String token = "用户 Token";
RongCoreClient.connect(token, new IRongCoreCallback.ConnectCallback() {
/**
* 成功回调
* @param userId 当前用户 ID
*/
@Override
public void onSuccess(String userId) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// 尽管不强制要求在主线程初始化 RCCallPlusClient,但示例中后续调用均在主线程,建议在主线程初始化
// 请确保在同一线程完成 RCCallPlusClient 的初始化、反初始化和使用,保证一致性
RCCallPlusConfig config = RCCallPlusConfig.Builder.create().build();
/**
* 初始化并设置通话全局配置;重复调用时 SDK 内部会重新初始化
* @param config 设置通话全局配置
* @return 方法同 步返回结果,用于判断是否初始化成功
*/
RCCallPlusResultCode resultCode = RCCallPlusClient.getInstance().init(config);
}
});
}
/**
* 错误回调
* @param errorCode 错误码
*/
@Override
public void onError(IRongCoreEnum.ConnectionErrorCode errorCode) {
}
/**
* 数据库回调
* @param code 数据库打开状态:DATABASE_OPEN_SUCCESS 打开成功;DATABASE_OPEN_ERROR 打开失败
*/
@Override
public void onDatabaseOpened(DatabaseOpenStatus code) {
}
});
进行一对一通话
CallPlus for Android 定义了仅限两位用户通话的一对一通话类型 RCCallPlusType.PRIVATE。发起一对一通话时,只允许传入一个被叫用户 ID,仅在被叫接听成功后才会建立通话。被叫接听成功后开始计时计费。
本节将简单介绍如何发起一对一通话、如何接收来电,以及接通后双方通话界面如何显示。
步骤 9 拨打
注意
自 CallPlus 2.0 起,新增 startCall 重载方法,支持在发起呼叫时通过配置推送属性自定义远程推送标题等属性,并支持携带自定义数据。
您可以使用 startCall 发起一对一通话。方法调用后,SDK 内部会以异步方式执行;在主叫与被叫端触发以下回调:
- 本地主叫用户通过 IRCCallPlusResultListener 的 [onStartCall] 获取执行结果。
- 远端被叫用户通过 IRCCallPlusEventListener 的 [onReceivedCall] 获取来电通知。
若远端被叫用户接听,本地主叫用户将收到 IRCCallPlusEventListener 的 [onRemoteUserStateChanged] 回调,其中 RCCallPlusUserSessionStatus 为 CONNECTING 表示对方已接听并连接中。
private void startCall(String remoteUserId) {
// 打开摄像头采集;请提前完成摄像头、麦克风权限的动态申请
RCCallPlusClient.getInstance().startCamera();
RCCallPlusClient.getInstance().enableMicrophone(true);
setLocalVideoView();
// 创建远端视图对象;remoteUserId 为远端用户 userId
RCCallPlusRemoteVideoView remoteVideoView = new RCCallPlusRemoteVideoView(remoteUserId, context, isTiny);
// 2.34.0 版本开始支持使用 TextureView 渲染视频
// IRCCallPlusRemoteVideoView remoteVideoView = new RCCallPlusRemoteVideoTextureView(context, remoteUserId, isTiny);
// FIT:视频帧通过保持宽高比(可能显示黑边)来缩放以适应视图大小
remoteVideoView.setRenderMode(RCCallPlusRenderMode.FIT);
// 远端视图显示在最顶层,为防止被底部控件遮挡,进行如下设置:
remoteVideoView.setZOrderOnTop(true);
remoteVideoView.setZOrderMediaOverlay(true);
List<IRCCallPlusRemoteVideoView> remoteVideoViewList = new ArrayList<>();
remoteVideoViewList.add(remoteVideoView);
// 设置远端视图给 SDK,从2.34.0版本开始setVideoView()方法标注为废弃
//RCCallPlusClient.getInstance().setVideoView(remoteVideoViewList);
//从2.34.0版本开始,调用setVideoView2()方法设置视图
RCCallPlusClient.getInstance().setVideoView2(remoteVideoViewList);
FrameLayout.LayoutParams remoteVideoViewParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
remoteVideoViewParams.gravity = Gravity.CENTER_HORIZONTAL;
// 将远端视图添加到 XML 中显示
// 示例中 mRemoteVideoViewFrameLayout 为 android.widget.FrameLayout 对象
mRemoteVideoViewFrameLayout.removeAllViews();
mRemoteVideoViewFrameLayout.addView(remoteVideoView, remoteVideoViewParams);
List<String> userIds = new ArrayList<>();
userIds.add(remoteUserId); // remoteUserId 为被呼叫的远端用户 userId
RCCallPlusType callType = RCCallPlusType.PRIVATE; // PRIVATE:1v1 通话
RCCallPlusMediaType mediaType = RCCallPlusMediaType.VIDEO;
RCCallPlusPushConfig pushConfig = RCCallPlusPushConfig.Builder
.create()
.build();
/**
* 开始发起呼叫
* 该方法内部为异步执行;结果回调见 {@link RCCallPlusClient#setCallPlusResultListener(IRCCallPlusResultListener)} 监听的 {@link
IRCCallPlusResultListener#onStartCall(RCCallPlusCode, String, List)}方法
*/
RCCallPlusClient.getInstance().startCall(userIds, callType, mediaType, pushConfig, "extra");
}
实现 setLocalVideoView 方法,调用 CallPlus SDK 的 setVideoView (2.34.0版本起请使用setVideoView2方法),传入 RCCallPlusLocalVideoView 或 RCCallPlusLocalVideoTextureView 设置本地摄像头渲染视图。
/**
* 设置本地视频渲染视图
*/
private void setLocalVideoView() {
// 创建本地视图对象
RCCallPlusLocalVideoView localVideoView = new RCCallPlusLocalVideoView(context);
//或使用 TextureView 渲染本地视频
//IRCCallPlusLocalVideoView localVideoView = new RCCallPlusLocalVideoTextureView(context);
// FIT:视频帧通过保持宽高比(可能显示黑边)来缩放以适应视图大小
localVideoView.setRenderMode(RCCallPlusRenderMode.FIT);
// 设置本地视图给 SDK,从2.34.0版本开始,使用 setVideoView2() 方法代替 setVideoView() 方法
RCCallPlusClient.getInstance().setVideoView2(localVideoView);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER_HORIZONTAL; // 在父布局中横向居中显示
// 将本地视图添加到 XML 中显示
// 示例中 mLocalVideoViewFrameLayout 为 android.widget.FrameLayout 对象
mLocalVideoViewFrameLayout.removeAllViews();
mLocalVideoViewFrameLayout.addView(localVideoView, params);
}
步骤 10 接听
重要
非兼容性变更:自 CallPlus 2.0 起,
onReceivedCall方法发生非兼容变更,新的方法会携带extra字段。升级时请同步修改相关代码。
被叫用户可以选择接听来电 accept 或挂断来电 hangup。执行接听和挂断操作所需传入的 callId 值,可通过 RCCallPlusSession 的 getCallId() 获取。
private void acceptCall(RCCallPlusSession callSession) {
setRemoteUserVideoView(callSession.getRemoteUserList());
/**
* 开始接听通话
* 该方法内部为异步执行;结果回调见 {@link RCCallPlusClient#setCallPlusResultListener(IRCCallPlusResultListener)} 监听的 {@link
IRCCallPlusResultListener#onAccept(RCCallPlusCode, String)}方法
*/
RCCallPlusClient.getInstance().accept(callSession.getCallId());
}
要接收远端呼叫通知,必须已注册
IRCCallPlusEventListener并实现onReceivedCall(RCCallPlusSession callSession)。被叫用户通过与融云服务端的连接接收来电通知。若需通过离线推送接收来电通知,App 必须已集成第三方厂商推送,详见推送 2.0 集成概述。
调用接听或挂断后,SDK 内部会以异步方式执行。在主叫与被叫端触发以下回调:
- 被叫用户通过 IRCCallPlusResultListener 以下回调获取调用结果:
- [onAccept]:接听结果
- [onHangup]:挂断结果
- 主叫用户通过 IRCCallPlusEventListener 的 [onRemoteUserStateChanged] 回调获取远端被叫用户状态 RCCallPlusUserSessionStatus,判断被叫用户是否已接听。实现可参见上文“添加通话所需监听”。
通话接通后,需要设置远端用户视频渲染视图。可参考以下示例实现 setRemoteUserVideoView,调用 CallPlus SDK 的 setVideoView (2.34.0版本起请使用setVideoView2方法),传入 RCCallPlusRemoteVideoView 或 RCCallPlusRemoteVideoTextureView 列表设置远端用户视频流渲染视图。
/**
* 设置远端用户视频渲染视图
*/
private void setRemoteUserVideoView(List<RCCallPlusUser> remoteUserList) {
List<IRCCallPlusRemoteVideoView> remoteVideoViewList = new ArrayList<>();
for (RCCallPlusUser callPlusUser : remoteUserList) {
IRCCallPlusRemoteVideoView remoteVideoView = new RCCallPlusRemoteVideoView(callPlusUser.getUserId(), context, isTiny);
//2.34.0版本 开始支持使用TextureView渲染视频
//IRCCallPlusRemoteVideoView remoteVideoView = new RCCallPlusRemoteVideoTextureView(context, callPlusUser.getUserId(), isTiny);
// 视频帧通过保持宽高比(可能显示黑边)来缩放以适应视图大小
remoteVideoView.setRenderMode(RCCallPlusRenderMode.FIT);
remoteVideoViewList.add(remoteVideoView);
// 示例中,远端视图显示在最顶层;为防止被底部控件遮挡,进行如下设置:
remoteVideoView.setZOrderOnTop(true);
remoteVideoView.setZOrderMediaOverlay(true);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER_HORIZONTAL;
// TODO 将每个远端视图(remoteVideoView)添加到 XML 中显示;多人通话需添加多个控件显示,本示例仅展示一个远端用户
mRemoteVideoViewFrameLayout.removeAllViews();
mRemoteVideoViewFrameLayout.addView(remoteVideoView, params);
}
/**
* 设置远端用户视频流渲染视图给 SDK
* 若未为远端用户设置视频渲染视图,将不会产生该用户视频流的下行流量
*/
//RCCallPlusClient.getInstance().setVideoView(remoteVideoViewList);
//从2.34.0版本开始,调用setVideoView2()方法设置视图
RCCallPlusClient.getInstance().setVideoView2(remoteVideoViewList);
}
发起多人通话
CallPlus for Android 提供了支持多人呼叫的通话类型 RCCallPlusType.MULTI。发起多人通话与一对一通话流程相似,但通话类型需指定为 RCCallPlusGroupType。多人通话一旦发起成功即开始计费。
下文仅描述发起多人通话的方法。在实际项目中,建议先按照一对一通话实现完整流程,再按多人通话补充实现与一对一通话有差异的步骤。
在一对一通话过程中可邀请用户加入通话。一旦邀请成功,通话类型会自动转为多人通话。详见多人通话。
步骤 11 拨打多人通话
通过 startCall 可发起多人通话。该方法以异步方式执行,结果可在 IRCCallPlusResultListener 的 [onStartCall] 中获取。多人通话与单人通话在 startCall 方法中差异仅体现为传入的 RCCallPlusType 类型不同。
List<String> userIds = new ArrayList<>();
userIds.add(remoteUserId); // remoteUserId 为被呼叫的远端用户 userId。多人通话可添加多个用户
RCCallPlusType callType = RCCallPlusType.MULTI; // PRIVATE:单人通话,MULTI:多人通话
RCCallPlusMediaType mediaType = RCCallPlusMediaType.VIDEO;
RCCallPlusPushConfig pushConfig = RCCallPlusPushConfig.Builder
.create()
.build();
RCCallPlusClient.getInstance().startCall(userIds, callType, mediaType, pushConfig, "extra");
附录
以下为上文示例中 showDialog() 的实现,仅供参考。
private AlertDialog showDialog(Context context, String content, String positiveBtn, final DialogInterface.OnClickListener positiveListener, final String negativeBtn, final DialogInterface.OnClickListener negativeListener) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder = builder.setMessage(content);
builder.setCancelable(false);
if (!TextUtils.isEmpty(positiveBtn)) {
builder.setPositiveButton(positiveBtn, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (positiveListener != null) {
positiveListener.onClick(dialog, which);
} else {
dialog.dismiss();
}
}
});
}
if (!TextUtils.isEmpty(negativeBtn)) {
builder.setNegativeButton(negativeBtn, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (negativeListener != null) {
negativeListener.onClick(dialog, which);
} else {
dialog.dismiss();
}
}
});
}
return builder.show();
}