Link Visual视频Media SDK

Link Visual App端SDK提供了音视频播放、语音对讲等功能。

依赖SDK

概述

API通道

提供API通道能力

初始化

初始化的操作请参见SDK初始化

Pod集成

在Podfile中添加以下配置后执行pod update

// 1. 在podfile中添加引用源
source 'https://github.com/aliyun/aliyun-specs.git'


// 2. 添加库依赖
pod 'LinkVisualMedia', '2.7.5-ilop'

更多版本发布信息请看Link Visual SDK更新记录

工程配置

C++与Objective-C混编需要将涉及到SDK使用的.m文件后缀改为.mm

因SDK部分使用了C++来编写,涉及到与Objective-C的混编,为了能让Clang编译器正确识别,需要将对SDK有引用的源码文件后缀从.m改为.mm。否则可能会遇到类似的报错:

ios_error

在项目的链接参数中添加-ObjC

因在SDK静态库中使用了categories,为了避免编译时报错"selector not recognized",需要添加该链接参数,详细见https://developer.apple.com/library/archive/qa/qa1490/_index.html

ios_config_link

支持swift

在swift项目中使用桥接的方式来调用LinkVisualMedia库。请创建BridgingHeader文件,并在文件中添加以下内容。

bridgeheader

//
// TestBridgingHeader.h
// swift-test
//
#define USE_SWIFT
#import "LinkVisualMedia/LVMedia.h"
#import "LinkVisualMedia/LVGlkView.h"
#import "LinkVisualMedia/LVLivePlayer.h"
#import "LinkVisualMedia/LVVodPlayer.h"
#import "LinkVisualMedia/LVLiveIntercom.h"
#import "LinkVisualMedia/LVAudioFilePlayer.h"
#import "LinkVisualMedia/LVAudioFileRecorder.h"
#import "LinkVisualMedia/LVOSSUploader.h"

接口文档

LinkVisual Media SDK文档(iOS)

播放器

视频播放器按功能分为三种。

  • 直播播放器

    • 支持接入LinkVisual设备的直播播放。

    • 具有播放延迟低的特性。

    • 具备与设备之间P2P的通信能力。

  • 点播播放器 (设备录像)

    • 用于设备本地录像回放的播放,可调整播放进度。

    • 具备与设备之间P2P的通信能力。

  • 点播播放器(HLS云存录像)

    • 用于基于HLS的云端录像回放的播放,支持MPEG-TS和fMP4容器,AES-128加密方式。

播放器功能表

功能

直播播放器

点播播放器(设备录像)

点播播放器(HLS云存录像)

视频播放

音频播放

暂停/恢复

-

播放重连

-

-

跳至指定位置播放

-

总时长

-

当前播放进度

-

播放器状态变更通知

播放静音

变速播放

-

单帧步进

-

画面缩放模式设置

播放停止时显示模式设置

NVR多画面播放

数字变焦

播放窗口截图

截图到文件

边播边录

硬解码

获取码流信息

提供YUV数据

提供原始码流数据

提供SEI数据

