iOS 腾讯云移动直播SDK对接(二)

本文借鉴官方文档编写,集成项目需要的推流和拉流部分

下载 SDK 开发包

点击下载SDK

2. 给 SDK 配置 License 授权

 获取测试用的 License,您会获得两个字符串:一个字符串是 licenseURL,另一个字符串是解密 key。

3.工程配置

配置运行系统为 iOS 9.0 以上。

如需要进入后台仍然运行相关功能,可选中当前工程项目,在 Capabilities 下设置 Background Modes 为 ON,并勾选 Audio,AirPlay and Picture in Picture

iOS 腾讯云移动直播SDK对接(二)_第1张图片

代码部分:

POD:

  #  腾讯云短视频SDK

pod 'TXLiteAVSDK_Professional'

1.引入头文件

在用到SDK的地方引入头文件#import "TXLiteAVSDK_Smart/TXLiteAVSDK.h"

2.配置SDK

在项目启动时配置SDK,这里有个坑的地方,licenceURL在控制台生成的时候是http开头,我们iOS需要将它改为https的,才能下载成功。

 

 //直播
#define TX_Live_licenceKey          @"a3a6**********0877"
#define TX_Live_licenceURL          @"https://license.vod2.myqcloud.com/license/v1/d766fa35**********955c322/TXLiveSDK.licence"
  
[TXLiveBase setLicenceURL:TX_Live_licenceURL key:TX_Live_licenceKey];

 

3.直播推流部分

 3.1初始化 TXLivePush 组件

首先创建一个TXLivePushConfig对象。该对象可以指定一些高级配置参数,但一般情况下我们不建议您操作该对象,因为我们已经在其内部配置好了所有需要校调的参数。之后再创建一个TXLivePush对象,该对象负责完成推流的主要工作

{
    TCBeautyPanel             *_beautyPanel;    // 美颜控件
}

@property (nonatomic, strong) TXLivePush *livePusher;



#pragma mark == setUpLivePusher
- (void)setUpLivePusher {
    // config初始化
    TXLivePushConfig *config = [[TXLivePushConfig alloc] init];
    config.pauseFps = 10;
    config.pauseTime = 300;
    config.pauseImg = [UIImage imageNamed:@"pause_publish"];
    //是否允许点击曝光聚焦
    config.touchFocus = NO;
    //是否允许双指手势放大预览画面
    config.enableZoom = NO;
    //否为纯音频推流
    config.enablePureAudioPush = NO;
    //是否开启耳返特效
    config.enableAudioPreview = NO;
    //        config.frontCamera = _btnCamera.tag == 0 ? YES : NO;
    //    /水印图片,设为 nil 等同于关闭水印
    config.watermark = nil;
    config.watermarkPos = CGPointMake(10, 10);
    // 推流器初始化
    self.livePusher = [[TXLivePush alloc] initWithConfig:config];
    //设置混响效果
    [self.livePusher setReverbType:NO];
    //设置变声类型
    [self.livePusher setVoiceChangerType:NO];
    //打开后置摄像头旁边的闪关灯
    [self.livePusher toggleTorch:NO];
    //设置视频镜像效果
    [self.livePusher setMirror:NO];
    //开启静音
    [self.livePusher setMute:NO];
    //设置视频编码质量
    [self.livePusher setVideoQuality:VIDEO_QUALITY_HIGH_DEFINITION adjustBitrate:NO adjustResolution:NO];
    
#ifdef ENABLE_CUSTOM_MODE_AUDIO_CAPTURE
    config.enableAEC = NO;
    config.customModeType = CUSTOM_MODE_AUDIO_CAPTURE;
    config.audioSampleRate = CUSTOM_AUDIO_CAPTURE_SAMPLERATE;
    config.audioChannels = CUSTOM_AUDIO_CAPTURE_CHANNEL;
#endif
    
    // 修改软硬编需要在setVideoQuality之后设置config.enableHWAcceleration
    config.enableHWAcceleration = YES;
    
    // 横屏推流需要先设置config.homeOrientation = HOME_ORIENTATION_RIGHT,然后再[pusher setRenderRotation:90]
    config.homeOrientation =  HOME_ORIENTATION_DOWN;
    [self.livePusher setRenderRotation:0];
    
    [self.livePusher setLogViewMargin:UIEdgeInsetsMake(120, 10, 60, 10)];
    //打开包含视频状态信息的调试浮层--调试模式下打开
    [self.livePusher showVideoDebugLog:YES];
    //设置推流是否覆盖时钟
    [self.livePusher setEnableClockOverlay:NO];
    
    [self.livePusher setConfig:config];
}

