有奖:语音产品征文挑战赛火热进行中> HOT

业务流程

本节汇总了秀场直播中一些常见的业务流程,帮助您更好地理解整个场景的实现流程。
主播开播及关播
主播跨房 PK 连麦
RTC 观众进房连麦
CDN 观众进房连麦
下图展示了主播(房主)本地预览、创建房间、进房开播、退房关播的流程。
?
?
?
下图展示了主播 A 邀请主播 B 进行跨房 PK 连麦的流程。跨房 PK 过程中,两个房间内的观众都可以看到两个房主 PK 连麦直播的画面。
?
?
?
下图展示了 RTC 实时互动直播间观众进入房间、申请连麦、结束连麦、退出房间的流程。
?
?
?
下图展示了 RTC 旁路直播间 CDN 观众进入房间、申请连麦、结束连麦、退出房间的流程。
?
?
?

接入准备

步骤一:开通服务

秀场直播场景通常需要依赖腾讯云 实时音视频 TRTC腾讯美颜特效 两项付费 PaaS 服务构建。其中 TRTC 负责提供实时音视频互动能力,腾讯特效负责提供美颜特效能力。如果您使用第三方美颜产品,可忽略腾讯特效集成部分。
开通 TRTC 服务
开通腾讯特效服务
1. 首先,您需要登录 实时音视频 TRTC 控制台 创建应用,您可根据需要选择升级 TRTC 应用版本,例如旗舰版可解锁更多增值功能服务。
?
?
?
说明:
建议创建两个应用分别用于测试环境和生产环境,首次开通 TRTC 服务可前往 试用中心 免费领取 10000 分钟试用时长包。
TRTC 包月套餐(入门版、基础版、尊享版、旗舰版)可以解锁不同的增值功能服务,详情可见 包月套餐说明
2. 应用创建完毕之后,您可以在应用管理-应用概览栏目看到该应用的基本信息,其中需要您保管好 SDKAppIDSDKSecretKey 便于后续使用,同时应避免密钥泄露造成流量盗刷。
?
?
?
1. 首先,您需要登录 腾讯云视立方控制台 > 移动端 License,单击新建测试 License。测试版 License 免费测试有效期为14天,可续期一次共28天。根据实际需求填写 App NamePackage NameBundle ID,选择腾讯特效,选择所需测试的能力:高级套餐 S1-07原子能力 X1-01原子能力 X1-02、原子能力 X1-03,勾选后准确填写 公司名称、所属行业类型,上传公司营业执照单击确定提交审核申请,等待人工审核流程。
?
?
?
2. 测试版 License 成功创建后,页面会显示生成的 License 信息。此时 Key 和 LicenseURL 两个参数暂未生效,等待提交审核通过后方可生效使用。在 SDK 初始化配置时需要传入 License URL 和 License Key 两个参数,请妥善保存以下信息
?
?
?

步骤二:导入 SDK

TRTC SDK 和腾讯特效 SDK 已经发布到 mavenCentral 库,您可以通过配置 gradle 自动下载更新。
1. 在 dependencies 中添加合适版本 SDK 的依赖。
// TRTC 精简版 SDK, 包含 TRTC 和直播播放两项功能, 体积小巧
dependencies {
implementation 'com.tencent.liteav:LiteAVSDK_TRTC:latest.release'
}
?
// TRTC 全功能版 SDK, 另含直播、短视频、点播等多项功能, 体积略大
dependencies {
implementation 'com.tencent.liteav:LiteAVSDK_Professional:latest.release'
}
?
// 腾讯特效 SDK 例如:S1-07套餐如下
dependencies {
implementation 'com.tencent.mediacloud:TencentEffect_S1-07:latest.release'
}
说明:
自动加载(aar)的方案需要确保您在 repositories 中添加了 mavenCentral 仓库。
SDK 版本号推荐使用最新版本,如需使用稳定版本或指定版本号请 联系我们
除了推荐的自动加载方式,您还可以选择下载 SDK 并手动导入,详见 手动导入 TRTC SDK手动导入腾讯特效 SDK
2. 在 defaultConfig 中,指定 App 使用的 CPU 架构。
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "arm64-v8a"
}
}
说明:
TRTC SDK 支持 armeabi/armeabi-v7a/arm64-v8a 架构,Android 端另有支持 x86/x86_64 架构的 模拟器专用版 SDK
目前腾讯特效 SDK 支持 armeabi-v7a/arm64-v8a 架构。
3. 单击 Sync Now,自动下载 SDK 并集成到工程里。如果您的腾讯特效套餐包含动效和滤镜功能,那么您需要在 SDK 下载页面 下载对应的套餐包,将包内免费的滤镜素材(./assets/lut)和贴纸动效(./MotionRes)解压并放置在您工程下的如下目录:
动效:../assets/MotionRes
滤镜:../assets/lut

步骤三:工程配置

1. 权限配置
在 AndroidManifest.xml 中配置 App 权限,秀场直播场景下 TRTC SDK 及腾讯特效 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 权限,以正常使用蓝牙功能,具体信息请参见 Android 官方说明
2. 混淆配置
由于我们在 SDK 内部使用了 Java 的反射特性,需要您在 proguard-rules.pro 文件中将 SDK 相关类加入不混淆名单:
-keep class com.tencent.** { *; }
-keep class org.light.** { *;}
-keep class org.libpag.** { *;}
-keep class org.extra.** { *;}
-keep class com.gyailib.**{ *;}
-keep class androidx.exifinterface.** { *;}

步骤四:鉴权与许可

