视频多媒体SDK

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

依赖的SDK

SDK

概述

API通道

提供IoT业务协议封装的HTTPS请求能力,并通过整合安全组件来提升通道的安全性。

初始化

初始化前需确保已正确集成安全图片。具体操作,请参见SDK初始化集成安全图片

依赖引入

// 1. 在根目录下的build.gradle中添加Aliyun Maven仓库的引用
allprojects {
    repositories {
        maven {
            url "http://maven.aliyun.com/nexus/content/repositories/releases"
        }
    }
}

// 2. App build.gradle中添加依赖
implementation('com.aliyun.iotx:linkvisual-media:2.5.0-ilop')

混淆配置

# keep and don't warn Link Visual

-dontwarn com.aliyun.iotx.linkvisual.**

-keep class com.aliyun.iotx.** {*;}
-keep class com.aliyun.iotx.linkvisual.media.** { *; }

SDK接口文档

LinkVisual Media SDK文档(Android)

播放器

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

  • 直播播放器

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

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

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

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

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

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

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

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

播放器功能表

  • √:表示支持。

  • ×:表示不支持。

功能

直播播放器

点播播放器(设备录像)

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

视频播放

音频播放

暂停/恢复

×

播放重连

×

×

跳至指定位置播放

×

总时长

×

当前播放进度

×

播放器状态变更通知

播放静音

变速播放

×

单帧步进

×

画面缩放模式设置

播放停止时显示模式设置

NVR多画面播放

数字变焦

播放窗口截图

截图到文件

边播边录

硬解码

获取码流信息

提供YUV数据

提供SEI数据