3.2 开启推流

从接口获取推流地址rtmpUrl,

需要开启预览展示到自己视图上

设置美颜 等控件

启动推流:如果已经通过startPreview接口启动了摄像头预览,就可以调用 TXLivePush 中的startPush接口开始推流。如果 startPush 接口返回 -5,则代表您的 License 校验失败了,请检查第2步“给 SDK 配置 License 授权”中的工作是否有问题

 


#pragma mark - 推流逻辑

- (BOOL)startPush {
    //推流地址
    NSString *rtmpUrl = self.pushModel.push;
    if (!([rtmpUrl hasPrefix:@"rtmp://"])) {
        Alert(@"推流地址不合法,目前只支持rtmp推流!");
        return NO;
    }
    
    // 检查摄像头权限
    AVAuthorizationStatus statusVideo = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if (statusVideo == AVAuthorizationStatusDenied) {
        Alert(@"获取摄像头权限失败,请前往隐私-相机设置里面打开应用权限");
        return NO;
    }
    
    // 检查麦克风权限
    AVAuthorizationStatus statusAudio = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
    if (statusAudio == AVAuthorizationStatusDenied) {
        Alert(@"获取麦克风权限失败,请前往隐私-麦克风设置里面打开应用权限");
        return NO;
    }
    
    
    // 设置delegate
    [self.livePusher setDelegate:self];
    /*美颜 --设置初始值*/
    [self setDefaultBeauty];
    
    // 开启预览
    [self.livePusher startPreview:self.pushV];
    
#ifdef ENABLE_CUSTOM_MODE_AUDIO_CAPTURE
    [CustomAudioFileReader sharedInstance].delegate = self;
    [[CustomAudioFileReader sharedInstance] start:CUSTOM_AUDIO_CAPTURE_SAMPLERATE
                                         channels:CUSTOM_AUDIO_CAPTURE_CHANNEL
                                  framLenInSample:1024];
#endif
    
    // 开始推流
    int ret = [self.livePusher startPush:rtmpUrl];
    if (ret != 0) {
        NSString *alerText = [NSString stringWithFormat:@"推流器启动失败: %d", ret];
        Alert(alerText);
        NSLog(@"推流器启动失败");
        return NO;
    }
    
    return YES;
}
#pragma mark - 美颜滤镜相关接口函数
/* @name 美颜滤镜相关接口函数
 getBeautyManager
 
 * 获取美颜管理对象
 *
 * 通过美颜管理,您可以使用以下功能:
 * - 设置"美颜风格"、“美白”、“红润”、“大眼”、“瘦脸”、“V脸”、“下巴”、“短脸”、“小鼻”、“亮眼”、“白牙”、“祛眼袋”、“祛皱纹”、“祛法令纹”等美容效果。
 * - 调整“发际线”、“眼间距”、“眼角”、“嘴形”、“鼻翼”、“鼻子位置”、“嘴唇厚度”、“脸型”
 * - 设置人脸挂件(素材)等动态效果
 * - 添加美妆
 * - 进行手势识别
 */
- (void)setDefaultBeauty{
    //设置美颜(磨皮)算法
    [[self.livePusher getBeautyManager] setBeautyStyle:TXBeautyStyleSmooth];
    /**
     * 设置美颜级别
     * @param level 美颜级别,取值范围0 - 9; 0表示关闭,1 - 9值越大,效果越明显。
     */
    [[self.livePusher getBeautyManager] setBeautyLevel:6];
    
    /**
     * 设置美白级别
     *
     * @param level 美白级别,取值范围0 - 9;0表示关闭,1 - 9值越大,效果越明显。
     */
    [[self.livePusher getBeautyManager] setWhitenessLevel:1];
    
    /**
     * 设置红润级别
     *
     * @param level 红润级别,取值范围0 - 9;0表示关闭,1 - 9值越大,效果越明显。
     */
    [[self.livePusher getBeautyManager] setRuddyLevel:1];
    
    
    /**
     #if TARGET_OS_IPHONE
     * 设置大眼级别(企业版有效,其它版本设置此参数无效)
     *
     * @param level 大眼级别,取值范围0 - 9;0表示关闭,1 - 9值越大,效果越明显。
     */
    [[self.livePusher getBeautyManager] setEyeScaleLevel:0];
    
    
    /**
     * 设置瘦脸级别(企业版有效,其它版本设置此参数无效)
     *
     * @param level 瘦脸级别,取值范围0 - 9;0表示关闭,1 - 9值越大,效果越明显。
     */
    [[self.livePusher getBeautyManager] setFaceSlimLevel:0];
    
}

