Android 直播推流 SDK 开发指南

1 阅读对象

本文档为技术文档,需要阅读者:

具有基本的Android开发能力,准备接入网易视频云或正在接入网易视频云。

2 文档概述

LiveStreamingSDK是一个适用于Android平台的RTMP直播推流SDK,针对Android设备采集摄像头和麦克风的音视频数据,并进行H.264和AAC编码,用RTMP协议推流,可以进行二次开发。给开发者提供一套编码参数集合,以便灵活调节相应的分辨率和码率。通过接入LiveStreamingSDK,用户可以快速开发一款Android端直播产品。

3 功能特性

4 开发准备

4.1 开发环境配置

4.2 设备以及系统

设备要求:搭载Android系统的设备,支持的CPU架构:armv7、arm64 系统要求:Android 4.2(API 17)及其以上

4.3 代码混淆配置

为了保证正常使用SDK,请在proguard-project.txt文件中添加以下代码:

-keep class com.netease.** { *; }

-keep class jp.co.cyberagent.android.gpuimage.** { *; }

5 集成SDK

本文是根据官网的直播推流 Demo 来介绍 SDK 的集成,可在官网下载最新的直播推流 Android SDK,来查看更多的实现细节。

5.1 导入Demo到Android Studio

pic

pic

pic

5.2 向已有工程中导入SDK

pic

5.3 配置AndroidManifest.xml

直播推流SDK需要摄像头、录音、访问网络、读写SD卡、获取设备信息等权限。在AndroidManifest.xml中加入以下配置:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.netease.livestreamingcapture"
    android:versionCode="1"
    android:versionName="1.2.1" >

    <!-- 声明sdk版本 -->
    <uses-sdk
        android:minSdkVersion="17"
        android:targetSdkVersion="22" />

    <!-- 权限声明 -->   
    <!-- 允许挂载和反挂载文件系统 -->   
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />   
    <!-- 允许程序创建显示在其他程序之上,并且类型为TYPE_SYSTEM_ALERT的窗体 -->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <!-- 允许程序向外部存储设备写数据 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- 允许程序打开网络套接字 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 允许程序获取网络相关信息 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!-- 允许程序向外部存储设备写数据 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- 允许程序写音频数据 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <!-- 允许程序使用PowerManager WakeLocks以防止处理器休眠或者屏幕锁屏 -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <!-- 允许程序获取Wifi网络状态信息 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!-- 允许程序使用设备的camera -->
    <uses-permission android:name="android.permission.CAMERA" />
    <!-- 允许程序使用闪光灯 -->
    <uses-permission android:name="android.permission.FLASHLIGHT" />
    <!-- 允许程序获得设备信息 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <!-- 配置一个程序用于调试 -->
    <uses-permission android:name="android.permission.SET_DEBUG_APP" />

    <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />

    <uses-feature android:name="android.hardware.camera.autofocus"/>

    <!-- 声明程序使用camera和自动对焦功能 -->
    <uses-feature android:name="android.hardware.camera"/>
    <uses-feature android:name="android.hardware.camera.autofocus"/>
    <!-- 声明程序使用OpenGL ES 2.0 -->
    <uses-feature android:glEsVersion="0x00020000" android:required="true" />


    <application
        android:name=".CrashApplication"
        android:allowBackup="true"
        android:hardwareAccelerated="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" 
        android:theme="@style/AppTheme" >
        <!-- 欢迎页面activity,默认竖屏模式 -->
        <activity android:name=".WelcomeActivity" android:label="@string/app_name" android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!-- 直播参数设置页面activity,默认竖屏模式 -->
        <activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="portrait" />
        <!-- 直播主页面activity,默认竖屏模式 -->
        <activity android:name=".MediaPreviewActivity" android:label="@string/app_name" android:screenOrientation="portrait"/>

        <!-- 声明直播异常报警服务 -->
        <service android:name="com.netease.livestreamingcapture.AlertService"/>

        <receiver android:name="com.netease.pushservice.receiver.PushServiceBootReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.ACTION_BATTERY_CHANGED" />
            </intent-filter>
        </receiver>

    </application>

</manifest>

6 功能使用和API接口介绍

6.1 推流参数设置

推流参数设置在类MediaPreviewActivity的方法paraSet()中实现,包括:

推流相关API接口包括:

6.2 摄像头参数设置

摄像头参数设置包括:

提供的接口API包括:

6.3 美颜滤镜

美颜滤镜设置包括美颜滤镜和普通滤镜的切换,以及美颜滤镜的强度调节。

提供的接口API包括:

6.4 视频截图

视频截图功能的接口API包括:

视频截图后的数据采用回调方式通知应用层,详见“7 SDK回调消息”

6.5 水印

水印功能实现了在采集视频上叠加png图像的功能, 水印的设置包括:

提供的接口API包括:

6.6 涂鸦

涂鸦功能实现了在采集视频上叠加bmp图像的功能,涂鸦的设置包括:

提供的接口API包括:

6.7 伴音

伴音功能实现了在麦克风采集的声音中混合MP3文件声音的功能,设置包括:

提供的接口API包括:

6.8 摄像头缩放(Zoom)

摄像头缩放(Zoom)功能提供的API包括:

6.9 闪光灯操作(Flash)

闪光灯操作(Flash)功能提供的API包括:

6.10 自动和手动对焦

自动和手动对焦功能提供的API包括:

6.11 程序切后台操作

程序切后台操作会调用onPause,切回前台会调用onResume。为了提供程序切后台之后仍然可以推流的功能,SDK提供了如下几个API接口:

6.12 视频镜像

视频镜像是为了用户左右调整播放端看到的视频而提供的API接口,并不能用于调整直播端本地预览的图像。API接口如下:

使用方法:调用setVideoMirror(true)实现镜像,调用setVideoMirror(false)去除镜像。

6.13 日志管理

日志管理提供的API接口包括:

6.14 自定义采集

自定义采集提供的API接口包括:

6.15 其他功能和API接口

7 SDK回调消息

LiveStreamingSDK通过消息回调的方式传递SDK到应用层的各种状态消息,包括:开始/停止直播完毕,切换摄像头完毕等等,具体如下:

public static final int MSG_INIT_LIVESTREAMING_ERROR = 0;//初始化直播出错
public static final int MSG_INIT_LIVESTREAMING_VIDEO_ERROR = 1; //初始化视频直播出错
public static final int MSG_INIT_LIVESTREAMING_AUDIO_ERROR = 2; //初始化音频直播出错
public static final int MSG_START_LIVESTREAMING_ERROR = 3;//开始直播出错
public static final int MSG_STOP_LIVESTREAMING_ERROR = 4;//停止直播出错
public static final int MSG_AUDIO_PROCESS_ERROR = 5;//音频编码打包出错
public static final int MSG_VIDEO_PROCESS_ERROR = 6; //视频编码打包出错
public static final int MSG_START_PREVIEW_ERROR = 7//打开视频预览失败
public static final int MSG_RTMP_URL_ERROR = 8; //RTMP URL连接出错,会进一步调用网络信息报警service,弹出悬浮窗
public static final int MSG_URL_NOT_AUTH = 9; //RTMP URL非法
public static final int MSG_SEND_STATICS_LOG_ERROR = 10; //发送统计日志出错
public static final int MSG_SEND_HEARTBEAT_LOG_ERROR = 11;//发送心跳日志出错
public static final int MSG_AUDIO_RECORD_ERROR = 12;//音频录制权限打开失败
public static final int MSG_AUDIO_SAMPLE_RATE_NOT_SUPPORT_ERROR = 13;//设置的音频采样率不支持
public static final int MSG_AUDIO_PARAMETER_NOT_SUPPORT_BY_HARDWARE_ERROR = 14;//设置的音频硬件编码参数不支持
public static final int MSG_NEW_AUDIORECORD_INSTANCE_ERROR = 15;//音频采集实例创建失败
public static final int MSG_AUDIO_START_RECORDING_ERROR = 16;//音频采集失败
public static final int MSG_QOS_TO_STOP_LIVESTREAMING = 17;//网络QoS较差   
public static final int MSG_HW_VIDEO_PACKET_ERROR = 18; //视频硬件编码出错
public static final int MSG_WATERMARK_INIT_ERROR = 19; //视频水印初始化出错
public static final int MSG_WATERMARK_PIC_OUT_OF_VIDEO_ERROR = 20; //视频水印超出原始视频
public static final int MSG_WATERMARK_PARA_ERROR = 21; //视频水印参数出错
public static final int MSG_CAMERA_PREVIEW_SIZE_NOT_SUPPORT_ERROR = 22; //摄像头不支持设置的preview size
public static final int MSG_START_PREVIEW_FINISHED = 23; //开始preview完成
public static final int MSG_START_LIVESTREAMING_FINISHED = 24; //开始直播完成
public static final int MSG_STOP_LIVESTREAMING_FINISHED = 25; //停止直播完成
public static final int MSG_STOP_VIDEO_CAPTURE_FINISHED = 26; //停止视频采集完成
public static final int MSG_STOP_RESUME_VIDEO_CAPTURE_FINISHED = 27; //停止后台运行的音频推流服务,用于程序切后台
public static final int MSG_STOP_AUDIO_CAPTURE_FINISHED = 28; //停止音频采集完成
public static final int MSG_STOP_RESUME_AUDIO_CAPTURE_FINISHED = 29; //继续音频采集完成
public static final int MSG_SWITCH_CAMERA_FINISHED = 30; //切换摄像头完毕
public static final int MSG_SEND_STATICS_LOG_FINISHED = 31; //发送统计信息完毕
public static final int MSG_SERVER_COMMAND_STOP_LIVESTREAMING = 32; //服务器下发停止直播的命令
public static final int MSG_SEND_HEARTBEAT_LOG_FINISHED = 33; //发送心跳信息完毕
public static final int MSG_CAMERA_NOT_SUPPORT_FLASH = 34; //用户所设置的采集分辨率,摄像头并不支持
public static final int MSG_GET_STATICS_INFO = 35; //获得统计信息完毕
public static final int MSG_BAD_NETWORK_DETECT = 36; //连续一分钟视频帧率和码率都是0的消息
public static final int MSG_SCREENSHOT_FINISHED = 37; //直播中视频截图完成消息
public static final int MSG_SET_CAMERA_ID_ERROR = 38; //设置camera id出错(单摄像头设备常见)
public static final int MSG_SET_GRAFFITI_ERROR = 39; //设置视频涂鸦出错
public static final int MSG_MIX_AUDIO_FINISHED = 40: //伴音一首MP3文件结束
public static final int MSG_URL_FORMAT_NOT_RIGHT = 41: //推流URL格式不正确(例如使用拉流url进行推流)
public static final int MSG_URL_IS_EMPTY = 42: //推流URL为空
public static final int MSG_VIDEO_CROP_ERROR = 43;  //视频剪裁失败
public static final int MSG_SPEED_CALC_SUCCESS = 44; //测速成功
public static final int MSG_SPEED_CALC_FAIL = 45; //测速失败

同时,需要开发者继承如下接口,处理SDK抛出的事件。

handleMessage(int msg, Object object);

8 注意事项

(1)关于SDK直播的断网重连,需要开发者在检测到网络恢复后,自行调用API接口restartLiveStream,由于 SDK无法检测网络何时恢复,所以SDK不提供直接断网重连的API接口。

或者,开发者可以通过调用如下两段代码实现重启直播的功能:

停止直播:

m_tryToStopLivestreaming = true;
mLSMediaCapture.stopLiveStreaming();

重启直播:

boolean ret = mLSMediaCapture.initLiveStream(mliveStreamingURL,mLSLiveStreamingParaCtx);    
mLSMediaCapture.startLiveStreaming();

建议停止直播代码在检测到网络变差的时候调用,重启直播代码在检测到网络恢复之后再调用,同时,重启直播代码必须在检测到

MSG_STOP_LIVESTREAMING_FINISHED

回调之后调用,防止没有释放完毕资源又开始下一次直播。

(2)关于视频参数(采集分辨率、编码分辨率、码率和帧率)的设置,请开发者仔细阅读下面的建议。

采集分辨率 编码分辨率 建议码率
1280x720 1280x720 1500kbps
1280x720 960x540 800kbps
960x720 960x720 1000kbps
960x720 960x540 800kbps
960x540 960x540 800kbps
640x480 640x480 600kbps
640x480 640x360 500kbps
320x240 320x240 250kbps
320x240 320x180 200kbps
采集分辨率 编码分辨率 建议码率
320x240 320x240 250kbps
320x240 320x180 200kbps