播放器的使用示例:

  • 直播播放器

    // 构造播放器实例
    LVLivePlayer player = new LVLivePlayer(getApplicationContext());
    
    // 设置textureview,可使用SDK提供的带画面缩放的ZoomableTextureView组件, 画面不旋转
    player.setTextureView(zoomableTextureView, LVVideoRotationMode.LV_VIDEO_ROTATE_0_CLOCKWISE);
    // 设置必要的监听
    player.setPlayerListener(new ILVPlayerListener() {
        @Override
        public void onError(LVPlayerError error) {
            // 播放报错
        }
        @Override
        public void onPlayerStateChange(LVPlayerState state) {
            Log.d(TAG, "play state= " + state.name());
            switch (state) {
                case STATE_BUFFERING:
                    // 显示正在缓冲
                    break;
                case STATE_IDLE:
                    break;
                case STATE_READY:
                    // 隐藏正在缓冲
                    updatePlayInfo();
                    break;
                case STATE_ENDED:
                    // 隐藏正在缓冲
                    break;
                default:
                    break;
            }
        }
        @Override
        public void onRenderedFirstFrame(int elapsedTimeInMs) {
            // 显示回调,elapsedTimeInMs为出图耗时
        }
        @Override
        public void onVideoSizeChanged(int width, int height) {
            // 宽高变化回调
        }
        @Override
        public void onSeiInfoUpdate(byte[] buffer, int length, long timeStamp) {
            // 码流中私有格式的SEI数据帧回调,不再建议使用
        }
        @Override
        public void onStandardSeiInfoUpdate(byte[] buffer, int length, long timeStamp) {
            // 码流中标准的SEI数据帧回调
        }
        @Override
        public void onVideoJitterBufferEmpty() {
        }
    });
    
    // 设置数据源,数据源为设备的IotId
    player.setLiveDataSource(iotId, LVStreamType.LV_STREAM_TYPE_MAJOR);
    // 设置自动重连次数
    player.setReconnectCount(3);
    // 设置解码策略为硬解码优先
    player.setDecoderStrategy(LVDecoderStrategy.LV_DECODER_STRATEGY_HARDWARE_FIRST);
    // 设置画面模式为保持宽高
    player.setVideoScalingMode(LVVideoScalingMode.LV_VIDEO_SCALING_MODE_FIT);
    // 设置播放停止时保留最后一帧画面
    player.setPlayerStoppedDrawingMode(LVPlayerStoppedDrawingMode.LV_ALWAYS_KEEP_LAST_FRAME);
    ...
    // 开始播放
    player.start();
    ...
    // 停止播放
    player.stop();
    ...
    // 释放播放器资源
    player.release();     
  • 点播播放器 (设备录像)

    // 构造播放器实例
    LVVodPlayer player = new LVVodPlayer(getApplicationContext());
    // 设置textureview,可使用SDK提供的带画面缩放的ZoomableTextureView组件
    player.setTextureView(zoomableTextureView);
    
    // 设置必要的监听
    player.setPlayerListener(new ILVPlayerListener() {
        @Override
        public void onError(LVPlayerError error) {
            // 播放报错
        }
        @Override
        public void onPlayerStateChange(LVPlayerState state) {
            Log.d(TAG, "play state= " + state.name());
            switch (state) {
                case STATE_BUFFERING:
                    // 显示正在缓冲
                    break;
                case STATE_IDLE:
                    break;
                case STATE_READY:
                    // 隐藏正在缓冲
                    updatePlayInfo();
                    break;
                case STATE_ENDED:
                    // 隐藏正在缓冲
                    break;
                default:
                    break;
            }
        }
        @Override
        public void onRenderedFirstFrame(int elapsedTimeInMs) {
            // 显示回调,elapsedTimeInMs为出图耗时
        }
        @Override
        public void onVideoSizeChanged(int width, int height) {
            // 宽高变化回调
        }
        @Override
        public void onSeiInfoUpdate(byte[] buffer, int length, long timeStamp) {
            // 码流中私有格式的SEI数据帧回调,不再建议使用
        }
        @Override
        public void onStandardSeiInfoUpdate(byte[] buffer, int length, long timeStamp) {
            // 码流中标准的SEI数据帧回调
        }
        @Override
        public void onVideoJitterBufferEmpty() {
        }
    });
    
    // 设置播放完成监听
    player.setVodCompletionListener(new ILVVodPlayerCompletionListener() {
        @Override
        public void onCompletion() {
            // 播放完成
        }
    });
    
    // 设置数据源:以下两种方式都可以
    // 1. 按设备文件名,初始播放偏移为20S
    player.setDataSourceByLocalRecordFileName(iotId, "fileNamexxxxxxxx", 20000);
    // 2. 按设备时间,从2022-08-29 17:54:14到2022-08-30 02:47:34的录像,初始播放偏移为20S,类型为所有录像
    player.setDataSourceByLocalRecordTime(iotId, 1661766854, 1661798854, 20000, 99);
    
    // 设置解码策略为硬解码优先
    player.setDecoderStrategy(LVDecoderStrategy.LV_DECODER_STRATEGY_HARDWARE_FIRST);
    // 设置画面模式为保持宽高
    player.setVideoScalingMode(LVVideoScalingMode.LV_VIDEO_SCALING_MODE_FIT);
    ...
    // 开始播放
    player.start();
    ...
    // 暂停
    player.pause();
    ...
    // 恢复
    player.resume();
    ...
    // 停止播放
    player.stop();
    ...
    // 释放播放器资源
    player.release();                 
  • 点播播放器(HLS云存)

    // 构造播放器实例
    LVVodPlayer player = new LVVodPlayer(getApplicationContext());
    // 设置textureview,可使用SDK提供的带画面缩放的ZoomableTextureView组件
    player.setTextureView(zoomableTextureView);
    // 设置必要的监听
    player.setPlayerListener(new ILVPlayerListener() {
        @Override
        public void onError(LVPlayerError error) {
            // 播放报错
        }
        @Override
        public void onPlayerStateChange(LVPlayerState state) {
            Log.d(TAG, "play state= " + state.name());
            switch (state) {
                case STATE_BUFFERING:
                    // 显示正在缓冲
                    break;
                case STATE_IDLE:
                    break;
                case STATE_READY:
                    // 隐藏正在缓冲
                    updatePlayInfo();
                    break;
                case STATE_ENDED:
                    // 隐藏正在缓冲
                    break;
                default:
                    break;
            }
        }
        @Override
        public void onRenderedFirstFrame(int elapsedTimeInMs) {
            // 显示回调,elapsedTimeInMs为出图耗时
        }
        @Override
        public void onVideoSizeChanged(int width, int height) {
            // 宽高变化回调
        }    
        @Override
        public void onSeiInfoUpdate(byte[] buffer, int length, long timeStamp) {
            // 码流中私有格式的SEI数据帧回调,不再建议使用
        }
        @Override
        public void onStandardSeiInfoUpdate(byte[] buffer, int length, long timeStamp) {
            // 码流中标准的SEI数据帧回调
        }
        @Override
        public void onVideoJitterBufferEmpty() {
        }
    });
    // 设置播放完成监听
    player.setVodCompletionListener(new ILVVodPlayerCompletionListener() {
        @Override
        public void onCompletion() {
            // 播放完成
        }
    });
    
    // 设置数据源,按云存文件名,初始播放偏移为20S
    player.setDataSourceByCloudRecordFileName(iotId, "fileNamexxxxxxxx", 20000);
    
    // 设置解码策略为硬解码优先
    player.setDecoderStrategy(LVDecoderStrategy.LV_DECODER_STRATEGY_HARDWARE_FIRST);
    // 设置画面模式为保持宽高
    player.setVideoScalingMode(LVVideoScalingMode.LV_VIDEO_SCALING_MODE_FIT);
    ...
    // 开始播放
    player.start();
    ...
    // 暂停
    player.pause();
    ...
    // 恢复
    player.resume();
    ...
    // 停止播放
    player.stop();
    ...
    // 释放播放器资源
    player.release();                 