播放器的使用示例:

  • 直播播放器

    // 构造播放器实例
    self.player = [[LVLivePlayer alloc] init];
    // 设置必要的监听
    self.player.livePlayerDelegate = self;
    ...
    #pragma mark LVLivePlayerDelegate
    - (void) onLivePlayerError:(LVLivePlayer *_Nonnull)player error:(NSError *_Nonnull)error{
      [self appendInfoText:[NSString stringWithFormat:@"播放出错: %@\n", error]];
    }
    
    - (void) onLivePlayerStateChange:(LVLivePlayer *_Nonnull)player playerState:(LVPlayerState)state{
      [self appendInfoText:[NSString stringWithFormat:@"状态变更: %d\n", state]];
    }
    
    - (void) onLivePlayerRenderedFirstFrame:(LVLivePlayer *_Nonnull)player elapsedTimeInMs:(NSInteger)elapsedTimeInMs{
      [self appendInfoText:[NSString stringWithFormat:@"首帧出图耗时: %ldms\n", (long)elapsedTimeInMs]];
      [self appendInfoText:[self.player getStatisticsInfo]];
    }
    
    - (void) onLivePlayerVideoSizeChanged:(LVLivePlayer *_Nonnull)player width:(NSInteger)width height:(NSInteger)height{
      [self appendInfoText:[NSString stringWithFormat:@"图像大小变化: w=%ld h=%ld\n", (long)width, (long)height]];
    }
    
    // 不再推荐使用, 将会废弃
    - (void) onLivePlayerSeiInfoUpdate:(LVLivePlayer *_Nonnull)player sei:(NSData*_Nonnull)data timeStamp:(NSInteger)timeStamp{
        [self appendInfoText:[NSString stringWithFormat:@"私有sei: %lu %ld %@", (unsigned long)data.length, timeStamp,[data description]]];
    }
    - (void) onLivePlayerStandardSeiInfoUpdate:(LVLivePlayer *_Nonnull)player sei:(NSData*_Nonnull)data timeStamp:(NSInteger)timeStamp{
        [self appendInfoText:[NSString stringWithFormat:@"标准sei: %lu %ld %@", (unsigned long)data.length, timeStamp,[data description]]];
    }
    
    - (void) onLivePlayerVideoJitterBufferEmpty:(LVLivePlayer *_Nonnull)player{
    }
    ...
    // 创建LVGlkView,放在scrollview中具备画面缩放能力
    self.lvGlkView = [[LVGlkView alloc] initWithFrame:CGRectMake(0,0,self.scrollView.frame.size.width, self.scrollView.frame.size.height)];;
    [self.scrollView addSubview:self.lvGlkView];
    [self.lvGlkView mas_makeConstraints:^(MASConstraintMaker *make) {
      make.centerX.equalTo(@(0));
      make.centerY.equalTo(@(0));
      make.height.equalTo(self.scrollView.mas_height);
      make.width.equalTo(self.scrollView.mas_width);
    }];
    // 为播放器设置用于画面渲染的窗口, 画面不做旋转
    [self.player setWindow:self.lvGlkView videoRotationMode:LV_MEDIA_VIDEO_ROTATE_90_CLOCKWISE];
    
    ...
    // 设置数据源,数据源为设备的IotId
    [self.player setLiveDataSource:iotId, streamType:LV_STREAM_TYPE_MAJOR];
    // 设置自动重连次数
    [self.player setReconnectCount:3];
    // 设置解码策略为硬解码优先
    [self.player setDecoderStrategy:LV_DECODER_STRATEGY_HARDWARE_FIRST];
    // 设置画面模式为保持宽高
    [self.player setVideoScalingMode:LV_MEDIA_VIDEO_SCALING_MODE_FIT];
    // 设置播放停止时画面保留最后一帧
    [self.player setPlayerStoppedDrawingMode:LV_PLAYER_STOPPED_DRAWING_MODE_ALWAYS_KEEP_LAST_FRAME];
    ...
    // 开始播放
    [self.player start];
    ...
    // 停止播放
    [self.player stop];
  • 点播播放器 (设备录像)

    // 构造播放器实例
    self.player = [[LVVodPlayer alloc] init];
    // 设置必要的监听
    self.player.vodPlayerDelegate = self;
    ...
    #pragma mark LVVodPlayerDelegate
    - (void) onVodPlayerError:(LVVodPlayer *_Nonnull)player error:(NSError *_Nonnull)error{
      [self appendInfoText:[NSString stringWithFormat:@"播放出错: %@\n", error]];
    }
    
    - (void) onVodPlayerStateChange:(LVVodPlayer *_Nonnull)player playerState:(LVPlayerState)state{
      [self appendInfoText:[NSString stringWithFormat:@"状态变更: %d\n", state]];
    }
    
    - (void) onVodPlayerRenderedFirstFrame:(LVVodPlayer *_Nonnull)player elapsedTimeInMs:(NSInteger)elapsedTimeInMs{
      [self appendInfoText:[NSString stringWithFormat:@"首帧出图耗时: %ldms\n", (long)elapsedTimeInMs]];
      [self appendInfoText:[self.player getStatisticsInfo]];
    }
    
    - (void) onVodPlayerVideoSizeChanged:(LVVodPlayer *_Nonnull)player width:(NSInteger)width height:(NSInteger)height{
      [self appendInfoText:[NSString stringWithFormat:@"图像大小变化: w=%ld h=%ld\n", (long)width, (long)height]];
    }
    // 不再推荐使用, 将会废弃
    - (void) onVodPlayerSeiInfoUpdate:(LVVodPlayer *_Nonnull)player sei:(NSData*_Nonnull)data timeStamp:(NSInteger)timeStamp{
        [self appendInfoText:[NSString stringWithFormat:@"私有sei: %lu %ld %@", (unsigned long)data.length, timeStamp,[data description]]];
    }
    - (void) onVodPlayerStandardSeiInfoUpdate:(LVVodPlayer *_Nonnull)player sei:(NSData*_Nonnull)data timeStamp:(NSInteger)timeStamp{
        [self appendInfoText:[NSString stringWithFormat:@"标准sei: %lu %ld %@", (unsigned long)data.length, timeStamp,[data description]]];
    }
    
    - (void) onVodPlayerVideoJitterBufferEmpty:(LVLivePlayer *_Nonnull)player{
    }
    
    - (void)onVodPlayerCompletion:(LVVodPlayer * _Nonnull)player {
      [self appendInfoText:@"播放结束"];
    }
    ...
    // 创建LVGlkView,放在scrollview中具备画面缩放能力
    self.lvGlkView = [[LVGlkView alloc] initWithFrame:CGRectMake(0,0,self.scrollView.frame.size.width, self.scrollView.frame.size.height)];;
    [self.scrollView addSubview:self.lvGlkView];
    [self.glkView mas_makeConstraints:^(MASConstraintMaker *make) {
      make.centerX.equalTo(@(0));
      make.centerY.equalTo(@(0));
      make.height.equalTo(self.scrollView.mas_height);
      make.width.equalTo(self.scrollView.mas_width);
    }];
    // 为播放器设置用于画面渲染的窗口
    [self.player setWindow:self.lvGlkView];
    
    ...
    // 设置数据源:以下两种方式都可以
    // 1. 按设备文件名,初始播放偏移为20S
    [self.player setDataSourceByLocalRecordFileName:iotId fileName:@"fileNamexxxxxxxx" seekToPositionInMs:20000];
    // 2. 按设备时间,从2022-08-29 17:54:14到2022-08-30 02:47:34的录像,初始播放偏移为20S,类型为所有录像
    [self.player setDataSourceByLocalRecordTime:iotId beginTimeInS:1661766854 endTimeInS:1661798854 seekToPositionInMs:20000 recordType:99];
    // 设置解码策略为硬解码优先
    [self.player setDecoderStrategy:LV_DECODER_STRATEGY_HARDWARE_FIRST];
    // 设置画面模式为保持宽高
    [self.player setVideoScalingMode:LV_MEDIA_VIDEO_SCALING_MODE_FIT];
    ...
    // 开始播放
    [self.player start];
    ...
    // 暂停
    [self.player pause];
    ...
    // 恢复
    [self.player resume];
    ...
    // 停止播放
    [self.player stop];
  • 点播播放器(HLS云存)

    // 构造播放器实例
    self.player = [[LVVodPlayer alloc] init];
    // 设置必要的监听
    self.player.vodPlayerDelegate = self;
    ...
    #pragma mark LVVodPlayerDelegate
    - (void) onVodPlayerError:(LVVodPlayer *_Nonnull)player error:(NSError *_Nonnull)error{
      [self appendInfoText:[NSString stringWithFormat:@"播放出错: %@\n", error]];
    }
    
    - (void) onVodPlayerStateChange:(LVVodPlayer *_Nonnull)player playerState:(LVPlayerState)state{
      [self appendInfoText:[NSString stringWithFormat:@"状态变更: %d\n", state]];
    }
    
    - (void) onVodPlayerRenderedFirstFrame:(LVVodPlayer *_Nonnull)player elapsedTimeInMs:(NSInteger)elapsedTimeInMs{
      [self appendInfoText:[NSString stringWithFormat:@"首帧出图耗时: %ldms\n", (long)elapsedTimeInMs]];
      [self appendInfoText:[self.player getStatisticsInfo]];
    }
    
    - (void) onVodPlayerVideoSizeChanged:(LVVodPlayer *_Nonnull)player width:(NSInteger)width height:(NSInteger)height{
      [self appendInfoText:[NSString stringWithFormat:@"图像大小变化: w=%ld h=%ld\n", (long)width, (long)height]];
    }
    // 不再推荐使用, 将会废弃
    - (void) onVodPlayerSeiInfoUpdate:(LVVodPlayer *_Nonnull)player sei:(NSData*_Nonnull)data timeStamp:(NSInteger)timeStamp{
        [self appendInfoText:[NSString stringWithFormat:@"私有sei: %lu %ld %@", (unsigned long)data.length, timeStamp,[data description]]];
    }
    - (void) onVodPlayerStandardSeiInfoUpdate:(LVVodPlayer *_Nonnull)player sei:(NSData*_Nonnull)data timeStamp:(NSInteger)timeStamp{
        [self appendInfoText:[NSString stringWithFormat:@"标准sei: %lu %ld %@", (unsigned long)data.length, timeStamp,[data description]]];
    }
    
    - (void) onVodPlayerVideoJitterBufferEmpty:(LVLivePlayer *_Nonnull)player{
    }
    
    - (void)onVodPlayerCompletion:(LVVodPlayer * _Nonnull)player {
      [self appendInfoText:@"播放结束"];
    }
    ...
    // 创建LVGlkView,放在scrollview中具备画面缩放能力
    self.lvGlkView = [[LVGlkView alloc] initWithFrame:CGRectMake(0,0,self.scrollView.frame.size.width, self.scrollView.frame.size.height)];;
    [self.scrollView addSubview:self.lvGlkView];
    [self.glkView mas_makeConstraints:^(MASConstraintMaker *make) {
      make.centerX.equalTo(@(0));
      make.centerY.equalTo(@(0));
      make.height.equalTo(self.scrollView.mas_height);
      make.width.equalTo(self.scrollView.mas_width);
    }];
    // 为播放器设置用于画面渲染的窗口
    [self.player setWindow:self.lvGlkView];
    
    ...
    // 设置数据源:设备云存文件名,初始播放偏移为20S
    [self.player setDataSourceByCloudRecordFileName:iotId fileName:@"fileNamexxxxxxxx" seekToPositionInMs:20000];
    // 设置解码策略为硬解码优先
    [self.player setDecoderStrategy:LV_DECODER_STRATEGY_HARDWARE_FIRST];
    // 设置画面模式为保持宽高
    [self.player setVideoScalingMode:LV_MEDIA_VIDEO_SCALING_MODE_FIT];
    ...
    // 开始播放
    [self.player start];
    ...
    // 暂停
    [self.player pause];
    ...
    // 恢复
    [self.player resume];
    ...
    // 停止播放
    [self.player stop];

