最近在腾讯云集成了一下移动直播的SDK,从0到1的整个过程,中途遇到的问题也详细地给大家列举出来,希望对将要用到腾讯云移动直播产品的开发者们,起到一点点作用。若有不足的地方欢迎指出并赐教,谢谢!
此前,移动直播开发文档有的,我再次就不再复述,大家可以按照文档的步骤,一步一步来。地址:https://cloud.tencent.com/document/product/454/7876。首先,介绍一下,我主要使用这个SDK做了哪些功能:
其次,下载官网的SDK(https://github.com/tencentyun/MLVBSDK),根据官网配置好需要的 License和APPID等等。那么开始集成SDK,将Demo中的Common和LiveRoom文件拖到你的工程中
command b 运行,注意(这里的 Bundle ID必须和你工程的 Bundle ID一直,否则报License url不匹配)。
那么问题来了,首先将TCBeautyPanel这个工程拖进来,会提示一下错误。(在Common->TCBeautyPanel目录下)
产生错误:
Multiple commands produce '/Users/chenrongke/Library/Developer/Xcode/DerivedData/BigWork-ewykfxpdwrmuqjayrhykmhghoeiq/Build/Products/Debug-iphoneos/BigWork.app/Info.plist':
1) Target 'BigWork' (project 'BigWork') has copy command from '/Users/chenrongke/Desktop/BigWork/BigWork/Common/TCBeautyPanel/Resources/Info.plist' to '/Users/chenrongke/Library/Developer/Xcode/DerivedData/BigWork-ewykfxpdwrmuqjayrhykmhghoeiq/Build/Products/Debug-iphoneos/BigWork.app/Info.plist'
解决办法:xcode的file->Workspace Settings->New Build System 修改为legcay Build System
第二个错误:(导致出现异常的原因是因为工程中添加了一些.c文件(第三方开源解压缩库))
解决办法:将Build Setting ->Compile Sources As 改为 Objective-C
由于修改所有文件的编译类型,所有可能会导致其他包括c、c 代码的提示错误,不过都是些的提示异常,按提示修改即可。
注意,这里我们使用MLVBLiveRoom组件,需要考虑AFNetworking版本,最新版本的请求方法有变化,组件使用的是旧版本的,我这里指定 pod 'AFNetworking','~> 3.2.1’还可以正常使用。(当然你也可以使用最新AFN但需要修改MLVBLiveRoom组件里被AF废弃了的方法),这样,我们继承SDK运行就没有其他报错了,可以进行功能的开发了。
登录&直播间:
1、通过GET方法在@“https://room.zijiebao.com/weapp/utils/get_login_info_debug”的链接请求到
sdkAppID、userSig、userID
然后通过获取到的数据初始化MLVBLoginInfo,为初始化LiveRoom做准备
代码语言:txt复制// 输入代码内容
- (void)login{
__block NSString *userID = [[NSUserDefaults standardUserDefaults] objectForKey:@"userID"];
NSString *strCgiUrl = kHttpServerAddr_GetLoginInfo;
if (userID != nil && userID.length > 0) {
strCgiUrl = [NSString stringWithFormat:@"%@?userID=%@",kHttpServerAddr_GetLoginInfo,userID];
}
// 从后台获取随机产生的userID,以及IMSDK所需要的appid、account_type, sig等信息
AFHTTPSessionManager *httpSession = [AFHTTPSessionManager manager];
[httpSession setRequestSerializer:[AFJSONRequestSerializer serializer]];
[httpSession setResponseSerializer:[AFJSONResponseSerializer serializer]];
httpSession.requestSerializer.timeoutInterval = 5.0;
httpSession.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", @"text/xml", @"text/plain", nil];
__weak __typeof(self) weakSelf = self;
__weak AFHTTPSessionManager *weakManager = httpSession;
[httpSession GET:strCgiUrl parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[weakManager invalidateSessionCancelingTasks:NO];
int errCode = [responseObject[@"code"] intValue];
NSString *errMsg = responseObject[@"message"];
NSNumber * sdkAppID = responseObject[@"sdkAppID"];
NSString * userSig = responseObject[@"userSig"];
if (errCode != 0) {
NSLog(@"request login info failed: errCode[%d] errMsg[%@]", errCode, errMsg);
[weakSelf.view crk_MakeToast:errMsg duration:2 position:CSToastPositionCenter];
[self onLoginFailed];
return;
}
if (userID == nil || userID.length == 0) {
userID = responseObject[@"userID"];
if (userID == nil || userID.length == 0) {
NSLog(@"request login info failed: invalid userID");
[weakSelf.view crk_MakeToast:@"用户账号非法" duration:2 position:CSToastPositionCenter];
[self onLoginFailed];
return;
}else{
[[NSUserDefaults standardUserDefaults] setObject:userID forKey:@"userID"];
}
}
_userID = userID;
MLVBLoginInfo *loginInfo = [MLVBLoginInfo new];
loginInfo.sdkAppID = [sdkAppID intValue];
loginInfo.userID = userID;
loginInfo.userName = _userName;
loginInfo.userAvatar = @"headpic.png";
loginInfo.userSig = userSig;
// 初始化LiveRoom
[weakSelf.liveRoom loginWithInfo:loginInfo completion:^(int errCode, NSString *errMsg) {
__strong __typeof(weakSelf) self = weakSelf; if (nil == self) return;
dispatch_async(dispatch_get_main_queue(), ^{
// self->_createBtn.enabled = YES;
});
NSLog(@"init LiveRoom errCode[%d] errMsg[%@]", errCode, errMsg);
if (errCode == 0) {
//登录成功,获取直播间列表
[self getRoomList];
// weakSelf.initSucc = YES;
} else {
[self onLoginFailed];
[weakSelf.view crk_MakeToast:@"LiveRoom init失败" duration:2 position:CSToastPositionCenter];
}
}];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"request login info failed: err[%@]", [error description]);
[weakSelf.view crk_MakeToast:@"网络请求超时,请检查网络设置" duration:2 position:CSToastPositionCenter];
[self onLoginFailed];
[weakManager invalidateSessionCancelingTasks:NO];
}];
}
2、调用liveRoom loginWithInfo:loginInfo completion:^(int errCode, NSString *errMsg)的方法
进行 Room登录和IM初始化及登录,登录失败再次手动登录
3、登录成功,调用_liveRoom getRoomList:0 count:100 completion:^(int errCode, NSString errMsg, NSArray<MLVBRoomInfo > *roomInfoArray)方法获取房间列表
代码语言:txt复制//获取直播间列表
- (void)getRoomList{
[_liveRoom getRoomList:0 count:100 completion:^(int errCode, NSString *errMsg, NSArray<MLVBRoomInfo *> *roomInfoArray) {
NSLog(@"getRoomList errCode[%d] errMsg[%@]", errCode, errMsg);
self.roomList = roomInfoArray;
dispatch_async(dispatch_get_main_queue(), ^{
[self.tbvMicro reloadData];
});
}];
}
创建直播间:
1、使用[_liveRoom createRoom:self.userID roomInfo:_roomName completion:^(int errCode, NSString *errMsg)
创建一个直播间
2、开始推流和本地预览
_liveRoom startLocalPreview:YES view:_pusherView;(使用demo控件MLVBLiveRoom)
实际上是通过TXLivePushConfig初始化TXLivePush的推流,_livePusher startPreview:view使用这个方法进行推流
3、直播间相关功能相机转换、美颜、聊天、PK、静音
代码语言:txt复制相机转换: [_liveRoom switchCamera];( [_livePusher switchCamera] )
代码语言:txt复制静音: [self.liveRoom muteLocalAudio:YES];([_livePusher setMute:mute])
代码语言:txt复制聊天:(文字聊天)使用MLVBRoom中的model LiveRoomMsgModel存储消息的详情(消息类型,用户名,昵称,时间,高度)
代码语言:txt复制消息发送接口[_liveRoom sendRoomTextMsg:textMsg completion:nil];(自定义的消息sendRoomCustomMsg 接口)
接收消息回调:onRecvRoomTextMsg:(NSString *)roomID userID:(NSString *)userID userName:(NSString *)userName userAvatar:(NSString *)userAvatar message:(NSString *)message接收方接收到消息,刷新UI( onRecvRoomCustomMsg 自定义消息回调)
直播美颜滤镜:
美颜:美颜光滑、美颜自然、p图、美白、红润……等
我这里没有用Demo里面的TCBeautyPanel的库,文档描述使用: TXLivePush 中的setBeautyStyle接口,
但这个接口已经被废弃了,推荐使用TXBeautyManager这个类来设置。(getBeautyManager这个方法可以
获取到,liveRoom和TXLivePush 都有这个同名方法)
通过setBeautyStyle方法给出一个磨皮的算法,然后TXBeautyManager里面开发了很多美颜的方法,这里就不
一一展示了(在TXBeautyManager.h文件中,你可以清楚的看到美颜的各种方法以及他的功能)
代码语言:txt复制// 输入代码内容
/**
* 美颜(磨皮)算法
* SDK 内置了多种不同的磨皮算法,您可以选择最适合您产品定位的方案。
*/
typedef NS_ENUM(NSInteger, TXBeautyStyle) {
TXBeautyStyleSmooth = 0, ///< 光滑,适用于美女秀场,效果比较明显。
TXBeautyStyleNature = 1, ///< 自然,磨皮算法更多地保留了面部细节,主观感受上会更加自然。
TXBeautyStylePitu = 2 ///< 企业版美颜算法,仅在 [企业版 SDK](https://cloud.tencent.com/document/product/647/32689#Enterprise) 中生效
};
/**
* 设置美颜(磨皮)算法
*
* SDK 内部集成了两套风格不同的磨皮算法,一套我们取名叫“光滑”,适用于美女秀场,效果比较明显。
* 另一套我们取名“自然”,磨皮算法更多地保留了面部细节,主观感受上会更加自然。
*
* @param beautyStyle 美颜风格,光滑或者自然,光滑风格磨皮更加明显,适合娱乐场景。
*/
- (void)setBeautyStyle:(TXBeautyStyle)beautyStyle;
/**
* 设置美颜级别
* @param level 美颜级别,取值范围0 - 9; 0表示关闭,1 - 9值越大,效果越明显。
*/
- (void)setBeautyLevel:(float)level;
滤镜:使用TXBeautyManager 的setFilter方法,要求png图片进行滤镜效果,这里遇到了一个问题,我是直接
用了App里面展示的图片进行渲染,导致效果发生严重的偏差。后来看了文档,是我获取到的照片出错,
应该拿到demo中FilterResource.bundle同名的图片。
代码语言:txt复制// 错误的示范
}else if ([stytle isEqualToString:@"滤镜"]){
[self.beautyMng setFilter:[UIImage imageNamed:@"bailan.png"]];
}else if ([stytle isEqualToString:@"动效"]){
}
//改正后
}else if ([stytle isEqualToString:@"滤镜"]){
NSString * path = [[NSBundle mainBundle] pathForResource:@"FilterResource" ofType:@"bundle"];
path = [path stringByAppendingPathComponent:[dict objectForKey:@"img"]];
UIImage *image = [UIImage imageWithContentsOfFile:path];
[self.beautyMng setFilter:image];
}else if ([stytle isEqualToString:@"动效"]){
}
观众互动(连麦):
我这边连麦的功能只有在观众的界面,整个过程就是:观众进入(enterRoom)加入了IM Group,同时也
进行了拉流的操作(TXLivePlayer),然后发起连麦(liveroom requestJoinAnchor)
连麦逻辑:开始连麦是需要判断主播是否正在连麦或者PK中,只有主播处于空闲状态下才提示主播连
麦请求,开始推流(startLocalPreview)。主播收到连麦的请求(onRequestJoinAnchor),通过
responseJoinAnchor处理这个请求。观众收到主播连麦处理回调(joinAnchor),同意:然后双方进行推流
拉流,不同意,观众立即停止推流。停止连麦onKickoutJoinAnchor,观众停止推流,改变UI,主播停止
拉流修改UI
这里遇到一个问题:进行连麦的时候,观众端观看主播卡死,而主播端也不能刷出观众的连麦视频页面
(两边的推流都出现了问题,并过了一段时间,自动停止推流)。查看了房间监控的直播流量监控,发现看到连麦后,推流就为0帧了。(查看工具:http://dev.video.isd.com)
主要是因为网络的问题,网络不稳定,而我们的推流的画面质量太高,数据传输不过来。服务器70秒内无
法收到帧数据,直接断开直播放,日志打印网络超时。后面修改成了最低的画面质量就可以了。
主播PK:
逻辑:首先判断当前主播是否已经在PK或连麦中,如果是就停止PK quitRoomPK,否则获取主播列表
getRoomList(过滤掉当前主播)。选择某个主播进行PK(requestRoomPK),等待对方回应。对方主播收到onRequestRoomPK请求,调用responseRoomPK进行回应。拒接则当前主播一个提示。
同意则进行PK,同时布局UI,liveRoom的startRemoteView接口播放邀约主播的流。
这里还遇到了一个问题,主播PK一端断开了,另一端退出不了,quitRoomPK:返回错误-6(房间不存在)
原因:没有使用onQuitRoomPK的回调方法,没有移除pk的界面,再次推出pk房间已经不存在了
总结&问题:
遇到的问题:
1、在连麦和PK卡死的情况下,通过TXLivePushConfig 修改videoBitrateMin 和videoBitrateMax ,尝试通过修改码率来改变画质,但是没有效果。(通过监控器可以看出,码率确实是不在自定义的范围内)
原因:在自定义码率完成后,我还调用了TXLivePush 的setVideoQuality方法来设置画质(sdk推荐使用),
然后码率就会被重新配置,码率在1200到1800之间(好像是高清的画质),所以,两者只能设置其一,因为
不管哪个在前面都会被后者覆盖
2、 TXCAudioCore.mm, restart, 1969:AudioCenter: retry to start augraph after starting augraph failed, 系统异常,录音失败-10874,直播只有画面没有声音
解决方法:重新pod一下 pod 'TXLiteAVSDK_Professional', :podspec => 'http://pod-1252463788.cosgz.myzijiebao.com/liteavsdkspec/TXLiteAVSDK_Professional.podspec'
就好了,原因暂时不明。百度时查找到相似的问题,说移除AVAudioSession sharedInstance相关方法,或者添加一些关于音频的库。
3、使用MLVBLiveRoom组件,需要考虑AFNetworking版本,最新版本的请求方法有变化,组件使用的是旧版本的,我这里指定 pod 'AFNetworking','~> 3.2.1’还可以正常使用。
往后还会有更多的关于腾讯云音视频集成的相关问题,请大家多多关注。有不对的地方也请开发者们多提意见,谢谢大家!