tencent cloud

Android
最后更新时间:2025-11-27 20:47:56
Android
最后更新时间: 2025-11-27 20:47:56

业务流程

本节汇总了 1V1 音视频通话中一些常见的业务流程,帮助您更好地理解整个场景的实现过程。
语音通话流程
视频通话流程
下图展示了 1V1 语音通话的序列图,其中包含呼叫、接听、通话、挂断等流程。



下图展示了 1V1 视频通话的序列图,其中包含呼叫、接听、通话、挂断等流程。




接入准备

步骤一:开通服务

1V1 音视频通话场景通常需要依赖腾讯云 即时通信 IM实时音视频 TRTC 两项付费 PaaS 服务构建。
1. 首先您需要登录 实时音视频 TRTC 控制台 创建应用,此时在 即时通信 IM 控制台 会同步自动创建一个与当前 TRTC 应用相同 SDKAppID 的 IM 体验版应用,二者账号与鉴权体系可复用。后续您可根据需要选择升级 TRTC 或 IM 应用版本,例如高级版本可解锁更多增值功能服务。



说明:
建议创建两个应用分别用于测试环境和生产环境,一年内每个腾讯云账号(UIN)每月赠送10,000分钟免费时长。
TRTC 包月套餐分为体验版(默认)、基础版和专业版,可解锁不同的增值功能服务,详情可见 版本功能与包月套餐说明
2. 创建应用完毕之后,您可以在应用管理 > 应用概览栏目看到该应用的基本信息,其中需要您保管好 SDKAppIDSDKSecretKey 便于后续使用,同时应避免密钥泄露造成流量盗刷。




步骤二:导入 SDK

TRTC SDK 和 IM SDK 已经发布到 mavenCentral 库,您可以通过配置 gradle 自动下载更新。
1. 在 dependencies 中添加合适版本 SDK 的依赖。
dependencies {
// TRTC 精简版 SDK, 包含 TRTC 和直播播放两项功能
implementation 'com.tencent.liteav:LiteAVSDK_TRTC:latest.release'
// 添加 IM SDK,推荐填写最新的版本号
implementation 'com.tencent.imsdk:imsdk-plus:Version number'

// 如果您需要添加 Quic 插件,请取消下一行的注释(注意:要求插件版本号和 IM SDK 版本号相同)
// implementation 'com.tencent.imsdk:timquic-plugin:Version number'
}
说明:
除了推荐的自动加载方式,您还可以选择下载 SDK 并手动导入,详见 手动集成 TRTC SDK手动集成 IM SDK
Quic 插件提供 axp-quic 多路传输协议,弱网抗性更优,网络丢包率达到 70% 的条件下,仍然可以提供服务。仅对旗舰版用户开放,对于非旗舰版,请 购买旗舰版套餐包 后可使用,详见 价格说明。为确保功能正常使用,请将终端 SDK 更新至 7.7.5282 及其以上的版本
2. 在 defaultConfig 中,指定 App 使用的 CPU 架构。
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "arm64-v8a"
}
}
说明:
TRTC SDK 支持 armeabi/armeabi-v7a/arm64-v8a 架构,另外支持模拟器专用的 x86/x86_64 架构。
IM SDK 支持 armeabi-v7a/arm64-v8a/x86/x86_64 架构,为了缩减安装包体积,您可以选择只打包部分架构的 SO 文件。

步骤三:工程配置

1. 在 AndroidManifest.xml 中配置 App 权限,音视频通话场景下 TRTC SDK 及 IM SDK 需要以下权限:
<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.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" />
注意:
请勿设置 android:hardwareAccelerated="false",关闭硬件加速之后,会导致对方的视频流无法渲染。
TRTC SDK 没有内置权限申请逻辑,需要您自行声明相应的权限,部分权限(如存储、录音、相机等)还需要在运行时动态申请。
若 Android 项目 targetSdkVersion 为 31 或者目标设备涉及到 Android 12 及更高系统版本,官方要求需要在代码中动态申请 android.permission.BLUETOOTH_CONNECT 权限,以正常使用蓝牙功能,具体信息请参见 蓝牙权限
2. 由于我们在 SDK 内部使用了 Java 的反射特性,需要您在 proguard-rules.pro 文件中将 SDK 相关类加入不混淆名单:
-keep class com.tencent.** { *; }

步骤四:鉴权凭证

UserSig 是腾讯云设计的一种安全保护签名,目的是为了阻止恶意攻击者盗用您的云服务使用权。腾讯云实时音视频(TRTC)、即时通信(IM)服务都采用了该套安全保护机制,TRTC 在进房时鉴权,IM 在登录时鉴权。
调试跑通阶段:可以通过 客户端示例代码控制台获取 两种方法计算生成 UserSig,仅用于调试测试。
正式运行阶段:推荐安全等级更高的服务端计算 UserSig 方案,防止客户端被逆向破解泄露密钥。
具体实现流程如下:
1. 您的 App 在调用 SDK 的初始化函数之前,首先要向您的服务器请求 UserSig。
2. 您的服务器根据 SDKAppID 和 UserID 计算 UserSig。
3. 服务器将计算好的 UserSig 返回给您的 App。
4. 您的 App 将获得的 UserSig 通过特定 API 传递给 SDK。
5. SDK 将 SDKAppID + UserID + UserSig 提交给腾讯云服务器进行校验。
6. 腾讯云校验 UserSig,确认合法性。
7. 校验通过后,会向 IM SDK 提供即时通信服务、TRTC SDK 提供实时音视频服务。



