iOS

最近更新时间:2025-04-16 15:33:53

我的收藏

业务流程

本节汇总了电商直播场景中一些常见的业务流程,帮助您更好地理解整个场景的实现流程。
主播开播及关播
主播跨房 PK 连麦
RTC 观众进房连麦
CDN 观众进房连麦
带货商品管理
下图展示了主播(房主)本地预览、创建房间、进房开播、退房关播的流程。



下图展示了主播 A 邀请主播 B 进行跨房 PK 连麦的流程。跨房 PK 过程中,两个房间内的观众都可以看到两个房主 PK 连麦直播的画面。



下图展示了 RTC 实时互动直播间观众进入房间、申请连麦、结束连麦、退出房间的流程。



下图展示了 RTC 旁路直播间 CDN 观众进入房间、申请连麦、结束连麦、退出房间的流程。



下图展示了直播带货场景中主播编辑、上架商品,观众浏览、购买商品的流程。




接入准备

步骤一:开通服务

电商直播场景通常需要依赖腾讯云 实时音视频 TRTC腾讯美颜特效播放器 SDK 等付费 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 两个参数,请妥善保存以下信息



若您想在已创建的测试应用中申请测试播放器功能,则需选择您想测试的应用,单击测试新功能。


2. 根据实际需求填写 App NamePackage NameBundle ID,选择播放器(高级版),单击确定



3. 测试版 License 成功创建后,页面会显示已生成的 License 信息。在 SDK 初始化配置时需要传入 License Key 和 License URL 两个参数,请妥善保存以下信息。



注意:
同一应用的 License URL 和 Key 唯一,测试版 License 升级为正式版后 License URL 和 Key 不变。
测试版 License 有效期内可单击右侧的编辑,进入修改 Bundle ID 和 Package Name 信息,单击确定即可保存。

步骤二:导入 SDK

TRTC SDK 和腾讯特效 SDK 已经发布到 CocoaPods 库,您可以通过 CocoaPods 集成。
1. 安装 CocoaPods。
在终端窗口中输入如下命令(需要提前在 Mac 中安装 Ruby 环境)。
sudo gem install cocoapods
2. 创建 Podfile 文件。
进入项目所在路径,输入以下命令行之后项目路径下会出现一个 Podfile 文件。
pod init
3. 编辑 Podfile 文件。
根据您的项目需要选择合适的版本,并编辑 Podfile 文件。
platform :ios, '8.0'
target 'App' do

# TRTC 精简版
# 安装包体积增量最小,但仅支持实时音视频(TRTC)和 直播播放器(TXLivePlayer)两项功能。
pod 'TXLiteAVSDK_TRTC', :podspec => 'https://liteav.sdk.qcloud.com/pod/liteavsdkspec/TXLiteAVSDK_TRTC.podspec'

# TRTC 全功能版(推荐)
# 包含实时音视频(TRTC)、直播播放器(TXLivePlayer)、RTMP 推流(TXLivePusher)、点播播放器(TXVodPlayer)和短视频录制和编辑(UGSV)等众多功能。
pod 'TXLiteAVSDK_Professional', :podspec => 'https://liteav.sdk.qcloud.com/pod/liteavsdkspec/TXLiteAVSDK_Professional.podspec'

# 腾讯特效 SDK 例如:S1-07套餐如下
pod 'TencentEffect_S1-07'

end
注意:
电商直播场景的实现通常需要依赖 TRTC、播放器等多项能力的组合,为避免单独集成的符号冲突问题,推荐您集成全功能版 SDK。
4. 更新并安装 SDK。
在终端窗口中输入如下命令以更新本地库文件,并安装 SDK。
pod install
或使用以下命令更新本地库版本:
pod update
pod 命令执行完后,会生成集成了 SDK 的 .xcworkspace 后缀的工程文件,双击打开即可。
说明:
若 pod 搜索失败,建议尝试更新 pod 的本地 repo 缓存,更新命令如下:
pod setup
pod repo update
rm ~/Library/Caches/CocoaPods/search_index.json
除了推荐的自动加载方式,您还可以选择下载 SDK 并手动导入,详见 手动导入 TRTC SDK手动导入腾讯特效 SDK
5. 添加美颜资源到实际项目工程中。
下载并解压对应套餐的 SDK 和美颜资源,将 resources/motionRes 文件夹下 bundle 资源添加到实际工程中。
在 Build Settings 中的 Other Linker Flags 添加 -ObjC
6. 将 Bundle Identifier 修改成与申请的测试授权一致。

步骤三:工程配置

1. 权限配置。
电商直播场景下 LiteAVSDK 及腾讯特效 SDK 需要以下权限。在 App 的 Info.plist 中添加以下两项,分别对应麦克风和摄像头在系统弹出授权对话框时的提示信息。
Privacy - Microphone Usage Description,并填入麦克风使用目的提示语。
Privacy - Camera Usage Description,并填入摄像头使用目的提示语。



2. 如需 App 进入后台仍然运行相关功能,可在 XCode 中选中当前工程项目,并在 Capabilities 下将设置项 Background Modes 设定为 ON,并勾选 Audio,AirPlay and Picture in Picture ,如下图所示:




步骤四:鉴权与许可

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,示例代码如下。
[TELicenseCheck setTELicense:LicenseURL key:LicenseKey completion:^(NSInteger authresult, NSString * _Nonnull errorMsg) {
if (authresult == TELicenseCheckOk) {
NSLog(@"鉴权成功");
} else {
NSLog(@"鉴权失败");
}
}];
注意:
建议在相关业务模块的初始化代码中触发鉴权许可,避免在使用前才临时去下载 License,同时鉴权时应具有网络权限。
实际应用的 Bundle ID 必须和创建 License 时绑定的 Bundle ID 完全匹配,否则会导致 License 校验失败,鉴权错误码
直播播放、点播播放功能需要配置播放器 Licence 授权后方可播放成功,否则将播放失败(黑屏),全局仅需设置一次即可。若您暂未获取 Licence,可 快速免费申请测试版 Licence 以正常播放,正式版 Licence 需 购买。申请 License 成功后,您将获得两个字符串:License URL License Key
在您的 App 调用 SDK 相关功能之前(建议在 - [AppDelegate application:didFinishLaunchingWithOptions:] 中)进行如下设置:
@import TXLiteAVSDK_Player;
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString * const licenceURL = @"<获取到的licenseUrl>";
NSString * const licenceKey = @"<获取到的key>";

//TXLiveBase 位于 "TXLiveBase.h" 头文件中
[TXLiveBase setLicenceURL:licenceURL key:licenceKey];
// TXLiveBase.delegate = self;
NSLog(@"SDK Version = %@", [TXLiveBase getSDKVersionStr]);
}

#pragma mark - TXLiveBaseDelegate
- (void)onLicenceLoaded:(int)result Reason:(NSString *)reason {
NSLog(@"onLicenceLoaded: result:%d reason:%@", result, reason);
}
@end
License 设置成功后(需稍等一段时间,具体时间长短依据网络情况而定),您可以通过调用如下方法查看 License 信息:
NSLog(@"%@", [TXLiveBase getLicenceInfo]);
注意:
实际应用的 Bundle ID 必须和创建 License 时绑定的 Bundle ID 完全匹配,否则会导致 License 校验失败。

步骤五:初始化 SDK