3.3 直播推流-代理


#pragma mark ------(直播delegate) TXLivePushListener
- (void)onPushEvent:(int)evtID withParam:(NSDictionary *)param {
    dispatch_async(dispatch_get_main_queue(), ^{
        if (evtID == PUSH_ERR_NET_DISCONNECT || evtID == PUSH_ERR_INVALID_ADDRESS) {
            // 断开连接时,模拟点击一次关闭推流
            [self stopPush];
            
        } else if (evtID == PUSH_ERR_OPEN_CAMERA_FAIL) {
            [self stopPush];
            Alert(@"获取摄像头权限失败,请前往隐私-相机设置里面打开应用权限");
        } else if (evtID == PUSH_EVT_OPEN_CAMERA_SUCC) {
            [self.livePusher toggleTorch:NO];
            
        } else if (evtID == PUSH_ERR_OPEN_MIC_FAIL) {
            [self stopPush];
            Alert(@"获取麦克风权限失败,请前往隐私-麦克风设置里面打开应用权限");
            
        } else if (evtID == PUSH_EVT_CONNECT_SUCC) {
            //打开后置摄像头旁边的闪关灯
            [self.livePusher toggleTorch:NO];
            //设置视频镜像效果
            [self.livePusher setMirror:NO];
            
            [self.livePusher setMute:NO];
            [self.livePusher showVideoDebugLog:NO];
            [self.livePusher setMirror:NO];
            [self.livePusher setReverbType:NO];
            [self.livePusher setVoiceChangerType:NO];
            
            BOOL isWifi = [AFNetworkReachabilityManager sharedManager].reachableViaWiFi;
            if (!isWifi) {
                __weak __typeof(self) weakSelf = self;
                [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
                    if (weakSelf.pushModel.push.length == 0) {
                        return;
                    }
                    if (status == AFNetworkReachabilityStatusReachableViaWiFi) {
                        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@""
                                                                                       message:@"您要切换到WiFi再推流吗?"
                                                                                preferredStyle:UIAlertControllerStyleAlert];
                        [alert addAction:[UIAlertAction actionWithTitle:@"是" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
                            [alert dismissViewControllerAnimated:YES completion:nil];
                            
                            // 先暂停,再重新推流
                            [weakSelf.livePusher stopPush];
                            [weakSelf.livePusher startPush:weakSelf.pushModel.push];
                        }]];
                        [alert addAction:[UIAlertAction actionWithTitle:@"否" style:UIAlertActionStyleCancel handler:^(UIAlertAction *_Nonnull action) {
                            [alert dismissViewControllerAnimated:YES completion:nil];
                        }]];
                        [weakSelf presentViewController:alert animated:YES completion:nil];
                    }
                }];
            }
        } else if (evtID == PUSH_WARNING_NET_BUSY) {
            Alert(@"您当前的网络环境不佳,请尽快更换网络保证正常直播");
        }
    });
}

- (void)onNetStatus:(NSDictionary *)param {
    // 这里可以上报相关推流信息到业务服务器
    // 比如:码率,分辨率,帧率,cpu使用,缓存等信息
    // 字段请在TXLiveSDKTypeDef.h中定义
    /*
    dispatch_async(dispatch_get_main_queue(), ^{
        int netspeed = [(NSNumber *) [param valueForKey:NET_STATUS_NET_SPEED] intValue];
        int videoEncBitrate = [(NSNumber *) [param valueForKey:NET_STATUS_VIDEO_BITRATE] intValue];
        int fps = [(NSNumber *) [param valueForKey:NET_STATUS_VIDEO_FPS] intValue];
        int gop = [(NSNumber *) [param valueForKey:NET_STATUS_VIDEO_GOP] intValue];
        
        NSString *encBitrateText = [NSString stringWithFormat:@"%dkbps", videoEncBitrate];
        NSString *upBitrateText = [NSString stringWithFormat:@"%dkbps", netspeed];
        NSString *fpsText = [NSString stringWithFormat:@"%d", fps];
        NSString *gopText = [NSString stringWithFormat:@"%ds", gop];
        NSLog(@"%@\n%@\n%@\n%@\n",encBitrateText,upBitrateText,fpsText,gopText);
    });
     */
}

 3.4推流结束后,可以调用 TXLivePush 中的stopPush接口结束推流。请注意,如果已经启动了摄像头预览,请在结束推流时将其关闭,否则会导致 SDK 的表现异常。


