Android 音频录制与播放
上一篇主要介绍了音频相关的一些基础知识,本篇主要介绍在Android系统中如何进行音频的录制,播放
音频录制
Android SDK中提供了AudioRecord
,MediaRecorder
两个API经行音频的录制,具体的优缺点等如下:
- AudioRecord 『added in API level 3』(基于字节流录音):
优点:可以实现语音的实时处理,进行边录边播,对音频的实时处理。
缺点:输出的是PCM的语音数据,如果保存成音频文件是不能被播放器播放的。要用到这个去进行处理。
适用场景:需要实时处理分析的录音场景等,如:会说话的汤姆猫『AppStore | GooglePlay』
- MediaRecorder 『added in API level 1』(基于文件音视频录制):
优点:封装度很高,操作简单,无需处理中间录制过程;录制的音频文件是经过压缩的,需要设置编码器;录制的音频文件可以使用系统自带的播放器播放
缺点:无法实现实时处理音频,输出的音频格式少。
适用场景:录制过程需要实时处理的场景等
音频播放
-
AudioTrack『added in API level 3』:
AudioTrack 则更接近底层,提供了非常强大的控制能力,支持低延迟播放,适合流媒体和VoIP语音电话等场景 -
SoundPool 『added in API level 1』:
优点:主要用于播放一些较短的声音片段,支持从程序的资源或文件系统加载;CPU的资源占用量低、反应延迟小,并且可以加载多个音频到SoundPool
中,通过资源ID来管理
缺点:SoundPool加载资源,最大只能申请 1MB 的内存控件,因此只能用来播放一些很短的声音片段
适用场景:播放短,反应要求高的音频 -
MediaPlayer 『added in API level 1』(基于字节流音视频播放):
优点:支持本地,网络音频资源的播放
缺点:资源占用量较高、加载延迟时间较长;不支持多个音频同时播放等
适用场景:播放长音频
Google官方给出了兼容支持
AudioRecord
录制流程
- 构造一个
AudioRecord
对象,其中需要的最小音频缓存buffer
大小可以通过getMinBufferSize()
方法得到,如果buffer
容量过小,将导致对象构造失败 - 初始化一个
buffer
,该buffer
大于等于AudioRecord
对象用于写音频数据的buffer
大小 - 开始录音
- 创建一个数据流,一边从
AudioRecord
中读取音频数据到初始化的buffer
,一边将buffer
中的数据导入数据流 - 关闭数据流
- 停止录音
参数配置
- audioSource :音频采集的输入源
- DEFAULT(默认)
- VOICE_RECOGNITION(用于语音识别,等同于DEFAULT)
- MIC(由手机麦克风输入)
- VOICE_COMMUNICATION(用于VoIP应用)
- sampleRateInHz:采样率
目前44100Hz是唯一可以保证兼容所有Android手机的采样率 - channelConfig:通道数的配置
- CHANNEL_IN_MONO:单通道
- CHANNEL_IN_STEREO:双通道
- audioFormat:数据位宽
- ENCODING_PCM_8BIT:8bit
- ENCODING_PCM_16BIT:16bit
- bufferSizeInBytes:AudioRecord 内部的音频缓冲区的大小,该缓冲区的值不能低于一帧“音频帧”(Frame)的大小
示例代码
1 | public class AudioCapturer { |
AudioTrack
播放流程
- 配置参数,初始化内部的音频播放缓冲区到,如果
buffer
容量过小,将导致对象构造失败 - 开始播放
- 需要一个线程,不断地向 AudioTrack 的缓冲区
写入
音频数据,注意,这个过程一定要及时,否则就会出现underrun
的错误,该错误在音频开发中比较常见,意味着应用层没有及时地“送入”音频数据,导致内部的音频播放缓冲区为空 - 停止播放,释放资源
参数配置
- streamType:当前应用使用的哪一种音频管理策略
当系统有多个进程需要播放音频时,这个管理策略会决定最终的展现效果- STREAM_VOCIE_CALL:电话声音
- STREAM_SYSTEM:系统声音
- STREAM_RING:铃声
- STREAM_MUSCI:音乐声
- STREAM_ALARM:警告声
- STREAM_NOTIFICATION:通知声
- sampleRateInHz:采样率
采样率的取值范围必须在 4000Hz~192000Hz 之间 - channelConfig:通道数的配置
- CHANNEL_IN_MONO:单通道
- CHANNEL_IN_STEREO:双通道
- audioFormat:数据位宽
- ENCODING_PCM_8BIT:8bit
- ENCODING_PCM_16BIT:16bit
- bufferSizeInBytes:配置的是 AudioTrack 内部的音频缓冲区的大小,该缓冲区的值不能低于一帧“音频帧”(Frame)的大小
- mode:AudioTrack 播放模式
- MODE_STATIC
static:一次性将所有的数据都写入播放缓冲区,简单高效,通常用于播放铃声、系统提醒的音频片段 - MODE_STREAM
streaming:按照一定的时间间隔不间断地写入音频数据,理论上它可用于任何音频播放的场景
- MODE_STATIC
示例代码
1 | public class AudioPlayer { |
MediaRecorder
如上所示表述整个MediaRecorder的整个生命过程,可以看出初始化之后,在任意的状态下调用reset()
方法均可以回到MediaRecorder刚刚初始化完成的状态
MediaPlayer
MediaPlayer 工作流程
- 创建一个MediaPlayer对象
- 调用setDataSource()方法,设置音频文件的路径
- 接着调用prepare()方法,使MediaPlayer进入的准备状态
- 调用start()方法,开始播放音频『pause()方法表示:暂停播放』
MediaPlayer常用的控制方法
方法名 | 功能描述 |
---|---|
setDataSource() | 设置要播放的音频文件的位置 |
prepare() | 在开始播放之前调用这个方法完成准备工作 |
start() | 开始或继续播放音频 |
pause() | 暂停播放音频 |
reset() | 将MediaPlayer对象重置到刚刚创建的状态 |
seekTo() | 从指定位置开始播放音频 |
stop() | 停止播放音频。调用这个方法后的MediaPlayer对象无法再播放音频 |
release() | 释放掉与MediaPlayer对象相关的资源 |
isPlaying() | 判断当前MediaPlayer是否正在播放音频 |
getDuration() | 获取站如的音频文件的时长 |
注意事项
- 在使用
star()
播放流媒体之前,需要装载流媒体资源。这里最好使用prepareAsync()
异步的方式装载流媒体资源,在使用prepareAsync()
异步加载时,为避免还没有装载完就调用了start()
而保存,需要绑定MediaPlayer.setOnPreparedListener()
事件,它将在异步装在完成后回调
原因:流媒体资源的装载是会消耗系统资源,在一些硬件不理想的设备上,如果使用prepare()
同步的方式装载资源,可能会造成UI界面卡顿,其次避免装载超时而引发ANR
等问题 - 使用完MediaPlayer需要回收资源。MediaPlayer时很消耗系统资源的,所以在使用完MediaPlayer,及时主动回收资源
- 对于单曲循环之类的操作,除了使用
setLooping()
方法设置之外,还可以为MediaPlayer注册回调函数,MediaPlayer.setOnCompletionListener()
,它会在MediaPlayer播放完被回调 - 由于无法确保播放的流媒体是完整(中间有错误),我们需要处理这个错误,否则会影响用户体验。可以在MediaPlayer中注册
setOnErrorListener()
错误回调,一般重新播放或者播放下一个流媒体
跨平台
关于音频编解码在各平台上的情况如下
从上图可知,AAC,FLAC,MP3三种编码是全平台支持的音频编码方式(或音频压缩方式),注意编码方式并不是文件格式即文件的扩展名
- AAC 主要扩展名
.aac
.mp4
.m4a
- FLAC 扩展名
.flac
- MP3 扩展名
.mp3
总结
- 音频的录制,Android SDK提供了两套音频采集的API,分别是:
MediaRecorder
和AudioRecord
,前者是一个更加上层一点的API,它可以直接把手机麦克风录入的音频数据进行编码压缩(如:AMR
,OGG
等)并存储成文件,而后者则更接近底层,能够更加自由灵活的控制,可以得到原始的一帧帧PCM
音频数据 - 如果要简单的进行音频的采集,录制成音频文件,则推荐适用
MediaRecorder
,而如果需要对音频做进一步的算法处理,或者采用第三方的编码库进行压缩、以及网络传输等应用,则建议适用AudioRecord
MediaRecorder
底层的实现也是调用了AudioRecord
与Android Framework
层的AudioFlinger
进行交互
关于音视频相关的资料参差不齐,目前尚未有大量相关专门的书籍来介绍该领域的图书或者易懂视频,很多情况需要根据所处应用场景灵活应变。
推荐刚刚发行的一本关于音频方面的图书《Android音视频开发》
推荐国内比较专业音视频方面相关的介绍《雷霄骅的专栏》
附录
- 音频编码格式的比较
- 第一行代码
- Android MediaRecorder架构详解
- 参考代码
- 浏览器引擎
- 主流浏览器内核介绍
- 腾讯X5内核介绍
- Android 音视频开发学习思路