初始化 TRTC SDK
初始化腾讯特效 SDK
初始化播放器 SDK
// 创建 TRTC SDK 实例(单例模式)
self.trtcCloud = [TRTCCloud sharedInstance];
// 设置事件监听器
self.trtcCloud.delegate = self;

// 来自 SDK 的各类事件通知(比如:错误码,警告码,音视频状态参数等)
- (void)onError:(TXLiteAVError)errCode errMsg:(nullable NSString *)errMsg extInfo:(nullable NSDictionary *)extInfo {
NSLog(@"%d: %@", errCode, errMsg);
}

- (void)onWarning:(TXLiteAVWarning)warningCode warningMsg:(nullable NSString *)warningMsg extInfo:(nullable NSDictionary *)extInfo {
NSLog(@"%d: %@", warningCode, warningMsg);
}

// 移除事件监听器
self.trtcCloud.delegate = nil;
// 销毁 TRTC SDK 实例(单例模式)
[TRTCCloud destroySharedIntance];
说明:
建议监听 SDK 事件通知,对一些常见错误进行日志打印和处理,详见 错误码表
// 加载美颜相关资源
NSDictionary *assetsDict = @{@"core_name":@"LightCore.bundle",
@"root_path":[[NSBundle mainBundle] bundlePath]
};

// 初始化腾讯特效 SDK
self.beautyKit = [[XMagic alloc] initWithRenderSize:previewSize assetsDict:assetsDict];

// 释放腾讯特效 SDK
[self.beautyKit deinit];
说明:
初始化腾讯特效 SDK 之前,还需进行资源拷贝等准备工作,详细步骤可参考 腾讯特效 SDK 使用流程
点播播放场景 SDK 初始化。
// 1. 设置 SDK 接入环境(中国地区无需设置)
// 若您服务全球用户, 配置 SDK 接入环境为全球接入环境
[TXLiveBase setGlobalEnv:"GDPR"];

// 2. 创建 Player
TXVodPlayer *_txVodPlayer = [[TXVodPlayer alloc] init];

// 3. 关联渲染 View
[_txVodPlayer setupVideoWidget:_myView insertIndex:0];

// 4. 播放器参数配置
TXVodPlayConfig *_config = [[TXVodPlayConfig alloc]init];
[_config setEnableAccurateSeek:true]; // 设置是否精确 seek,默认 true
[_config setMaxCacheItems:5]; // 设置缓存文件个数为5
[_config setProgressInterval:200]; // 设置进度回调间隔,单位毫秒
[_config setMaxBufferSize:50]; // 最大预加载大小,单位 MB
[_txVodPlayer setConfig:_config]; // 把 config 传给 _txVodPlayer