播放器状态介绍

通过设置播放器状态监听器,可接收到状态变更事件,用于相关UI元素的变更。

状态变更事件如:播放中发生错误、主动停止播放等。

播放器状态图

  • IDLE:播放器没有任何内容播放时的状态。

  • BUFFERING:播放器正在缓冲,当前的位置还不可以播放。状态变更事件如:开始播放时缓冲、seekTo()后重新缓冲、网络不佳引起点播缓冲。

  • READY:播放器已经有内容在播放。状态变更事件如:首帧数据已经渲染、seekTo()缓冲完成开始播放新内容。对于点播播放器,若已seekTo()或播放到文件结尾,则会回调LVVodPlayerDelegate代理的onVodPlayerCompletion方法,状态会自动切换到ENDED。

  • ENDED:播放器已结束播放。播放出错或stop()或播放结束后会切换到该状态。

播放器错误列表

错误主码

错误子码

描述

解决办法

LV_PLAYER_ERROR_CODE_SOURCE

LV_PLAYER_ERROR_SUB_CODE_SOURCE_STREAM_CONNECT

与数据源建立连接失败

通常因网络问题引起连接失败,请您确保网络正常后重试。

LV_PLAYER_ERROR_SUB_CODE_SOURCE_INVALID_PARAMETER

错误的数据源参数

请检查配置参数是否合法,然后重试。

LV_PLAYER_ERROR_SUB_CODE_SOURCE_QUERY_URL_FAILED

请求播放地址失败

请根据错误信息中msg字段的描述,确定问题并修复。

LV_PLAYER_ERROR_CODE_RENDER

LV_PLAYER_ERROR_SUB_CODE_RENDER_DECODE

解码错误

若在持续一段时间内,解码均发生失败,您可转存码流数据,然后分析数据。日志级别设置到Debug后默认会在应用的tmp目录下转存原始码流数据。

LV_PLAYER_ERROR_CODE_UNEXPECTED

LV_PLAYER_ERROR_SUB_CODE_UNEXPECTED_PULL_STREAM_TIMEOUT

超过8秒未拉取到流或连接被异常断开

请检查以下项目然后重试:1、检查设备是否未推流;2、检查应用端和设备端的网络是否异常。

LV_PLAYER_ERROR_SUB_CODE_UNEXPECTED_PLAY_DURATION_EXCEED

连续播放时长超过上限

避免长时间的无人播放消耗不必要的带宽,如果您有连续观看的需求可以考虑升级流量套餐服务来解除该限制。

语音对讲

提供App和IPC设备之间端到端的单/双向实时对讲能力。

  • 单讲:App端采集并发送音频数据到设备端进行播放,App端采集音频期间手机保持声音静默。

  • 全双工对讲:App端和设备端都需要同时做采音和放音,设备端必须支持AEC,否则不建议使用该方案。

  • 半双工对讲:APP端和设备端都需要做采音和放音,一端上始终不会出现同时采音和放音的情况,因此设备不要求支持AEC,使用上类似对讲机,由APP端在一次对讲会话中可多次人为控制录音的开启和结束。

支持以下格式的音频。

类型

采样率

编码

解码

G711A

8Khz/16Khz

G711U

8Khz/16Khz

AAC_LC

8Khz/16Khz

语音对讲使用方式:

  1. 创建语音对讲实例,并设置音频参数。

        // 创建语音对讲实例
      LVMediaAudioHeader header;
      header.audioBitPerSample = 16;
      header.audioChannel = 1;
      header.audioSamplesPerSec = 8000;
      header.audioEncType = LV_MEDIA_AUDIO_ENC_G711A;
      self.liveIntercom = [LVLiveIntercom create:header];
  2. 注册监听器,并处理语音对讲回调。

    请在对应的事件回调中处理,包括对讲开始、录音开始和结束、音量回调(用于UI展示)。

    在语音通道建立和对讲过程中,可能发生的错误详见语音对讲错误列表。

    self.liveIntercom.liveIntercomDelegate = self;
    self.liveIntercom.liveIntercomVoiceChangeDelegate = self;
    
    #pragma mark - LiveIntercomDelgate
    - (void) onLiveIntercomTalkReady:(LVLiveIntercom *_Nonnull)liveIntercom{
      [self appendInfoText:@"可以开始说话了\n"];
    }
    
    - (void) onLiveIntercomRecorderStart:(LVLiveIntercom *_Nonnull)liveIntercom{
      [self appendInfoText:@"录音机启动\n"];
    }
    
    - (void) onLiveIntercomRecorderEnd:(LVLiveIntercom *_Nonnull)liveIntercom{
      [self appendInfoText:@"录音机结束\n"];
    }
    
    - (void) onLiveIntercomRecorderVolume:(LVLiveIntercom *_Nonnull)liveIntercom volume:(NSInteger)volume{
      [self appendInfoText:[NSString stringWithFormat:@"音量变化%ld\n", volume]];
    }
    
    - (void) onLiveIntercomError:(LVLiveIntercom *_Nonnull)liveIntercom error:(NSError *_Nonnull)error{
      [self appendInfoText:[NSString stringWithFormat:@"对讲出错%@:\n", error]];
    }
  3. 设置增益水平。

    可以设置App端声音采集的增益值,提供“-1 - None, 0 - Mild, 1 - Medium , 2 - high , 3 - Aggressive , 4 - very Aggressive , 5 - Max”六种水平供选择(默认值为无),请根据设备效果来调整。

    [self.liveIntercom setGainLevel:-1];
  4. 设置对讲模式。

    提供五种模式供选择:

    • 单讲:App端采集并发送音频数据到设备端进行播放,App端采集音频期间手机保持声音静默。

    • 全双工对讲(独立):App端和设备端都需要同时做采音和放音,设备端必须支持AEC,否则不建议使用该方案将会使用设备对讲通道的声音进行播放,可以单独存在不依赖直播通道。

    • 全双工对讲(伴随直播):App端和设备端都需要同时做采音和放音,设备端必须支持AEC,否则不建议使用该方案将会使用设备直播通道的声音进行播放,要求必须有已开播的直播通道,可通过LVLivePlayer.audioFocus()方法在对讲开启前选择对应的已存在的直播通道。

    • 半双工对讲(独立):APP端和设备端都需要做采音和放音,一端上始终不会出现同时采音和放音的情况,因此设备不要求支持AEC;使用上类似对讲机,由APP端在一次对讲会话中可多次人为控制录音的开启和结束;将会使用设备对讲通道的声音进行播放,可以单独存在不依赖直播通道;使用限制:该模式需要设备端SDK使用v2.3.3及以上版本的支持,如果使用较旧的设备SDK,将会降级到全双工对讲。

    • 半双工对讲(伴随直播):APP端和设备端都需要做采音和放音,一端上始终不会出现同时采音和放音的情况,因此设备不要求支持AEC;使用上类似对讲机,由APP端在一次对讲会话中可多次人为控制录音的开启和结束;将会使用设备直播通道的声音进行播放,要求必须有已开播的直播通道,可通过LVLivePlayer.audioFocus()方法在对讲开启前选择对应的已存在的直播通道;使用限制:该模式需要设备端SDK使用v2.3.3及以上版本的支持,如果使用较旧的设备SDK,将会降级到全双工对讲。

    // 设置使用独立双讲
    [self.liveIntercom setLiveIntercomMode:LV_LIVE_INTERCOM_MODE_DOUBLE_TALK];
  5. 开始对讲。

    对讲开始后,会请求音频焦点,并设置到通话模式(若已连接蓝牙耳机或者线控耳机则路由到耳机上)。

    // 开始对讲
    [self.liveIntercom start:iotId];
  6. 对讲机讲话状态切换(仅半双工对讲需要关注)。

    开启半双工对讲后,由用户来主动切换对讲状态,按需去做收放音。

    // 该状态下APP端停止播放,采集音频发给设备端,同时设备端会停止音频采集,播放APP端采集的声音
    [self.liveIntercom listen:YES];
    ...
    // 该状态下APP端恢复播放,同时设备端会停止播放声音,恢复音频采集
    [self.liveIntercom listen:NO];
  7. 结束对讲。

    对讲结束后释放音频焦点,并设置到常规模式。对讲过程中默认开启手机回声消除。

    // 停止对讲
    [self.liveIntercom stop];