TRTC 鉴权凭证
腾讯特效鉴权许可
UserSig 是腾讯云设计的一种安全保护签名,目的是为了阻止恶意攻击者盗用您的云服务使用权,TRTC 在进房时校验该鉴权凭证。
调试跑通阶段:可以通过 客户端示例代码控制台 两种方法计算生成 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. 校验通过后,会向 TRTC SDK 提供实时音视频服务。
?
?
?
注意:
调试跑通阶段的本地 UserSig 计算方式不推荐应用到线上环境,容易被逆向破解导致密钥泄露。
我们提供了多个语言版本(Java/GO/PHP/Nodejs/Python/C#/C++)的 UserSig 服务端计算源代码,详见 UserSig 计算源码
?
使用腾讯美颜特效之前,需要向腾讯云校验许可凭证。设置 License 需要用到 License Key 和 License Url,示例代码如下。
import com.tencent.xmagic.telicense.TELicenseCheck;
?
// 如果仅仅是为了触发下载或更新 License,而不关心鉴权结果,则第4个参数传入 null
TELicenseCheck.getInstance().setTELicense(context, URL, KEY, new TELicenseCheck.TELicenseCheckListener() {
@Override
public void onLicenseCheckFinish(int errorCode, String msg) {
// 注意:此回调不一定在调用线程
if (errorCode == TELicenseCheck.ERROR_OK) {
// 鉴权成功
} else {
// 鉴权失败
}
?
}
});
注意:
建议在相关业务模块的初始化代码中触发鉴权许可,避免在使用前才临时去下载 License,同时鉴权时应具有网络权限。
实际应用的包名必须和创建 License 时绑定的 Package Name 完全匹配,否则会导致 License 校验失败,详情可参见 鉴权错误码
?

步骤五:初始化 SDK

初始化 TRTC SDK
初始化腾讯特效 SDK
// 创建 TRTC SDK 实例(单例模式)
TRTCCloud mTRTCCloud = TRTCCloud.sharedInstance(context);
// 设置事件监听器
mTRTCCloud.setListener(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);
}
};
?
// 移除事件监听器
mTRTCCloud.setListener(null);
// 销毁 TRTC SDK 实例(单例模式)
TRTCCloud.destroySharedInstance();
说明:
建议监听 SDK 事件通知,对一些常见错误进行日志打印和处理,详请可参见 错误码表
?
import com.tencent.xmagic.XmagicApi;
?
// 初始化美颜 SDK
XmagicApi mXmagicApi = new XmagicApi(context, XmagicResParser.getResPath(), new XmagicApi.OnXmagicPropertyErrorListener());
?
// 开发调试时,可以把日志级别设置为DEBUG,发布包请设置为 WARN,否则会影响性能
mXmagicApi.setXmagicLogLevel(Log.WARN);
?
// 释放美颜 SDK,此方法需要在 GL 线程中调用
mXmagicApi.onDestroy();
说明:
初始化腾讯特效 SDK 之前,还需进行资源拷贝等准备工作,详细步骤可参考 腾讯特效 SDK 使用流程
?

接入过程

API 时序图

?
?
?

步骤一:主播进房推流

TRTC SDK 用于承载视频画面的控件只支持传入 TXCloudVideoView 类型,因此您需要先在布局文件中定义视图渲染控件。
<com.tencent.rtmp.ui.TXCloudVideoView
android:id="@+id/live_cloud_view_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
注意:
如果您需要指定使用 TextureViewSurfaceView 作为视图渲染控件,请参照 高级功能-视图渲染控件
1. 主播进房前开启本地视频预览及音频采集。
// 获取用于展示主播本地画面预览的视频渲染控件
TXCloudVideoView mTxcvvAnchorPreviewView = findViewById(R.id.live_cloud_view_main);
?
// 设置视频编码参数,决定远端用户看到的画面质量
TRTCCloudDef.TRTCVideoEncParam encParam = new TRTCCloudDef.TRTCVideoEncParam();
encParam.videoResolution = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_960_540;
encParam.videoFps = 15;
encParam.videoBitrate = 1300;
encParam.videoResolutionMode = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_MODE_PORTRAIT;
mTRTCCloud.setVideoEncoderParam(encParam);
?
// boolean mIsFrontCamera 可指定使用前置/后置摄像头进行视频采集
mTRTCCloud.startLocalPreview(mIsFrontCamera, mTxcvvAnchorPreviewView);
?
// 这里可指定声音音质,从低到高分别为 SPEECH/DEFAULT/MUSIC
mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT);
注意:
您可根据业务需求自行设置视频编码参数 TRTCVideoEncParam,各档位最佳分辨率、码率搭配详见 TRTCVideoResolution
enterRoom 之前调用以上接口,SDK 只会开启摄像头预览和音频采集,并一直等到您调用 enterRoom 之后才开始推流。
enterRoom 之后调用以上接口,SDK 会开启摄像头预览和音频采集,并自动开始推流。
2. 主播设置本地画面的渲染参数,以及编码器输出画面模式(可选项)。
TRTCCloudDef.TRTCRenderParams params = new TRTCCloudDef.TRTCRenderParams();
params.mirrorType = TRTCCloudDef.TRTC_VIDEO_MIRROR_TYPE_AUTO; // 画面镜像模式
params.fillMode = TRTCCloudDef.TRTC_VIDEO_RENDER_MODE_FILL; // 画面填充模式
params.rotation = TRTCCloudDef.TRTC_VIDEO_ROTATION_0; // 画面旋转角度
// 设置本地画面的渲染参数
mTRTCCloud.setLocalRenderParams(params);
?
// 设置编码器输出的画面镜像模式
mTRTCCloud.setVideoEncoderMirror(boolean mirror);
// 设置视频编码器输出的画面方向
mTRTCCloud.setVideoEncoderRotation(int rotation);
注意:
设置本地画面渲染参数仅影响本地画面的渲染效果。
设置编码器输出模式会影响房间中其他用户所观看到(以及云端录制文件)的画面效果。
3. 主播正式开始直播,进房推流。
public void enterRoomByAnchor(String roomId, String userId) {
TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();
// 以字符串房间号为例
params.strRoomId = roomId;
params.userId = userId;
// 从业务后台获取到的 UserSig
params.userSig = getUserSig(userId);
// 替换成您的 SDKAppID
params.sdkAppId = SDKAppID;
// 指定主播角色
params.role = TRTCCloudDef.TRTCRoleAnchor;
// 以互动直播场景进房
mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);
}
?
// 进房结果事件回调
@Override
public void onEnterRoom(long result) {
if (result > 0) {
// result 代表加入房间所消耗的时间(毫秒)
Log.d(TAG, "Enter room succeed");
} else {
// result 代表进房失败的错误码
Log.d(TAG, "Enter room failed");
}
}
注意:
TRTC 房间号分为整型 roomId 和字符串类型 strRoomId,两种类型的房间不互通,建议统一房间号类型。
TRTC 用户角色分为主播和听众,只有主播才有推流权限,进房时需指定用户角色,如未指定则默认为主播角色。
秀场直播场景下,进房模式建议选用 TRTC_APP_SCENE_LIVE

步骤二:观众进房拉流