// 5. 播放器事件监听
- (void)onPlayEvent:(TXVodPlayer *)player event:(int)EvtID withParam:(NSDictionary*)param { if (EvtID == PLAY_EVT_VOD_PLAY_PREPARED) { //收到播放器已经准备完成事件,此时可以调用 pause、resume、getWidth、getSupportedBitrates 等接口 } else if (EvtID == PLAY_EVT_PLAY_BEGIN) { // 收到开始播放事件 } else if (EvtID == PLAY_EVT_PLAY_END) { // 收到开始结束事件 } }
直播播放场景 SDK 初始化。
// 1. 创建 Player
V2TXLivePlayer *_txLivePlayer = [[V2TXLivePlayer alloc] init];

// 2. 关联渲染 View
[_txLivePlayer setRenderView:_myView];

// 3. 播放器事件监听
[_txLivePlayer setObserver:self];

- (void)onVideoLoading:(id<V2TXLivePlayer>)player extraInfo:(NSDictionary *)extraInfo {
// 视频加载事件
}

- (void)onVideoPlaying:(id<V2TXLivePlayer>)player firstPlay:(BOOL)firstPlay extraInfo:(NSDictionary *)extraInfo {
// 视频播放事件
}

接入过程

API 时序图





步骤一:主播进房推流

1. 主播进房前开启本地视频预览及音频采集。
// 获取用于展示主播本地画面预览的视频渲染控件
@property (nonatomic, strong) UIView *anchorPreviewView;
@property (nonatomic, strong) TRTCCloud *trtcCloud;

- (void)setupTRTC {
self.trtcCloud = [TRTCCloud sharedInstance];
self.trtcCloud.delegate = self;
// 设置视频编码参数,决定远端用户看到的画面质量
TRTCVideoEncParam *encParam = [[TRTCVideoEncParam alloc] init];
encParam.videoResolution = TRTCVideoResolution_960_540;
encParam.videoFps = 15;
encParam.videoBitrate = 1300;
encParam.resMode = TRTCVideoResolutionModePortrait;
[self.trtcCloud setVideoEncoderParam:encParam];
// isFrontCamera 可指定使用前置/后置摄像头进行视频采集
[self.trtcCloud startLocalPreview:self.isFrontCamera view:self.anchorPreviewView];

// 这里可指定声音音质,从低到高分别为 SPEECH/DEFAULT/MUSIC
[self.trtcCloud startLocalAudio:TRTCAudioQualityDefault];
}
注意:
您可根据业务需求自行设置视频编码参数 TRTCVideoEncParam,各档位最佳分辨率、码率搭配详见 TRTCVideoResolution
enterRoom 之前调用以上接口,SDK 只会开启摄像头预览和音频采集,并一直等到您调用 enterRoom 之后才开始推流。
enterRoom 之后调用以上接口,SDK 会开启摄像头预览和音频采集,并自动开始推流。
2. 主播设置本地画面的渲染参数,以及编码器输出画面模式(可选项)。
- (void)setupRenderParams {
TRTCRenderParams *params = [[TRTCRenderParams alloc] init];
// 画面镜像模式
params.mirrorType = TRTCVideoMirrorTypeAuto;
// 画面填充模式
params.fillMode = TRTCVideoFillMode_Fill;
// 画面旋转角度
params.rotation = TRTCVideoRotation_0;
// 设置本地画面的渲染参数
[self.trtcCloud setLocalRenderParams:params];

// 设置编码器输出的画面镜像模式
[self.trtcCloud setVideoEncoderMirror:YES];
// 设置视频编码器输出的画面方向
[self.trtcCloud setVideoEncoderRotation:TRTCVideoRotation_0];
}
注意:
设置本地画面渲染参数仅影响本地画面的渲染效果。
设置编码器输出模式会影响房间中其他用户所观看到(以及云端录制文件)的画面效果。
3. 主播正式开始直播,进房推流。
- (void)enterRoomByAnchorWithUserId:(NSString *)userId roomId:(NSString *)roomId {
TRTCParams *params = [[TRTCParams alloc] init];
// 以字符串房间号为例
params.strRoomId = roomId;
params.userId = userId;
// 从业务后台获取到的 UserSig
params.userSig = @"userSig";
// 替换成您的 SDKAppID
params.sdkAppId = 0;
// 指定主播角色
params.role = TRTCRoleAnchor;
// 以互动直播场景进房
[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];
}

// 进房结果事件回调
- (void)onEnterRoom:(NSInteger)result {
if (result > 0) {
// result 代表加入房间所消耗的时间(毫秒)
NSLog(@"Enter room succeed!");
} else {
// result 代表进房失败的错误码
NSLog(@"Enter room failed!");
}
}
注意:
TRTC 房间号分为整型 roomId 和字符串类型 strRoomId,两种类型的房间不互通,建议统一房间号类型。
TRTC 用户角色分为主播和听众,只有主播才有推流权限,进房时需指定用户角色,如未指定则默认为主播角色。
电商直播场景下,进房模式建议选用 TRTCAppSceneLIVE

步骤二:观众进房拉流

1. 观众进入 TRTC 房间。
- (void)enterRoomByAudienceWithUserId:(NSString *)userId roomId:(NSString *)roomId {
TRTCParams *params = [[TRTCParams alloc] init];
// 以字符串房间号为例
params.strRoomId = roomId;
params.userId = userId;
// 从业务后台获取到的 UserSig
params.userSig = @"userSig";
// 替换成您的 SDKAppID
params.sdkAppId = 0;
// 指定观众角色
params.role = TRTCRoleAudience;
// 以互动直播场景进房
[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];
}

// 进房结果事件回调
- (void)onEnterRoom:(NSInteger)result {
if (result > 0) {
// result 代表加入房间所消耗的时间(毫秒)
NSLog(@"Enter room succeed!");
} else {
// result 代表进房失败的错误码
NSLog(@"Enter room failed!");
}
}
2. 观众订阅主播音视频流。
- (void)onUserAudioAvailable:(NSString *)userId available:(BOOL)available {
// 某远端用户发布/取消了自己的音频
// 在自动订阅模式下,您无需做任何操作,SDK 会自动播放远端用户音频
}

- (void)onUserVideoAvailable:(NSString *)userId available:(BOOL)available {
// 某远端用户发布/取消了主路视频画面
if (available) {
// 订阅远端用户的视频流,并绑定视频渲染控件
[self.trtcCloud startRemoteView:userId streamType:TRTCVideoStreamTypeBig view:self.remoteView];
} else {
// 停止订阅远端用户的视频流,并释放渲染控件
[self.trtcCloud stopRemoteView:userId streamType:TRTCVideoStreamTypeBig];
}
}
3. 观众设置远端画面的渲染模式(可选项)。
- (void)setupRemoteRenderParams {
TRTCRenderParams *params = [[TRTCRenderParams alloc] init];
// 画面镜像模式
params.mirrorType = TRTCVideoMirrorTypeAuto;
// 画面填充模式
params.fillMode = TRTCVideoFillMode_Fill;
// 画面旋转角度
params.rotation = TRTCVideoRotation_0;
// 设置远端画面的渲染模式
[self.trtcCloud setRemoteRenderParams:@"userId" streamType:TRTCVideoStreamTypeBig params:params];
}

步骤三:观众连麦互动

1. 观众切换为主播角色。
- (void)switchToAnchor {
// 切换为主播角色
[self.trtcCloud switchRole:TRTCRoleAnchor];
}

// 切换角色事件回调
- (void)onSwitchRole:(TXLiteAVError)errCode errMsg:(NSString *)errMsg {
if (errCode == ERR_NULL) {
// 切换角色成功
}
}
2. 观众开始本地音视频采集和推流。
- (void)setupTRTC {
// 设置视频编码参数,决定远端用户看到的画面质量
TRTCVideoEncParam *encParam = [[TRTCVideoEncParam alloc] init];
encParam.videoResolution = TRTCVideoResolution_480_270;
encParam.videoFps = 15;
encParam.videoBitrate = 550;
encParam.resMode = TRTCVideoResolutionModePortrait;
[self.trtcCloud setVideoEncoderParam:encParam];
// isFrontCamera 可指定使用前置/后置摄像头进行视频采集
[self.trtcCloud startLocalPreview:self.isFrontCamera view:self.audiencePreviewView];
// 这里可指定声音音质,从低到高分别为 SPEECH/DEFAULT/MUSIC
[self.trtcCloud startLocalAudio:TRTCAudioQualityDefault];
}
注意:
您可根据业务需求自行设置视频编码参数 TRTCVideoEncParam,各档位最佳分辨率、码率搭配详见 TRTCVideoResolution
3. 观众下麦停止推流。
- (void)switchToAudience {
// 切换为观众角色
[self.trtcCloud switchRole:TRTCRoleAudience];
}

// 切换角色事件回调
- (void)onSwitchRole:(TXLiteAVError)errCode errMsg:(NSString *)errMsg {
if (errCode == ERR_NULL) {
// 停止摄像头采集推流
[self.trtcCloud stopLocalPreview];
// 停止麦克风采集推流
[self.trtcCloud stopLocalAudio];
}
}

步骤四:退出与解散房间

1. 退出房间。
- (void)exitRoom {
[self.trtcCloud stopLocalAudio];
[self.trtcCloud stopLocalPreview];
[self.trtcCloud exitRoom];
}

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

备选方案

API 时序图





步骤一:主播旁路推流

1. 前置条件:打开 TRTC 控制台,在应用管理页选择目标应用,点击配置进入基础功能页面,点击开启旁路转推,同时建议选择指定流旁路。旁路转推域名可在 云直播控制台 添加,也可使用系统默认的推流域名。



2. 主播进房前开启本地视频预览及音频采集。
// 获取用于展示主播本地画面预览的视频渲染控件
@property (nonatomic, strong) UIView *anchorPreviewView;


- (void)setupTRTC {
self.trtcCloud = [TRTCCloud sharedInstance];
self.trtcCloud.delegate = self;
// 设置视频编码参数,决定远端用户看到的画面质量
TRTCVideoEncParam *encParam = [[TRTCVideoEncParam alloc] init];
encParam.videoResolution = TRTCVideoResolution_960_540;
encParam.videoFps = 15;
encParam.videoBitrate = 1300;
encParam.resMode = TRTCVideoResolutionModePortrait;
[self.trtcCloud setVideoEncoderParam:encParam];

// isFrontCamera 可指定使用前置/后置摄像头进行视频采集
[self.trtcCloud startLocalPreview:self.isFrontCamera view:self.anchorPreviewView];
// 这里可指定声音音质,从低到高分别为 SPEECH/DEFAULT/MUSIC
[self.trtcCloud startLocalAudio:TRTCAudioQualityDefault];
}
注意:
您可根据业务需求自行设置视频编码参数 TRTCVideoEncParam,各档位最佳分辨率、码率搭配详见 TRTCVideoResolution
enterRoom 之前调用以上接口,SDK 只会开启摄像头预览和音频采集,并一直等到您调用 enterRoom 之后才开始推流。
enterRoom 之后调用以上接口,SDK 会开启摄像头预览和音频采集,并自动开始推流。
3. 主播设置本地画面的渲染参数,以及编码器输出画面模式。
- (void)setupRenderParams {
TRTCRenderParams *params = [[TRTCRenderParams alloc] init];
// 画面镜像模式
params.mirrorType = TRTCVideoMirrorTypeAuto;
// 画面填充模式
params.fillMode = TRTCVideoFillMode_Fill;
// 画面旋转角度
params.rotation = TRTCVideoRotation_0;
// 设置本地画面的渲染参数
[self.trtcCloud setLocalRenderParams:params];
// 设置编码器输出的画面镜像模式
[self.trtcCloud setVideoEncoderMirror:YES];
// 设置视频编码器输出的画面方向
[self.trtcCloud setVideoEncoderRotation:TRTCVideoRotation_0];
}
注意:
设置本地画面渲染参数仅影响本地画面的渲染效果。
设置编码器输出模式会影响房间中其他用户所观看到(以及云端录制文件)的画面效果。
4. 主播正式开始直播,进房推流。
- (void)enterRoomByAnchorWithUserId:(NSString *)userId roomId:(NSString *)roomId {
TRTCParams *params = [[TRTCParams alloc] init];
// 以字符串房间号为例
params.strRoomId = roomId;
params.userId = userId;
// 从业务后台获取到的 UserSig
params.userSig = @"userSig";
// 替换成您的 SDKAppID
params.sdkAppId = 0;
// 指定主播角色
params.role = TRTCRoleAnchor;
// 以互动直播场景进房
[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];
}

// 进房结果事件回调
- (void)onEnterRoom:(NSInteger)result {
if (result > 0) {
// result 代表加入房间所消耗的时间(毫秒)
NSLog(@"Enter room succeed!");
} else {
// result 代表进房失败的错误码
NSLog(@"Enter room failed!");
}
}
注意:
TRTC 房间号分为整型 roomId 和字符串类型 strRoomId,两种类型的房间不互通,建议统一房间号类型。
TRTC 用户角色分为主播和听众,只有主播才有推流权限,进房时需指定用户角色,如未指定则默认为主播角色。
电商直播场景下,进房模式建议选用 TRTCAppSceneLIVE
5. 主播将音视频流转推到直播 CDN。
- (void)startPublishMediaToCDN:(NSString *)streamName {
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0];
// 设定推流地址过期时间
NSTimeInterval time = [date timeIntervalSince1970] + (24 * 60 * 60);
// 生成鉴权信息,getSafeUrl 方法可在云直播控制台-域名管理-推流配置-推流地址示例代码获取
NSString *secretParam = [self getSafeUrl:LIVE_URL_KEY streamName:streamName time:time];
// 媒体流发布的目标地址
TRTCPublishTarget* target = [[TRTCPublishTarget alloc] init];
// 目标地址设定为旁路转推到 CDN
target.mode = TRTCPublishBigStreamToCdn;
TRTCPublishCdnUrl* cdnUrl = [[TRTCPublishCdnUrl alloc] init];
// 拼接发布到直播服务商的推流地址(RTMP 格式)
cdnUrl.rtmpUrl = [NSString stringWithFormat:@"rtmp://%@/live/%@?%@", PUSH_DOMAIN, streamName, secretParam];
// 腾讯云直播推流地址为 true,第三方为 false
cdnUrl.isInternalLine = YES;
NSMutableArray* cdnUrlList = [NSMutableArray array];
// 可以添加多个 CDN 推流地址
[cdnUrlList addObject:cdnUrl];
target.cdnUrlList = cdnUrlList;
// 设置媒体流编码输出参数(可根据业务需求自定义)
TRTCStreamEncoderParam* encoderParam = [[TRTCStreamEncoderParam alloc] init];
encoderParam.audioEncodedSampleRate = 48000;
encoderParam.audioEncodedChannelNum = 1;
encoderParam.audioEncodedKbps = 50;
encoderParam.audioEncodedCodecType = 0;
encoderParam.videoEncodedWidth = 540;
encoderParam.videoEncodedHeight = 960;
encoderParam.videoEncodedFPS = 15;
encoderParam.videoEncodedGOP = 2;
encoderParam.videoEncodedKbps = 1300;

// 开始发布媒体流
[self.trtcCloud startPublishMediaStream:target encoderParam:encoderParam mixingConfig:nil];
}
注意:
单主播直播时仅需发起旁路转推任务,待有观众连麦或主播 PK 时再将此任务更新为混流转码任务。
推流鉴权 KEY LIVE_URL_KEY 及推流域名 PUSH_DOMAIN 等信息需在 云直播控制台-域名管理 获取。
国际站用户、旧版架构用户如调用 startPublishMediaStream 报错,请 联系我们 协助发布配置。
发布媒体流后,SDK 会通过回调 onStartPublishMediaStream 带给您后台启动的任务标识(即 taskId)。
- (void)onStartPublishMediaStream:(NSString *)taskId code:(int)code message:(NSString *)message extraInfo:(NSDictionary *)extraInfo {
// taskId: 当请求成功时,TRTC 后台会在回调中提供给您这项任务的 taskId,后续您可以通过该 taskId 结合 updatePublishMediaStream 和 stopPublishMediaStream 进行更新和停止
// code: 回调结果,0 表示成功,其余值表示失败
}

步骤二:观众拉流播放

CDN 观众无需进入 TRTC 房间,可直接拉取主播旁路 CDN 流播放。
// 初始化播放器
self.livePlayer = [[V2TXLivePlayer alloc] init];
// 设置播放器回调监听
[self.livePlayer setObserver:self];
// 设置播放器的视频渲染控件
[self.livePlayer setRenderView:self.remoteView];
// 设置延迟调节模式(可选项)
[self.livePlayer setCacheParams:1.f maxTime:5.f]; // 自动模式
[self.livePlayer setCacheParams:1.f maxTime:1.f]; // 极速模式
[self.livePlayer setCacheParams:5.f maxTime:5.f]; // 流畅模式

// 拼接拉流播放地址
NSString *flvUrl = [NSString stringWithFormat:@"http://%@/live/%@.flv", PLAY_DOMAIN, streamName];
NSString *hlsUrl = [NSString stringWithFormat:@"http://%@/live/%@.m3u8", PLAY_DOMAIN, streamName];
NSString *rtmpUrl = [NSString stringWithFormat:@"rtmp://%@/live/%@", PLAY_DOMAIN, streamName];
NSString *webrtcUrl = [NSString stringWithFormat:@"webrtc://%@/live/%@", PLAY_DOMAIN, streamName];

// 启动播放
[self.livePlayer startLivePlay:flvUrl];

// 自定义设置填充模式(可选项)
[self.livePlayer setRenderFillMode:V2TXLiveFillModeFit];
// 自定义设置画面渲染方向(可选项)
[self.livePlayer setRenderRotation:V2TXLiveRotation0];
注意:
播放域名 PLAY_DOMAIN 需要您在 云直播控制台 添加自有已备案域名进行直播播放,并需 配置域名 CNAME
使用直播播放功能需要提前配置播放器 Licence 授权,否则将播放失败(黑屏),详见 鉴权与许可

步骤三:观众连麦互动

1. 连麦观众需要进入 TRTC 房间与主播实时互动。
// 进入 TRTC 房间并开始推流
- (void)enterRoomWithUserId:(NSString *)userId roomId:(NSString *)roomId {
TRTCParams *params = [[TRTCParams alloc] init];
// 以字符串房间号为例
params.strRoomId = roomId;
params.userId = userId;
// 从业务后台获取到的 UserSig
params.userSig = @"userSig";
// 替换成您的 SDKAppID
params.sdkAppId = 0;
// 指定主播角色
params.role = TRTCRoleAnchor;
// 开启本地音视频采集
[self startLocalMedia];
// 以互动直播场景进房
[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];
}

// 开启本地视频预览及音频采集
- (void)startLocalMedia {
// 设置视频编码参数,决定远端用户看到的画面质量
TRTCVideoEncParam *encParam = [[TRTCVideoEncParam alloc] init];
encParam.videoResolution = TRTCVideoResolution_480_270;
encParam.videoFps = 15;
encParam.videoBitrate = 550;
encParam.resMode = TRTCVideoResolutionModePortrait;
[self.trtcCloud setVideoEncoderParam:encParam];
// isFrontCamera 可指定使用前置/后置摄像头进行视频采集
[self.trtcCloud startLocalPreview:self.isFrontCamera view:self.audiencePreviewView];
// 这里可指定声音音质,从低到高分别为 SPEECH/DEFAULT/MUSIC
[self.trtcCloud startLocalAudio:TRTCAudioQualityDefault];
}

// 进房结果事件回调
- (void)onEnterRoom:(NSInteger)result {
if (result > 0) {
// result 代表加入房间所消耗的时间(毫秒)
NSLog(@"Enter room succeed!");
} else {
// result 代表进房失败的错误码
NSLog(@"Enter room failed!");
}
}
注意:
您可根据业务需求自行设置视频编码参数 TRTCVideoEncParam,各档位最佳分辨率、码率搭配详见 TRTCVideoResolution
2. 连麦观众进房成功后开始订阅主播音视频流。
- (void)onUserAudioAvailable:(NSString *)userId available:(BOOL)available {
// 某远端用户发布/取消了自己的音频
// 在自动订阅模式下,您无需做任何操作,SDK 会自动播放远端用户音频
}

- (void)onUserVideoAvailable:(NSString *)userId available:(BOOL)available {
// 某远端用户发布/取消了主路视频画面
if (available) {
// 订阅远端用户的视频流,并绑定视频渲染控件
[self.trtcCloud startRemoteView:userId streamType:TRTCVideoStreamTypeBig view:self.remoteView];
} else {
// 停止订阅远端用户的视频流,并释放渲染控件
[self.trtcCloud stopRemoteView:userId streamType:TRTCVideoStreamTypeBig];
}
}

- (void)onFirstVideoFrame:(NSString *)userId streamType:(TRTCVideoStreamType)streamType width:(int)width height:(int)height {
// SDK 开始渲染本地或远端用户的首帧画面
if (![userId isEqualToString:@""]) {
// 收到主播首帧画面,停止播放 CDN 流
[self.livePlayer stopPlay];
}
}
注意:
TRTC 拉流 startRemoteView 可直接复用之前 CDN 拉流 setRenderView 的视频渲染控件。
为避免在切换拉流器时画面中断,建议等待收到 TRTC 首帧回调 onFirstVideoFrame 后再停止 CDN 拉流。
3. 主播更新发布混合媒体流。
// 连麦观众进房事件回调
- (void)onRemoteUserEnterRoom:(NSString *)userId {
if (![self.mixUserList containsObject:userId]) {
[self.mixUserList addObject:userId];
}
[self updatePublishMediaToCDN];
}

// 更新发布混合媒体流到直播 CDN
- (void)updatePublishMediaToCDN {
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0];
// 设定推流地址过期时间
NSTimeInterval time = [date timeIntervalSince1970] + (24 * 60 * 60);
// 生成鉴权信息,getSafeUrl 方法可在云直播控制台-域名管理-推流配置-推流地址示例代码获取
NSString *secretParam = [self getSafeUrl:LIVE_URL_KEY streamName:self.streamName time:time];
// 媒体流发布的目标地址
TRTCPublishTarget* target = [[TRTCPublishTarget alloc] init];
// 目标地址设定为混流转推到 CDN
target.mode = TRTCPublishMixStreamToCdn;
TRTCPublishCdnUrl* cdnUrl = [[TRTCPublishCdnUrl alloc] init];
// 拼接发布到直播服务商的推流地址(RTMP 格式)
cdnUrl.rtmpUrl = [NSString stringWithFormat:@"rtmp://%@/live/%@?%@", PUSH_DOMAIN, self.streamName, secretParam];
// 腾讯云直播推流地址为 true,第三方为 false
cdnUrl.isInternalLine = YES;
NSMutableArray* cdnUrlList = [NSMutableArray array];
// 可以添加多个 CDN 推流地址
[cdnUrlList addObject:cdnUrl];
target.cdnUrlList = cdnUrlList;
// 设置媒体流编码输出参数
TRTCStreamEncoderParam* encoderParam = [[TRTCStreamEncoderParam alloc] init];
encoderParam.audioEncodedSampleRate = 48000;
encoderParam.audioEncodedChannelNum = 1;
encoderParam.audioEncodedKbps = 50;
encoderParam.audioEncodedCodecType = 0;
encoderParam.videoEncodedWidth = 540;
encoderParam.videoEncodedHeight = 960;
encoderParam.videoEncodedFPS = 15;
encoderParam.videoEncodedGOP = 2;
encoderParam.videoEncodedKbps = 1300;
TRTCStreamMixingConfig *config = [[TRTCStreamMixingConfig alloc] init];
if (self.mixUserList.count) {
NSMutableArray<TRTCUser *> *userList = [NSMutableArray array];
NSMutableArray<TRTCVideoLayout *> *layoutList = [NSMutableArray array];
for (int i = 1; i < MIN(self.mixUserList.count, 16); i++) {
TRTCUser *user = [[TRTCUser alloc] init];
// 整型房间号为 intRoomId
user.strRoomId = self.roomId;
user.userId = self.mixUserList[i];
[userList addObject:user];
TRTCVideoLayout *layout = [[TRTCVideoLayout alloc] init];
if ([self.mixUserList[i] isEqualToString:self.userId]) {
// 主播画面布局
layout.rect = CGRectMake(0, 0, 540, 960);
layout.zOrder = 0;
} else {
// 连麦观众画面布局
layout.rect = CGRectMake(400, 5 + i * 245, 135, 240);
layout.zOrder = 1;
}
layout.fixedVideoUser = user;
layout.fixedVideoStreamType = TRTCVideoStreamTypeBig;
[layoutList addObject:layout];
}
// 指定转码流中的每一路输入音频的信息
config.audioMixUserList = [userList copy];
// 指定混合画面的中每一路视频画面的位置、大小、图层以及流类型等信息
config.videoLayoutList = [layoutList copy];
}
// 更新发布媒体流
[self.trtcCloud updatePublishMediaStream:self.taskId publishTarget:target encoderParam:encoderParam mixingConfig:config];
}