语音对讲错误列表

错误枚举

描述

解决办法

LV_LIVE_INTERCOM_ERROR_START_REQUEST_FAILED

发起语音对讲请求失败,详细错误原因请参考subCode

检查并修复以下异常,然后重试:

  • 检查网络是否故障。

  • 设备是否离线。

  • 检查服务端是否出现异常。

LV_LIVE_INTERCOM_ERROR_CONNECT_STREAM_FAILED

建立语音对讲流通道失败

检查并修复以下异常,然后重试:

  • 检查网络是否故障。

  • 检查是否因5秒内设备未及时响应导致上报超时。

LV_LIVE_INTERCOM_ERROR_SEND_STREAM_DATA_FAILED

发送音频数据失败

网络环境异常,请切换至良好的网络环境中并重试。

LV_LIVE_INTERCOM_ERROR_RECEIVE_STREAM_DATA_FAILED

接收音频数据失败

网络环境异常,请切换至良好的网络环境中并重试。

LV_LIVE_INTERCOM_ERROR_INIT_AUDIO_RECORDER_FAILED

录音机初始化错误

检查并修复以下异常,然后重试:

  • 检查是否录音权限未授权。

  • 检查是否有其它应用占用了录音机,终止应用进程并重试。

LV_LIVE_INTERCOM_ERROR_START_AUDIO_RECORDER_FAILED

录音机启动错误

检查是否有其它应用占用了录音机,终止应用进程并重试。

LV_LIVE_INTERCOM_ERROR_READ_AUDIO_RECORDER_FAILED

录音机数据读取错误

录音机异常,需重启应用端设备,例如重启手机。

LV_LIVE_INTERCOM_ERROR_INIT_AUDIO_TRACK_FAILED

音频播放器创建失败

音频播放器异常,需重启应用端设备,例如重启手机。

音频文件录制、播放及上传

提供录制音频文件、播放本地或者网络音频文件及上传音频文件的能力。

录制及播放音频文件支持以下格式。

文件类型

采样率

编码方式

AMR

8Khz(支持录制和播放)/16Khz(仅播放)

amr

WAV

8Khz/16Khz

PCM

G711

音频文件录制、播放及上传的使用方式:

  • 音频文件录制

    // 创建音频文件录音机
    self.audioFileRecorder = [[LVAudioFileRecorder alloc] init];
    
    // 设置录制代理
    self.audioFileRecorder.audioFileRecorderDelegate = self;
    
    #pragma mark - LVAudioFileRecorderDelegate
    - (void) onAudioFileRecorderError:(LVAudioFileRecorder *_Nonnull)recorder error:(NSError *_Nonnull)error{
      [self ims_showHUDWithMessage:[NSString stringWithFormat:@"amr录制失败 %@", error]];
    }
    
    - (void) onAudioFileRecorderRecordStart:(LVAudioFileRecorder *_Nonnull)recorder{
      [self ims_showHUDWithMessage:@"amr录制开始"];
    }
    
    - (void) onAudioFileRecorderRecordEnd:(LVAudioFileRecorder *_Nonnull)recorder{
      [self ims_showHUDWithMessage:@"amr录制结束"];
    }
    
    ...
    // 设置录音参数配置并启动录音
    LVMediaAudioHeader header;
    header.audioBitPerSample = 16;
    header.audioChannel = 1;
    header.audioSamplesPerSec = 8000;
    header.audioEncType = LV_MEDIA_AUDIO_ENC_AMRNB;
    NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"test.amr"];
    [self.audioFileRecorder startRecorder:&header filePath:filePath];
    
    ...
    // 停止录制
    [self.audioFileRecorder stopRecorder];
  • 音频文件播放

    // 创建音频文件播放器
    self.audioFilePlayer = [[LVAudioFilePlayer alloc] init];
    
    // 设置播放代理
    self.audioFilePlayer.audioFileplayerDelegate = self;
    
    #pragma mark - LVAudioFilePlayerDelegate
    - (void) onAudioFilePlayerCompletion:(LVAudioFilePlayer *_Nonnull)player{
      [self ims_showHUDWithMessage:@"amr文件播放完成"];
    }
    
    ...
    // 播放本地文件
    NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"test.amr"];
    [self.audioFilePlayer startPlay:LV_AUDIO_FILE_TYPE_AMR filePath:filePath];
    
    // 播放网络文件
    NSString *tmpPath = @"https://lv-demo.oss-cn-hangzhou.aliyuncs.com/test.amr";
    [self.audioFilePlayer startPlay:LV_AUDIO_FILE_TYPE_AMR filePath:tmpPath];
    
    // 停止播放
    [self.audioFilePlayer stopPlay];
  • 文件上传

    // 创建文件上传器
    self.ossUploader = [[LVOSSUploader alloc] init];
    
    // 设置文件上传代理
    self.ossUploader.OSSUploaderDelegate = self;
    
    #pragma mark - LVOSSUploaderDelegate
    - (void)
    onOSSUploaderError:(LVOSSUploader *_Nonnull)ossUploader sessionId:(NSString *_Nonnull)sessionId fileName:(NSString *_Nonnull)fileName error:(NSError*_Nonnull)error{
      [self ims_showHUDWithMessage:[NSString stringWithFormat:@"amr文件上传失败 %@", error]];
    }
    
    -(void) onOSSUploaderProgress:(LVOSSUploader *_Nonnull)ossUploader uploadBytes:(NSInteger)uploadBytes totalBytes:(NSInteger)totalBytes{
    }
    
    -(void) onOSSUploaderCompletion:(LVOSSUploader *_Nonnull)ossUploader sessionId:(NSString *_Nonnull)sessionId fileName:(NSString *_Nonnull)fileName{
      [self ims_showHUDWithMessage:@"amr上传完成"];
    }
    
    - (void) onAudioFileRecorderRecordVolume:(LVAudioFileRecorder *_Nonnull)recorder volume:(NSInteger)volume{
    }
    
    ...
    // 开始上传
    NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"test.amr"];
    [self.ossUploader upload:tmpPath
           fileName:@"test.amr"
           sessionId:@"123456"
           uploadUrl:@"https://vision-customer-daily.oss-cn-hangzhou.aliyuncs.com/test.amr"];
                        