1. 观众进入 TRTC 房间。
public void enterRoomByAudience(String roomId, String userId) {
TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();
// 以字符串房间号为例
params.strRoomId = roomId;
params.userId = userId;
// 从业务后台获取到的 UserSig
params.userSig = getUserSig(userId);
// 替换成您的 SDKAppID
params.sdkAppId = SDKAppID;
// 指定观众角色
params.role = TRTCCloudDef.TRTCRoleAudience;
// 以互动直播场景进房
mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);
}
?
// 进房结果事件回调
@Override
public void onEnterRoom(long result) {
if (result > 0) {
// result 代表加入房间所消耗的时间(毫秒)
Log.d(TAG, "Enter room succeed");
} else {
// result 代表进房失败的错误码
Log.d(TAG, "Enter room failed");
}
}
2. 观众订阅主播音视频流。
@Override
public void onUserAudioAvailable(String userId, boolean available) {
// 某远端用户发布/取消了自己的音频
// 在自动订阅模式下,您无需做任何操作,SDK 会自动播放远端用户音频
}
?
@Override
public void onUserVideoAvailable(String userId, boolean available) {
// 某远端用户发布/取消了主路视频画面
if (available) {
// 订阅远端用户的视频流,并绑定视频渲染控件
mTRTCCloud.startRemoteView(userId, TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_BIG, TXCloudVideoView view);
} else {
// 停止订阅远端用户的视频流,并释放渲染控件
mTRTCCloud.stopRemoteView(userId, TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_BIG);
}
}
3. 观众设置远端画面的渲染模式(可选项)。
TRTCCloudDef.TRTCRenderParams params = new TRTCCloudDef.TRTCRenderParams();
params.mirrorType = TRTCCloudDef.TRTC_VIDEO_MIRROR_TYPE_AUTO; // 画面镜像模式
params.fillMode = TRTCCloudDef.TRTC_VIDEO_RENDER_MODE_FILL; // 画面填充模式
params.rotation = TRTCCloudDef.TRTC_VIDEO_ROTATION_0; // 画面旋转角度
// 设置远端画面的渲染模式
mTRTCCloud.setRemoteRenderParams(userId, TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_BIG, params)

步骤三:观众连麦互动

1. 观众切换为主播角色。
// 切换为主播角色
mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAnchor);
?
// 切换角色事件回调
@Override
public void onSwitchRole(int errCode, String errMsg) {
if (errCode == TXLiteAVCode.ERR_NULL) {
// 切换角色成功
}
}
2. 观众开始本地音视频采集和推流。
// 获取用于展示连麦观众本地画面预览的视频渲染控件
TXCloudVideoView mTxcvvAudiencePreviewView = findViewById(R.id.live_cloud_view_sub);
?
// 设置视频编码参数,决定远端用户看到的画面质量
TRTCCloudDef.TRTCVideoEncParam encParam = new TRTCCloudDef.TRTCVideoEncParam();
encParam.videoResolution = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_480_270;
encParam.videoFps = 15;
encParam.videoBitrate = 550;
encParam.videoResolutionMode = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_MODE_PORTRAIT;
mTRTCCloud.setVideoEncoderParam(encParam);
?
// boolean mIsFrontCamera 可指定使用前置/后置摄像头进行视频采集
mTRTCCloud.startLocalPreview(mIsFrontCamera, mTxcvvAudiencePreviewView);
?
// 这里可指定声音音质,从低到高分别为 SPEECH/DEFAULT/MUSIC
mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT);
注意:
您可根据业务需求自行设置视频编码参数 TRTCVideoEncParam,各档位最佳分辨率、码率搭配详见 TRTCVideoResolution
3. 观众下麦停止推流。
// 切换为观众角色
mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAudience);
?
// 切换角色事件回调
@Override
public void onSwitchRole(int errCode, String errMsg) {
if (errCode == TXLiteAVCode.ERR_NULL) {
// 停止摄像头采集推流
mTRTCCloud.stopLocalPreview();
// 停止麦克风采集推流
mTRTCCloud.stopLocalAudio();
}
}

步骤四:退出与解散房间

1. 退出房间
public void exitRoom() {
mTRTCCloud.stopLocalAudio();
mTRTCCloud.stopLocalPreview();
mTRTCCloud.exitRoom();
}
?
// 离开房间事件回调
@Override
public void onExitRoom(int reason) {
if (reason == 0) {
Log.d(TAG, "主动调用 exitRoom 退出房间");
} else if (reason == 1) {
Log.d(TAG, "被服务器踢出当前房间");
} else if (reason == 2) {
Log.d(TAG, "当前房间整个被解散");
}
}
注意:
待 SDK 占用的所有资源释放完毕后,SDK 会抛出 onExitRoom 回调通知到您。
如果您要再次调用 enterRoom 或者切换到其他的音视频 SDK,请等待 onExitRoom 回调到来后再执行相关操作。否则可能会遇到例如摄像头、麦克风设备被强占等各种异常问题。
2. 解散房间
服务端解散:TRTC 提供了服务端解散房间 API DismissRoom(区分数字房间 ID 和字符串房间 ID),您可以调用此接口把房间所有用户从房间移出,并解散房间。
客户端解散:各个客户端调用退出房间 exitRoom 接口,当房间内的所有主播和观众完成退房后,根据 TRTC 房间生命周期规则,房间将会自动解散,详情请参见 退出房间
警告:
建议您当一次直播结束之后,可以在服务端调用解散房间 API 确保房间解散,防止观众意外进房导致产生非期望的费用。

备选方案

API 时序图

?
?
?

步骤一:主播旁路推流