// 更新媒体流的事件回调
- (void)onUpdatePublishMediaStream:(NSString *)taskId code:(int)code message:(NSString *)message extraInfo:(NSDictionary *)extraInfo {
// 您调用媒体流发布接口 (updatePublishMediaStream) 时传入的 taskId,会通过此回调再带回给您,用于标识该回调属于哪一次更新请求
// code: 回调结果,0 表示成功,其余值表示失败
}
注意:
为了保证 CDN 播放连续并且不会发生断流,您需要保持媒体流编码输出参数 encoderParam 以及流名称 streamName 不变。
媒体流编码输出参数、混合画面布局参数可根据业务需求自定义;当前仅支持最高16路音视频输入,如果用户只有音频也会被算作一路。
同一个任务不支持纯音频、音视频、纯视频之间的切换。
4. 观众下麦退房,主播更新混流任务。

// 设置播放器回调监听
[self.livePlayer setObserver:self];
// 可复用 TRTC 视频渲染控件
[self.livePlayer setRenderView:self.remoteView];
// 重新开始播放 CDN 媒体流
[self.livePlayer startLivePlay:flvUrl];


- (void)onVideoLoading:(id<V2TXLivePlayer>)player extraInfo:(NSDictionary *)extraInfo {
// 视频加载事件
}