音频文件错误列表

错误枚举

描述

解决办法

LV_AUDIO_FILE_ERROR_CREATE_FILE_FAILED

文件创建失败

请检查文件能否创建,是否可以写入。

LV_AUDIO_FILE_ERROR_INIT_AUDIO_RECORDER_FAILED

录音机初始化错误

检查并修复以下异常,然后重试:

  • 检查是否录音权限未授权。

  • 检查是否有其它应用占用了录音机,终止应用进程并重试。

LV_AUDIO_FILE_ERROR_START_AUDIO_RECORDER_FAILED

录音机启动错误

检查是否有其它应用占用了录音机,终止应用进程并重试。

LV_AUDIO_FILE_ERROR_READ_AUDIO_RECORDER_FAILED

录音机数据读取错误

录音机异常,需重启应用端设备,例如重启手机,一般比较少见。

LV_AUDIO_FILE_ERROR_READ_FILE_FAILED

文件读取失败

请检查文件是否存在,是否可以读取。

LV_AUDIO_FILE_ERROR_INIT_AUDIO_TRACK_FAILED

音频播放器创建失败

手机的音频播放器异常,需要重启应用或者手机,一般比较少见。

从1.x SDK迁移到2.x版本指南

iOS Media SDK在2.0.0版本对接口、方法和类进行了大幅改动。如果您正在使用2.0.0-ilop以下版本,建议通过本文提供的方法升级至2.0.0-ilop。

说明

1.x版本文档见Link Visual视频Media SDK

重要变化

重要变化

1.x版本

2.x版本

播放器和语音对讲拆分

所有类型播放器和对讲功能都放在IMSLinkVisualPlayerViewController中

按功能拆分为:

  • 直播LVLivePlayer

  • 点播LVVodPlayer

  • 语音对讲LVLiveIntercom

播放器与ViewController分离

播放器和语音对讲所有功能都封住在IMSLinkVisualPlayerViewController中

不再提供ViewController,提供设置LVGlkView的接口。

拆分常用的网关接口请求封装

封装打包在SDK中

剥离这部分代码封装,以源码形式提供。

API变化细节(建议通过文本搜索来定位)

全局组件

变更细节

1.x

2.x

修改建议

新增全局LVMedia组件

-

LVMedia

更新包名与类名。

接口新增:直播预建连接口

-

(LVPlayerCode) preConnectByIotId:(NSString *_Nonnull)iotId streamType:(LVStreamType)streamType;

从2.0.0开始,iOS支持直播预建连功能。

接口新增:日志级别设置

-

(void) setLogLevel:(IMSLinkVisualMediaLogLevel)level;

全局日志级别设置接口。

直播播放器

变更细节

1.x

2.x

修改建议

包名与类名变更

IMSLinkVisualPlayerViewController

LVLivePlayer

更新包名与类名。

播放器不再提供ViewController

IMSLinkVisualPlayerViewController封装了GLKView用于渲染

播放器与渲染View解耦合

需要在VC中创建LVGlkView,并在VC的viewDidAppear时调用 (LVPlayerCode) setWindow:(LVGlkView *_Nullable)view 设置给播放器。

接口新增:设置为加密的rtmp直播地址

-

(LVPlayerCode) setDataSource:(NSString *_Nonnull)url

-

设置加密的直播数据源中设置的decryptIv和decryptKey从Base64解码后的二进制数据改为解码器前的字符串

(BOOL)setDataSource_Live:(NSString *_Nullable)rtmpPathneedEncrypt:(BOOL)needEncryptiv:(NSData *_Nullable)ivkey:(NSData *_Nullable)key;

(LVPlayerCode) setDataSource:(NSString *_Nonnull)url isEncrypted:(BOOL)isEncrypted decryptIvBase64:(NSString *_Nullable)decryptIvBase64 decryptKeyBase64:(NSString *_Nullable)decryptKeyBase64;

请注意将Base64解码去除,由SDK内部来完成对Base64字符串的解码。

接口命名调整:设置基于生活物联网平台连接的IPC设备直播数据源

(BOOL)setDataSource:(NSString*_Nullable)iotIdstreamType:(IMSLinkVisualPlayerLiveStreamType)streamTypecacheDurationInMs:(int)cacheDurationInMs;

  1. (LVPlayerCode) setLiveDataSource:(NSString *_Nonnull)iotId streamType:(LVStreamType)streamType;

  2. (LVPlayerCode) setLiveDataSource:(NSString *_Nonnull)iotId streamType:(LVStreamType)streamType cacheDuration:(NSInteger)cacheDuration;

调整接口名。

接口移除:基于生活物联网平台连接的IPC设备直播数据源

(BOOL)setDataSource:(NSString*_Nullable)iotIdstreamType:(IMSLinkVisualPlayerLiveStreamType)streamTypeneedForceIFrame:(BOOL)needForceIFrame __attribute__ ((deprecated));

-

从2.0.0开始强制要求打开加密和强制I帧。

指令接口,如setDataSource()/start()/stop()等增加返回值

-

返回值枚举:

enum LVPlayerCode{
    /** 执行成功 */
    LV_PLAYER_SUCCESS  = 0,
    /** 执行失败, 通用错误 */
    LV_PLAYER_ERROR_FAILED  = -1,
    /** 错误的输入参数 */
    LV_PLAYER_ERROR_INVALID_PARAMETER   = -2,
    /** 不支持的接口 */
    LV_PLAYER_ERROR_UNSUPPORTED = -3,
};

可以通过判断返回值作为接口操作是否成功的判断。

新增接口:获取当前码流的宽高

-

  1. (NSInteger) getVideoWidth;

  2. (NSInteger) getVideoHeight;

-

类名与方法名变更:设置解码器策略和获取解码器类型

  1. (IMSLinkVisualPlayerDecodeMode)getDecoderStrategy;

  2. (BOOL)setDecoderStrategy:(IMSLinkVisualPlayerDecodeMode)decodeMode

  1. (LVPlayerCode) setDecoderStrategy:(LVDecoderStrategy)decoderStrategy;

  2. (LVDecoderType) getDecoderType;

