云信小课堂 | 低延时直播功能的快速实现

云信小课堂 | 低延时直播功能的快速实现_第1张图片

Vol. 12

5e9c90730f97e5b43d947ec44425bb79.png

低延时直播是网易云信推出的低延时、强同步、高质量的直播产品。低延时直播产品基于云信全球智能路由网络,为开发者提供毫秒级延时、多平台同步、高可靠高并发的直播服务。

接下同大家一起,用 15 分钟的时间快速实现低延时直播的功能。

视频讲解

15分钟视频详解,手把手教你接入

前期准备

  • 开发工具:Xcode

  • 开发语言:Objective-C

  • 使用到的 SDK

  #直播推流

  pod 'NMCLiveStreaming', '3.3.0'

  #播放器拉流

  pod 'NELivePlayer', '3.1.3'

https://doc.yunxin.163.com/docs/jEyODA1OTE/DcxNjY0OTI?platformId=110002

参考官网低延时直播使用指南在云信后台直播模块-域名管理界面,开通低延时直播,获取推流地址以及对应的拉流地址和低延时拉流地址。

具体步骤

第一步:首先实现推流

1.传入获取到的“推流地址”和自定义的“推流配置”创建推流实例

NSString *url = @"推流地址";
//----推流配置----
LSLiveStreamingParaCtxConfiguration *config = [LSLiveStreamingParaCtxConfiguration defaultLiveStreamingConfiguration];
    config.sLSVideoParaCtx.interfaceOrientation       = LS_CAMERA_ORIENTATION_PORTRAIT;//摄像头的方向,可以选择横屏或者竖屏
    config.sLSVideoParaCtx.cameraPosition             = LS_CAMERA_POSITION_BACK;//前后摄像头
...
//----创建推流实例----
_mediaCapture = [[LSMediaCapture alloc]initLiveStream:url withLivestreamParaCtxConfiguration:config];
    if (_mediaCapture == nil) {
        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:@"初始化失败" forKey:NSLocalizedDescriptionKey];
        NSError *error = [NSError errorWithDomain:@"LSMediaCaptureErrorDomain" code:0 userInfo:userInfo];
        NSLog(@"---%@", error.localizedDescription);
    }

2.设置画布开启推流的视频预览

//开启预览
    [self.mediaCapture startVideoPreview:self.localPreview];

3.开始推流直播

推流之前需要在项目 info.plist 文件中配置请求允许 App 使用摄像头和麦克风。

NSCameraUsageDescription
app需要使用摄像头进行直播录制
NSMicrophoneUsageDescription
app需要使用麦克风进行直播录制
//开始推流
    [_mediaCapture startLiveStream:^(NSError *error) {
        if (error) {
            NSLog(@"---%@", error.localizedDescription);
        }
    }];

这样本地摄像头采集的画面和声音就可以通过预览画布看到,并且推流直播出去了。其他用户就可以通过对应的拉流地址和低延时拉流地址播放观看了。

4.结束推流直播释放推流实例

//结束预览
    [self.mediaCapture pauseVideoPreview];
    
    //结束推流
    [_mediaCapture stopLiveStream:^(NSError *error) {
        if (error) {
            NSLog(@"---%@", error.localizedDescription);
        }
    }];
    
    //释放
    [_mediaCapture unInitLiveStream];
    _mediaCapture = nil;

进阶

1.在直播过程中 ,可以进行视频推流的相关操作,如中断恢复音频,中断恢复视频

[_mediaCapture resumeVideoLiveStream]; //恢复视频推流
[_mediaCapture pauseVideoLiveStream];//中断视频推流
[_mediaCapture pauseAudioLiveStream];//中断音频推流
[_mediaCapture resumeAudioLiveStream];//恢复音频推流

2.直播过程中还可以进行 MP4 录制,录制直播内容之后保存在本地,可以先 创建一个本地路径 ,传入相关方法就可以了 ,也可以进行录制的配置 ,如下 

- (void)recordBtnTapped:(UIButton *)sender {
    if (sender.isSelected) {
        //以开始录制的时间作为时间戳,作为文件名后缀
        NSString *fileName = @"/vcloud_";
        NSDate *date = [NSDate date];
        NSTimeInterval sec = [date timeIntervalSinceNow];
        NSDate *currDate = [[NSDate alloc] initWithTimeIntervalSinceNow:sec];
        
        NSDateFormatter *df = [NSDateFormatter new];
        [df setDateFormat:@"yyyyMMddHHmmss"];
        NSString *dfStr = [df stringFromDate:currDate];
        fileName = [fileName stringByAppendingString:dfStr];
        fileName = [fileName stringByAppendingString:@".mp4"];
        
        //存储在Documents路径里
        NSArray *arr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documntsPath = arr[0];
        
        NSString *savePath = [documentsPath stringByAppendingString:fileName];
        
        BOOL isStrated = [_mediaCapture startRecord:savePath videoStreamingQuality:paraCtx.videoStreamingQuality];
        if (isStrated) {
            _isRecording = YES;
        }
    }else {
        BOOL isStoped = [_mediaCapture stopRecord];
        if (isStoped) {
            _isRecording = NO;
        }
    }
}