1. 前置条件:打开 TRTC 控制台,在应用管理页选择目标应用,点击配置进入基础功能页面,点击开启旁路转推,同时建议选择指定流旁路。旁路转推域名可在 云直播控制台 添加,也可使用系统默认的推流域名。
?
?
?
2. 主播进房前开启本地视频预览及音频采集。
TRTC SDK 用于承载视频画面的控件只支持传入 TXCloudVideoView 类型,因此您需要先在布局文件中定义视图渲染控件。
<com.tencent.rtmp.ui.TXCloudVideoView
android:id="@+id/live_cloud_view_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
注意:
如果您需要指定使用 TextureViewSurfaceView 作为视图渲染控件,请参照 高级功能-视图渲染控件
// 获取用于展示主播本地画面预览的视频渲染控件
TXCloudVideoView mTxcvvAnchorPreviewView = findViewById(R.id.live_cloud_view_main);
?
// 设置视频编码参数,决定远端用户看到的画面质量
TRTCCloudDef.TRTCVideoEncParam encParam = new TRTCCloudDef.TRTCVideoEncParam();
encParam.videoResolution = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_960_540;
encParam.videoFps = 15;
encParam.videoBitrate = 1300;
encParam.videoResolutionMode = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_MODE_PORTRAIT;
mTRTCCloud.setVideoEncoderParam(encParam);
?
// boolean mIsFrontCamera 可指定使用前置/后置摄像头进行视频采集
mTRTCCloud.startLocalPreview(mIsFrontCamera, mTxcvvAnchorPreviewView);
?
// 这里可指定声音音质,从低到高分别为 SPEECH/DEFAULT/MUSIC
mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT);
注意:
您可根据业务需求自行设置视频编码参数 TRTCVideoEncParam,各档位最佳分辨率、码率搭配详见 TRTCVideoResolution
enterRoom 之前调用以上接口,SDK 只会开启摄像头预览和音频采集,并一直等到您调用 enterRoom 之后才开始推流。
enterRoom 之后调用以上接口,SDK 会开启摄像头预览和音频采集,并自动开始推流。
3. 主播设置本地画面的渲染参数,以及编码器输出画面模式。
TRTCCloudDef.TRTCRenderParams params = new TRTCCloudDef.TRTCRenderParams();
params.mirrorType = TRTCCloudDef.TRTC_VIDEO_MIRROR_TYPE_AUTO; // 画面镜像模式
params.fillMode = TRTCCloudDef.TRTC_VIDEO_RENDER_MODE_FILL; // 画面填充模式
params.rotation = TRTCCloudDef.TRTC_VIDEO_ROTATION_0; // 画面旋转角度
// 设置本地画面的渲染参数
mTRTCCloud.setLocalRenderParams(params);
?
// 设置编码器输出的画面镜像模式
mTRTCCloud.setVideoEncoderMirror(boolean mirror);
// 设置视频编码器输出的画面方向
mTRTCCloud.setVideoEncoderRotation(int rotation);
注意:
设置本地画面渲染参数仅影响本地画面的渲染效果。
设置编码器输出模式会影响房间中其他用户所观看到(以及云端录制文件)的画面效果。
4. 主播正式开始直播,进房推流。
public void enterRoomByAnchor(String roomId, String userId) {
TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();
// 以字符串房间号为例
params.strRoomId = roomId;
params.userId = userId;
// 从业务后台获取到的 UserSig
params.userSig = getUserSig(userId);
// 替换成您的 SDKAppID
params.sdkAppId = SDKAppID;
// 指定主播角色
params.role = TRTCCloudDef.TRTCRoleAnchor;
// 以互动直播场景进房
mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);
}
?
// 进房结果事件回调
@Override
public void onEnterRoom(long result) {
if (result > 0) {
// result 代表加入房间所消耗的时间(毫秒)
Log.d(TAG, "Enter room succeed");
} else {
// result 代表进房失败的错误码
Log.d(TAG, "Enter room failed");
}
}
注意:
TRTC 房间号分为整型 roomId 和字符串类型 strRoomId,两种类型的房间不互通,建议统一房间号类型。
TRTC 用户角色分为主播和听众,只有主播才有推流权限,进房时需指定用户角色,如未指定则默认为主播角色。
秀场直播场景下,进房模式建议选用 TRTC_APP_SCENE_LIVE
5. 主播将音视频流转推到直播 CDN。
public void startPublishMediaToCDN(String streamName) {
// 设定推流地址过期时间
long txTime = (System.currentTimeMillis() / 1000) + (24 * 60 * 60);
// 生成鉴权信息,getSafeUrl 方法可在云直播控制台-域名管理-推流配置-推流地址示例代码获取
String secretParam = UrlHelper.getSafeUrl(LIVE_URL_KEY, streamName, txTime);
?
// 媒体流发布的目标地址
TRTCCloudDef.TRTCPublishTarget target = new TRTCCloudDef.TRTCPublishTarget();
// 目标地址设定为旁路转推到 CDN
target.mode = TRTCCloudDef.TRTC_PublishBigStream_ToCdn;
TRTCCloudDef.TRTCPublishCdnUrl cdnUrl = new TRTCCloudDef.TRTCPublishCdnUrl();
// 拼接发布到直播服务商的推流地址(RTMP 格式)
cdnUrl.rtmpUrl = "rtmp://" + PUSH_DOMAIN + "/live/" + streamName + "?" + secretParam;
// 腾讯云直播服务为 true,第三方直播服务为 false
cdnUrl.isInternalLine = true;
// 可以添加多个 CDN 推流地址
target.cdnUrlList.add(cdnUrl);
?
// 设置媒体流编码输出参数(可根据业务需求自定义)
TRTCCloudDef.TRTCStreamEncoderParam trtcStreamEncoderParam = new TRTCCloudDef.TRTCStreamEncoderParam();
trtcStreamEncoderParam.audioEncodedChannelNum = 1;
trtcStreamEncoderParam.audioEncodedKbps = 50;
trtcStreamEncoderParam.audioEncodedCodecType = 0;
trtcStreamEncoderParam.audioEncodedSampleRate = 48000;
trtcStreamEncoderParam.videoEncodedFPS = 15;
trtcStreamEncoderParam.videoEncodedGOP = 2;
trtcStreamEncoderParam.videoEncodedKbps = 1300;
trtcStreamEncoderParam.videoEncodedWidth = 540;
trtcStreamEncoderParam.videoEncodedHeight = 960;
?
// 开始发布媒体流
mTRTCCloud.startPublishMediaStream(target, trtcStreamEncoderParam, null);
}
注意:
单主播直播时仅需发起旁路转推任务,待有观众连麦或主播 PK 时再将此任务更新为混流转码任务。
推流鉴权 KEY LIVE_URL_KEY 及推流域名 PUSH_DOMAIN 等信息需在 云直播控制台-域名管理 获取。
国际站用户、旧版架构用户如调用 startPublishMediaStream 报错,请 联系我们 协助发布配置。
发布媒体流后,SDK 会通过回调 onStartPublishMediaStream 带给您后台启动的任务标识(即 taskId)。
@Override
public void onStartPublishMediaStream(String taskId, int code, String message, Bundle extraInfo) {
// taskId: 当请求成功时,TRTC 后台会在回调中提供给您这项任务的 taskId,后续您可以通过该 taskId 结合 updatePublishMediaStream 和 stopPublishMediaStream 进行更新和停止
// code: 回调结果,0 表示成功,其余值表示失败
}

步骤二:观众拉流播放

CDN 观众无需进入 TRTC 房间,可直接拉取主播旁路 CDN 流播放。
import com.tencent.live2.V2TXLivePlayer;
import com.tencent.live2.V2TXLivePlayerObserver;
import com.tencent.live2.impl.V2TXLivePlayerImpl;
?
// 初始化播放器
V2TXLivePlayer mLivePlayer = new V2TXLivePlayerImpl(context);
// 设置播放器回调监听
mLivePlayer.setObserver(mV2TXLivePlayerObserver);
?
// 设置播放器的视频渲染控件
mLivePlayer.setRenderView(TXCloudVideoView view);
mLivePlayer.setRenderView(TextureView view);
mLivePlayer.setRenderView(SurfaceView view);
?
// 设置延迟调节模式(可选项)
mLivePlayer.setCacheParams(1.0f, 5.0f); // 自动模式
mLivePlayer.setCacheParams(1.0f, 1.0f); // 极速模式
mLivePlayer.setCacheParams(5.0f, 5.0f); // 流畅模式
?
// 拼接拉流播放地址
String flvURL = "http://" + PLAY_DOMAIN + "/live/" + streamName + ".flv"; // FLV 地址
String hlsURL = "http://" + PLAY_DOMAIN + "/live/" + streamName + ".m3u8"; // HLS 地址
String rtmpURL = "rtmp://" + PLAY_DOMAIN + "/live/" + streamName; // RTMP 地址
String webrtcURL = "webrtc://" + PLAY_DOMAIN + "/live/" + streamName; // WebRTC 地址
?
// 启动播放
mLivePlayer.startLivePlay(flvURL);
?
// 自定义设置填充模式(可选项)
mLivePlayer.setRenderFillMode(V2TXLiveFillModeFit);
// 自定义设置画面渲染方向(可选项)
mLivePlayer.setRenderRotation(V2TXLiveRotation0);
注意:
播放域名 PLAY_DOMAIN 需要您在 云直播控制台 添加自有已备案域名进行直播播放,并需 配置域名 CNAME
直播播放功能需设置 Licence 后方可成功播放,否则将播放失败(黑屏),全局仅设置一次即可。若您暂未获取 Licence,可 快速免费申请测试版 Licence?以正常播放,正式版 Licence 需 购买
import com.tencent.rtmp.TXLiveBase;
// 设置 Licence
TXLiveBase.getInstance().setLicence(context, LICENSEURL, LICENSEURLKEY);