// 视频播放事件
- (void)onVideoPlaying:(id<V2TXLivePlayer>)player firstPlay:(BOOL)firstPlay extraInfo:(NSDictionary *)extraInfo {
if (firstPlay) {
[self.trtcCloud stopAllRemoteView];
[self.trtcCloud stopLocalAudio];
[self.trtcCloud stopLocalPreview];
[self.trtcCloud exitRoom];
}
}
注意:
为避免在切换拉流器时画面中断,建议等待收到播放器视频播放事件 onVideoPlaying 后再退出 TRTC 房间。
// 连麦观众退房事件回调
- (void)onRemoteUserLeaveRoom:(NSString *)userId reason:(NSInteger)reason {
if ([self.mixUserList containsObject:userId]) {
[self.mixUserList removeObject:userId];
}
// 主播更新混流任务
[self updatePublishMediaToCDN];
}

// 更新媒体流的事件回调
- (void)onUpdatePublishMediaStream:(NSString *)taskId code:(int)code message:(NSString *)message extraInfo:(NSDictionary *)extraInfo {
// 您调用媒体流发布接口 (updatePublishMediaStream) 时传入的 taskId,会通过此回调再带回给您,用于标识该回调属于哪一次更新请求
// code: 回调结果,0 表示成功,其余值表示失败
}