播放器状态介绍

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

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

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

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

  • READY:播放器已经有内容在播放。状态变更事件如:首帧数据已经渲染、seekTo()缓冲完成开始播放新内容。对于点播播放器,若已seekTo()或播放到文件结尾,则会回调OnCompletionListener.onCompletion()方法,状态会自动切换到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

解码错误

若在持续一段时间内,解码均发生失败,您可转存码流数据,然后分析数据。转存的操作步骤如下:

  • 运行命令adb shell setprop debug.lv.dump.enable true

  • 重启应用然后播放视频。

  • 运行命令adb pull /sdcard/Android/data/${pkgname}/files/LinkVisual_dump/ 拉取。

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

8 Khz/16 Khz

G711U

8 Khz/16 Khz

AAC_LC

8 Khz/16 Khz

语音对讲使用方式:

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

    liveIntercom = new LVLiveIntercom(getApplicationContext(), AudioParams.AUDIOPARAM_MONO_8K_G711A);
  2. 注册监听器,并处理语音对讲回调。

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

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

    liveIntercom.setLiveIntercomListener(new ILVLiveIntercomListener() {
        @Override
        public void onTalkReady() {
            // 对端已链接,可以开始说话了
        }
        @Override
        public void onRecorderStart() {
            speakBtn.setEnabled(false);
            // 录音开启
        }
        @Override
        public void onRecorderEnd() {
            // 录音结束
        }
        @Override
        public void onRecorderVolume(int volume) {
        }
        @Override
        public void onError(LVLiveIntercomError error) {
            // 对讲发生错误:code: + error.getCode() + error.getSubCode() +  msg: + error.getMessage());
        }});
    }
  3. 设置增益水平。

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

    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,将会降级到全双工对讲。

    liveIntercom.setLiveIntercomMode(LVLiveIntercomMode.DoubleTalk);
  5. 开始对讲。

    对讲开始后,会请求音频焦点,并设置到通话模式,同时将对端播放声音强制路由到扬声器(若已连接蓝牙耳机或者线控耳机则路由到耳机上)。

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

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

    // 该状态下APP端停止播放,采集音频发给设备端,同时设备端会停止音频采集,播放APP端采集的声音
    liveIntercom.listen(true);
    ...
    // 该状态下APP端恢复播放,同时设备端会停止播放声音,恢复音频采集
    liveIntercom.listen(false);
  7. 结束对讲。

    对讲结束后释放音频焦点,并设置到常规模式,同时取消强制音频播放路由到扬声器规则。对讲过程中默认开启手机回声消除。

    // 停止对讲
    liveIntercom.stop();
  8. 释放对讲资源。

    对讲功能不再使用需要主动释放资源。

    // 释放对讲
    liveIntercom.release();

语音对讲错误列表

错误码

描述

解决办法

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

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

amr

WAV

8 Khz/16 Khz

PCM

