前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >移动直播集成(IOS版)

移动直播集成(IOS版)

原创
作者头像
rkChen
修改2020-07-07 10:21:53
1.7K0
修改2020-07-07 10:21:53
举报
文章被收录于专栏:音视频直播音视频直播

最近在腾讯云集成了一下移动直播的SDK,从0到1的整个过程,中途遇到的问题也详细地给大家列举出来,希望对将要用到腾讯云移动直播产品的开发者们,起到一点点作用。若有不足的地方欢迎指出并赐教,谢谢!

此前,移动直播开发文档有的,我再次就不再复述,大家可以按照文档的步骤,一步一步来。地址:https://cloud.tencent.com/document/product/454/7876。首先,介绍一下,我主要使用这个SDK做了哪些功能:

截屏2020-07-06 下午10.44.39.png
截屏2020-07-06 下午10.44.39.png

其次,下载官网的SDK(https://github.com/tencentyun/MLVBSDK),根据官网配置好需要的 License和APPID等等。那么开始集成SDK,将Demo中的Common和LiveRoom文件拖到你的工程中

截屏2020-07-06 下午10.53.27.png
截屏2020-07-06 下午10.53.27.png

command+b 运行,注意(这里的 Bundle ID必须和你工程的 Bundle ID一直,否则报License url不匹配)。

那么问题来了,首先将TCBeautyPanel这个工程拖进来,会提示一下错误。(在Common->TCBeautyPanel目录下)

viewfile.png
viewfile.png

产生错误:

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文件(第三方开源解压缩库))

viewfile-1.png
viewfile-1.png

解决办法:将Build Setting ->Compile Sources As 改为 Objective-C++

由于修改所有文件的编译类型,所有可能会导致其他包括c、c++代码的提示错误,不过都是些的提示异常,按提示修改即可。

注意,这里我们使用MLVBLiveRoom组件,需要考虑AFNetworking版本,最新版本的请求方法有变化,组件使用的是旧版本的,我这里指定 pod 'AFNetworking','~> 3.2.1’还可以正常使用。(当然你也可以使用最新AFN但需要修改MLVBLiveRoom组件里被AF废弃了的方法),这样,我们继承SDK运行就没有其他报错了,可以进行功能的开发了。

登录&直播间:

1、通过GET方法在@“https://room.qcloud.com/weapp/utils/get_login_info_debug”的链接请求到

sdkAppID、userSig、userID

然后通过获取到的数据初始化MLVBLoginInfo,为初始化LiveRoom做准备

// 输入代码内容
- (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)方法获取房间列表

//获取直播间列表
- (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、静音

相机转换: [_liveRoom switchCamera];( [_livePusher switchCamera] )
静音: [self.liveRoom muteLocalAudio:YES];([_livePusher setMute:mute])
聊天:(文字聊天)使用MLVBRoom中的model LiveRoomMsgModel存储消息的详情(消息类型,用户名,昵称,时间,高度)
消息发送接口[_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文件中,你可以清楚的看到美颜的各种方法以及他的功能)

// 输入代码内容
/**
 * 美颜(磨皮)算法
 * 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同名的图片。

截屏2020-07-06 下午11.32.26.png
截屏2020-07-06 下午11.32.26.png
// 错误的示范
}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:@"动效"]){
        
    }
截屏2020-07-06 下午11.39.30.png
截屏2020-07-06 下午11.39.30.png

观众互动(连麦):

我这边连麦的功能只有在观众的界面,整个过程就是:观众进入(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.myqcloud.com/liteavsdkspec/TXLiteAVSDK_Professional.podspec'

就好了,原因暂时不明。百度时查找到相似的问题,说移除AVAudioSession sharedInstance相关方法,或者添加一些关于音频的库。

3、使用MLVBLiveRoom组件,需要考虑AFNetworking版本,最新版本的请求方法有变化,组件使用的是旧版本的,我这里指定 pod 'AFNetworking','~> 3.2.1’还可以正常使用。

往后还会有更多的关于腾讯云音视频集成的相关问题,请大家多多关注。有不对的地方也请开发者们多提意见,谢谢大家!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 登录&直播间:
  • 创建直播间:
  • 直播美颜滤镜:
  • 观众互动(连麦):
  • 主播PK:
    • 原因:没有使用onQuitRoomPK的回调方法,没有移除pk的界面,再次推出pk房间已经不存在了
    • 总结&问题:
      • 原因:在自定义码率完成后,我还调用了TXLivePush 的setVideoQuality方法来设置画质(sdk推荐使用),
        • 然后码率就会被重新配置,码率在1200到1800之间(好像是高清的画质),所以,两者只能设置其一,因为
          • 不管哪个在前面都会被后者覆盖
            • 解决方法:重新pod一下 pod 'TXLiteAVSDK_Professional', :podspec => 'http://pod-1252463788.cosgz.myqcloud.com/liteavsdkspec/TXLiteAVSDK_Professional.podspec'
            相关产品与服务
            云直播
            云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档