修改类名与方法名。

接口移除:P2P全局初始化和释放

  1. (void)initP2P;

  2. (void)deallocP2P;

-

无需有该动作。

接口移除:设备P2P预建连

(void)preCreateP2P:(NSString*_Nonnull)iotId;

-

从2.0.0开始,预建连请用LVMedia全局对象的preConnect接口完成。

接口移除:所有播放器触发stop动作

(void)stopAllPlayer;

-

从2.0.0开始,自行停止对应的播放器即可,该接口有替代实现,无需有该动作。

属性移除:激活音频管理器

activeAudioManager;

-

从2.0.0开始,SDK因为将对讲与播放器剥离,只有在使用对应功能时才会触发录音权限,该接口已无意义。

接口变更:音频焦点接口

(void)activePlayer;

  1. (LVPlayerCode) audioFocus;

  2. (BOOL)isAudioFocus;

从2.0.0开始,SDK不再支持多路音频同时播放,至多只有一路音频播放。当存在多路观看(如NVR多分屏)场景时,请交由用户来调用关心的那一路播放器的audioFocus()接口来完成多路播放器之间声音播放的切换。

接口名调整:设置播放器缓存

  1. (void)setDisplayBuffer;

  2. (NSInteger)bufferCount;

  1. (LVPlayerCode) setBufferedFrameCount;

  2. (NSInteger)frameCount;

接口名调整。

接口名调整:设置播放器抗抖动最大缓冲区时长

  1. (void)setMaxJitterBufferSizeInMs;

  2. (NSInteger)jitterBufferSizeInMs;

  1. (LVPlayerCode) setMaxJitterBufferSizeInMs;

  2. (NSInteger)jitterBufferSizeInMs;

接口名调整。

接口移除:VC中屏蔽语音对讲

(instancetype_Nonnull)initDisableIntercom;

-

从2.0.0开始,播放器和语音对讲已按功能做了拆分,不再耦合,该接口已无意义。

接口名调整:截图

(UIImage * __nullable)videoSnapshot;

(UIImage *_Nullable) snapShot;

接口名调整。

接口新增:截图到文件

-

  1. (LVPlayerCode) snapShotToFile;

  2. (NSString *_Nonnull)jpegFilePath;

-

接口名调整:边播边录

  1. (BOOL)startRecordVideoWithfilePath:(NSString *_Nullable)filePath;

  2. (BOOL)stopRecordVideo;

  3. (NSTimeInterval)getRecordMP4Duratio;

  1. (LVPlayerCode) startRecordingContent:(NSString *_Nonnull)contentFilePath;

  2. (LVPlayerCode) stopRecordingContent;

  3. (NSInteger) getCurrentRecordingContentDurationInMs;

接口名调整。

属性移除:取消后台切换自动恢复

cancelForeground

-

从2.0.0开始,因不再提供VC,相应的后台监听/恢复逻辑也移除,需要客户在自己的VC中按照需求处理后台切换。

属性变更:帧率/码率

  1. frameRate

  2. bitRate

(LVPlayInfo) getCurrentPlayInfo;

属性改为接口。

属性变更:连接类型

connectType

(LVStreamConnectType) getStreamConnectType;

属性改为接口。

接口变更:日志级别设置

(void)setLogLevel:(IMSLinkVisualMediaLogLevel)logLevel decodeLog:(bool)bShow;

[LVMedia getInstance] (void) setLogLevel:(IMSLinkVisualMediaLogLevel)level;

从2.0.0开始,设置日志级别请用LVMedia全局对象的setLogLevel接口完成。

属性变更:静音

mute

  1. (LVPlayerCode) mute:(BOOL)isMute;

  2. (BOOL) isMute;

由属性改为接口。

属性变更:设置画面缩放模式接口参数调整

contentMode

(LVPlayerCode) setVideoScalingMode:(LVMediaVideoScalingMode)videoScalingMode;

LVVideoScalingMode{
//保持宽高
LV_VIDEO_SCALING_MODE_FIT,
//强制填充
LV_VIDEO_SCALING_MODE_FILL;
}

由属性改为接口,修改参数名和类名。

属性变更:播放器状态

playerState

(LVPlayerState) getPlayerState;

属性改为接口,从2.0.0开始iOS的状态机发生了调整,详见状态图。

代理变更:IMSLinkVisualDelegate

IMSLinkVisualDelegate

  1. LVLivePlayerDelegate

  2. LVLivePlayerExternalRenderDelegate

  1. 移除linkVisualConnect;

  2. linkVisualReady和linkVisualStop由LVLivePlayerDelegate的onLivePlayerStateChange来替代;

  3. linkVisual:withFrame由LVLivePlayerExternalRenderDelegate的onLivePlayerVideoFrameUpdate来替代;

  4. linkVisualResolutionChange由LVLivePlayerDelegate的onLivePlayerVideoSizeChanged来替代;

  5. linkVisual:frameRate bitRate移除,需要客户自行调用接口来获取;

  6. linkVisualVideoJitterBufferEmpty由LVLivePlayerDelegate的onLivePlayerVideoJitterBufferEmpty来替代。

属性变更:设置播放器内/外部渲染模式

lvDisplayMode

(LVPlayerCode) setUseExternalRender;(BOOL)useExternalVideoRender useExternalAudioRender: (BOOL)useExternalAudioRender;

属性变更为接口,除了支持视频的外部渲染外还支持音频的外部播放。

新增接口:获取一帧YUV数据接口

-

  1. (LVPlayerCode) lockAndGetYuv420pFrame:(LVYuv420pFrame *_Nonnull)yuv420pFrame;

  2. (LVPlayerCode) unlockYuv420pFrame;

自定义渲染方式不再回调中返回数据,需要在渲染线程中来获取。

点播播放器

变更细节

1.x

2.x

修改建议

包名与类名变更

IMSLinkVisualPlayerViewController

LVVodPlayer

更新包名与类名。

播放器不再提供ViewController

IMSLinkVisualPlayerViewController封装了GLKView用于渲染

播放器与渲染View解耦合

需要在VC中创建LVGlkView,并在VC的viewDidAppear时调用 (LVPlayerCode) setWindow:(LVGlkView *_Nullable)view 设置给播放器。

接口新增:设置rtmp点播地址及hls点播地址数据源

-

(LVPlayerCode) setDataSource:(NSString *_Nonnull)url

-

设置加密的直播数据源中设置的decryptIv和decryptKey从Base64解码后的二进制数据改为解码器前的字符串

(BOOL)setDataSource_Vod:(NSString *_Nullable)rtmpPathneedEncrypt:(BOOL)needEncryptiv:(NSData *_Nullable)ivkey:(NSData *_Nullable)key;

(LVPlayerCode) setDataSource:(NSString *_Nonnull)url isEncrypted:(BOOL)isEncrypted decryptIvBase64:(NSString *_Nullable)decryptIvBase64 decryptKeyBase64:(NSString *_Nullable)decryptKeyBase64;

请注意将Base64解码去除,由SDK内部来完成对Base64字符串的解码。