G711

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

  • 音频文件录制

    // 创建音频文件录音机
    LVAudioFileRecorder recorder = new LVAudioFileRecorder(getApplicationContext());
    
    // 设置录制监听器
    recorder.setRecorderListener(new ILVAudioFileRecorderListener() {
                @Override
                public void onRecordStart() {
                    appendLog("录音开始");
                    isRecording = true;
                }
    
                @Override
                public void onRecordEnd() {
                    appendLog("录音结束");
                    isRecording = false;
                }
    
                @Override
                public void onRecordVolume(int volume) {
                }
    
                @Override
                public void onError(LVAudioFileErrorCode code, String message) {
                    appendLog("录制出错: code:" + code + " msg:" + message);
                    isRecording = false;
                }
            });
    
    // 设置录音参数配置并启动录音
    File audioFile = new File(String.format("/sdcard/%d.amr", System.currentTimeMillis()));
    LVAudioFileCode code = recorder.startRecorder(AudioParams.AUDIOPARAM_MONO_8K_AMR, audioFile.getAbsolutePath());
    
    // 停止录制
    recorder.stopRecorder();
    
    // 录音机资源释放
    recorder.release();
  • 音频文件播放

    // 创建音频文件播放器
    LVAudioFilePlayer player = new LVAudioFilePlayer(getApplicationContext());
    
    // 设置播放监听器
    player.setPlayerListener(new ILVAudioFilePlayerListener() {
            @Override
            public void onCompletion() {
                appendLog("播放结束");
            }
        });
    
    // 播放本地文件
    LVAudioFileCode code = player.startPlay(LVAudioFileType.LV_AUDIO_FILE_TYPE_WAV, "/sdcard/test.wav");
    
    // 播放网络文件
    LVAudioFileCode code = player.startPlay("https://link-vision-temp-sh.oss-cn-shanghai.aliyuncs.com/test.amr");
    
    // 停止播放
    player.stopPlay();
    
    // 播放器资源释放
    player.release();
  • 文件上传

    // 创建文件上传器
    LVOSSUploader uploader = new LVOSSUploader(getApplicationContext());
    
    // 设置文件上传监听器
    uploader.setOSSUploaderCallback(new ILVOSSUploaderListener() {
                @Override
                public void onError(String sessionId, String fileName, int code, String message) {
                    appendLog("上传失败 sessionId=" + sessionId + " fileName=" + fileName + " code=" + code + " message=" + message);
                }
    
                @Override
                public void onProgress(long uploadBytes, long totalBytes) {
                    appendLog("上传进度 " + uploadBytes + "/" + totalBytes);
                }
    
                @Override
                public void onCompletion(String sessionId, String fileName) {
                    appendLog("上传完成 sessionId=" + sessionId + " fileName=" + fileName);
                }
            });
    
    // 开始上传
    uploader.upload(audioFile.getAbsolutePath(), "test.wav", "123456", "https://oss.example.com/test.wav");
    
    // 上传器资源释放
    uploader.release();

音频文件错误列表

错误枚举

描述

解决办法

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版本指南

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

说明

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

重要变化

重要变化

1.x版本

2.x版本

渲染组件支持

支持TextureViewGLSurfaceView两种组件。

只提供TextureView,移除对GLSurfaceView的支持。

直播播放器

LivePlayer

改名为LVLivePlayer

点播播放器

  • 卡录像点播播放器为VodPlayer

  • 云存录像播放器为HlsPlayer

不再区分卡录像点播还是云存录像点播,统一为LVVodPlayer,自动识别设置的数据源来完成相应的转换。

语音对讲

LiveIntercomV2

改名为LVLiveIntercom

升级步骤

gradle集成,方式与1.x版本类似,修改版本号即可,混淆配置无变化。

说明

从2.0.0开始,linkvisual-media不再默认依赖ExoPlayer,如果您还需要使用继续使用ExoPlayer请在依赖中添加

implementation('com.google.android.exoplayer:exoplayer-core:2.10.5')
implementation('com.google.android.exoplayer:exoplayer-ui:2.8.3')
implementation('com.google.android.exoplayer:exoplayer-hls:2.10.5')

混淆配置中添加:

-dontwarn com.google.android.exoplayer2.**

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

全局组件

变更细节

1.x

2.x

修改建议

包名与类名变更

com.aliyun.iotx.linkvisual.media.LinkVisualMedia

com.aliyun.iotx.linkvisual.media.LVMedia

更新包名与类名。

接口变更:直播预建连接口

  1. void preConnectByIotId(final String iotId)

  2. void preConnectByIotId(final String iotId, int streamType)

LVPlayerCode preConnectByIotId(String iotId, LVStreamType streamType)

修改接口名。

直播播放器

变更细节

1.x

2.x

修改建议

包名与类名变更

com.aliyun.iotx.linkvisual.media.video.player.LivePlayer

com.aliyun.iotx.linkvisual.media.player.LVLivePlayer

更新包名与类名。

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

void setDataSource(String url, boolean isEncrypted, byte[] decryptIv, byte[] decryptKey)

LVPlayerCode setDataSource(String url, boolean isEncrypted, String decryptIvBase64, String decryptKeyBase64)

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

接口命名调整:设置基于物联网智能视频服务连接的IPC设备直播数据源

  1. void setIPCLiveDataSource(String iotId, int streamType)

  2. void setIPCLiveDataSource(String iotId, int streamType, int cacheDurationInMs)

  1. LVPlayerCode setLiveDataSource(String iotId, LVStreamType streamType)

  2. LVPlayerCode setLiveDataSource(String iotId, LVStreamType streamType, int cacheDurationInMs)

除接口名修改外,第二个参数码流类型由int值改为枚举,方便理解和维护。

接口移除:基于物联网智能视频服务连接的IPC设备直播数据源

  1. void setIPCLiveDataSource(String iotId, int streamType, boolean relayEncrypted, int relayEncryptType, boolean forceIFrame)

  2. void setIPCLiveDataSource(String iotId, int streamType, boolean relayEncrypted, int relayEncryptType, boolean forceIFrame, int cacheDurationInMs)

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