步骤三:观众连麦互动

1. 连麦观众需要进入 TRTC 房间与主播实时互动。
// 进入 TRTC 房间并开始推流
public void enterRoom(String roomId, String userId) {
TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();
// 以字符串房间号为例
params.strRoomId = roomId;
params.userId = userId;
// 从业务后台获取到的 UserSig
params.userSig = getUserSig(userId);
// 替换成您的 SDKAppID
params.sdkAppId = SDKAppID;
// 指定主播角色
params.role = TRTCCloudDef.TRTCRoleAnchor;
// 开启本地音视频采集
startLocalMedia();
// 以互动直播场景进房推流
mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);
}
?
// 开启本地视频预览及音频采集
public void startLocalMedia() {
// 获取用于展示连麦观众本地画面预览的视频渲染控件
TXCloudVideoView mTxcvvAudiencePreviewView = findViewById(R.id.live_cloud_view_sub);
// 设置视频编码参数,决定远端用户看到的画面质量
TRTCCloudDef.TRTCVideoEncParam encParam = new TRTCCloudDef.TRTCVideoEncParam();
encParam.videoResolution = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_480_270;
encParam.videoFps = 15;
encParam.videoBitrate = 550;
encParam.videoResolutionMode = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_MODE_PORTRAIT;
mTRTCCloud.setVideoEncoderParam(encParam);
// boolean mIsFrontCamera 可指定使用前置/后置摄像头进行视频采集
mTRTCCloud.startLocalPreview(mIsFrontCamera, mTxcvvAudiencePreviewView);
// 这里可指定声音音质,从低到高分别为 SPEECH/DEFAULT/MUSIC
mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT);
}
?
// 进房结果事件回调
@Override
public void onEnterRoom(long result) {
if (result > 0) {
// result 代表加入房间所消耗的时间(毫秒)
Log.d(TAG, "Enter room succeed");
} else {
// result 代表进房失败的错误码
Log.d(TAG, "Enter room failed");
}
}
注意:
您可根据业务需求自行设置视频编码参数 TRTCVideoEncParam,各档位最佳分辨率、码率搭配详见 TRTCVideoResolution
2. 连麦观众进房成功后开始订阅主播音视频流。
@Override
public void onUserAudioAvailable(String userId, boolean available) {
// 某远端用户发布/取消了自己的音频
// 在自动订阅模式下,您无需做任何操作,SDK 会自动播放远端用户音频
}
?
@Override
public void onUserVideoAvailable(String userId, boolean available) {
// 某远端用户发布/取消了主路视频画面
if (available) {
// 订阅远端用户的视频流,并绑定视频渲染控件
mTRTCCloud.startRemoteView(userId, TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_BIG, TXCloudVideoView view);
} else {
// 停止订阅远端用户的视频流,并释放渲染控件
mTRTCCloud.stopRemoteView(userId, TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_BIG);
}
}
?
@Override
public void onFirstVideoFrame(String userId, int streamType, int width, int height) {
// SDK 开始渲染本地或远端用户的首帧画面
if (!userId.isEmpty()) {
// 收到主播首帧画面,停止播放 CDN 流
mLivePlayer.stopPlay();
}
}
注意:
TRTC 拉流 startRemoteView 可直接复用之前 CDN 拉流 setRenderView 的视频渲染控件。
为避免在切换拉流器时画面中断,建议等待收到 TRTC 首帧回调 onFirstVideoFrame 后再停止 CDN 拉流。
3. 主播更新发布混合媒体流。
// 连麦观众进房事件回调
@Override
public void onRemoteUserEnterRoom(String userId) {
if (!mixUserList.contains(userId)) {
mixUserList.add(userId);
}
updatePublishMediaToCDN(streamName, mixUserList, taskId);
}
?
// 更新媒体流的事件回调
@Override
public void onUpdatePublishMediaStream(String taskId, int code, String message, Bundle extraInfo) {
// 您调用媒体流发布接口 (updatePublishMediaStream) 时传入的 taskId,会通过此回调再带回给您,用于标识该回调属于哪一次更新请求
// code: 回调结果,0 表示成功,其余值表示失败
}
?
// 更新发布混合媒体流到直播 CDN
public void updatePublishMediaToCDN(String streamName, List<String> mixUserList, String taskId) {
// 设定推流地址过期时间
long txTime = (System.currentTimeMillis() / 1000) + (24 * 60 * 60);
// 生成鉴权信息,getSafeUrl 方法可在云直播控制台-域名管理-推流配置-推流地址示例代码获取
String secretParam = UrlHelper.getSafeUrl(LIVE_URL_KEY, streamName, txTime);
?
// 媒体流发布的目标地址
TRTCCloudDef.TRTCPublishTarget target = new TRTCCloudDef.TRTCPublishTarget();
// 目标地址设定为混流转推到 CDN
target.mode = TRTCCloudDef.TRTC_PublishMixStream_ToCdn;
TRTCCloudDef.TRTCPublishCdnUrl cdnUrl = new TRTCCloudDef.TRTCPublishCdnUrl();
// 拼接发布到直播服务商的推流地址(RTMP 格式)
cdnUrl.rtmpUrl = "rtmp://" + PUSH_DOMAIN + "/live/" + streamName + "?" + secretParam;
// 腾讯云直播服务为 true,第三方直播服务为 false
cdnUrl.isInternalLine = true;
// 可以添加多个 CDN 推流地址
target.cdnUrlList.add(cdnUrl);
?
// 设置媒体流编码输出参数
TRTCCloudDef.TRTCStreamEncoderParam trtcStreamEncoderParam = new TRTCCloudDef.TRTCStreamEncoderParam();
trtcStreamEncoderParam.audioEncodedChannelNum = 1;
trtcStreamEncoderParam.audioEncodedKbps = 50;
trtcStreamEncoderParam.audioEncodedCodecType = 0;
trtcStreamEncoderParam.audioEncodedSampleRate = 48000;
trtcStreamEncoderParam.videoEncodedFPS = 15;
trtcStreamEncoderParam.videoEncodedGOP = 2;
trtcStreamEncoderParam.videoEncodedKbps = 1300;
trtcStreamEncoderParam.videoEncodedWidth = 540;
trtcStreamEncoderParam.videoEncodedHeight = 960;
// 媒体流转码配置参数
TRTCCloudDef.TRTCStreamMixingConfig trtcStreamMixingConfig = new TRTCCloudDef.TRTCStreamMixingConfig();
if (mixUserList != null) {
ArrayList<TRTCCloudDef.TRTCUser> audioMixUserList = new ArrayList<>();
ArrayList<TRTCCloudDef.TRTCVideoLayout> videoLayoutList = new ArrayList<>();
for (int i = 0; i < mixUserList.size() && i < 16; i++) {
TRTCCloudDef.TRTCUser user = new TRTCCloudDef.TRTCUser();
// 整型房间号为 intRoomId
user.strRoomId = mRoomId;
user.userId = mixUserList.get(i);
audioMixUserList.add(user);
TRTCCloudDef.TRTCVideoLayout videoLayout = new TRTCCloudDef.TRTCVideoLayout();
if (mixUserList.get(i).equals(mUserId)) {
// 主播画面布局
videoLayout.x = 0;
videoLayout.y = 0;
videoLayout.width = 540;
videoLayout.height = 960;
videoLayout.zOrder = 0;
} else {
// 连麦观众画面布局
videoLayout.x = 400;
videoLayout.y = 5 + i * 245;
videoLayout.width = 135;
videoLayout.height = 240;
videoLayout.zOrder = 1;
}
videoLayout.fixedVideoUser = user;
videoLayout.fixedVideoStreamType = TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_BIG;
videoLayoutList.add(videoLayout);
}
// 指定转码流中的每一路输入音频的信息
trtcStreamMixingConfig.audioMixUserList = audioMixUserList;
// 指定混合画面的中每一路视频画面的位置、大小、图层以及流类型等信息
trtcStreamMixingConfig.videoLayoutList = videoLayoutList;
}
?
// 更新发布媒体流
mTRTCCloud.updatePublishMediaStream(taskId, target, trtcStreamEncoderParam, trtcStreamMixingConfig);
}
注意:
为了保证 CDN 播放连续并且不会发生断流,您需要保持媒体流编码输出参数 trtcStreamEncoderParam 以及流名称 streamName 不变。
媒体流编码输出参数、混合画面布局参数可根据业务需求自定义;当前仅支持最高16路音视频输入,如果用户只有音频也会被算作一路。
同一个任务不支持纯音频、音视频、纯视频之间的切换。
4. 观众下麦退房,主播更新混流任务。
// 可复用 TRTC 视频渲染控件
mLivePlayer.setRenderView(TXCloudVideoView view);
// 重新开始播放 CDN 媒体流
mLivePlayer.startLivePlay(URL);
?
// 播放器事件回调
private V2TXLivePlayerObserver mV2TXLivePlayerObserver = new V2TXLivePlayerObserver() {
@Override
public void onVideoLoading(V2TXLivePlayer player, Bundle extraInfo) {
// 视频加载事件
}
@Override
public void onVideoPlaying(V2TXLivePlayer player, boolean firstPlay, Bundle extraInfo) {
// 视频播放事件
if (firstPlay) {
mTRTCCloud.stopAllRemoteView();
mTRTCCloud.stopLocalAudio();
mTRTCCloud.stopLocalPreview();
mTRTCCloud.exitRoom();
}
}
};
注意:
为避免在切换拉流器时画面中断,建议等待收到播放器视频播放事件 onVideoPlaying 后再退出 TRTC 房间。
// 连麦观众退房事件回调
@Override
public void onRemoteUserLeaveRoom(String userId, int reason) {
if (mixUserList.contains(userId)) {
mixUserList.remove(userId);
}
// 主播更新混流任务
updatePublishMediaToCDN(streamName, mixUserList, taskId);
}
?
// 更新媒体流的事件回调
@Override
public void onUpdatePublishMediaStream(String taskId, int code, String message, Bundle extraInfo) {
// 您调用媒体流发布接口 (updatePublishMediaStream) 时传入的 taskId,会通过此回调再带回给您,用于标识该回调属于哪一次更新请求
// code: 回调结果,0 表示成功,其余值表示失败
}