(3)直播地址需要从视频云官网获取,SDK中会进行直播地址检测,非法的直播地址将导致直播失败,SDK抛出

MSG_INIT_LIVESTREAMING_ERROR

如果打开 error 级别的日志,会打印

initOutMedia Failed: URL Not Authenticated

(4)如果设置直播输出格式为FLV,对应的flv文件会写到Android设备的/sdcard目录,文件名为media.flv。

(5)由于Android设备camera支持的采集分辨率不一致,大多数都支持640x480采集,所以对于Demo中设置的三档分辨率,如果设备不支持,则采用640x480进行采集。

(6)请用户首先调用getCameraSupportSize方法查询Android设备支持的采集分辨率,然后根据实际情况设置合理的preview分辨率。

(7)关于直播中程序切后台和设备锁屏的处理,请按照demo中onPause和onRestart中的调用逻辑实现。如果直播中程序切后台,音频推流保持不变,视频推切后台之前的最后一帧图像,当程序切回前台,恢复音视频正常推流。如果直播中设备锁屏,音视频推流不变。

(8)由于增加了摄像头聚焦的API接口,通过设备传感器触发的自动聚焦机制暂时删除。

(9)增加的接口API uninitLsMediaCapture用于反初始化直播实例,必须调用,而且,由于 stoplivestreaming异步释放资源的特点,uninitLsMediaCapture与stoplivestreaming连续调用时,uninitLsMediaCapture的参数设置为false,否则设置为true。

(10)增加了摄像头对焦API setCameraFocus,去掉了SDK根据设备传感器进行自动对焦的功能,将摄像头对焦的接口开放出来,利于用户灵活使用。

(11)在使用视频涂鸦功能的时候,传递的涂鸦图片分辨率需要满足是2的倍数的要求。

9 补充知识与建议

9.1 网络异常处理

直播推流过程中,网络切换、网络断开和弱网络情况经常出现。SDK要能够及时将这些情况通知应用层并进行必要的补救措施。 例如网络断开情况,考虑到重连的时机和次数应该由开发者自己掌控比较合适,SDK没有进行断网情况下的自动重连。而弱网络情况下,SDK会通过消息回调方式上报弱网络的状态信息。

9.2 码率、帧率、分辨率、清晰度及流畅度概念

直播推流过程中,视频码率、帧率和分辨率会影响视频清晰度和流畅度。其中,帧率代表单位时间内视频图像的数量,数量越多,视频越流畅;分辨率代表图像细节显示的程度,相同内容的画面,分辨率越高,显示的图像细节越丰富,清晰度越高;码率代表单位时间内压缩后的视频信息量大小,在相同帧率和分辨率的情况下,码率越高,图像清晰度越高。 综上所述,更高的码率和分辨率会带来更清晰的图像,更高的帧率会带来更流畅的视频。然而,由于网络带宽限制,实际使用中码率往往不可能太高,导致清晰度和帧率存在一个上限。 请用户按照8(2)中建议的分辨率、码率进行合理设置。

10 Demo日志收集

Demo和SDK崩溃信息收集
为了方便开发者收集SDK崩溃信息,增加 CrashApplication.java、CrashHandler.java和util文件夹。 其中,CrashApplication.java文件创建崩溃信息收集示例CrashHandler,CrashHandler.java文件实现具体的崩溃信息收集和记录,崩溃信息默认写到手机的Environment.getExternalStorageDirectory() + "/crash/"目录,日志文件名是"crash-" + time + "-" + timestamp + ".log"。每一次崩溃都会生成一个日志文件。 util文件夹包含的内容是支撑崩溃信息收集的底层逻辑代码。用户在使用SDK时,可以参考或者使用demo提供的这套日志收集工具。

SDK日志收集
为了方便开发者收集SDK日志信息,在初始化时可以设置日志级别以及日志是否上传。SDK对外接口的日志会打印到控制台,TAG为"NeteaseLiveStream"。 强烈建议用户在接入过程中将日志级别设置为 info 级别,便于捕捉程序异常和进行问题分析。

11 API说明

有关API的详细说明,可参见SDK包中docs,打开index.html查看,或者打开下面的在线文档。

网易视频云直播推流LiveStreaming Android SDK API详细文档