接口移除:移除prepare步骤

  1. prepare()

  2. void setOnPreparedListener(OnPreparedListener listener)

  3. com.aliyun.iotx.linkvisual.media.video.listener.OnPreparedListener

设置数据源后,在播放start()前无需再调用prepare()

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

返回值枚举:

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

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

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

  1. int getVideoWidth()

  2. int getVideoHeight()

无。

类名变更:解码器策略和解码器类型枚举

  1. com.aliyun.iotx.linkvisual.media.video.HardwareDecoderable.DecoderStrategy

  2. com.aliyun.iotx.linkvisual.media.video.HardwareDecoderable.DecoderType

  1. com.aliyun.iotx.linkvisual.media.player.bean.LVDecoderStrategy

  2. com.aliyun.iotx.linkvisual.media.player.bean.LVDecoderType

修改类名。

接口变更:取消设置音量接口改为静音和取消静音接口

  1. void setVolume(float audioVolume)

  2. float getVolume()

  1. LVPlayerCode mute(boolean isMute)

  2. boolean isMute()

不支持应用内单独控制播放音量,音量控制统一交由系统音量来完成。

新增接口:增加音频焦点接口

  1. LVPlayerCode audioFocus()

  2. boolean isAudioFocus()

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

接口移除:移除音频播放流通道设置接口

void setAudioStreamType(final int streamType)

直播播放器始终使用 AudioManager.STREAM_MUSIC通道,不再支持切换。

接口移除:移除对GLSurfaceView的支持

  1. void setSurfaceView(SurfaceView mSurfaceView)

  2. void clearSurfaceView()

请替换为TextureView,相比GLSurfaceView有以下优势:

  1. 支持硬件加速,可随View移动不产生黑边。

  2. 支持电子变焦(请使用SDK提供ZoomableTextureView)。

  3. 支持多窗口播放。

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

void setVideoScalingMode(int mVideoScalingMode)

LVPlayerCode setVideoScalingMode(LVVideoScalingMode videoScalingMode)

com.aliyun.iotx.linkvisual.media.player.bean.LVVideoScalingMode {
//保持宽高
LV_VIDEO_SCALING_MODE_FIT,
//强制填充
LV_VIDEO_SCALING_MODE_FILL;
}

修改参数名和类名。

接口变更:边播边录

  1. boolean startRecordingContent(File contentFile)

  2. boolean stopRecordingContent()

  3. long getCurrentRecordingContentDuration()

  1. LVPlayerCode startRecordingContent(String contentFilePath)

  2. LVPlayerCode stopRecordingContent()

  3. long getCurrentRecordingContentDurationInMs()

  1. 开始录制参数类型由File改为String。

  2. 获取录制时长接口名调整。

接口移除:设置播放停止时画面行为接口

  1. void setPlayerStoppedDrawingMode(PlayerStoppedDrawingMode playerStoppedDrawingMode)

  2. PlayerStoppedDrawingMode getPlayerStoppedDrawingMode()

暂未支持,后续版本中会补充该功能。

接口变更:获取播放状态接口

int getPlayState()

  1. LVPlayerState getPlayerState()

  2. com.aliyun.iotx.linkvisual.media.player.bean.LVPlayerState

播放器状态由int改为枚举值,方便理解和维护。

接口变更:获取当前流连接类型接口

StreamConnectType getStreamConnectType()

  1. LVStreamConnectType getStreamConnectType()

  2. com.aliyun.iotx.linkvisual.media.player.bean.LVStreamConnectType

修改类名。

接口变更:获取当前播放帧率/码率信息接口

PlayInfo getCurrentPlayInfo()

  1. LVPlayInfo getCurrentPlayInfo()

  2. com.aliyun.iotx.linkvisual.media.player.bean.LVPlayInfo

修改类名。

接口变更:设置直播播放器回调接口

  1. void setOnRenderedFirstFrameListener(OnRenderedFirstFrameListener listener)

  2. void setOnErrorListener(OnErrorListener listener)

  3. void setOnPlayerStateChangedListener(OnPlayerStateChangedListener listener)

  4. void setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener)

  5. void setOnVideoQualityListener(OnVideoQualityListener listener)

  6. void setOnSeiInfoListener(SeiInfoBuffer seiInfoBuffer, OnSeiInfoListener onSeiInfoListener)

LVPlayerCode setPlayerListener(ILVPlayerListener listener)