步骤四:主播关播与退房

public void exitRoom() {
// 停止所有发布的媒体流
mTRTCCloud.stopPublishMediaStream("");
mTRTCCloud.stopLocalAudio();
mTRTCCloud.stopLocalPreview();
mTRTCCloud.exitRoom();
}
?
// 停止媒体流的事件回调
@Override
public void onStopPublishMediaStream(String taskId, int code, String message, Bundle extraInfo) {
// 您调用停止发布媒体流 (stopPublishMediaStream) 时传入的 taskId,会通过此回调再带回给您,用于标识该回调属于哪一次停止请求
// code: 回调结果,0 表示成功,其余值表示失败
}
?
// 离开房间事件回调
@Override
public void onExitRoom(int reason) {
if (reason == 0) {
Log.d(TAG, "主动调用 exitRoom 退出房间");
} else if (reason == 1) {
Log.d(TAG, "被服务器踢出当前房间");
} else if (reason == 2) {
Log.d(TAG, "当前房间整个被解散");
}
}
注意:
停止发布媒体流传参 taskId 填写空字符串,将会停止所有您发布的媒体流。
待 SDK 占用的所有资源释放完毕后,SDK 会抛出 onExitRoom 回调通知到您。

高级功能

主播跨房 PK 连麦

1. 任意一方发起跨房 PK 连麦。
public void connectOtherRoom(String roomId, String userId) {
try {
JSONObject jsonObj = new JSONObject();
// 数字房间号为 roomId
jsonObj.put("strRoomId", roomId);
jsonObj.put("userId", userId);
mTRTCCloud.ConnectOtherRoom(jsonObj.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
?
// 请求跨房连麦的结果回调
@Override
public void onConnectOtherRoom(String userId, int errCode, String errMsg) {
// 要跨房通话的另一个房间中的主播的用户 ID
// 错误码,ERR_NULL 代表请求成功
// 错误信息
}
注意:
跨房 PK 连麦的本地用户和对端用户必须都为主播角色,且必须都有音频/视频上行。
可通过多次调用 ConnectOtherRoom() 来实现与多个房间主播跨房连麦,目前限制一个房间最多可以和其他三个房间的主播跨房连麦,一个房间中最多10个主播可与其他房间的主播跨房连麦。
2. 两个房间中的所有用户都会收到来自另一个房间中的 PK 主播的音视频流可用回调。
@Override
public void onUserAudioAvailable(String userId, boolean available) {
// 某远端用户发布/取消了自己的音频
// 在自动订阅模式下,您无需做任何操作,SDK 会自动播放远端用户音频
}
?
@Override
public void onUserVideoAvailable(String userId, boolean available) {
// 某远端用户发布/取消了主路视频画面
if (available) {
// 订阅远端用户的视频流,并绑定视频渲染控件
mTRTCCloud.startRemoteView(userId, TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_BIG, TXCloudVideoView view);
} else {
// 停止订阅远端用户的视频流,并释放渲染控件
mTRTCCloud.stopRemoteView(userId, TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_BIG);
}
}
3. 任意一方退出跨房 PK 连麦。
// 退出跨房连麦
mTRTCCloud.DisconnectOtherRoom();
?
// 退出跨房连麦的结果回调
@Override
public void onDisConnectOtherRoom(int errCode, String errMsg) {
super.onDisConnectOtherRoom(errCode, errMsg);
}
注意:
调用 DisconnectOtherRoom() 后,即退出与所有其他房间主播的跨房 PK 连麦。
跨房 PK 连麦的发起端和接收端任意一端均可调用 DisconnectOtherRoom() 退出跨房 PK 连麦。

第三方美颜接入

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 集成腾讯特效,独立集成腾讯美颜特效指引详见 独立集成腾讯特效

双路编码模式

开启双路编码模式后,当前用户的编码器会同时输出【高清大画面】和【低清小画面】两路视频流(但只有一路音频流)。这样,房间中的其他用户就可以根据自身的网络情况或屏幕大小选择订阅【高清大画面】或是【低清小画面】。
1. 开启大小画面双路编码模式。
public void enableDualStreamMode(boolean enable) {
// 小流的视频编码参数(可自定义)
TRTCCloudDef.TRTCVideoEncParam smallVideoEncParam = new TRTCCloudDef.TRTCVideoEncParam();
smallVideoEncParam.videoResolution = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_480_270;
smallVideoEncParam.videoFps = 15;
smallVideoEncParam.videoBitrate = 550;
smallVideoEncParam.videoResolutionMode = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_MODE_PORTRAIT;
mTRTCCloud.enableEncSmallVideoStream(enable, smallVideoEncParam);
}
注意:
双路编码开启后,会消耗更多的 CPU 和 网络带宽,所以 Mac、Windows 或者高性能 Pad 可以考虑开启,不建议手机端开启。
2. 选择拉取远端用户视频流类型。
// 订阅远端用户视频流时可选视频流类型
mTRTCCloud.startRemoteView(String userId, int streamType, TXCloudVideoView view);
?
// 亦可随时切换指定远端用户的大小画面
mTRTCCloud.setRemoteVideoStreamType(String userId, int streamType);
注意:
双路编码开启后,可通过指定 streamType 视频流类型为 TRTC_VIDEO_STREAM_TYPE_SMALL 来拉取低清小画面观看。

视图渲染控件

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(TXCloudVideoView view);
?
// 更新远端用户视频渲染控件
mTRTCCloud.updateRemoteView(String userId, int streamType, TXCloudVideoView view);
注意:
传参 view 为目标视频渲染控件,streamType 仅支持 TRTC_VIDEO_STREAM_TYPE_BIGTRTC_VIDEO_STREAM_TYPE_SUB

直播互动消息

直播互动在直播场景中尤为重要,用户通过点赞、赠送礼物、发送弹幕等方式与主播进行互动。实现直播互动功能的前提是开通 即时通信 IM 服务,并导入 IM SDK,详细指引请参考 语聊房接入指引-接入准备

点赞消息

1. 点赞者在客户端发送点赞相关的群组自定义消息,发送成功后业务方在本地渲染点赞效果。
// 构造点赞消息体
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("cmd", "like_msg");
JSONObject msgJsonObject = new JSONObject();
msgJsonObject.put("type", 1); // 点赞类型
msgJsonObject.put("likeCount", 10); // 点赞数量
jsonObject.put("msg", msgJsonObject);
} catch (JSONException e) {
e.printStackTrace();
}
String data = jsonObject.toString();
?
// 发送群自定义消息(点赞消息建议设置为低优先级)
V2TIMManager.getInstance().sendGroupCustomMessage(data.getBytes(), mRoomId,
V2TIMMessage.V2TIM_PRIORITY_LOW, new V2TIMValueCallback<V2TIMMessage>() {
@Override
public void onError(int i, String s) {
// 发送点赞消息失败
}
?
@Override
public void onSuccess(V2TIMMessage v2TIMMessage) {
// 发送点赞消息成功
// 本地渲染点赞效果
}
});
2. 房间内其他用户客户端收到群自定义消息回调,然后进行消息解析和点赞效果渲染。
// 收到群自定义消息
V2TIMManager.getInstance().addSimpleMsgListener(new V2TIMSimpleMsgListener() {
@Override
public void onRecvGroupCustomMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, byte[] customData) {
String customStr = new String(customData);
if (!customStr.isEmpty()) {
try {
JSONObject jsonObject = new JSONObject(customStr);
String command = jsonObject.getString("cmd");
JSONObject messageJsonObject = jsonObject.getJSONObject("msg");
if (command.equals("like_msg")) {
int type = messageJsonObject.getInt("type"); // 点赞类型
int likeCount = messageJsonObject.getInt("likeCount"); // 点赞数量
// 根据点赞类型和数量渲染点赞效果
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});

礼物消息

1. 送礼者向业务服务端发起请求,业务服务端完成计费结算后调用 REST API 向群组中发送自定义消息。
1.1 请求 URL 示例
https://xxxxxx/v4/group_open_http_svc/send_group_msg?sdkappid=88888888&identifier=admin&usersig=xxx&random=99999999&contenttype=json
1.2 请求包体示例
{
"GroupId": "@TGS#12DEVUDHQ",
"Random": 2784275388,
"MsgPriority": "High", // 消息的优先级,礼物消息应设置为高优先级
"MsgBody": [
{
"MsgType": "TIMCustomElem",
"MsgContent": {
// type: 礼物类型; giftUrl: 礼物资源地址; giftName: 礼物名称; giftCount: 礼物数量
"Data": "{\\"cmd\\": \\"gift_msg\\", \\"msg\\": {\\"type\\": 1, \\"giftUrl\\": \\"xxx\\", \\"giftName\\": \\"xxx\\", \\"giftCount\\": 1}}"
}
}
]
}
2. 房间内其他用户客户端收到群自定义消息回调,然后进行消息解析和礼物特效渲染。
// 收到群自定义消息
V2TIMManager.getInstance().addSimpleMsgListener(new V2TIMSimpleMsgListener() {
@Override
public void onRecvGroupCustomMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, byte[] customData) {
String customStr = new String(customData);
if (!customStr.isEmpty()) {
try {
JSONObject jsonObject = new JSONObject(customStr);
String command = jsonObject.getString("cmd");
JSONObject messageJsonObject = jsonObject.getJSONObject("msg");
if (command.equals("gift_msg")) {
int type = messageJsonObject.getInt("type"); // 礼物类型
int giftCount = messageJsonObject.getInt("giftCount"); // 礼物数量
String giftUrl = messageJsonObject.getString("giftUrl"); // 礼物资源地址
String giftName = messageJsonObject.getString("giftName"); // 礼物名称
// 根据礼物类型、礼物数量、礼物资源地址、礼物名称渲染礼物特效
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});

弹幕消息

秀场直播间通常会有文本形式的弹幕消息互动,这里可以通过 IM 的发送及接收群聊普通文本消息来实现。
// 发送公屏弹幕消息
V2TIMManager.getInstance().sendGroupTextMessage(text, groupID, V2TIMMessage.V2TIM_PRIORITY_NORMAL, new V2TIMValueCallback<V2TIMMessage>() {
@Override
public void onError(int i, String s) {
// 发送弹幕消息失败
}
?
@Override
public void onSuccess(V2TIMMessage v2TIMMessage) {
// 发送弹幕消息成功
// 本地展示消息文本
}
});
?
// 接收公屏弹幕消息
V2TIMManager.getInstance().addSimpleMsgListener(new V2TIMSimpleMsgListener() {
@Override
public void onRecvGroupTextMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, String text) {
// 根据发送者信息 sender 和消息文本 text 渲染弹幕消息
}
});
注意:
建议将礼物消息设置为高优先级;弹幕消息设置为正常优先级;点赞消息设置为低优先级。
本人在客户端发送群聊消息,不会触发消息接收回调,只有群组内的其他用户可以接收到。

异常处理

异常错误处理

TRTC SDK 遇到不可恢复的错误会在 onError 回调中抛出,详见 TRTC 错误码表
1. UserSig 相关
UserSig 校验失败会导致进房失败,您可参考 UserSig 生成与校验 进行校验。
枚举
取值
描述
ERR_TRTC_INVALID_USER_SIG
-3320
进房参数 userSig 不正确,请检查 TRTCParams.userSig 是否为空。
ERR_TRTC_USER_SIG_CHECK_FAILED
-100018
UserSig 校验失败,请检查参数 TRTCParams.userSig 是否填写正确或已经过期。
2. 进退房相关
进房失败请先检查进房参数是否正确,且进退房接口必须成对调用,即便进房失败也需要调用退房接口。
枚举
取值
描述
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 的房间。
3. 设备相关
可监听设备相关错误,在出现相关错误时 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
麦克风正在被占用中,例如移动设备正在通话时,打开麦克风会失败。

远端镜像模式无效问题

TRTC 设置画面镜像分为本地预览镜像 setLocalRenderParams 和视频编码镜像 setVideoEncoderMirror,两者分别影响本地预览画面镜像效果,以及视频编码输出画面的镜像效果(远端观众及云端录制的镜像模式)。如果希望本地预览的镜像效果同时在远端观众侧生效,请按照如下方法进行编码。
// 设置本地画面的渲染参数
TRTCCloudDef.TRTCRenderParams params = new TRTCCloudDef.TRTCRenderParams();
params.mirrorType = TRTCCloudDef.TRTC_VIDEO_MIRROR_TYPE_ENABLE; // 画面镜像模式
params.fillMode = TRTCCloudDef.TRTC_VIDEO_RENDER_MODE_FILL; // 画面填充模式
params.rotation = TRTCCloudDef.TRTC_VIDEO_ROTATION_0; // 画面旋转角度
mTRTCCloud.setLocalRenderParams(params);
?
// 设置编码器输出的画面镜像模式
mTRTCCloud.setVideoEncoderMirror(true);

RTMP 与 TRTC 互通问题

为降低客户接入门槛,TRTC 支持 RTMP 标准协议推拉流。您可根据实际情况选择安装 OBS 、FFmpeg 或其他 RTMP 库进行推流。
本功能目前已结束免费内测,接入的 RTMP 流会作为房间中的虚拟用户产生正常的通话费用。具体接入指引详见 实时音视频 通过 RTMP 与 TRTC 互通
RTMP 属于 TRTC 一个子模块,能与 TRTC 其他端互通,互通延迟正常情况下小于600ms,也可使用 TRTC 录制、转推等已有能力。网络架构如下图所示。
?
?
?
推拉流地址生成
// 推流地址生成规则
rtmp://rtmp.rtc.qq.com/push/房间号?sdkappid=应用&userid=用户名&usersig=签名
?
// 拉流地址生成规则
rtmp://rtmp.rtc.qq.com/pull/房间号?sdkappid=应用&userid=用户名&usersig=签名&remoteuserid=对端用户名&sessionid=会话id
注意:
本功能自2023年02月15日起结束免费内测,如需使用该功能需要订阅 TRTC 应用包月套餐尊享版或旗舰版来解锁功能。
本功能默认只支持字符串房间号,不超过64个字符;如需使用数字房间号,则需在推拉流 URL 地址中拼接参数 &use_number_room_id=1

摄像头缩放/对焦/切换问题

秀场直播场景下,主播可能会对摄像头有自定义调整的需求,TRTC SDK 设备管理类下也有解决此类需求的相关接口。
1. 查询、设置摄像头的缩放倍数。
// 获取摄像头的最大缩放倍数(仅适用于移动端)
float zoomRatio = mTRTCCloud.getDeviceManager().getCameraZoomMaxRatio();
// 设置摄像头的缩放倍数(仅适用于移动端)
// 取值范围1-5,取值为1表示最远视角(正常镜头),取值为5表示最近视角(放大镜头);最大值推荐为5,若超过5,视频数据会变得模糊不清
mTRTCCloud.getDeviceManager().setCameraZoomRatio(zoomRatio);
2. 设置摄像头的对焦功能及位置。
// 开启或关闭摄像头的自动对焦功能(仅适用于移动端)
mTRTCCloud.getDeviceManager().enableCameraAutoFocus(false);
// 设置摄像头的对焦位置(仅适用于移动端)
// 使用该接口的前提是先通过 enableCameraAutoFocus 关闭自动对焦功能
mTRTCCloud.getDeviceManager().setCameraFocusPosition(int x, int y);
3. 判断、切换前置或后置摄像头。
// 判断当前是否为前置摄像头(仅适用于移动端)
boolean isFrontCamera = mTRTCCloud.getDeviceManager().isFrontCamera();
// 切换前置或后置摄像头(仅适用于移动端)
// 传入true: 切换为前置;传入false: 切换为后置
mTRTCCloud.getDeviceManager().switchCamera(!isFrontCamera);
?


http://www.vxiaotou.com