步骤四:主播关播与退房

- (void)exitRoom {
// 停止所有发布的媒体流
[self.trtcCloud stopPublishMediaStream:@""];
[self.trtcCloud stopLocalAudio];
[self.trtcCloud stopLocalPreview];
[self.trtcCloud exitRoom];
}

// 停止媒体流的事件回调
- (void)onStopPublishMediaStream:(NSString *)taskId code:(int)code message:(NSString *)message extraInfo:(NSDictionary *)extraInfo {
// 您调用停止发布媒体流 (stopPublishMediaStream) 时传入的 taskId,会通过此回调再带回给您,用于标识该回调属于哪一次停止请求
// code: 回调结果,0 表示成功,其余值表示失败
}

// 离开房间事件回调
- (void)onExitRoom:(NSInteger)reason {
if (reason == 0) {
NSLog(@"主动调用 exitRoom 退出房间");
} else if (reason == 1) {
NSLog(@"被服务器踢出当前房间");
} else if (reason == 2) {
NSLog(@"当前房间整个被解散");
}
}
注意:
停止发布媒体流传参 taskId 填写空字符串,将会停止所有您发布的媒体流。
待 SDK 占用的所有资源释放完毕后,SDK 会抛出 onExitRoom 回调通知到您。

高级功能

商品信息弹窗

商品信息弹窗功能可以通过 IM 自定义消息 实现,也可以通过 SEI 信息 实现,下面将分别介绍这两种实现方式。

自定义消息

自定义消息需要依赖腾讯云 即时通信 IM 的能力,您需提前开通服务并导入 IM SDK,详细指引请参考 语聊房接入指引-接入准备
1. 发送自定义消息。
方式一:主播在客户端发送商品弹窗相关的群组自定义消息。
// 构造商品弹窗消息体
NSDictionary *msgDict = @{
@"itemNumber": @1, // 商品编号
@"itemPrice": @199.0, // 商品价格
@"itemTitle": @"xxx", // 商品标题
@"itemUrl": @"xxx" // 商品图片地址
};
NSDictionary *dataDict = @{
@"cmd": @"item_popup_msg",
@"msg": msgDict
};
NSError *error;
NSData *data = [NSJSONSerialization dataWithJSONObject:dataDict options:0 error:&error];

// 发送群自定义消息(商品弹窗消息建议设置为高优先级)
[[V2TIMManager sharedInstance] sendGroupCustomMessage:data to:groupID priority:V2TIM_PRIORITY_HIGH succ:^{
// 发送商品弹窗消息成功
// 本地渲染商品弹窗效果
} fail:^(int code, NSString *desc) {
// 发送商品弹窗消息失败
}];
方式二:后台运营在服务端发送商品弹窗相关的群组自定义消息。
请求 URL 示例:
https://xxxxxx/v4/group_open_http_svc/send_group_msg?sdkappid=88888888&identifier=admin&usersig=xxx&random=99999999&contenttype=json
请求包体示例:
{
"GroupId": "@TGS#12DEVUDHQ",
"Random": 2784275388,
"MsgPriority": "High", // 消息的优先级,商品弹窗消息建议设置为高优先级
"MsgBody": [
{
"MsgType": "TIMCustomElem",
"MsgContent": {
// itemNumber: 商品编号; itemPrice: 商品价格; itemTitel: 商品标题; itemUrl: 商品图片地址
"Data": "{\\"cmd\\": \\"item_popup_msg\\", \\"msg\\": {\\"itemNumber\\": 1, \\"itemPrice\\": 199.0, \\"itemTitle\\": \\"xxx\\", \\"itemUrl\\": \\"xxx\\"}}"
}
}
]
}
2. 接收自定义消息。
房间内其他用户客户端收到群自定义消息回调,然后进行消息解析和商品弹窗效果渲染。
// 收到群自定义消息
[[V2TIMManager sharedInstance] addSimpleMsgListener:self];
- (void)onRecvGroupCustomMessage:(NSString *)msgID groupID:(NSString *)groupID sender:(V2TIMGroupMemberInfo *)info customData:(NSData *)data {
if (data.length > 0) {
NSError *error;
NSDictionary *dataDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!error) {
NSString *command = dataDict[@"cmd"];
NSDictionary *msgDict = dataDict[@"msg"];
if ([command isEqualToString:@"item_popup_msg"]) {
NSNumber *itemNumber = msgDict[@"itemNumber"]; // 商品编号
NSNumber *itemPrice = msgDict[@"itemPrice"]; // 商品价格
NSString *itemTitle = msgDict[@"itemTitle"]; // 商品标题
NSString *itemUrl = msgDict[@"itemUrl"]; // 商品图片地址
// 根据商品编号、商品价格、商品标题、商品图片地址渲染商品弹窗效果
}
} else {
NSLog(@"解析错误: %@", error.localizedDescription);
}
}
}

SEI 信息

SEI 信息会插入到主播视频流中进行传输,能够实现商品信息弹窗和主播直播画面的精准同步。
1. 发送 SEI 信息。
主播在 TRTC 客户端发送商品弹窗相关的 SEI 消息。
// 构造商品弹窗消息体
NSDictionary *msgDict = @{
@"itemNumber": @1, // 商品编号
@"itemPrice": @199.0, // 商品价格
@"itemTitle": @"xxx", // 商品标题
@"itemUrl": @"xxx" // 商品图片地址
};
NSDictionary *dataDict = @{
@"cmd": @"item_popup_msg",
@"msg": msgDict
};
NSError *error;
NSData *data = [NSJSONSerialization dataWithJSONObject:dataDict options:0 error:&error];

// 发送 SEI 信息
[self.trtcCloud sendSEIMsg:data repeatCount:1];
2. 接收 SEI 信息。
方式一:观众在 TRTC 客户端接收 SEI 消息,然后进行消息解析和商品弹窗效果渲染。
// 设置 TRTC 事件监听器
self.trtcCloud.delegate = self;