注意:
调试跑通阶段的本地 UserSig 计算方式不推荐应用到线上环境,容易被逆向破解导致密钥泄露。
我们提供了多个语言版本(Java/Go/PHP/Nodejs/Python/C#/C++)的 UserSig 服务端计算源代码,详见 服务端计算 UserSig

步骤五:初始化 SDK

1. IM SDK 初始化与添加事件监听器
// 添加事件监听器
V2TIMManager.getInstance().addIMSDKListener(imSdkListener);
// 初始化 IM SDK,调用这个接口后,可以立即调用登录接口
V2TIMManager.getInstance().initSDK(context, sdkAppID, null);

// SDK 初始化后会抛出一些事件,例如连接状态、登录票据过期等
private V2TIMSDKListener imSdkListener = new V2TIMSDKListener() {
@Override
public void onConnecting() {
Log.d(TAG, "IM SDK 正在连接到腾讯云服务器");
}

@Override
public void onConnectSuccess() {
Log.d(TAG, "IM SDK 已经成功连接到腾讯云服务器");
}
};

// 移除事件监听器
V2TIMManager.getInstance().removeIMSDKListener(imSdkListener);
// 反初始化 IM SDK
V2TIMManager.getInstance().unInitSDK();
说明:
如果您的应用生命周期跟 SDK 生命周期一致,退出应用前可以不进行反初始化。若您只在进入特定界面后才初始化 SDK,退出界面后不再使用,可以对 SDK 进行反初始化。
2. TRTC SDK 创建实例与设置事件监听器
// 创建 TRTC SDK 实例(单例模式)
TRTCCloud mTRTCCloud = TRTCCloud.sharedInstance(context);
// 添加 TRTC 事件监听器
mTRTCCloud.addListener(trtcSdkListener);

// 来自 SDK 的各类事件通知(比如:错误码,警告码,音视频状态参数等)
private TRTCCloudListener trtcSdkListener = new TRTCCloudListener() {
@Override
public void onError(int errCode, String errMsg, Bundle extraInfo) {
Log.d(TAG, errCode + errMsg);
}
@Override
public void onWarning(int warningCode, String warningMsg, Bundle extraInfo) {
Log.d(TAG, warningCode + warningMsg);
}
};

// 移除 TRTC 事件监听器
mTRTCCloud.removeListener(trtcSdkListener);
// 销毁 TRTC SDK 实例(单例模式)
TRTCCloud.destroySharedInstance();
说明:
建议监听 SDK 事件通知,对一些常见错误进行日志打印和处理,详见 错误码表

接入过程

步骤一:登录

初始化 IM SDK 后,您需要调用 SDK 登录接口验证账号身份,获得账号的功能使用权限。因此在使用其他功能之前,请务必确保登录成功,否则可能导致功能异常或不可用。如您仅需使用 TRTC 音视频服务,可忽略此步骤。

时序图





登录操作

// 登录:userID 可自定义,userSig 参考步骤一生成获取
V2TIMManager.getInstance().login(userID, userSig, new V2TIMCallback() {
@Override
public void onSuccess() {
Log.i("imsdk", "success");
}
@Override
public void onError(int code, String desc) {
// 如果返回以下错误码,表示使用 UserSig 已过期,请您使用新签发的 UserSig 进行再次登录。
// 1. ERR_USER_SIG_EXPIRED(6206)
// 2. ERR_SVR_ACCOUNT_USERSIG_EXPIRED(70001)
// 注意:其他的错误码,请不要在这里调用登录接口,避免 IM SDK 登录进入死循环。
Log.i("imsdk", "failure, code:" + code + ", desc:" + desc);
}
});

登出操作

// 登出
V2TIMManager.getInstance().logout(new V2TIMCallback() {
@Override
public void onSuccess() {
Log.i("imsdk", "success");
}
@Override
public void onError(int code, String desc) {
Log.i("imsdk", "failure, code:" + code + ", desc:" + desc);
}
});
说明:
如果您的应用生命周期跟 IM SDK 生命周期一致,退出应用前可以不登出。若您只在进入特定界面后才使用 IM SDK,退出界面后不再使用,可以进行登出操作和对 IM SDK 进行反初始化。

步骤二:呼叫

时序图





发起呼叫

1. 主叫端本地画面预览(仅视频通话,语音通话忽略此步骤)
// 设置视频编码参数,决定远端用户看到的画面质量
TRTCCloudDef.TRTCVideoEncParam encParam = new TRTCCloudDef.TRTCVideoEncParam();
encParam.videoResolution = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_960_540;
encParam.videoFps = 15;
encParam.videoBitrate = 850;
encParam.videoResolutionMode = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_MODE_PORTRAIT;
mTRTCCloud.setVideoEncoderParam(encParam);

// 开启本地摄像头预览(可指定使用前置/后置摄像头进行视频采集)
mTRTCCloud.startLocalPreview(isFrontCamera, previewView);
注意:
您可根据业务需求自行设置视频编码参数 TRTCVideoEncParam,各档位最佳分辨率和码率搭配详见 分辨率码率参照表
enterRoom 之前调用以上接口,SDK 只会开启摄像头预览,并一直等到您调用 enterRoom 之后才开始本地视频推流。
2. 主叫端发送呼叫邀请信令
// 构造自定义数据
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("cmd", "av_call");
JSONObject msgJsonObject = new JSONObject();
msgJsonObject.put("callType", "videoCall"); // 指定通话类型(视频通话、语音通话)
msgJsonObject.put("roomId", generateRoomId()); // 指定 TRTC 房间号(主叫端可随机生成)
jsonObject.put("msg", msgJsonObject);
} catch (JSONException e) {
e.printStackTrace();
}
String data = jsonObject.toString();