- (void)stopPush {
    if (_livePusher) {
        [_livePusher setDelegate:nil];
        [_livePusher stopPreview];
        [_livePusher stopBGM];
        [_livePusher stopRecord];
        [_livePusher stopPush];
    }
#ifdef ENABLE_CUSTOM_MODE_AUDIO_CAPTURE
    [[CustomAudioFileReader sharedInstance] stop];
    [CustomAudioFileReader sharedInstance].delegate = nil;
#endif
}

4.直播拉流部分

 4.1初始化TXLivePlayer

@property (nonatomic, strong) TXLivePlayer *livePlayer;


- (TXLivePlayer *)livePlayer {
    if (!_livePlayer) {
        _livePlayer = [[TXLivePlayer alloc] init];
        _livePlayer.enableHWAcceleration = YES;
        //        _livePlayer.config.connectRetryCount = 5;
        //        _livePlayer.config.connectRetryInterval = 5;
        //设置播放器代理
        _livePlayer.delegate = self;
    }
    return _livePlayer;
}

4.2从服务器拉取直播拉流地址,并检查是否符合要求,

添加到视图上开始播放

#pragma mark == setUpPlayer (初始化播放器)


-(BOOL)checkPlayUrl:(NSString*)playUrl {
    if ([playUrl hasPrefix:@"rtmp:"]) {
        _playType = PLAY_TYPE_LIVE_RTMP;
    } else if (([playUrl hasPrefix:@"https:"] || [playUrl hasPrefix:@"http:"]) && ([playUrl rangeOfString:@".flv"].length > 0)) {
        _playType = PLAY_TYPE_LIVE_FLV;
    } else if (([playUrl hasPrefix:@"https:"] || [playUrl hasPrefix:@"http:"]) && [playUrl rangeOfString:@".m3u8"].length > 0) {
        _playType = PLAY_TYPE_VOD_HLS;
    } else{
        Alert(@"播放地址不合法,直播目前仅支持rtmp,flv播放方式!");
        return NO;
    }
    
    return YES;
}

- (BOOL)startPlay {
    //    CGRect frame = CGRectMake(self.view.bounds.size.width, 0, self.view.bounds.size.width, self.view.bounds.size.height);
    //    _videoView.frame = frame;
    //    [_loadingImageView removeFromSuperview];
    
    NSString *playUrl = self.roomModel.play_url;
    
    if (![self checkPlayUrl:playUrl]) {
        return NO;
    }
    
    [self.livePlayer setDelegate:self];
    //    [_livePlayer setupVideoWidget:CGRectZero containView:self.playerView insertIndex:0];
    [self.livePlayer setupVideoWidget:CGRectZero containView:self.roomV.bgView insertIndex:0];
    
    
    int ret = [_livePlayer startPlay:playUrl type:_playType];
    
    //    frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
    //    [UIView animateWithDuration:0.4 animations:^{
    //        _videoView.frame = frame;
    //    } completion:^(BOOL finished) {
    //        [self.view addSubview:_loadingImageView];
    //    }];
    
    if (ret != 0) {
        Alert(@"播放器启动失败");
        return NO;
    }
    
    // 播放参数初始化
    //显示调试日志--调试模式下打开
    [self.livePlayer showVideoDebugLog:NO];//YES
    [self setCacheStrategy:CACHE_STRATEGY_AUTO];  // 默认自动

    //竖屏直播模式
    [self.livePlayer setRenderRotation:HOME_ORIENTATION_DOWN];
    
    //图像铺满屏幕
    [self.livePlayer setRenderMode:RENDER_MODE_FILL_SCREEN];
    
    
    return YES;
}

 

 

 

备注:在iOS工程中添加一些 C 文件或 C++文件(例如美颜),有时会报错:

 unknown type name 'NSString' NSObjcRuntime.h

 parse issue  expected unqualified-id

解决方案:

 在 prefix.pch 文件中 添加一下代码:

#ifdef __OBJC__

/*你自己的Demo */

 #endif

 

你可能感兴趣的:(腾讯云直播)