3.直播过程中也可以加入伴音,播放本地音频文件,比如直播中加入播放背景音乐,获取本地文件路径传入播放方法就可以了  

NSString* musicFileURL = [[NSBundle mainBundle]pathForResource:@"lovest" ofType:@"mp3"];
                    if (musicFileURL == nil) {
                        NSLog(@"have not found music file");
                        return;
                    }
                    if (![_mediaCapture startPlayMusic:musicFileURL withEnableSignleFileLooped:YES]) {
                        NSLog(@"播放音乐文件失败");
                        return;
                    };

第二步:实现播放器拉流播放

作为对比,拉流实现创建两个播放器实例,一个进行普通直播拉流播放,用到普通的拉流地址,另一个进行低延时直播拉流播放,用到低延时拉流地址。低延时拉流地址以 nertc:// 格式开头。

传入拉流地址,创建播放器实例

第一个播放器播放低延时直播

NSURL *url = [NSURL URLWithString:@"低延时拉流地址"];
    self.liveplayer = [[NELivePlayerController alloc] init];
    NSError *error = [self.liveplayer setPlayUrl:url];
    NSLog(@"---%@", error.localizedDescription);

1.添加播放视图

self.liveplayer.view.frame = _liveplayerView.bounds;
    [_liveplayerView addSubview:self.liveplayer.view];

2.播放器播放配置

[self.liveplayer setBufferStrategy:NELPLowDelay]; // 直播低延时模式
    [self.liveplayer setScalingMode:NELPMovieScalingModeNone]; // 设置画面显示模式,默认原始大小
    [self.liveplayer setShouldAutoplay:YES]; // 设置prepareToPlay完成后是否自动播放
    [self.liveplayer setPauseInBackground:NO]; // 设置切入后台时的状态,暂停还是继续播放
    [self.liveplayer setPlaybackTimeout:15 *1000]; // 设置拉流超时时间

初始化视频文件为播放做准备

[self.liveplayer prepareToPlay];

第二个播放器播放普通直播

NSURL *commonUrl = [NSURL URLWithString:@"拉流地址"];
    self.commonliveplayer = [[NELivePlayerController alloc] init];
    NSError *error1 = [self.commonliveplayer setPlayUrl:commonUrl];
    NSLog(@"---%@", error1.localizedDescription);

1.播放器播放配置

[self.liveplayer setShouldAutoplay:YES]; // 设置prepareToPlay完成后是否自动播放
    [self.liveplayer setPauseInBackground:NO]; // 设置切入后台时的状态,暂停还是继续播放
    [self.liveplayer setPlaybackTimeout:15 *1000]; // 设置拉流超时时间

初始化视频文件为播放做准备

[self.liveplayer prepareToPlay];

2.添加播放器初始化完成的通知回调

// 播放器媒体流初始化完成后触发,收到该通知表示可以开始播放
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(NELivePlayerDidPreparedToPlay:)
                                                 name: NELivePlayerDidPreparedToPlayNotification
                                               object: nil];

3.在播放器初始化完成的通知回调里面调用播放方法开始播放

- (void)NELivePlayerDidPreparedToPlay:(NSNotification*)notification {
    [self.liveplayer play];
    [self.commonliveplayer play];
}

4.停止播放销毁播放器实例

[self.liveplayer shutdown];
    self.liveplayer = nil;
    
    [self.commonliveplayer shutdown];
    self.commonliveplayer = nil;

这样一个简单的直播推流到拉流播放的功能就完成了。更多有意思的配置和功能实现可以参考SDK的API说明一一探索。

进阶:

1.播放器相关监听,在播放前播放中播放后的一些时间添加监听通知 ,第一时间拿到通知回调 ,做一些业务上的处理 

// 播放器媒体流初始化完成后触发,收到该通知表示可以开始播放
[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(NELivePlayerDidPreparedToPlay:)
                                             name: NELivePlayerDidPreparedToPlayNotification
                                           object: nil];


// 播放器加载状态发生变化时触发,如开始缓冲,缓冲结束
[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(NeLivePlayerloadStateChanged:)
                                             name: NELivePlayerLoadStateChangedNotification
                                           object: nil];


// 正常播放结束或播放过程中发生错误导致播放结束时触发的通知    
[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(NELivePlayerPlayBackFinished:)
                                             name: NELivePlayerPlaybackFinishedNotification
                                           object: nil];


// 第一帧视频图像显示时触发的通知    
[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(NELivePlayerFirstVideoDisplayed:)
                                             name: NELivePlayerFirstVideoDisplayedNotification
                                           object: nil];
// 第一帧音频播放时触发的通知                                         
[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(NELivePlayerFirstAudioDisplayed:)
                                             name: NELivePlayerFirstAudioDisplayedNotification
                                           object: nil];




