直播
iOS
产品介绍
简介
主要功能
产品优势
应用场景
使用限制
快速开始
推流端SDK
概述
更新日志
集成SDK
开发指南
实现流程
进阶功能
API 参考
播放器SDK
概览
更新日志
下载 SDK 和示例代码
跑通示例项目
集成SDK
开发指南
播放功能
播放控制
查询参数
数据回调
时间戳校对方案
外挂字幕
API 参考
最佳实践
OBS推流使用指南
服务协议

快速实现低延时直播

更新时间: 2022/07/18 18:04:47

本文介绍网易云信低延时直播主播端推流以及播放器的实现方法。

视频讲解

前期准备

注意事项

  • 低延时直播的视频源必须不包含 B 帧,否则会出现画面跳跃等现象。
  • 建议 GOP 关键帧间隔设置为 1~2 秒(否则会增加延时)。

集成推流 SDK 和播放器 SDK

步骤1 通过 CocoaPods 集成 SDK

请确保您的 Mac 已经安装 Ruby 环境。

  1. 安装 CocoaPods。

    在终端窗口中输入如下命令:

    sudo gem install cocoapods
    
  2. 创建 Podfile 文件。

    从 Terminal 中进入您所创建项目所在路径,运行以下命令创建 Podfile 文件。

    pod init
    
  3. 编辑 Podfile 文件,在 Podfile 文件中增加类似如下代码:

    # platform :ios, '9.0' 
    target '{YourApp}' do
        pod 'NMCLiveStreaming', '~> {version}'
        pod 'NELivePlayer', '~> {version}'
    end
    
    • YourApp:您的 Target 名称。
    • version:待集成的播放器和推流 SDK 版本号。建议使用最新版本,请从 SDK 下载中心查看最新版本的版本号。
  4. 执行以下命令查询本地库版本。

    pod search NELivePlayer         
    
  5. 若不是最新版本,可以执行以下命令更新本地库版本。

    pod repo update
    
  6. 执行以下命令安装安装 SDK。

    pod install        
    

步骤2 设置签名并添加媒体设备权限

  1. 设置签名。

    1. 在 Xcode 中,选择目标 TARGETS 和 Project Name,单击 Signing & Capabilities 页签,选中 Automatically manage signing

    Xcode_Signing.png

    1. 在 Team 中选择您的开发团队。
  2. Signing & Capabilities 页面,打开后台音频权限。

    打开后台音频权限之后,应用在手机中后台运行时,SDK 默认在后台也可以继续处理音频流,维持通话。

  3. 编辑 info.plist 文件,授权麦克风、摄像头和 WiFi 的使用权限。

    使用 SDK 的音视频功能,需要授权麦克风和摄像头的使用权限。在 App 的 Info.plist 中添加以下三项。

    • Privacy - Microphone Usage Description,并填入麦克风使用目的提示语。
    • Privacy - Camera Usage Description,并填入摄像头使用目的提示语。
    • Application uses Wi-Fi,设置为 YES

实现主播端推流

  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 使用摄像头和麦克风。

    <key>NSCameraUsageDescription</key>
    <string>app需要使用摄像头进行直播录制</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>app需要使用麦克风进行直播录制</string>
    
    //开始推流
        [_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 录制,录制直播内容之后保存在本地。

    1. 先创建一个本地路径 ,传入相关方法就可以了 。
    2. 也可以进行录制的配置 ,示例代码如下 :
    - (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;
                        };
    

实现播放器拉流播放

您可以分别创建普通直播播放器和低延时直播播放器,对比两者的时延差异。

步骤1 创建低延时直播的播放器

  1. 传入拉流地址,创建低延时直播的播放器实例。

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

传入的拉流地址为网易云信控制台上获取的拉流地址(NERTC),获取方法请参见获取低延时直播的推拉流地址。示例如下:

nertc://xxx.live.126.net/live/xxxxxxx?xxx=xxx

  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]; // 设置拉流超时时间
    
  3. 初始化视频文件为播放做准备。

    [self.liveplayer prepareToPlay];
    

步骤2 创建普通直播的播放器

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

    NSURL *commonUrl = [NSURL URLWithString:@"拉流地址"];
    self.commonliveplayer = [[NELivePlayerController alloc] init];
    NSError *error1 = [self.commonliveplayer setPlayUrl:commonUrl];
    NSLog(@"---%@", error1.localizedDescription);
    
  2. 添加播放视图。

    self.commonliveplayer.view.frame = _liveplayerView.bounds;
    [_commonliveplayerView addSubview:self.liveplayer.view];
    
  3. 播放器播放配置。

    [self.commonliveplayer setShouldAutoplay:YES]; // 设置prepareToPlay完成后是否自动播放
    [self.commonliveplayer setPauseInBackground:NO]; // 设置切入后台时的状态,暂停还是继续播放
    [self.commonliveplayer setPlaybackTimeout:15 *1000]; // 设置拉流超时时间
    
  4. 初始化视频文件为播放做准备。

    [self.commonliveplayer prepareToPlay];
    

步骤3 添加通知回调

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

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

步骤4 开始播放

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

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

步骤5 销毁播放器实例

停止播放,销毁播放器实例。

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

进阶

  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
}
  1. 视频本地缓存处理,可以快速切换播放视频 ,提高播放体验。
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];

  1. 切换播放源,切换播放不同的地址。
NELPUrlConfig *urlConfig = [[NELPUrlConfig alloc] init];
        
   //配置缓存(非必须)
   urlConfig.cacheConfig = [[NELPUrlCacheConfig alloc] init];
   urlConfig.cacheConfig.isCache = YES;
   urlConfig.cacheConfig.cacheRootPath = nil;
    //切换
    [self.liveplayer switchContentUrl:url config:urlConfig];
  1. 截图操作,播放的过程也支持截图操作,在需要截图的地方调用一下截图的方法就可以。
UIImage *image = [self.liveplayer getSnapshot];

  1. 设置音量,播放过程中可以设置音量大小,开关静音。
//设置静音
[self.liveplayer setMute:NO];
//设置音量
[self.liveplayer setVolume:1.0];

  1. 获取播放信息。
NELivePlayerRealTimeInfo *info = [playView2 addSubview:_commonliveplayerView];
返回 参数 说明
videoReceiveBitrate NSTimeInterval 视频接收的码率
videoReceiveFramerate 视频接收的帧率
videoPlayFramerate 视频播放的帧率
videoCacheDuration 视频缓存的时长
videoCacheBytes 视频缓存的大小
audioReceiveBitrate 音频接收的码率
audioCacheDuration 音频缓存的时长
audioCacheBytes 音频缓存的大小
AVPlayTimeDifference 音频和视频的播放时间差

查询播放的实时信息相关参数,需要收到 preparedToPlay 通知之后再查询。

此文档是否对你有帮助?
有帮助
我要吐槽
  • 视频讲解
  • 前期准备
  • 注意事项
  • 集成推流 SDK 和播放器 SDK
  • 步骤1 通过 CocoaPods 集成 SDK
  • 步骤2 设置签名并添加媒体设备权限
  • 实现主播端推流
  • 进阶
  • 实现播放器拉流播放
  • 步骤1 创建低延时直播的播放器
  • 步骤2 创建普通直播的播放器
  • 步骤3 添加通知回调
  • 步骤4 开始播放
  • 步骤5 销毁播放器实例
  • 进阶