接口命名调整:设置基于生活物联网平台连接的IPC设备录像点播数据源

  1. (BOOL)setDataSource:(NSString*_Nullable)iotId vodFileName:(NSString*_Nullable)vodFileName;

  2. (BOOL)setDataSource:(NSString*_Nullable)iotId vodFileName:(NSString*_Nullable)vodFileName seekTime:(NSInteger)seekTime;

  3. (BOOL)setDataSource:(NSString*_Nullable)iotId vodStartTime:(NSInteger)vodStartTime vodEndTime:(NSInteger)vodEndTime seekTime:(NSInteger)seekTime;

  4. (BOOL)setDataSource:(NSString*_Nullable)iotId vodStartTime:(NSInteger)vodStartTime vodEndTime:(NSInteger)vodEndTime seekTime:(NSInteger)seekTime recordType:(NSInteger)recordType;

  1. (LVPlayerCode) setDataSourceByLocalRecordFileName:(NSString *_Nonnull)iotId fileName:(NSString *_Nonnull)fileName;

  2. (LVPlayerCode) setDataSourceByLocalRecordFileName:(NSString *_Nonnull)iotId fileName:(NSString *_Nonnull)fileName seekToPositionInMs:(NSInteger)seekToPositionInMs;

  3. (LVPlayerCode) setDataSourceByLocalRecordTime:(NSString *_Nonnull)iotId beginTimeInS:(NSInteger)beginTimeInS endTimeInS:(NSInteger)endTimeInS seekToPositionInMs:(NSInteger)seekToPositionInMs recordType:(NSInteger)recordType;

调整接口名。

接口移除:基于生活物联网平台连接的IPC设备录像点播数据源

  1. (BOOL)setNoEncryptDataSource:(NSString*_Nullable)iotId vodFileName:(NSString*_Nullable)vodFileName;

  2. (BOOL)setNoEncryptDataSource:(NSString*_Nullable)iotId vodStartTime:(NSInteger)vodStartTime vodEndTime:(NSInteger)vodEndTime seekTime:(NSInteger)seekTime;

-

从2.0.0开始强制要求打开加密和强制I帧。

接口命名调整:设置基于生活物联网平台连接的IPC设备云存点播数据源

  1. (BOOL)setDataSource:(NSString*_Nullable)iotId hlsFileName:(NSString*_Nullable)hlsFileName seekTime:(NSTimeInterval)seekTime;

  2. (BOOL)setDataSource_HLS:(NSString *_Nullable)hlsPath seekTime:(NSTimeInterval)seekTime;

  1. (LVPlayerCode) setDataSourceByCloudRecordFileName:(NSString *_Nonnull)iotId fileName:(NSString *_Nonnull)fileName;

  2. (LVPlayerCode) setDataSourceByCloudRecordFileName:(NSString *_Nonnull)iotId fileName:(NSString *_Nonnull)fileName seekToPositionInMs:(NSInteger)seekToPositionInMs;

调整接口名。

指令接口,如setDataSource()/start()/stop()等增加返回值

-

返回值枚举:

enum LVPlayerCode{
    /** 执行成功 */
    LV_PLAYER_SUCCESS  = 0,
    /** 执行失败, 通用错误 */
    LV_PLAYER_ERROR_FAILED  = -1,
    /** 错误的输入参数 */
    LV_PLAYER_ERROR_INVALID_PARAMETER   = -2,
    /** 不支持的接口 */
    LV_PLAYER_ERROR_UNSUPPORTED = -3,
};

可以通过判断返回值作为接口操作是否成功的判断。

接口名调整:恢复播放

restore

resume

修改接口名。

接口名调整:逐帧播放

nextFrame

playFrameByFrame

修改接口名。

接口名调整:seek到对应的时间

seekToDuration

seekTo

修改接口名。

新增接口:获取当前码流的宽高

-

  1. (NSInteger) getVideoWidth;

  2. (NSInteger) getVideoHeight;

-

类名与方法名变更:设置解码器策略和获取解码器类型

  1. (IMSLinkVisualPlayerDecodeMode)getDecoderStrategy;

  2. (BOOL)setDecoderStrategy:(IMSLinkVisualPlayerDecodeMode)decodeMode

  1. (LVPlayerCode) setDecoderStrategy:(LVDecoderStrategy)decoderStrategy;

  2. (LVDecoderType) getDecoderType;

修改类名与方法名。

接口移除:P2P全局初始化和释放

  1. (void)initP2P;

  2. (void)deallocP2P;

-

无需有该动作。

接口移除:设备P2P预建连

(void)preCreateP2P:(NSString*_Nonnull)iotId;

-

从2.0.0开始,预建连请用LVMedia全局对象的preConnect接口完成。

接口移除:所有播放器触发stop动作

(void)stopAllPlayer;

-

从2.0.0开始,自行停止对应的播放器即可,该接口有替代实现,无需有该动作。

属性移除:激活音频管理器

activeAudioManager;

-

从2.0.0开始,SDK因为将对讲与播放器剥离,只有在使用对应功能时才会触发录音权限,该接口已无意义。

接口变更:音频焦点接口

(void)activePlayer;

  1. (LVPlayerCode) audioFocus;

  2. (BOOL)isAudioFocus;

从2.0.0开始,SDK不再支持多路音频同时播放,至多只有一路音频播放。当存在多路观看(如NVR多分屏)场景时,请交由用户来调用关心的那一路播放器的audioFocus()接口来完成多路播放器之间声音播放的切换。

接口移除:设置播放器缓存

  1. (void)setDisplayBuffer;

  2. (NSInteger)bufferCount;

-

该接口仅在直播播放器中支持,点播播放器移除。

接口移除:设置播放器抗抖动最大缓冲区时长

  1. (void)setMaxJitterBufferSizeInMs;

  2. (NSInteger)jitterBufferSizeInMs;

-

该接口仅在直播播放器中支持,点播播放器移除。

接口移除:VC中屏蔽语音对讲

(instancetype_Nonnull)initDisableIntercom;

-

从2.0.0开始,播放器和语音对讲已按功能做了拆分,不再耦合,该接口已无意义。

接口名调整:截图

(UIImage * __nullable)videoSnapshot;

(UIImage *_Nullable) snapShot;

接口名调整。

接口新增:截图到文件

-

  1. (LVPlayerCode) snapShotToFile;

  2. (NSString *_Nonnull)jpegFilePath;

-

接口名调整:边播边录

  1. (BOOL)startRecordVideoWithfilePath:(NSString *_Nullable)filePath;

  2. (BOOL)stopRecordVideo;

  3. (NSTimeInterval)getRecordMP4Duratio;

  1. (LVPlayerCode) startRecordingContent:(NSString *_Nonnull)contentFilePath;

  2. (LVPlayerCode) stopRecordingContent;

  3. (NSInteger) getCurrentRecordingContentDurationInMs;

接口名调整。

属性移除:取消后台切换自动恢复

cancelForeground

-

从2.0.0开始,因不再提供VC,相应的后台监听/恢复逻辑也移除,需要客户在自己的VC中按照需求处理后台切换。

属性变更:帧率/码率

  1. frameRate

  2. bitRate

