一、引言
小编所在的语音SDK项目,提供的是AI服务,录音是基础,识别是品质。录音方式选择,录音参数设置,录音策略的制定(如解决首字吞字问题),录音架构选择,对识别都有着重要影响。
二、Android两种录音方式
1、音频采集简介
Android提供了两个API用于录音的实现:MediaRecorder 和AudioRecord。
(1). MediaRecorder:录制的音频文件是经过压缩后的,需要设置编码器。并且录制的音频文件可以用系统自带的Music播放器播放。MediaRecorder已经集成了录音、编码、压缩等,并支持少量的录音音频格式,但是这也是他的缺点,支持的格式过少并且无法实时处理音频数据。
(2). AudioRecord:主要实现对音频实时处理以及边录边播功能,相对MediaRecorder比较专业,输出是PCM语音数据,如果保存成音频文件,是不能够被播放器播放的,所以必须先写代码实现数据编码以及压缩。
2、优、缺点
录音方式 | 优点 | 缺点 |
---|---|---|
AudioRecord(基于字节流录音) | 可实现语音的实时处理,边录边播,对音频的实时处理,AudioTrack更接近底层。 | 输出的是PCM的语音数据,如果保存成音频文件是不能被播放器播放的。要用AudioTrack进行处理。API还有待完善,常见的暂停功能都不支持。 |
MediaRecorder(基于文件录音) | 已集成了录音,编码,压缩等。封装度很高,操作简单,录制的音频文件可以用系统自带的播放器播放。 | 缺点:无法实现实时处理音频,输出的音频格式少。录制的音频文件是经过压缩后的,需要设置编码器。 |
技术选型,目前行业现状:API多是选用AudioRecord。
三、AudioRecord
1、AudioRecord
AndioRecord 类的主要功能是让各种 Java 应用能够管理音频资源,以便它们通过此类能从平台的音频输入硬件记录音频。此功能的实现就是通过 "pulling 同步"(reading读取)AudioRecord对象的声音数据来完成的。在录音过程中,应用所需要做的就是通过后面三个类方法中的一个去及时地获取AudioRecord 对象的录音数据。
AudioRecord 类提供了三个获取声音数据的方法,分别是read(byte[], int, int), read(short[], int, int), read(ByteBuffer, int)。无论选择使用那一个方法,都必须事先设定方便用户使用的声音数据的存储格式。
开始录音的时候,一个AudioRecord需要初始化一个相关联的声音buffer,这个buffer主要是用来保存新的声音数据。这个buffer的大小,可以在对象构造期间去指定。它表明一个AudioRecord对象还没有被读取(同步)声音数据前能录多长的音(即一次可以录制的声音容量)。声音数据从音频硬件中被读出,数据大小不超过整个录音数据的大小(可以分多次读出),即每次读取初始化 buffer 容量的数据。音频采集工作,需要构造一个AudioRecord对象,然后传入各种不同配置的参数。
2、利用AudioRecord实现Android录音的流程
(1). 构造一个AudioRecord对象,其中需要的最小录音缓存buffer大小可以通过getMinBufferSize方法得到。如果buffer容量过小,将导致对象构造的失败;
(2). 初始化一个buffer,该buffer大于等于AudioRecord对象用于写声音数据的buffer大小;
(3). 调用startRecording函数,开始录音;
(4). 创建一个数据流,一边从AudioRecord中读取声音数据到初始化的buffer,一边将buffer中数据导入数据流,生成PCM格式文件;
(5). 录音结束时,关闭数据流,停止录音;
3、构造函数
publicAudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, intbufferSizeInBytes)
参数说明
(1). audioSource这个参数指的是音频采集的输入源,接受的值定义在MediaRecorder.AudioSource里面,一般来说使用DEFAULT或者MIC即可。
(2). sampleRateInHz指定采集音频的采样频率,比较通用的是44100(44.1kHz),这个值是科学家们通过奈葵斯特采样定理得出的一个人能接受最佳的采样频率值。
(3). channelConfig指定AudioRecord采集几个声道的声音,预设值定义在AudioFormat中,常用值有CHANNEL_CONFIGURATION_MONO(单声道) 和 CHANNEL_CONFIGURATION_STEREO(双声道)。
(4). audioFormat指定采样PCM数据的采样格式,预设值定义在也AudioFormat中,常用值有:
ENCODING_PCM_8BIT、ENCODING_PCM_16BIT和ENCODING_PCM_FLOAT,其中ENCODING_PCM_16BIT可以保证兼容大部分Andorid手机。
(5). bufferSizeInBytes配置AudioRecord内部的音频数据缓冲区,一般来说缓存区越小,产生的音频延迟也越小。可以通过AudioRecord.getMinBufferSize获取最小的缓冲区。(将音频采集到缓冲区中然后再从缓冲区中读取)
4、录音参数设置
(1). audioSource:音频源,从哪个硬件设备获取音频,一般直接设置成麦克风。
MediaRecorder.AudioSource.MIC,AudioRecorder为它设置了默认值:
AUDIO_INPUT =MediaRecorder.AudioSource.MIC;
AudioSource可以设置的来源包括:
(2). sampleRateInHz:音频采样率,越高质量越好。
(3). ChannelConfig:声道设置
(4). audioFormat:音频格式
(5). bufferSizeInBytes:采集数据需要的缓冲区的大小
四、录音编码
1、编码格式
AudioRecorder录音声音数据从音频硬件中被读出,编码格式为 PCM格式,PCM是英文Pulse-codemodulation的缩写,中文译名是脉冲编码调制。但 PCM语音数据,如果保存成音频文件,是不能够被播放器播放的。
2、播放PCM文件
Audacity工具可以导入pcm原始文件,并且提供了波形图查看和播放功能。
操作流程是:
文件 => 导入 => 原始数据 => 设置PCM数据格式=> 导入
具体效果图如下:
五、录音问题
项目测试,遇到的用户反馈的录音问题举例:录音架构、适配
(1). start线程、read loop线程,是同一个线程还是分开的子线程,线程的释放策略;
(2). 是否有常驻线程,是否有超时守候机制;
(3). 是否有麦克风占用问题、是否有read线程卡住问题;
(4). 对不同硬件设置,录音的参数设置是否有适配策略(Audiosource、Channel);
(5). 是否可支持蓝牙输入;
注:参考
https://cloud.tencent.com/developer/article/1560099
https://www.jianshu.com/p/90c4071c7768
https://developer.android.com/reference/android/media/AudioRecord
https://blog.csdn.net/u010126792/article/details/86309592
https://www.jianshu.com/p/01b374acd6a4