// 资源释放成功后触发的通知    
[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(NELivePlayerReleaseSuccess:)
                                             name: NELivePlayerReleaseSueecssNotification
                                           object: nil];


// 视频码流解析失败时触发的通知                                               
[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(NELivePlayerVideoParseError:)
                                             name: NELivePlayerVideoParseErrorNotification
                                           object: nil];
                                               
// seek完成通知
[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(NELivePlayerSeekComplete:)
                                             name: NELivePlayerMoviePlayerSeekCompletedNotification
                                           object: nil];
// HTTP状态通知                                               
[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(NELivePlayerHttpCodeResponse:)
                                             name: NELivePlayerHttpCodeResponseNotification
                                           object: nil];

收到通知可以在通知方法里面做一些业务处理

// 初始化完成通知响应
- (void)NELivePlayerDidPreparedToPlay:(NSNotification*)notification {
[self.livepalyer play]; //如果设置shouldAutoplay为YES,此处可以不用调用play
}


// 播放完成通知响应
- (void)NELivePlayerPlayBackFinished:(NSNotification*)notification {
NSDictionary *userInfo = [notification userInfo];
NELPMovieFinishReason reason = [userInfo[NELivePlayerPlaybackDidFinishReasonUserInfoKey] integerValue];
switch (reason) {
case NELPMovieFinishReasonPlaybackEnded: //结束
break;
case NELPMovieFinishReasonPlaybackError: //失败
{
   //获取错误码
NSInteger code = [userInfo[NELivePlayerPlaybackDidFinishErrorKey] integerValue];
break;
}
}
}
//HTTP状态响应
- (void)NELivePlayerHttpCodeResponse:(NSNotification *)notification {
NSDictionary * userInfo = [notification userInfo];
    NELivePlayerHttpCodeModel *codeModel = userInfo[NELivePlayerHttpCodeResponseInfoKey];
    // http code: codeModel.code
    // http header: codeModel.header
}

2.视频本地缓存处理,可以快速切换播放视频 ,提高播放体验

NELPUrlConfig *urlConfig = [[NELPUrlConfig alloc] init];
    urlConfig.cacheConfig = [[NELPUrlCacheConfig alloc] init];
    urlConfig.cacheConfig.isCache = YES;
    urlConfig.cacheConfig.cacheRootPath = nil;
    
    //初始化方式一
    self.liveplayer = [[NELivePlayerController alloc] initWithContentURL:url
                                                         config:urlConfig
                                                          error:&error];
        
    //初始化方式二
    self.liveplayer = [[NELivePlayerController alloc] init];
    [self.liveplayer setPlayUrl:url config:urlConfig];
        
    //切换方式
    [self.liveplayer switchContentUrl:url config:urlConfig];

3.切换播放源,切换播放不同的地址 。

NELPUrlConfig *urlConfig = [[NELPUrlConfig alloc] init];
        
   //配置缓存(非必须)
   urlConfig.cacheConfig = [[NELPUrlCacheConfig alloc] init];
   urlConfig.cacheConfig.isCache = YES;
   urlConfig.cacheConfig.cacheRootPath = nil;
    //切换
    [self.liveplayer switchContentUrl:url config:urlConfig];

4.截图操作,播放的过程也支持截图操作 ,在需要截图的地方调用一下截图的方法就可以 

UIImage *image = [self.liveplayer getSnapshot];

5.设置音量,播放过程中可以设置音量大小,开关静音

//设置静音
[self.liveplayer setMute:NO];
//设置音量
[self.liveplayer setVolume:1.0];

6.获取播放信息 

NELivePlayerRealTimeInfo *info = [playView2 addSubview:_commonliveplayerView];
返回 参数 说明 
videoReceiveBitrate
NSTimeInterval
视频接收的码率
videoReceiveFramerate
NSTimeInterval
视频接收的楨率
videoPlayFramerate
NSTimeInterval
视频播放的楨率
videoCacheDuration
NSTimeInterval
视频缓存的时长
videoCacheBytes
NSTimeInterval
视频缓存的大小
audioReceiveBitrate
NSTimeInterval
音频接收的码率
audioCacheDuration
NSTimeInterval
音频缓存的时长
audioCacheBytes
NSTimeInterval
音频缓存的大小
AVPlayTimeDifference
NSTimeInterval
音频和视频的播放时间差
注意 :
需要收到preparedToPlay通知之后再查询

以上为低延时直播功能的快速实现流程。更多接入指南请访问云信官网。

网易智企“易+”开源计划已正式发布低延时直播开源代码,点击链接立刻体验:https://github.com/GrowthEase/LLS-Player

「云信小课堂」推荐阅读

快速接入指南

(点击即可快速跳转)

音视频通话 | 构建本土「Clubhouse」

安卓端 PK 连麦 | iOS 端 PK 连麦

在线聊天室 | 聊天室内容审核

利用 UI 组件实现应用级别在线聊天室

协同办公系统 | 音视频安全检测

云信小课堂 | 低延时直播功能的快速实现_第2张图片

你可能感兴趣的:(android,java,spring,移动开发,vue)