com.aliyun.iotx.linkvisual.media.player.listener.ILVPlayerListener {
    void onError(LVPlayerError error);
    void onPlayerStateChange(LVPlayerState state);
    void onRenderedFirstFrame(int elapsedTimeInMs);
    void onVideoSizeChanged(int width, int height);
    void onSeiInfoUpdate(byte[] buffer, int length, long timeStamp);    void onVideoJitterBufferEmpty();
}

将多个Listener合并为一个。

接口变更:设置使用外部渲染接口

  1. void setUseExternalRender(boolean mUseExternalRender)

  2. void setOnExternalRenderListener

  3. boolean useExternalRender()

LVPlayerCode setUseExternalRender(boolean useExternalVideoRender, boolean useExternalAudioRender, ILVPlayerExternalRenderListener listener)

com.aliyun.iotx.linkvisual.media.player.listener.ILVPlayerExternalRenderListener {
    void onVideoFrameUpdate(int width, int height, long timestampInMs);
    void onAudioHeader(int audioBitPerSample, int audioSamplesPerSec, int audioChannel);
    boolean onAudioData(byte[] buffer, int offset, int length);
}

从2.0.0开始,除了支持视频YUV数据回调之外,还支持音频PCM回调。

接口变更:获取一帧YUV数据接口

Yuv420pFrame getYuvFrame()

Yuv420pFrame getYuv420pFrame()

修改接口名。

点播播放器

变更细节

1.x

2.x

修改建议

包名与类名变更

  1. com.aliyun.iotx.linkvisual.media.video.player.VodPlayer

  2. com.aliyun.iotx.linkvisual.media.video.player.HlsPlayer

com.aliyun.iotx.linkvisual.media.player.LVVodPlayer

更新包名与类名。从2.0.0开始,SDK将设备卡录像点播播放器和云存播放器统一为一种播放器。

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

void setDataSource(String url, boolean isEncrypted, byte[] decryptIv, byte[] decryptKey)

LVPlayerCode setDataSource(String url, boolean isEncrypted, String decryptIvBase64, String decryptKeyBase64)

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

接口命名调整:设置播放地址为已接入物联网智能视频服务的IPC设备指定录像名的本地录像文件地址

  1. void setDataSourceByIPCRecordFileName(String iotId, String fileName)

  2. void setDataSourceByIPCRecordFileName(String iotId, String fileName, long seekToPositionInMs)

  1. LVPlayerCode setDataSourceByLocalRecordFileName(String iotId, String fileName)

  2. LVPlayerCode setDataSourceByLocalRecordFileName(String iotId, String fileName, long seekToPositionInMs)

修改接口名。

接口移除:设置播放地址为已接入物联网智能视频服务的IPC设备指定录像名的本地录像文件地址

void setDataSourceByIPCRecordFileName(String iotId, String fileName, boolean encrypted, int encryptType)

从2.0.0开始强制要求打开加密,故移除可以关闭加密的接口。

接口命名调整:设置播放地址为已接入物联网智能视频服务的IPC设备指定录像时间段的本地录像文件地址

  1. void setDataSourceByIPCRecordTime(String iotId, int beginTimeInS, int endTimeInS, long seekToPositionInMs)

  2. void setDataSourceByIPCRecordTime(String iotId, int beginTimeInS, int endTimeInS, long seekToPositionInMs, int recordType)

LVPlayerCode setDataSourceByLocalRecordTime(String iotId, int beginTimeInS, int endTimeInS, long seekToPositionInMs, int recordType)

修改接口名。

接口移除:设置播放地址为已接入物联网智能视频服务的IPC设备指定录像时间段的本地录像文件地址.

  1. void setDataSourceByIPCRecordTime(String iotId, int beginTimeInS, int endTimeInS, boolean encrypted, int encryptType, long seekToPositionInMs)

  2. void setDataSourceByIPCRecordTime(String iotId, int beginTimeInS, int endTimeInS, boolean encrypted, int encryptType, long seekToPositionInMs, int recordType)

从2.0.0开始强制要求打开加密,故移除可以关闭加密的接口。

接口命名调整:设置播放地址为已接入物联网智能视频服务的IPC设备指定录像名的云端录像文件地址

  1. void setDataSourceByIPCRecordFileName(String iotId, String fileName)

  2. void setDataSourceByIPCRecordFileName(String iotId, String fileName, long seekToPositionInMs)

  1. LVPlayerCode setDataSourceByCloudRecordFileName(String iotId, String fileName)

  2. LVPlayerCode setDataSourceByCloudRecordFileName(String iotId, String fileName, long seekToPositionInMs)

修改接口名。

接口移除:移除prepare步骤

  1. prepare()

  2. void setOnPreparedListener(OnPreparedListener listener)

  3. com.aliyun.iotx.linkvisual.media.video.listener.OnPreparedListener