// 发送呼叫邀请信令
V2TIMManager.getSignalingManager().invite(receiver, data, false, v2TIMOfflinePushInfo, timeout, new V2TIMCallback() {
@Override
public void onError(int code, String desc) {
// 发送呼叫邀请信令失败
// 提示呼叫失败,可以尝试重试
}

@Override
public void onSuccess() {
// 发送呼叫邀请信令成功
// 渲染呼叫页面,播放呼叫铃声
}
});
注意:
音视频通话场景中,通常需要在邀请信令中配置离线推送信息 v2TIMOfflinePushInfo,详情参见 离线推送消息
建议在邀请信令中设置合理的超时时间参数 timeout,单位为秒,SDK 会进行超时检测,从而实现呼叫超时自动挂断。
3. 被叫端收到呼叫邀请通知
// 被叫用户收到呼叫请求, inviteID 为该条请求 ID,inviter 为主叫用户 ID
V2TIMManager.getSignalingManager().addSignalingListener(new V2TIMSignalingListener() {
@Override
public void onReceiveNewInvitation(String inviteID, String inviter,
String groupId, List<String> inviteeList, String data) {
if (!data.isEmpty()) {
try {
JSONObject jsonObject = new JSONObject(data);
String command = jsonObject.getString("cmd");
JSONObject messageJsonObject = jsonObject.getJSONObject("msg");
if (command.equals("av_call")) {
String callType = messageJsonObject.getString("callType");
String roomId = messageJsonObject.getString("roomId");
// 渲染呼叫页面,播放呼叫铃声
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});
注意:
主叫端发起呼叫请求、被叫端收到呼叫请求时,业务侧需要自行实现呼叫页面的渲染,以及呼叫铃声的播放。
4. 被叫端本地画面预览(仅视频通话,语音通话忽略此步骤)
if (callType.equals("videoCall")) {
// 设置视频编码参数,决定远端用户看到的画面质量
TRTCCloudDef.TRTCVideoEncParam encParam = new TRTCCloudDef.TRTCVideoEncParam();
encParam.videoResolution = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_960_540;
encParam.videoFps = 15;
encParam.videoBitrate = 850;
encParam.videoResolutionMode = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_MODE_PORTRAIT;
mTRTCCloud.setVideoEncoderParam(encParam);

// 开启本地摄像头预览(可指定使用前置/后置摄像头进行视频采集)
mTRTCCloud.startLocalPreview(isFrontCamera, previewView);
}

取消呼叫

1. 主叫端取消呼叫请求
V2TIMManager.getSignalingManager().cancel(inviteId, data, new V2TIMCallback() { @Override public void onError(int code, String desc) { // 取消呼叫请求失败
// 提示取消失败,可以尝试重试 } @Override public void onSuccess() { // 取消呼叫请求成功
// 销毁呼叫页面,停止播放呼叫铃声 } });
2. 被叫端收到取消通知
@Override public void onInvitationCancelled(String inviteID, String inviter, String data) {
// 销毁呼叫页面,停止播放呼叫铃声 }

呼叫超时

主叫端和被叫端均会收到超时通知,同时销毁呼叫页面并停止播放呼叫铃声。
@Override
public void onInvitationTimeout(String inviteID, List<String> inviteeList) {
// 提示呼叫超时,销毁呼叫页面,停止播放呼叫铃声
}

步骤三:接听

接听信令

1. 被叫端发送同意接听信令
V2TIMManager.getSignalingManager().accept(inviteId, data, new V2TIMCallback() { @Override public void onError(int code, String desc) { // 接听失败,提示异常或重试 } @Override public void onSuccess() { // 接听成功,渲染通话页面,停止播放呼叫铃声
if (callType.equals("videoCall")) {
// 开始视频通话
startVideoCall();
} else {
// 开始语音通话
startAudioCall();
} } });
2. 主叫端收到同意接听通知
@Override
public void onInviteeAccepted(String inviteID, String invitee, String data) {
if (callType.equals("videoCall")) {
// 开始视频通话
startVideoCall();
} else {
// 开始语音通话
startAudioCall();
}
}

语音通话

1. 主叫端和被叫端均进入同一个 TRTC 房间,开始语音通话。
private void startAudioCall() {
TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams(); params.sdkAppId = SDKAPPID; // TRTC应用标识, 在控制台获取 params.userSig = USERSIG; // TRTC鉴权凭证, 在服务端生成
params.strRoomId = roomId; // 房间号, 以字符串房间号为例 params.userId = userId; // 用户名, 建议和IM保持同步
mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_SPEECH);
mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_AUDIOCALL);
}
注意:
语音通话模式下,TRTC 进房场景需选用 TRTC_APP_SCENE_AUDIOCALL,同时不要指定进房角色 TRTCRoleType
开始音频采集 startLocalAudio 可同时设置音质参数,语音通话模式建议设置 TRTC_AUDIO_QUALITY_SPEECH
SDK 默认的自动订阅模式下,用户进入房间后,会立刻接收到该房间中的音频流,音频会自动解码播放,无需手动拉流。
2. 进房结果通知,标识通话状态。
// 标记是否正在通话中
boolean isOnCalling = false;

// 进房结果事件回调
@Override
public void onEnterRoom(long result) {
if (result > 0) {
// 进房成功,标识正在通话中
isOnCalling = true;
} else {
// 进房失败,提示通话异常
isOnCalling = false;
}
}

视频通话

1. 主叫端和被叫端均进入同一个 TRTC 房间,开始视频通话。
private void startVideoCall() {
TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();
params.sdkAppId = SDKAPPID; // TRTC应用标识, 在控制台获取
params.userSig = USERSIG; // TRTC鉴权凭证, 在服务端生成
params.strRoomId = roomId; // 房间号, 以字符串房间号为例
params.userId = userId; // 用户名, 建议和IM保持同步
mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_SPEECH);
mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_VIDEOCALL);
}
注意:
视频通话模式下,TRTC 进房场景需选用 TRTC_APP_SCENE_VIDEOCALL,同时不要指定进房角色 TRTCRoleType
开始音频采集 startLocalAudio 可同时设置音质参数,视频通话模式建议设置 TRTC_AUDIO_QUALITY_SPEECH
SDK 默认的自动订阅模式下,音频会自动解码播放,视频需要手动调用 startRemoteView 拉取远端视频流渲染播放。
2. 进房结果通知,标识通话状态,拉取远端视频流。
// 标记是否正在通话中
boolean isOnCalling = false;

// 进房结果事件回调
@Override
public void onEnterRoom(long result) {
if (result > 0) {
// 进房成功,标识正在通话中
isOnCalling = true;
} else {
// 进房失败,提示通话异常
isOnCalling = false;
}
}

// 拉取远端视频流
@Override
public void onUserVideoAvailable(String userId, boolean available) {
// 远端用户发布/取消了主路视频画面
if (available) {
// 订阅远端用户的视频流,并绑定视频渲染控件
mTRTCCloud.startRemoteView(userId, TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_BIG, view);
} else {
// 停止订阅远端用户的视频流,并释放渲染控件
mTRTCCloud.stopRemoteView(userId, TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_BIG);
}
}

步骤四:拒接

时序图





主动拒接

1. 被叫端发送拒绝接听信令
private void rejectInvite(String inviteId, String data, final V2TIMCallback callback) { V2TIMManager.getSignalingManager().reject(inviteId, data, new V2TIMCallback() { @Override public void onError(int code, String desc) { if (callback != null) { callback.onError(code, desc); } } @Override public void onSuccess() { if (callback != null) { callback.onSuccess(); } } }); }

JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("cmd", "av_call");
JSONObject msgJsonObject = new JSONObject();
msgJsonObject.put("callType", "videoCall"); // 指定通话类型(视频通话、语音通话)
msgJsonObject.put("reason", "active"); // 指定拒接类型(主动拒接、忙线拒接)
jsonObject.put("msg", msgJsonObject);
} catch (JSONException e) {
e.printStackTrace();
}

rejectInvite(inviteId, jsonObject.toString(), new V2TIMCallback() { @Override public void onError(int code, String desc) { // 拒接失败,提示异常或重试 } @Override public void onSuccess() { // 拒接成功,销毁呼叫页面,停止播放呼叫铃声 } });
2. 主叫端收到拒绝接听通知
@Override public void onInviteeRejected(String inviteID, String invitee, String data) {
if (!data.isEmpty()) {
try {
JSONObject jsonObject = new JSONObject(data);
String command = jsonObject.getString("cmd");
JSONObject messageJsonObject = jsonObject.getJSONObject("msg");
if (command.equals("av_call")) {
String reason = messageJsonObject.getString("reason");
if (reason.equals("active")) {
// 提示对方拒绝接听
} else if (reason.equals("busy")) {
// 提示对方忙线中
}
// 销毁呼叫页面,停止播放呼叫铃声
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}

忙线拒接

被叫端收到新的呼叫邀请,若判断本地通话状态为正在通话中,则自动忙线拒接。
@Override
public void onReceiveNewInvitation(String inviteID, String inviter,
String groupId, List<String> inviteeList, String data) {
if (!data.isEmpty()) {
try {
JSONObject jsonObject = new JSONObject(data);
String command = jsonObject.getString("cmd");
JSONObject messageJsonObject = jsonObject.getJSONObject("msg");
if (command.equals("av_call") && isOnCalling) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("cmd", "av_call");
JSONObject msgJsonObject = new JSONObject();
msgJsonObject.put("callType", "videoCall"); // 指定通话类型(视频通话、语音通话)
msgJsonObject.put("reason", "busy"); // 指定拒接类型(主动拒接、忙线拒接)
jsonObject.put("msg", msgJsonObject);
} catch (JSONException e) {
e.printStackTrace();
}
// 本地正在通话中,发送忙线拒接信令
rejectInvite(inviteId, jsonObject.toString(), new V2TIMCallback() {
@Override
public void onError(int code, String desc) {
// 忙线拒接失败
}
@Override
public void onSuccess() {
// 忙线拒接成功
}
});
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
注意:
主动拒接和忙线拒接都是使用 reject 信令实现的,但需注意通过信令的自定义数据 datareason 字段加以区分。

步骤五:挂断

时序图





挂断通话

1. 任一端退出房间,重置本地通话状态。
private void hangup() {
mTRTCCloud.stopLocalAudio();
mTRTCCloud.stopLocalPreview();
mTRTCCloud.exitRoom();
}

@Override
public void onExitRoom(int reason) {
// 已成功退出房间并挂断通话
isOnCalling = false;
}
2. 另一端收到远端退房通知,本地执行退房并重置通话状态。
@Override
public void onRemoteUserLeaveRoom(String userId, int reason) {
hangup();
}

@Override
public void onExitRoom(int reason) {
// 已成功退出房间并挂断通话
isOnCalling = false;
}

步骤六:功能控制

打开关闭麦克风

// 打开麦克风
mTRTCCloud.muteLocalAudio(false);
// 关闭麦克风
mTRTCCloud.muteLocalAudio(true);

打开关闭扬声器

// 打开扬声器
mTRTCCloud.muteAllRemoteAudio(false);
// 关闭扬声器
mTRTCCloud.muteAllRemoteAudio(true);

打开关闭摄像头

// 打开摄像头, 指定前置或后置摄像头及渲染控件
mTRTCCloud.startLocalPreview(isFrontCamera, videoView);
// 关闭摄像头
mTRTCCloud.stopLocalPreview();

听筒免提切换

// 切换听筒
mTRTCCloud.getDeviceManager().setAudioRoute(TXDeviceManager.TXAudioRoute.TXAudioRouteEarpiece);
// 切换免提
mTRTCCloud.getDeviceManager().setAudioRoute(TXDeviceManager.TXAudioRoute.TXAudioRouteSpeakerphone);

摄像头切换

// 判断当前是否为前置摄像头
boolean isFrontCamera = mTRTCCloud.getDeviceManager().isFrontCamera();
// 切换前置或后置摄像头, true: 切换为前置; false: 切换为后置
mTRTCCloud.getDeviceManager().switchCamera(!isFrontCamera);

高级功能

网络状态提示

音视频通话过程中,通常需要在对方网络状态较差时给予提示,从而会有通话卡顿的心理预期。
@Override
public void onNetworkQuality(TRTCCloudDef.TRTCQuality localQuality, ArrayList<TRTCCloudDef.TRTCQuality> remoteQuality) {
if (remoteQuality.size() > 0) {
switch (remoteQuality.get(0).quality) {
case TRTCCloudDef.TRTC_QUALITY_Excellent:
Log.i(TAG, "对方网络非常好");
break;
case TRTCCloudDef.TRTC_QUALITY_Good:
Log.i(TAG, "对方网络比较好");
break;
case TRTCCloudDef.TRTC_QUALITY_Poor:
Log.i(TAG, "对方网络一般");
break;
case TRTCCloudDef.TRTC_QUALITY_Bad:
Log.i(TAG, "对方网络较差");
break;
case TRTCCloudDef.TRTC_QUALITY_Vbad:
Log.i(TAG, "对方网络很差");
break;
case TRTCCloudDef.TRTC_QUALITY_Down:
Log.i(TAG, "对方网络极差");
break;
default:
Log.i(TAG, "未定义");
break;
}
}
}
注意:
localQuality 代表本地用户网络质量评估结果,其 userId 字段为空。
remoteQuality 代表远端用户网络质量评估结果,其结果受远端和本地共同影响。

通话时长统计

推荐使用 TRTC 远端用户进房时间作为统计通话时长的开始时间,本地用户退房时间作为统计通话时长的结束时间。
// 开始通话时间
long callStartTime = 0;
// 结束通话时间
long callFinishTime = 0;
// 通话持续时长(秒)
long callDuration = 0;

// 远端用户进房回调
@Override
public void onRemoteUserEnterRoom(String userId) {
callStartTime = System.currentTimeMillis();
}

// 本地用户退房回调
@Override
public void onExitRoom(int reason) {
callFinishTime = System.currentTimeMillis();
callDuration = (callFinishTime - callStartTime) / 1000;
}
注意:
若出现强杀、网络断开等异常结束情形,客户端可能无法统计到相关时间,可通过 服务端事件回调 监听进退房事件统计本次通话时长。

视频美颜特效

TRTC 支持接入第三方美颜特效产品,下面以腾讯特效为例,展示第三方美颜接入流程。
1. 集成腾讯特效 SDK、申请授权 License,详情请参照 秀场直播-接入准备 步骤实现。
2. 资源拷贝(如有)。如果您的资源文件是内置在 assets 目录的,那么使用前需要 copy 到 App 的私有目录。
XmagicResParser.setResPath(new File(getFilesDir(), "xmagic").getAbsolutePath());
//loading

//copy资源文件到私有目录,只需要做一次
XmagicResParser.copyRes(getApplicationContext());
如果您的资源文件是从 网络动态下载 的,下载成功后,需要设置资源文件路径。
XmagicResParser.setResPath(下载的资源文件本地路径);
3. 设置第三方美颜的视频数据回调,将美颜 SDK 处理每帧数据结果传入 TRTC SDK 内部做渲染处理。
mTRTCCloud.setLocalVideoProcessListener(TRTCCloudDef.TRTC_VIDEO_PIXEL_FORMAT_Texture_2D, TRTCCloudDef.TRTC_VIDEO_BUFFER_TYPE_TEXTURE, new TRTCCloudListener.TRTCVideoFrameListener() {
@Override
public void onGLContextCreated() {
// SDK 内部 OpenGL 环境已经创建,此时可进行第三方美颜的初始化工作
if (mXmagicApi == null) {
XmagicApi mXmagicApi = new XmagicApi(context, XmagicResParser.getResPath(), new XmagicApi.OnXmagicPropertyErrorListener());
} else {
mXmagicApi.onResume();
}
}

@Override
public int onProcessVideoFrame(TRTCCloudDef.TRTCVideoFrame srcFrame, TRTCCloudDef.TRTCVideoFrame dstFrame) {
// 用于对接第三方美颜组件的视频处理回调
if (mXmagicApi != null) {
dstFrame.texture.textureId = mXmagicApi.process(srcFrame.texture.textureId, srcFrame.width, srcFrame.height);
}
return 0;
}

@Override
public void onGLContextDestory() {
// SDK 内部 OpenGL 环境被销毁,此时可进行第三方美颜的资源销毁工作
mXmagicApi.onDestroy();
}
});
注意:
步骤1、步骤2根据不同的第三方美颜产品实现方式有所不同,步骤3 是 TRTC 集成第三方美颜的 通用且重要步骤
场景化集成腾讯美颜特效指引详见 TRTC SDK 集成腾讯特效,独立集成腾讯美颜特效指引详见 独立集成腾讯特效

大小窗口切换

TRTC 中有很多需要操控视频画面的接口,这些接口都需要您指定视频渲染控件。在 Android 平台中,使用 TXCloudVideoView 作为视频渲染控件,支持 SurfaceViewTextureView 两种渲染方案。下面介绍指定渲染控件类型,以及更新视频渲染控件的方法。
1. 如果您希望强制使用某一种方案,或者将本地视频渲染控件转换为 TXCloudVideoView,您可以按照如下方法进行编码。
// 强制使用 TextureView
TextureView textureView = findViewById(R.id.texture_view);
TXCloudVideoView cloudVideoView = new TXCloudVideoView(context);
cloudVideoView.addVideoView(textureView);

// 强制使用 SurfaceView
SurfaceView surfaceView = findViewById(R.id.surface_view);
TXCloudVideoView cloudVideoView = new TXCloudVideoView(surfaceView);
2. 如果您业务涉及到切换显示区域的交互场景,可以使用 TRTC SDK 更新本地预览画面、更新远端用户视频渲染控件功能实现。
// 更新本地预览画面渲染控件
mTRTCCloud.updateLocalView(videoView);

// 更新远端用户视频渲染控件
mTRTCCloud.updateRemoteView(userId, streamType, videoView);
注意:
videoViewTXCloudVideoView 类型的目标视频渲染控件,streamType 仅支持 TRTC_VIDEO_STREAM_TYPE_BIGTRTC_VIDEO_STREAM_TYPE_SUB

离线推送消息

音视频通话场景通常需要用到离线推送消息,使得被叫用户 App 不在线时也能收到来电消息。离线推送集成指引详见 离线消息推送,下面我们重点介绍其中步骤七:发送离线推送消息、步骤八:解析离线推送消息 的实现方法。

发送离线推送消息

调用 invite 发送通话邀请时,您可通过 V2TIMOfflinePushInfo 设置离线推送参数。调用 V2TIMOfflinePushInfo 的 setExt 设置自定义 ext 数据,当用户收到离线推送启动 App 的时候,可以在单击通知跳转的回调中获取到 ext 字段,然后根据 ext 字段内容跳转到指定的 UI 界面。
JSONObject contentObj = new JSONObject();
try {
contentObj.put("cmd", "av_call");
JSONObject contentDetailObj = new JSONObject();
contentDetailObj.put("callType", "videoCall");
contentDetailObj.put("roomId", generateRoomId());
contentObj.put("cmdInfo", contentDetailObj);
} catch (JSONException e) {
e.printStackTrace();
}
String data = contentObj.toString();

// OfflineMessageContainerBean 是 TUIKitDemo 的透传参数 ext 对应的 Javabean
OfflineMessageContainerBean containerBean = new OfflineMessageContainerBean(); OfflineMessageBean entity = new OfflineMessageBean();
entity.content = data; entity.sender = TUILogin.getLoginUser();
entity.action = OfflineMessageBean.REDIRECT_ACTION_CALL; entity.sendTime = System.currentTimeMillis() / 1000; entity.nickname = mNickname; entity.faceUrl = mFaceUrl; containerBean.entity = entity; V2TIMOfflinePushInfo v2TIMOfflinePushInfo = new V2TIMOfflinePushInfo(); v2TIMOfflinePushInfo.setExt(new Gson().toJson(containerBean).getBytes()); // OPPO 必须设置 ChannelID 才可以收到推送消息,这个 ChannelID 需要和控制台一致 v2TIMOfflinePushInfo.setAndroidOPPOChannelID("tuikit");
v2TIMOfflinePushInfo.setAndroidHuaWeiCategory("IM");
v2TIMOfflinePushInfo.setAndroidVIVOCategory("IM");
v2TIMOfflinePushInfo.setTitle(mNickname); v2TIMOfflinePushInfo.setDesc("You have a new call invitation"); // 设置自定义铃声 v2TIMOfflinePushInfo.setIOSSound("phone_ringing.mp3");
v2TIMOfflinePushInfo.setAndroidSound("phone_ringing");

V2TIMManager.getSignalingManager().invite(receiver, data, false, v2TIMOfflinePushInfo, timeout, new V2TIMCallback() {
@Override
public void onError(int code, String desc) {
// 发送呼叫邀请失败
}

@Override
public void onSuccess() {
// 发送呼叫邀请成功
}
});
注意:
为了兼容不同平台对离线推送消息的解析格式,建议通过包装类 OfflineMessageContainerBean 对透传参数 ext 进行设置。

解析离线推送消息

收到离线推送的通知栏消息,点击会自动跳转到您在之前配置的跳转界面,可以在界面启动的 onResume() 方法中,调用 getIntent().getExtras() 获取透传的离线推送参数再自定义跳转。具体可以参照 TUIKitDemo 的 handleOfflinePush() 方法。
private void handleOfflinePush() {
// 根据登录状态,判断是否需要重新登录 IM
// 1. 如果登录状态为 V2TIMManager.V2TIM_STATUS_LOGOUT,跳转到登录界面,重新登录 IM
if (V2TIMManager.getInstance().getLoginStatus() == V2TIMManager.V2TIM_STATUS_LOGOUT) {
Intent intent = new Intent(MainActivity.this, SplashActivity.class);
if (getIntent() != null) {
intent.putExtras(getIntent());
}
startActivity(intent);
finish();
return;
}

// 2. 否则,说明 App 只是处于退后台的状态,直接解析离线推送参数
final OfflineMessageBean bean = OfflineMessageDispatcher.parseOfflineMessage(getIntent());
if (bean != null) {
setIntent(null);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (manager != null) {
manager.cancelAll();
}

if (bean.action == OfflineMessageBean.REDIRECT_ACTION_CALL) {
Intent startActivityIntent = new Intent(context, MyCustomActivity.class);
startActivityIntent.putExtras(getIntent());
startActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startActivityIntent);
}
}
}
注意:
FCM 单击通知栏的消息会默认跳转至应用的默认 Launcher 界面,您可以在界面启动的 onResume() 方法中,通过调用 getIntent().getExtras() 获取透传的离线推送参数再自定义跳转。

异常处理

TRTC 异常错误处理

TRTC SDK 遇到不可恢复的错误会在 onError 回调中抛出,详见 错误码表

UserSig 相关

UserSig 校验失败会导致进房失败,您可使用 UserSig 工具 进行校验。
枚举
取值
描述
ERR_TRTC_INVALID_USER_SIG
-3320
进房参数 userSig 不正确,请检查 TRTCParams.userSig 是否为空。
ERR_TRTC_USER_SIG_CHECK_FAILED
-100018
UserSig 校验失败,请检查参数 TRTCParams.userSig 是否填写正确或已经过期。

进退房相关

进房失败请先检查进房参数是否正确,且进退房接口必须成对调用,即便进房失败也需要调用退房接口。
枚举
取值
描述
ERR_TRTC_CONNECT_SERVER_TIMEOUT
-3308
请求进房超时,请检查是否断网或者是否开启 VPN,您也可以切换4G进行测试。
ERR_TRTC_INVALID_SDK_APPID
-3317
进房参数 sdkAppId 错误,请检查 TRTCParams.sdkAppId 是否为空
ERR_TRTC_INVALID_ROOM_ID
-3318
进房参数 roomId 错误,请检查 TRTCParams.roomIdTRTCParams.strRoomId 是否为空,注意 roomId 和 strRoomId 不可混用。
ERR_TRTC_INVALID_USER_ID
-3319
进房参数 userId 不正确,请检查 TRTCParams.userId 是否为空。
ERR_TRTC_ENTER_ROOM_REFUSED
-3340
进房请求被拒绝,请检查是否连续调用 enterRoom 进入相同 Id 的房间。

设备相关

可监听设备相关错误,在出现相关错误时 UI 提示用户。
枚举
取值
描述
ERR_CAMERA_START_FAIL
-1301
打开摄像头失败,例如在 Windows 或 Mac 设备,摄像头的配置程序(驱动程序)异常,禁用后重新启用设备,或者重启机器,或者更新配置程序。
ERR_MIC_START_FAIL
-1302
打开麦克风失败,例如在 Windows 或 Mac 设备,麦克风的配置程序(驱动程序)异常,禁用后重新启用设备,或者重启机器,或者更新配置程序。
ERR_CAMERA_NOT_AUTHORIZED
-1314
摄像头设备未授权,通常在移动设备出现,可能是权限被用户拒绝了。
ERR_MIC_NOT_AUTHORIZED
-1317
麦克风设备未授权,通常在移动设备出现,可能是权限被用户拒绝了。
ERR_CAMERA_OCCUPY
-1316
摄像头正在被占用中,可尝试打开其他摄像头。
ERR_MIC_OCCUPY
-1319
麦克风正在被占用中,例如移动设备正在通话时,打开麦克风会失败。

收不到离线推送排查

1. 发送消息为自定义消息
自定义消息的离线推送和普通消息不太一样,自定义消息的内容我们无法解析,不能确定推送的内容,所以默认不推送,如果您有推送需求,需要您在 sendMessage 的时候设置 offlinePushInfodesc 字段,推送的时候会默认展示 desc 信息。
2. 设备通知栏设置影响
离线推送的直观表现就是通知栏提示,所以同其他通知一样受设备通知相关设置的影响,以华为为例:
“手机设置-通知-锁屏通知-隐藏或者不显示通知”,会影响锁屏状态下离线推送通知显示。
“手机设置-通知-更多通知设置-状态栏显示通知图标”,会影响状态栏下离线推送通知的图标显示。
“手机设置-通知-应用的通知管理-允许通知”,打开关闭会直接影响离线推送通知显示。
“手机设置-通知-应用的通知管理-通知铃声” 和 “手机设置-通知-应用的通知管理-静默通知”,会影响离线推送通知铃音的效果。
3. 按照流程接入完成,还是收不到离线推送
首先在 IM 控制台通过 离线测试工具 自测下是否可以正常推送。 推送异常情况,设备状态异常,需要检查下 IM 控制台配置各项参数是否正确,再者需要检查下代码初始化注册逻辑,包括厂商推送服务注册和 IM 设置离线推送配置相关逻辑是否正确设置。 推送异常情况,设备状态正常,需要看下是否需要正确填写 channel ID 或者后台服务是否正常。
离线推送依赖厂商能力,一些简单的字符可能会被厂商过滤不能透传推送。
如果离线推送消息出现推送不及时或者偶尔收不到情况,需要看下厂商的推送限制。

跳转界面不成功

单击离线推送消息的通知栏,跳转到指定界面,原理是后台根据您在控制台配置的各个厂商的跳转方式和界面参数,根据厂商接口规则,传递给厂商服务器,单击时进行对应界面启动跳转。对应界面启动还依赖清单文件的配置,必须和控制台配置的相对应,才能正确启动和跳转。
1. 首先需要重点排查下控制台和清单文件相关配置是否对应且正确,可参见 TUIKitDemo 的配置,注意部分厂商提供接口方式存在差异。
2. 如果跳转到了配置的界面,需要再看下配置界面内离线消息的解析和界面重定向是否正常。
本页内容是否解决了您的问题?
您也可以 联系销售 提交工单 以寻求帮助。

文档反馈