// 收到 SEI 消息
- (void)onRecvSEIMsg:(NSString *)userId message:(NSData *)message {
if (message.length > 0) {
NSError *error;
NSDictionary *dataDict = [NSJSONSerialization JSONObjectWithData:message options:0 error:&error];
if (!error) {
NSString *command = dataDict[@"cmd"];
NSDictionary *msgDict = dataDict[@"msg"];
if ([command isEqualToString:@"item_popup_msg"]) {
NSNumber *itemNumber = msgDict[@"itemNumber"]; // 商品编号
NSNumber *itemPrice = msgDict[@"itemPrice"]; // 商品价格
NSString *itemTitle = msgDict[@"itemTitle"]; // 商品标题
NSString *itemUrl = msgDict[@"itemUrl"]; // 商品图片地址
// 根据商品编号、商品价格、商品标题、商品图片地址渲染商品弹窗效果
}
} else {
NSLog(@"解析错误: %@", error.localizedDescription);
}
}
}
方式二:观众在 CDN 流播放器端接收 SEI 消息,然后进行消息解析和商品弹窗效果渲染。
// 设置 TRTC 发送端 SEI 消息的 PayloadType(需在发送前设置)
[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"setSEIPayloadType\\",\\"params\\":{\\"payloadType\\":5}}"];

// 开启播放器端接收 SEI 消息, 同时设置 PayloadType
[self.livePlayer enableReceiveSeiMessage:YES payloadType:5];

// SEI 消息回调与解析
- (void)onReceiveSeiMessage:(id<V2TXLivePlayer>)player payloadType:(int)payloadType data:(NSData *)data {
if (data.length > 0) {
NSError *error;
NSDictionary *dataDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!error) {
NSString *command = dataDict[@"cmd"];
NSDictionary *msgDict = dataDict[@"msg"];
if ([command isEqualToString:@"item_popup_msg"]) {
NSNumber *itemNumber = msgDict[@"itemNumber"]; // 商品编号
NSNumber *itemPrice = msgDict[@"itemPrice"]; // 商品价格
NSString *itemTitle = msgDict[@"itemTitle"]; // 商品标题
NSString *itemUrl = msgDict[@"itemUrl"]; // 商品图片地址
// 根据商品编号、商品价格、商品标题、商品图片地址渲染商品弹窗效果
}
} else {
NSLog(@"解析错误: %@", error.localizedDescription);
}
}
}
注意:
需要确保 TRTC 发送端和播放器接收端的 SEI PayloadType 一致,观众端才能顺利接收到经由 TRTC 旁路转推的 SEI 消息。

商品讲解回放

通过播放提前录制好的商品讲解视频,实现商品讲解回放功能。
首先需要进行 播放器初始化,然后开始播放录制视频。TXVodPlayer 支持两种播放模式,您可以根据需要自行选择:
通过 URL 方式
通过 FileId 方式
// 播放 URL 视频资源
NSString* url = @"http://1252463788.vod2.myqcloud.com/xxxxx/v.f20.mp4";
[_txVodPlayer startVodPlay:url];

// 播放沙盒本地视频资源
// 获取 Documents路径
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
// 获取本地视频路径
NSString *videoPath = [NSString stringWithFormat:@"%@/video1.m3u8",documentPath];
[_txVodPlayer startVodPlay:videoPath];
TXPlayerAuthParams *p = [TXPlayerAuthParams new];
p.appId = 1252463788;
p.fileId = @"4564972819220421305";
// psign 即播放器签名,签名介绍和生成方式参见链接:https://cloud.tencent.com/document/product/266/42436
p.sign = @"psignxxxxx"; // 播放器签名
[_txVodPlayer startVodPlayWithParams:p];
播放控制:调整进度、暂停播放、恢复播放、结束播放。
// 调整进度(秒)
[_txVodPlayer seek:time];

// 暂停播放
[_txVodPlayer pause];

// 恢复播放
[_txVodPlayer resume];

// 结束播放
[_txVodPlayer stopPlay];
注意:
结束播放时,如果要退出当前的 UI 界面,要记得用 removeVideoWidget 销毁 view 控件,否则会产生内存泄露或闪屏问题。
// 销毁 view 控件
[_txVodPlayer removeVideoWidget];

跨房 PK 连麦

1. 任意一方发起跨房 PK 连麦。
- (void)connectOtherRoom:(NSString *)roomId {
NSMutableDictionary *jsonDict = [[NSMutableDictionary alloc] init];
// 数字房间号为 roomId
[jsonDict setObject:roomId forKey:@"strRoomId"];
[jsonDict setObject:self.userId forKey:@"userId"];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDict options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[self.trtcCloud connectOtherRoom:jsonString];
}

// 请求跨房连麦的结果回调
- (void)onConnectOtherRoom:(NSString *)userId errCode:(TXLiteAVError)errCode errMsg:(NSString *)errMsg {
// 要跨房通话的另一个房间中的主播的用户 ID
// 错误码,ERR_NULL 代表请求成功
// 错误信息
}
注意:
跨房 PK 连麦的本地用户和对端用户必须都为主播角色,且必须都有音频/视频上行。
可通过多次调用 ConnectOtherRoom() 来实现与多个房间主播跨房连麦,目前限制一个房间最多可以和其他三个房间的主播跨房连麦,一个房间中最多10个主播可与其他房间的主播跨房连麦。
2. 两个房间中的所有用户都会收到来自另一个房间中的 PK 主播的音视频流可用回调。
- (void)onUserAudioAvailable:(NSString *)userId available:(BOOL)available {
// 某远端用户发布/取消了自己的音频
// 在自动订阅模式下,您无需做任何操作,SDK 会自动播放远端用户音频
}

- (void)onUserVideoAvailable:(NSString *)userId available:(BOOL)available {
// 某远端用户发布/取消了主路视频画面
if (available) {
// 订阅远端用户的视频流,并绑定视频渲染控件
[self.trtcCloud startRemoteView:userId streamType:TRTCVideoStreamTypeBig view:self.remoteView];
} else {
// 停止订阅远端用户的视频流,并释放渲染控件
[self.trtcCloud stopRemoteView:userId streamType:TRTCVideoStreamTypeBig];
}
}
3. 任意一方退出跨房 PK 连麦。
// 退出跨房连麦
[self.trtcCloud disconnectOtherRoom];

// 退出跨房连麦的结果回调
- (void)onDisconnectOtherRoom:(TXLiteAVError)errCode errMsg:(NSString *)errMsg {
}
注意:
调用 DisconnectOtherRoom() 后,即退出与所有其他房间主播的跨房 PK 连麦。
跨房 PK 连麦的发起端和接收端任意一端均可调用 DisconnectOtherRoom() 退出跨房 PK 连麦。

第三方美颜接入

TRTC 支持接入第三方美颜特效产品,下面以腾讯特效为例,展示第三方美颜接入流程。
1. 集成腾讯特效 SDK、申请授权 License,详情请参照 接入准备 步骤实现。
2. 设置 SDK 素材资源路径(如有)。
NSString *beautyConfigPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
beautyConfigPath = [beautyConfigPath stringByAppendingPathComponent:@"beauty_config.json"];
NSFileManager *localFileManager=[[NSFileManager alloc] init];
BOOL isDir = YES;
NSDictionary * beautyConfigJson = @{};
if ([localFileManager fileExistsAtPath:beautyConfigPath isDirectory:&isDir] && !isDir) {
NSString *beautyConfigJsonStr = [NSString stringWithContentsOfFile:beautyConfigPath encoding:NSUTF8StringEncoding error:nil];
NSError *jsonError;
NSData *objectData = [beautyConfigJsonStr dataUsingEncoding:NSUTF8StringEncoding];
beautyConfigJson = [NSJSONSerialization JSONObjectWithData:objectData
options:NSJSONReadingMutableContainers
error:&jsonError];
}
NSDictionary *assetsDict = @{@"core_name":@"LightCore.bundle",
@"root_path":[[NSBundle mainBundle] bundlePath],
@"tnn_"
@"beauty_config":beautyConfigJson
};
// 初始化SDK:width和height分别是texture的宽高
self.xMagicKit = [[XMagic alloc] initWithRenderSize:CGSizeMake(width,height) assetsDict:assetsDict];
3. 设置第三方美颜的视频数据回调,将美颜 SDK 处理每帧数据结果传入 TRTC SDK 内部做渲染处理。
// TRTC SDK 设置第三方美颜的视频数据回调
[self.trtcCloud setLocalVideoProcessDelegete:self pixelFormat:TRTCVideoPixelFormat_Texture_2D bufferType:TRTCVideoBufferType_Texture];