设置数据源后,在播放start()前无需再调用prepare()

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

-

返回值枚举:

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

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

新增接口:增加单独的播放恢复接口

void start()

LVPlayerCode resume()

从2.0.0 SDK开始,点播播放恢复接口不再与start()接口复用。

接口名调整:获取点播播放时长

  1. long getDuration()

  2. long getCurrentPosition()

  1. long getDurationMs()

  2. long getCurrentPositionMs()

修改接口名。

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

  1. int getVideoWidth()

  2. int getVideoHeight()

无。

类名变更:解码器策略和解码器类型枚举

  1. com.aliyun.iotx.linkvisual.media.video.HardwareDecoderable.DecoderStrategy

  2. com.aliyun.iotx.linkvisual.media.video.HardwareDecoderable.DecoderType

  1. com.aliyun.iotx.linkvisual.media.player.bean.LVDecoderStrategy

  2. com.aliyun.iotx.linkvisual.media.player.bean.LVDecoderType

修改类名。

接口变更:取消设置音量接口改为静音和取消静音接口

  1. void setVolume(float audioVolume)

  2. float getVolume()

  1. LVPlayerCode mute(boolean isMute)

  2. boolean isMute()

不支持应用内单独控制播放音量,音量控制统一交由系统音量来完成。

新增接口:增加音频焦点接口

  1. LVPlayerCode audioFocus()

  2. boolean isAudioFocus()

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

接口移除:移除音频播放流通道设置接口

void setAudioStreamType(final int streamType)

直播播放器始终使用 AudioManager.STREAM_MUSIC通道,不再支持切换。

接口移除:移除对GLSurfaceView的支持

  1. void setSurfaceView(SurfaceView mSurfaceView)

  2. void clearSurfaceView()

请替换为TextureView,相比GLSurfaceView有以下优势:

  1. 支持硬件加速,可随View移动不产生黑边。

  2. 支持电子变焦(请使用SDK提供ZoomableTextureView)。

  3. 支持多窗口播放。

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

void setVideoScalingMode(int mVideoScalingMode)

LVPlayerCode setVideoScalingMode(LVVideoScalingMode videoScalingMode)

com.aliyun.iotx.linkvisual.media.player.bean.LVVideoScalingMode {
//保持宽高
LV_VIDEO_SCALING_MODE_FIT,
//强制填充
LV_VIDEO_SCALING_MODE_FILL;
}

修改参数名和类名。

接口变更:边播边录

  1. boolean startRecordingContent(File contentFile)

  2. boolean stopRecordingContent()

  3. long getCurrentRecordingContentDuration()

  1. LVPlayerCode startRecordingContent(String contentFilePath)

  2. LVPlayerCode stopRecordingContent()

  3. long getCurrentRecordingContentDurationInMs()

  1. 开始录制参数类型由File改为String。

  2. 获取录制时长接口名调整。

接口移除:设置播放停止时画面行为接口

  1. void setPlayerStoppedDrawingMode(PlayerStoppedDrawingMode playerStoppedDrawingMode)

  2. PlayerStoppedDrawingMode getPlayerStoppedDrawingMode()

暂未支持,后续版本中会补充该功能。

接口变更:获取播放状态接口

int getPlayState()

  1. LVPlayerState getPlayerState()

  2. com.aliyun.iotx.linkvisual.media.player.bean.LVPlayerState

播放器状态由int改为枚举值,方便理解和维护。

接口变更:获取当前流连接类型接口

StreamConnectType getStreamConnectType()

  1. LVStreamConnectType getStreamConnectType()

  2. com.aliyun.iotx.linkvisual.media.player.bean.LVStreamConnectType

仅在设备卡录像点播下有效。

接口变更:获取当前播放帧率/码率信息接口

PlayInfo getCurrentPlayInfo()

  1. LVPlayInfo getCurrentPlayInfo()

  2. com.aliyun.iotx.linkvisual.media.player.bean.LVPlayInfo

修改类名。

接口变更:设置点播播放器回调接口

  1. void setOnRenderedFirstFrameListener(OnRenderedFirstFrameListener listener)

  2. void setOnErrorListener(OnErrorListener listener)

  3. void setOnPlayerStateChangedListener(OnPlayerStateChangedListener listener)

  4. void setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener)

  5. void setOnVideoQualityListener(OnVideoQualityListener listener)

  6. void setOnSeiInfoListener(SeiInfoBuffer seiInfoBuffer, OnSeiInfoListener onSeiInfoListener)

  7. void setOnCompletionListener(OnCompletionListener listener)

LVPlayerCode setPlayerListener(ILVPlayerListener listener)