(LVPlayInfo) getCurrentPlayInfo;

属性改为接口。

属性变更:连接类型

connectType

(LVStreamConnectType) getStreamConnectType;

属性改为接口。

接口变更:日志级别设置

(void)setLogLevel:(IMSLinkVisualMediaLogLevel)logLevel decodeLog:(bool)bShow;

[LVMedia getInstance] (void) setLogLevel:(IMSLinkVisualMediaLogLevel)level;

从2.0.0开始,设置日志级别请用LVMedia全局对象的setLogLevel接口完成。

属性变更:静音

mute

  1. (LVPlayerCode) mute:(BOOL)isMute;

  2. (BOOL) isMute;

由属性改为接口。

属性变更:播放速度

playSpeed

(LVPlayerCode) setPlaybackSpeed:(float)speed;

由属性改为接口。

属性变更:文件总时长和当前时长

  1. duration

  2. currentDuration

  1. (NSInteger) getDurationMs;

  2. (NSInteger) getCurrentPositionMs;

由属性改为接口。

属性变更:设置画面缩放模式接口参数调整

contentMode

(LVPlayerCode) setVideoScalingMode:(LVMediaVideoScalingMode)videoScalingMode;

LVVideoScalingMode{
//保持宽高
LV_VIDEO_SCALING_MODE_FIT,
//强制填充
LV_VIDEO_SCALING_MODE_FILL;
}

由属性改为接口,修改参数名和类名。

属性变更:播放器状态

playerState

(LVPlayerState) getPlayerState;

属性改为接口,从2.0.0开始iOS的状态机发生了调整,详见状态图。

代理变更:IMSLinkVisualDelegate

IMSLinkVisualDelegate

  1. LVVodPlayerDelegate

  2. LVVodPlayerExternalRenderDelegate

  1. 移除linkVisualConnect;

  2. linkVisualReady、linkVisualStop、linkVisualReplaySeekReady由LVVodPlayerDelegate的onLivePlayerStateChange来替代;

  3. linkVisual:withFrame由LVVodPlayerExternalRenderDelegate的onVodPlayerVideoFrameUpdate来替代;

  4. linkVisualResolutionChange由LVVodPlayerDelegate的onVodPlayerVideoSizeChanged来替代;

  5. linkVisual:frameRate bitRate移除,需要客户自行调用接口来获取;

  6. linkVisualVideoJitterBufferEmpty由LVVodPlayerDelegate的onVodPlayerVideoJitterBufferEmpty来替代;

  7. 移除linkVisualRestore、linkVisualPause;

  8. linkVisualPlayEnd由LVVodPlayerDelegate的onVodPlayerCompletion来替代;

  9. linkVisualReplay:currentTime移除,需要客户自行调用接口来获取。

属性变更:设置播放器内/外部渲染模式

lvDisplayMode

(LVPlayerCode) setUseExternalRender;(BOOL)useExternalVideoRender useExternalAudioRender: (BOOL)useExternalAudioRender;

属性变更为接口,除了支持视频的外部渲染外还支持音频的外部播放。

新增接口:获取一帧YUV数据接口

-

  1. (LVPlayerCode) lockAndGetYuv420pFrame:(LVYuv420pFrame *_Nonnull)yuv420pFrame;

  2. (LVPlayerCode) unlockYuv420pFrame;

自定义渲染方式不再回调中返回数据,需要在渲染线程中来获取。

语音对讲

变更细节

1.x

2.x

修改建议

包名与类名变更

IMSLinkVisualPlayerViewController

LVLiveIntercom

更新包名与类名。

接口变更:初始化接口

intercomEncodeParams

(id_Nonnull)create:(LVMediaAudioHeader)lvMediaAudioHeader;

从2.0.0 SDK开始,音频参数要求在创建对讲实例时传入。

接口变更:

  1. 与指定设备(通过iotId)进行对讲

  2. 与指定设备(通过url)进行对讲

(void)startIntercom:(IMSLinkVisualIntercomAudioMode)mode;

  1. (LVLiveIntercomCode) start:(NSString *_Nonnull)url decryptIvBase64:(NSString *_Nonnull)decryptIvBase64 decryptKeyBase64:(NSString *_Nonnull)decryptKeyBase64;

  2. (LVLiveIntercomCode) start:(NSString *_Nonnull)iotId;

从2.0.0 SDK开始对讲模式提供单独的接口来设置。

新增接口:对讲模式设置

-

(LVLiveIntercomCode) setLiveIntercomMode:(LVLiveIntercomMode)liveIntercomMode;

从2.0.0 SDK开始增加DoubleTalkWithLive模式:App端和设备端都需要同时做采音和放音,设备端必须支持AEC,否则不建议使用该方案;将会使用设备直播通道的声音进行播放,要求必须有已开播的直播通道,可通过LVLivePlayer.audioFocus()方法在对讲开启前选择对应的已存在的直播通道。

指令接口,如start()/stop()等增加返回值

-

返回值枚举:

enum LVPlayerCode{
    /** 执行成功 */
    LV_PLAYER_SUCCESS  = 0,
    /** 执行失败, 通用错误 */
    LV_PLAYER_ERROR_FAILED  = -1,
    /** 错误的输入参数 */
    LV_PLAYER_ERROR_INVALID_PARAMETER   = -2,
    /** 不支持的接口 */
    LV_PLAYER_ERROR_UNSUPPORTED = -3,
};

可以通过判断返回值作为接口操作是否成功的判断。

新增接口:静音

-

  1. (LVLiveIntercomCode) mute:(BOOL)isMute;

  2. (BOOL) isMute;

-

属性变更:增益和变声

  1. gainLevel

  2. voiceChangeType

  1. (LVLiveIntercomCode) setGainLevel:(NSInteger)gainLevel;

  2. (LVLiveIntercomCode) setVoiceChangeType:(LVLiveIntercomVoiceType)liveIntercomVoiceType;

属性变为方法。

接口移除:发送设备端接收的录音数据

(void)sendAudioData:(NSData *_Nullable)data;

-

从2.0.0 开始,SDK内部会进行数据的发送,该接口无意义。

接口变更:设置对讲监听器

intercomDelegate

LVLiveIntercomDelegate

  1. 移除linkVisualIntercomConnect;

  2. linkVisualIntercomReady替换为onLiveIntercomTalkReady;

  3. 移除linkVisualIntercom:audioParams;

  4. 移除linkVisualIntercom:audioData;

  5. 移除linkVisualIntercom:recordData, 使用LVLiveIntercomVoiceChangeDelegate来代替;

  6. linkVisualIntercomStop替代为onLiveIntercomRecorderEnd;

  7. 新增onLiveIntercomRecorderStart;

  8. linkVisualIntercom:errorOccurred替代为onLiveIntercomError。

接口变更:外部变声实现

通过在调用sendAudioData接口前完成对声音的处理

  1. (LVLiveIntercomCode) setUseExternalVoiceChange:(BOOL)useExternal;

  2. LVLiveIntercomVoiceChangeDelegate

开启外部变声并且实现外部对讲变声代理的onLiveIntercomAudioData方法来实现。