#pragma mark - TRTCVideoFrameDelegate

// 构造 YTProcessInput 传入到 SDK 内做渲染处理
- (uint32_t)onProcessVideoFrame:(TRTCVideoFrame *_Nonnull)srcFrame dstFrame:(TRTCVideoFrame *_Nonnull)dstFrame {
if (!self.xMagicKit) {
[self buildBeautySDK:srcFrame.width and:srcFrame.height texture:srcFrame.textureId];//初始化XMagic SDK
self.heightF = srcFrame.height;
self.widthF = srcFrame.width;
}
if(self.xMagicKit!=nil && (self.heightF!=srcFrame.height || self.widthF!=srcFrame.width)){
self.heightF = srcFrame.height;
self.widthF = srcFrame.width;
[self.xMagicKit setRenderSize:CGSizeMake(srcFrame.width, srcFrame.height)];
}
YTProcessInput *input = [[YTProcessInput alloc] init];
input.textureData = [[YTTextureData alloc] init];
input.textureData.texture = srcFrame.textureId;
input.textureData.textureWidth = srcFrame.width;
input.textureData.textureHeight = srcFrame.height;
input.dataType = kYTTextureData;
YTProcessOutput *output = [self.xMagicKit process:input withOrigin:YtLightImageOriginTopLeft withOrientation:YtLightCameraRotation0];
dstFrame.textureId = output.textureData.texture;
return 0;
}
注意:
步骤1、步骤2根据不同的第三方美颜产品实现方式有所不同,而步骤3是 TRTC 集成第三方美颜的通用且重要步骤
场景化集成腾讯美颜特效指引详见 TRTC SDK 集成腾讯特效,独立集成腾讯美颜特效指引详见 独立集成腾讯特效

双路编码模式

开启双路编码模式后,当前用户的编码器会同时输出【高清大画面】和【低清小画面】两路视频流(但只有一路音频流)。这样,房间中的其他用户就可以根据自身的网络情况或屏幕大小选择订阅【高清大画面】或是【低清小画面】。
1. 开启大小画面双路编码模式。
- (void)enableDualStreamMode:(BOOL)enable {
// 小流的视频编码参数(可自定义)
TRTCVideoEncParam *smallVideoEncParam = [[TRTCVideoEncParam alloc] init];
smallVideoEncParam.videoResolution = TRTCVideoResolution_480_270;
smallVideoEncParam.videoFps = 15;
smallVideoEncParam.videoBitrate = 550;
smallVideoEncParam.resMode = TRTCVideoResolutionModePortrait;
[self.trtcCloud enableEncSmallVideoStream:enable withQuality:smallVideoEncParam];
}
注意:
双路编码开启后,会消耗更多的 CPU 和 网络带宽,所以 Mac、Windows 或者高性能 Pad 可以考虑开启,不建议手机端开启。
2. 选择拉取远端用户视频流类型。
// 订阅远端用户视频流时可选视频流类型
[self.trtcCloud startRemoteView:userId streamType:TRTCVideoStreamTypeBig view:view];

// 亦可随时切换指定远端用户的大小画面
[self.trtcCloud setRemoteVideoStreamType:userId type:TRTCVideoStreamTypeSmall];
注意:
双路编码开启后,可通过指定 streamType 视频流类型为 TRTCVideoStreamTypeSmall 来拉取低清小画面观看。

视图渲染控件

如果您业务涉及到切换显示区域的交互场景,可以使用 TRTC SDK 更新本地预览画面、更新远端用户视频渲染控件功能实现。
// 更新本地预览画面渲染控件
[self.trtcCloud updateLocalView:view];

// 更新远端用户视频渲染控件
[self.trtcCloud updateRemoteView:view streamType:TRTCVideoStreamTypeBig forUser:userId];
注意:
传参 view 为目标视频渲染控件,streamType 仅支持 TRTCVideoStreamTypeBigTRTCVideoStreamTypeSub

异常处理

异常错误处理

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 本地和远端画面的镜像模式策略如下:
使用前置摄像头采集:本地预览画面无镜像效果,远端观众观看有镜像效果。
使用后置摄像头采集:本地预览画面无镜像效果,远端观众观看无镜像效果。
当然,您也可以通过 setLocalRenderParamssetVideoEncoderMirror 分别自定义本地预览画面镜像效果,以及视频编码输出画面的镜像效果(远端观众及云端录制的镜像模式)。如果您希望同时设置本地预览的镜像效果和远端观众观看的镜像效果,请按照如下方法进行编码。
// 设置本地画面的渲染参数
TRTCRenderParams *params = [[TRTCRenderParams alloc] init];
params.mirrorType = TRTCVideoMirrorTypeEnable; // 画面镜像模式
params.fillMode = TRTCVideoFillMode_Fill; // 画面填充模式
params.rotation = TRTCVideoRotation_0; // 画面旋转角度
[self.trtcCloud setLocalRenderParams:params];

// 设置编码器输出的画面镜像模式
[self.trtcCloud setVideoEncoderMirror:YES];

采集设备旋转导致观众画面旋转

如果您遇到采集设备(主播端手机)在旋转翻转时,观众端拉流观看的画面渲染方向发生变化,您可以通过关闭 SDK 重力感应来避免这种现象。
[self.trtcCloud setGravitySensorAdaptiveMode:TRTCGravitySensorAdaptiveMode_Disable];
说明:
该接口只需在采集端(主播端)调用,更多关于横竖屏视频画面旋转的控制方案详见 视频画面旋转

RTMP 与 TRTC 互通问题

为降低客户接入门槛,TRTC 支持 RTMP 标准协议推拉流。您可根据实际情况选择安装 OBSFFmpeg 或其他 RTMP 库进行推流。
本功能目前已结束免费内测,接入的 RTMP 流会作为房间中的虚拟用户产生正常的通话费用。具体接入指引详见 实时音视频 通过 RTMP 与 TRTC 互通
RTMP 属于 TRTC 一个子模块,能与 TRTC 其他端互通,互通延迟正常情况下小于600ms,也可使用 TRTC 录制、转推等已有能力。网络架构如下图所示。




推流地址生成

rtmp://rtmp.rtc.qq.com/push/房间号?sdkappid=应用&userid=用户名&usersig=签名
注意:
本功能自2023年02月15日起结束免费内测,如需使用该功能需要订阅 TRTC 应用包月套餐尊享版或旗舰版来解锁功能。
本功能默认只支持字符串房间号,不超过64个字符;如需使用数字房间号,则需在推拉流 URL 地址中拼接参数 &use_number_room_id=1

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

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