com.aliyun.iotx.linkvisual.media.player.listener.ILVPlayerListener {
    void onError(LVPlayerError error);
    void onPlayerStateChange(LVPlayerState state);
    void onRenderedFirstFrame(int elapsedTimeInMs);
    void onVideoSizeChanged(int width, int height);
    void onSeiInfoUpdate(byte[] buffer, int length, long timeStamp);    void onVideoJitterBufferEmpty();
}

LVPlayerCode setVodCompletionListener(ILVVodPlayerCompletionListener listener)

com.aliyun.iotx.linkvisual.media.player.listener.ILVVodPlayerCompletionListener{
    void onCompletion();
}

将多个Listener合并为二个。

接口变更:设置使用外部渲染接口

  1. void setUseExternalRender(boolean mUseExternalRender)

  2. void setOnExternalRenderListener

  3. boolean useExternalRender()

LVPlayerCode setUseExternalRender(boolean useExternalVideoRender, boolean useExternalAudioRender, ILVPlayerExternalRenderListener listener)

com.aliyun.iotx.linkvisual.media.player.listener.ILVPlayerExternalRenderListener {
    void onVideoFrameUpdate(int width, int height, long timestampInMs);
    void onAudioHeader(int audioBitPerSample, int audioSamplesPerSec, int audioChannel);
    boolean onAudioData(byte[] buffer, int offset, int length);
}

从2.0.0开始,除了支持视频YUV数据回调之外,还支持音频PCM回调。

接口变更:获取一帧YUV数据接口

Yuv420pFrame getYuvFrame()

Yuv420pFrame getYuv420pFrame()

修改接口名。

语音对讲

变更细节

1.x

2.x

修改建议

包名与类名变更

com.aliyun.iotx.linkvisual.media.audio.LiveIntercomV2

com.aliyun.iotx.linkvisual.media.liveintercom.LVLiveIntercom

更新包名与类名。

接口变更:初始化接口

LiveIntercomV2(Context context, final String iotId, final LiveIntercomMode liveIntercomMode, final AudioParams audioParams)

LVLiveIntercom(Context context, AudioParams audioParams)

从2.0.0 SDK开始,iotId和对讲模式不在初始化阶段传入,分别下放到start()setLiveIntercomMode()接口中。

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

返回值枚举:

LVLiveIntercomCode {
    //执行成功
    LV_LIVE_INTERCOM_SUCCESS,
    //执行失败, 通用错误
    LV_LIVE_INTERCOM_ERROR_FAILED,
    //错误的输入参数
    LV_LIVE_INTERCOM_ERROR_INVALID_PARAMETER,
    //不支持的接口
    LV_LIVE_INTERCOM_ERROR_UNSUPPORTED
}

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

新增接口:增加新的对讲模式

LVLiveIntercomCode setLiveIntercomMode(LVLiveIntercomMode liveIntercomMode)

从2.0.0 SDK开始增加DoubleTalkWithLive模式:

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

  • 使用设备直播通道的声音进行播放,要求必须有已开播的直播通道,可通过LVLivePlayer.audioFocus()方法在对讲开启前选择对应的已存在的直播通道。

接口变更:与指定设备(通过iotId)进行对讲

void start()

LVLiveIntercomCode start(String iotId)

需要传入iotId

接口变更:与指定设备(通过url)进行对讲

void startWithExternalRequest(LiveIntercomRequest liveIntercomRequest)

LVLiveIntercomCode start(String url, String decryptIvBase64, String decryptKeyBase64)

修改接口名,注意decryptIvBase64和decryptKeyBase64使用Base64编码的字符串。

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

void setLiveIntercomV2Listener(LiveIntercomV2Listener listener)

LVLiveIntercomCode setLiveIntercomListener(ILVLiveIntercomListener listener)

ILVLiveIntercomListener {
    void onTalkReady();
    void onRecorderStart();
    void onRecorderEnd();
    void onRecorderVolume(int volume);
    void onError(LVLiveIntercomError error);
}

修改接口名。

接口变更:外部变声实现

void setExternalVoiceChangeImpl(IVoiceChange voiceChangeImpl)

LVLiveIntercomCode setUseExternalVoiceChange(boolean useExternal, ILVLiveIntercomVoiceChangeListener listener)

ILVLiveIntercomVoiceChangeListener{
    boolean onAudioData(byte[] pcm, int length);    
}

修改接口名。

接口变更:内部变声类型设置

void setVoiceChangeType(LiveIntercomVoiceType voiceType)

LVLiveIntercomCode setVoiceChangeType(LVLiveIntercomVoiceType liveIntercomVoiceType)

修改接口名。