我们项目需要实现康复师和患者之间的视频问诊功能。技术栈是 uni-app(Vue 3 模式),在评估了腾讯云 TUICallKit 后,发现它无法满足我们的需求,uniapp客户端开发使用限制太多,官方现成的SDK用不了,于是选择直接接入 TRTC SDK。
然后问题来了。
TRTC 的官方文档分散在好几个地方:有腾讯云官网的通用文档、有 DCloud 插件市场的简要说明、有 GitHub 上的 Demo README……。API 有 50 多个、事件有 30 多种、iOS 和 Android 的差异藏在源码的各个角落。
这篇文章就是我在项目里完整走了一遍 TRTC 集成后整理的一站式参考手册。从架构到 API 到踩坑,全部覆盖。
SDK 版本:v1.2.0 | 基于 TRTC_UniApp/Api-Example 工程分析 | 官方文档:web.sdk.qcloud.com/trtc/uniapp…
一、4 层架构:一个 API 调用到底经历了什么
理解架构是排查问题的前提。TRTC UniApp SDK 分为清晰的 4 层:
┌─────────────────────────────────────────────────────┐
│ 业务页面 (.nvue) │
│ 调用 this.trtcCloud.enterRoom / startLocalPreview │
├─────────────────────────────────────────────────────┤
│ TrtcCloud (lib/index.js) │
│ 公开 API 封装层,单例模式,EventEmitter 风格 │
├─────────────────────────────────────────────────────┤
│ TrtcCloudImpl (lib/TrtcCloudImpl.js) │
│ 单例管理、参数校验、事件回调转换、原生模块桥接 │
├─────────────────────────────────────────────────────┤
│ 原生插件 (uni.requireNativePlugin) │
│ - TRTCCloudUniPlugin-TRTCCloudImpl │
│ - TXAudioEffectManagerModule │
│ - TRTCCloudUniPlugin-TXLocalViewComponent │
│ - TRTCCloudUniPlugin-TXRemoteViewComponent │
├─────────────────────────────────────────────────────┤
│ 腾讯云 TRTC 原生 SDK (Android/iOS) │
└─────────────────────────────────────────────────────┘
工程结构:
Api-Example/
├── TrtcCloud/ # 🔴 核心 SDK 封装层
│ ├── lib/
│ │ ├── index.js # TrtcCloud 主类(公开 API)
│ │ ├── TrtcCloudImpl.js # 原生桥接实现
│ │ ├── TrtcDefines.js # 所有枚举/类型定义
│ │ ├── TrtcCode.js # 完整错误码/警告码
│ │ └── constants.js # 平台常量
│ ├── view/
│ │ ├── TrtcLocalView.nvue # 本地视频渲染组件
│ │ └── TrtcRemoteView.nvue # 远端视频渲染组件
│ └── permission.js # iOS/Android 权限工具
├── debug/
│ └── GenerateTestUserSig.js # UserSig 生成(⚠️ 仅调试用)
└── pages/examples/ # 13 个示例页面
二、核心 API 全景
2.1 生命周期
import TrtcCloud from '@/TrtcCloud/lib/index';
// 创建单例(只能通过工厂方法)
const trtcCloud = TrtcCloud.createInstance();
// 销毁实例
TrtcCloud.destroyInstance();
2.2 事件系统
// 注册事件(类 EventEmitter)
trtcCloud.on('onEnterRoom', (result) => {
if (result > 0) console.log(`进房成功,耗时 ${result}ms`);
else console.error(`进房失败,错误码 ${result}`);
});
trtcCloud.on('onRemoteUserEnterRoom', (userId) => {
console.log(`用户 ${userId} 进入了房间`);
});
// 移除监听
trtcCloud.off('onEnterRoom');
trtcCloud.off('*'); // 移除所有
2.3 房间管理
| 方法 | 说明 |
|---|---|
enterRoom(params, scene) | 进入房间 |
exitRoom() | 退出房间 |
switchRole(role) | 切换角色(主播 ↔ 观众) |
进房参数 TRTCParams:
const params = {
sdkAppId: 1400000000, // 腾讯云应用 ID(必填)
userId: 'user_123', // 用户标识(必填)
userSig: 'xxx', // 用户签名(必填,服务端生成)
roomId: 12345, // 房间号(数字),与 strRoomId 二选一
// strRoomId: 'room_abc', // 字符串房间号(选填)
role: TRTCRoleAnchor, // 直播场景角色(选填)
};
trtcCloud.enterRoom(params, TRTCAppSceneVideoCall);
4 种应用场景:
| 场景 | 值 | 特点 | 适用 |
|---|---|---|---|
TRTCAppSceneVideoCall | 0 | 720P/1080P,300人在线,50人同时发言 | 视频通话 |
TRTCAppSceneLIVE | 1 | 主播<300ms延迟,十万人级别 | 互动直播 |
TRTCAppSceneAudioCall | 2 | 48kHz 双声道 | 语音通话 |
TRTCAppSceneVoiceChatRoom | 3 | K歌房、FM 电台 | 语音聊天室 |
⚠️ LIVE 和 VoiceChatRoom 场景必须通过
TRTCParams.role指定角色。
角色类型:
| 角色 | 说明 |
|---|---|
TRTCRoleAnchor(20) | 主播,可上行音视频,最多 50 人 |
TRTCRoleAudience(21) | 观众,只能观看,无人数上限 |
2.4 本地视频
| 方法 | 说明 |
|---|---|
startLocalPreview(front, viewId) | 开启本地预览(front=true 前置摄像头) |
stopLocalPreview() | 停止本地预览 |
switchCamera(front) | 切换前后摄像头 |
2.5 本地视频控制
| 方法 | 说明 |
|---|---|
muteLocalVideo(streamType, mute) | 静音/恢复本地视频 |
setVideoEncoderParam(param) | 设置视频编码参数 |
setLocalRenderParams(params) | 设置本地渲染参数(旋转、填充、镜像) |
视频分辨率选择:
| 分辨率 | VideoCall 建议码率 | LIVE 建议码率 |
|---|---|---|
| 480×360 | 400kbps | 600kbps |
| 640×360 | 500kbps | 900kbps |
| 960×540 | 850kbps | 1300kbps |
| 1280×720 | 1200kbps | 1800kbps |
| 1920×1080 | 2000kbps | 3000kbps |
2.6 远端视频
| 方法 | 说明 |
|---|---|
startRemoteView(userId, streamType, viewId) | 开始渲染远端画面 |
stopRemoteView(userId, streamType) | 停止渲染远端画面 |
setRemoteRenderParams(userId, streamType, params) | 设置远端渲染参数 |
视频流类型:
| 类型 | 说明 |
|---|---|
TRTCVideoStreamTypeBig(0) | 高清大画面(摄像头主画面) |
TRTCVideoStreamTypeSmall(1) | 低清小画面 |
TRTCVideoStreamTypeSub(2) | 辅流(屏幕分享) |
2.7 本地音频
| 方法 | 说明 |
|---|---|
startLocalAudio(quality) | 开启本地音频采集 |
stopLocalAudio() | 停止本地音频采集 |
muteLocalAudio(mute) | 静音/恢复本地音频 |
setAudioRoute(route) | 切换听筒(1) / 扬声器(0) |
2.8 远端音频
| 方法 | 说明 |
|---|---|
muteRemoteAudio(userId, mute) | 静音/恢复指定远端用户 |
muteAllRemoteAudio(mute) | 静音/恢复全部远端用户 |
enableAudioVolumeEvaluation(interval) | 开启音量回调(每 interval ms) |
⚠️
enableAudioVolumeEvaluation必须在startLocalAudio之前调用才生效。
2.9 屏幕分享(iOS 13+ / Android 5.0+)
| 方法 | 说明 |
|---|---|
startScreenCapture(streamType, encParams) | 开始屏幕分享 |
stopScreenCapture() | 停止屏幕分享 |
pauseScreenCapture() | 暂停 |
resumeScreenCapture() | 恢复 |
⚠️ iOS 端仅支持应用内屏幕分享(startScreenCaptureInApp),不支持全系统分享(ReplayKit 方式)。
2.10 美颜、音效、截图、消息
| 方法 | 说明 |
|---|---|
setBeautyStyle(style) | 美颜风格:光滑/自然/优图 |
setBeautyLevel(0-9) | 美颜级别,0=关闭 |
startPlayMusic(musicParam) | 播放背景音乐(支持本地/远端) |
stopPlayMusic(id) | 停止播放 |
snapshotVideo(userId, streamType) | 视频截图(返回 base64) |
sendCustomCmdMsg({cmdID, data, reliable, ordered}) | 发送自定义 UDP 消息 |
⚠️
setBeautyLevel必须在setBeautyStyle之前调用。
三、事件系统完全指南
所有事件通过 trtcCloud.on(eventName, callback) 注册。以下是完整事件列表:
3.1 核心事件
| 事件 | 参数 | 触发时机 |
|---|---|---|
onError | {code, message, extraInfo} | SDK 不可恢复错误 |
onWarning | {code, message, extraInfo} | 非严重警告(卡顿等) |
onEnterRoom | result(>0=耗时ms, <0=错误码) | 进房完成 |
onExitRoom | reason(0=主动退出, 1=被踢, 2=房间解散) | 退房完成 |
3.2 远端用户事件
| 事件 | 参数 | 触发时机 |
|---|---|---|
onRemoteUserEnterRoom | userId | 远端用户进房 |
onRemoteUserLeaveRoom | {userId, reason} | 远端用户退房 |
onUserVideoAvailable | {userId, available} | 远端视频开关 ⭐ |
onUserAudioAvailable | {userId, available} | 远端音频开关 |
onUserSubStreamAvailable | {userId, available} | 辅流(屏幕分享)开关 |
3.3 音视频状态事件
| 事件 | 参数 | 触发时机 |
|---|---|---|
onFirstVideoFrame | {userId, streamType, width, height} | 首帧画面开始渲染 |
onFirstAudioFrame | userId | 首帧音频开始播放 |
onMicDidReady | — | 麦克风就绪 |
onCameraDidReady | — | 摄像头就绪 |
onUserVideoSizeChanged | data[] | 视频分辨率变化 |
onUserVoiceVolume | {userVolumes[], totalVolume} | 音量回调(每 interval ms) |
3.4 网络与统计
| 事件 | 参数 | 触发时机 |
|---|---|---|
onNetworkQuality | {localQuality, remoteQuality} | 网络质量(每 2s) |
onStatistics | statics 对象 | 技术指标统计(每 2s) |
3.5 屏幕分享事件
| 事件 | 参数 |
|---|---|
onScreenCaptureStarted | {code, message} |
onScreenCaptureStopped | {code, message} |
onScreenCapturePaused | {code, message} |
onScreenCaptureResumed | {code, message} |
3.6 其他事件
| 事件 | 参数 | 说明 |
|---|---|---|
onSnapshotComplete | {base64Data, message} | 截图完成 |
onRecvCustomCmdMsg | {userId, cmdID, seq, message} | 收到自定义消息 |
onStart / onPlayProgress / onComplete | {id, ...} | 背景音乐播放回调 |
四、iOS 端配置
4.1 manifest.json
{
"app-plus": {
"distribute": {
"ios": {
"privacyDescription": {
"NSCameraUsageDescription": "需要访问你的摄像头进行视频通话",
"NSMicrophoneUsageDescription": "需要访问你的麦克风进行语音通话",
"NSPhotoLibraryUsageDescription": "需要访问你的相册",
"NSPhotoLibraryAddUsageDescription": "需要访问你的相册"
}
}
},
"nativePlugins": {
"TRTCCloudUniPlugin-TRTCCloudImpl": {
"__plugin_info__": {
"name": "TRTCCloudUniPlugin-TRTCCloudImpl",
"platforms": "Android,iOS"
}
}
}
}
}
4.2 iOS 权限检查
TRTC 示例提供了 5 种 iOS 权限的检测方法:
| 方法 | 检查权限 | 调用原生 API |
|---|---|---|
judgeIosPermissionCamera() | 相机 | AVCaptureDevice.authorizationStatusForMediaType('vide') |
judgeIosPermissionRecord() | 麦克风 | AVAudioSession.sharedInstance().recordPermission() |
judgeIosPermissionPush() | 推送通知 | UIApplication.sharedApplication().currentUserNotificationSettings |
judgeIosPermissionLocation() | 定位 | CLLocationManager.authorizationStatus() |
judgeIosPermissionPhotoLibrary() | 相册 | PHPhotoLibrary.authorizationStatus() |
import permission from '@/TrtcCloud/permission.js';
// 使用示例
const hasCamera = permission.judgeIosPermission('camera');
// 跳转系统设置
permission.gotoAppPermissionSetting();
4.3 iOS 特别注意事项
- iOS 切换到后台时硬编码器可能被系统释放,回到前台时可能短暂抛
ERR_VIDEO_ENCODE_FAIL(-1303) - 屏幕分享仅支持应用内(iOS 13.0+),不支持全系统级别
- 视频渲染必须用 nvue 的原生组件
<trtc-local-view>和<trtc-remote-view>
五、Android 端配置
5.1 manifest.json 权限
"android": {
"permissions": [
"android.permission.CAMERA",
"android.permission.RECORD_AUDIO",
"android.permission.INTERNET",
"android.permission.ACCESS_NETWORK_STATE",
"android.permission.WRITE_EXTERNAL_STORAGE",
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.MODIFY_AUDIO_SETTINGS"
],
"autoSdkPermissions": true
}
5.2 运行时权限
if (uni.getSystemInfoSync().platform === 'android') {
permission.requestAndroidPermission('android.permission.RECORD_AUDIO');
permission.requestAndroidPermission('android.permission.CAMERA');
}
5.3 注意
打自定义基座时必须勾选音频相关权限,否则音频路由切换会失效。
六、标准集成流程(6 步代码模板)
import TrtcCloud from '@/TrtcCloud/lib/index';
import { TRTCAppScene, TRTCVideoStreamType, TRTCAudioQuality } from '@/TrtcCloud/lib/TrtcDefines';
import permission from '@/TrtcCloud/permission.js';
export default {
data() {
return {
trtcCloud: null,
userId: 'user_' + Math.random().toString(36).substr(2, 9),
remoteUserId: null,
};
},
mounted() {
// ① 创建实例
this.trtcCloud = TrtcCloud.createInstance();
// ② 注册事件
this.trtcCloud.on('onEnterRoom', (result) => {
if (result > 0) {
console.log(`进房成功,耗时 ${result}ms`);
} else {
uni.showToast({ title: `进房失败: ${result}`, icon: 'none' });
}
});
this.trtcCloud.on('onRemoteUserEnterRoom', (userId) => {
this.remoteUserId = userId;
});
this.trtcCloud.on('onUserVideoAvailable', ({ userId, available }) => {
if (available) {
// 有远端视频流 → 开始渲染
this.trtcCloud.startRemoteView(userId, TRTCVideoStreamTypeBig, userId);
} else {
this.trtcCloud.stopRemoteView(userId, TRTCVideoStreamTypeBig);
}
});
// ③ 请求权限
if (uni.getSystemInfoSync().platform === 'android') {
permission.requestAndroidPermission('android.permission.RECORD_AUDIO');
permission.requestAndroidPermission('android.permission.CAMERA');
}
},
methods: {
async startCall() {
// ④ 进房
const params = {
sdkAppId: YOUR_SDK_APP_ID,
userId: this.userId,
roomId: 12345,
userSig: await this.getUserSig(), // ⚠️ 服务端获取!
};
this.trtcCloud.enterRoom(params, TRTCAppSceneVideoCall);
},
onJoinRoom() {
// ⑤ 开启本地音视频(建议在进房成功后调用)
this.trtcCloud.startLocalPreview(true, this.userId);
this.trtcCloud.startLocalAudio(TRTCAudioQualityDefault);
},
onLeaveRoom() {
// ⑥ 退房清理
this.trtcCloud.stopLocalPreview();
this.trtcCloud.stopLocalAudio();
this.trtcCloud.exitRoom();
},
},
onUnload() {
this.trtcCloud?.off('*');
TrtcCloud.destroyInstance();
this.trtcCloud = null;
},
};
七、13 个场景示例速览
官方 Demo 提供了 13 个示例页面,覆盖常见使用场景:
| 页面 | 关键 API |
|---|---|
| 1v1 音视频通话 | enterRoom, startLocalPreview, startRemoteView, switchCamera |
| 多人音视频 | 同上 + 动态远端 View 管理 |
| 视频通话 | 纯视频模式 |
| 语音通话 | startLocalAudio, muteLocalAudio, setAudioRoute |
| 本地画面渲染 | setLocalRenderParams(rotation, fillMode, mirrorType) |
| 远端画面渲染 | setRemoteRenderParams |
| 本地编码设置 | setVideoEncoderParam |
| 角色切换 | switchRole(Anchor/Audience) |
| 悬浮窗本地预览 | startLocalPreview + 悬浮窗布局 |
| 屏幕分享 | startScreenCapture, pause/resume |
| 视频截图 | snapshotVideo → onSnapshotComplete |
| 背景音效 | startPlayMusic → onPlayProgress → onComplete |
| 自定义消息 | sendCustomCmdMsg → onRecvCustomCmdMsg |
八、常见错误码速查
进房相关
| 错误码 | 含义 |
|---|---|
-3301 | 进入房间失败 |
-3316 | 进房参数为空 |
-3317 | sdkAppId 错误 |
-3318 | roomId 错误 |
-3319 | userId 不正确 |
-3320 | userSig 不正确 |
-3308 | 请求进房超时 |
-100013 | 服务不可用(套餐包用完/欠费) |
设备相关
| 错误码 | 含义 |
|---|---|
-1301 | 打开摄像头失败 |
-1314 | 摄像头未授权 |
-1316 | 摄像头被占用 |
-1302 | 打开麦克风失败 |
-1317 | 麦克风未授权 |
-1319 | 麦克风被占用 |
-1308 | 开始录屏失败 |
UserSig 相关
| 错误码 | 含义 |
|---|---|
-70001 | userSig 已过期 |
-70013 | userId 与 userSig 不匹配 |
-70014 | sdkAppId 与 userSig 不匹配 |
-70020 | sdkAppId 未找到 |
-70052 | userSig 已失效 |
九、踩坑记录 ⭐
这些注意事项每一条都是实战中踩出来的坑。
1. 必须用自定义基座运行
TRTC 依赖原生插件,不能直接在 HBuilder 标准基座中运行。必须打包自定义调试基座,且在真机上运行(模拟器不支持)。
2. 必须用 nvue 页面
所有视频页面必须是 .nvue 格式,<trtc-local-view> 和 <trtc-remote-view> 是原生组件,只在 nvue 中可用。
3. startLocalPreview 报 -2 错误?
原因:没有实例化本地预览的 view。解决方案:
- 确认页面是
.nvue文件 - 页面必须包含
<trtc-local-view>并绑定 viewId startLocalPreview的 viewId 参数需与组件 viewId 一致
4. 退房后必须等 onExitRoom 回调
调用 exitRoom() 后需要等待 onExitRoom 回调完成,才能再次 enterRoom,否则会出现设备被占用等异常。
5. muteLocalAudio vs stopLocalAudio
muteLocalAudio:发送极低码率静音包,录制兼容性好stopLocalAudio:完全停止采集和发送,录制出的 MP4 可能不完整- 推荐用
muteLocalAudio,除非你确实不需要录制
6. setBeautyLevel 必须在 setBeautyStyle 之前
美颜级别为 0 表示关闭美颜。先设级别再设风格,顺序不能反。
7. enableAudioVolumeEvaluation 必须在 startLocalAudio 之前
否则音量回调不会生效。
8. UserSig 安全警告 ⚠️
// ⚠️ Demo 中的 GenerateTestUserSig.js 仅用于本地调试!
// 生产环境必须在服务端生成 UserSig
// 绝对不要把 SecretKey 放在客户端代码中
9. 与 livepusher 模块冲突
uni-app 内置的 livepusher 使用 LiteAVSDK 推流版,TRTC 插件使用 LiteAVSDK_TRTC 版,两个 .aar 有类冲突。不能同时使用,必须二选一。
10. TRTC SDK vs TUICallKit
| TRTC SDK | TUICallKit | |
|---|---|---|
| 定位 | 音视频基础能力,无 UI | 包含 UI 和通话逻辑 |
| 适用场景 | 复杂定制场景(在线问诊、视频指导) | 1v1/多人标准通话 |
| 接入难度 | 需自行搭建业务逻辑 | 开箱即用 |
当 TUICallKit 无法满足需求时(如我们的视频问诊场景),使用 TRTC SDK 自行搭建。
11. 大小窗切换方案
同一用户使用两个 <trtc-remote-view> 绑定不同 viewId,通过 v-if 切换显示:
<trtc-remote-view v-if="!isSmall" class="big-view"
:userId="remoteUserId" viewId="remoteBigID" />
<trtc-remote-view v-if="isSmall" class="small-view"
:userId="remoteUserId" viewId="remoteSmallID" />
12. 不支持离线 .aar 打包
仅支持 HBuilder 中通过「本地插件」或「云端插件」方式打包。
十、集成 Checklist
接入 TRTC 前,对照这个清单逐一确认:
- 腾讯云已开通 TRTC 服务,获取 SDKAppID 和 SecretKey
- DCloud 插件市场已导入腾讯云原生音视频插件
- 页面使用
.nvue格式 - 已打包自定义调试基座
- manifest.json 已配置 iOS 隐私描述和 Android 权限
- 运行时权限请求已添加
- UserSig 在生产环境由服务端生成(不在客户端拼接 SecretKey)
-
onUnload/onBackPress中已处理实例销毁 - 退房后等待
onExitRoom回调再操作 - 真机测试通过(模拟器不支持)
总结
TRTC UniApp SDK 的核心要点:
- 4 层架构:业务 .nvue → TrtcCloud → TrtcCloudImpl → 原生插件 → 原生 SDK
- 50+ API 覆盖房间管理、音视频控制、屏幕分享、美颜、截图、消息
- 30+ 事件 覆盖进房/退房、远端流状态、网络质量、屏幕分享、音频播放
- 必须 nvue + 自定义基座,标准基座和模拟器都不行
- UserSig 安全第一,SecretKey 永远不要出现在客户端
- 生命周期管理很重要,退房等回调、销毁清监听、前后台保护编码器
标签:
uni-appTRTC腾讯云音视频实时通信nvue原生插件