1、简介
Android中用于音频采集的API包括两种,MediaRecoder和AudioRecoder。
- MediaRecoder
MediaRecorder 是基于 AudioRecorder 的 API(最终还是会创建AudioRecord用来与AudioFlinger进行交互) ,它可以直接将采集到的音频数据转化为执行的编码格式,并保存。这种方案相较于调用系统内置的用用程序,便于开发者在UI界面上布局,而且系统封装的很好,便于使用,唯一的缺点是使用它录下来的音频是经过编码的,没有办法的得到原始的音频。同时MediaRecorder即可用于音频的捕获也可以用于视频的捕获相当的强大。实际开发中没有特殊需求的话,用的是比较多的! - AudioRecoder
AudioRecord 是一个比较偏底层的API,它可以获取到一帧帧PCM数据,之后可以对这些数据进行处理。AudioRecord这种方式采集最为灵活,使开发者最大限度的处理采集的音频,同时它捕获到的音频是原始音频PCM格式的。像做变声处理的需要就必须要用它收集音频。
2、AudioRecoder的创建
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
int bufferSizeInBytes)
-
audioSource 该参数是音频采集的来源,定义的值在MediaRecorder.AudioSource类中。MIC表示采集源为手机麦克风。
-
sampleRateInHz 该参数表示采样率。44100Hz是科学家给出的最佳采样频率,并且在Android中也是多所有Android设备兼容最好的采样频率。
-
channelConfig 通道数,也就是声道数。常量定义在AudioFormat类中,CHANNEL_IN_MONO表示单声道,CHANNEL_IN_STEREO表示双声道。注意,之前可以通过CHANNEL_CONFIGURATION_MONO和CHANNEL_CONFIGURATION_STEREO指定,现在已经启用,使用了CHANNEL_IN_MONO和CHANNEL_IN_STEREO。
-
audioFormat 指音频采样精度,或者说是音频位宽。常量定义在AudioFormat类中,可选AudioFormat.ENCODING_PCM_16BIT或AudioFormat.ENCODING_PCM_8BIT等。16位将占用更多的空间,但采集的音频也更加接近原声。AudioFormat.ENCODING_PCM_16BIT目前兼容性更好。
-
bufferSizeInBytes 这个参数是AudioRecoder内部音频缓冲区的大小。该缓冲区的大小不能小于一个“音频帧”的大小。音频帧的计算方法为:int size = 采样率 x 位宽 x 采样时间 x 声道数。
采样时间是指采集一帧数据所用的时间,它的取值一般在2.5ms~120ms 之间,根据手机厂商等因素决定。每一帧采样的时间越短,产生的延时就越小,但是碎片化的数据也就越多。
AudioRecoder类中提供了一个静态方法int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)来获取缓冲区大小。音频缓冲区大小必须是“音频帧”大小的2~N倍。这里强烈建议使用该方法去计算缓冲区大小,而不是手动去计算。
3、音频采集
创建好AudioRecoder之后,就可以调用AudioRecord.startRecording()方法来开始采集。这里记得添加录音权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
AudioRecord.stop()方法用于停止录音。
使用完AudioRecoder后记得调用AudioRecoder.release()方法释放掉。
AudioRecoder会将采集的音频数据放到缓存区中。所以我们在采集的同时,需要开启一个新线的线程将采集的数据及时的读取出来。如果读取不及时读出数据会出现overrun。数据读取调用:
AudioRecord.read(byte[] audioData, int offsetInBytes, int sizeInBytes);
4、代码示例
private static final int SAMPLE_RATE_IN_HZ = 44100;
private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
/**
* 初始化AudioRecoder
*/
private void initAudioRecorder() {
/**
* sampleRateInHz 指定采集音频的采样频率,比较通用的是44100(44.1kHz),这个值是科学家们通过奈葵斯特采样定理得出的一个人能接受最佳的采样频率值
* channelConfig 指定AudioRecord采集几个声道的声音,预设值定义在AudioFormat中,常用值有 CHANNEL_CONFIGURATION_MONO(单声道) 和 CHANNEL_CONFIGURATION_STEREO(双声道)
* audioFormat 指定采样PCM数据的采样格式,预设值定义在也AudioFormat中,常用值有 ENCODING_PCM_8BIT、ENCODING_PCM_16BIT和ENCODING_PCM_FLOAT,值得强调的是ENCODING_PCM_16BIT可以保证兼容大部分Andorid手机
*
*/
recordBufSize = AudioRecord.getMinBufferSize(SAMPLE_RATE_IN_HZ, CHANNEL_CONFIG, AUDIO_FORMAT);
/**
* bufferSizeInBytes 配置AudioRecord内部的音频数据缓冲区,一般来说缓存区越小,产生的音频延迟也越小;值得注意的是,我们可以利用AudioRecord.getMinBufferSize()这个方法帮我们算出最小的缓存区大小,这个数值最好不要自己计算,毕竟不同厂商可能有不同的缓存区采集实现
*/
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE_IN_HZ, CHANNEL_CONFIG, AUDIO_FORMAT, recordBufSize);
if (audioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
mState = 1;
Log.e(TAG, "onCreate: AudioRecord创建成功,recordBufSize = " + recordBufSize);
} else {
Log.e(TAG, "onCreate: AudioRecord创建失败");
}
}
/**
* 开始录音
*/
private void startRecord() {
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
baos = null;
}
baos = new ByteArrayOutputStream();
//开始录音
audioRecord.startRecording();
//修改状态为开始录音
mState = 2;
//开启线程
new CollectThread().start();
}
/**
* 停止录音
*/
private void stopRecord() {
audioRecord.stop();
audioRecord.release();
mState = 0;
}
/**
* 采集线程
*/
class CollectThread extends Thread {
@Override
public void run() {
int read;
while (mState == 2) {
//创建byte数据用户保存录音数据
byte[] pcmData = new byte[recordBufSize];
//根据recordBufSize从audioRecord中读取指定长度的数据存入mPcmData
read = audioRecord.read(pcmData, 0, recordBufSize);
if (read >= AudioRecord.SUCCESS) {
synchronized (AudioRecordActivity.class) {
//保存数据到OutputStream
try {
baos.write(pcmData);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
这里只是介绍了使用AudioRecoder进行音频数据的采集,示例代码只是部分代码。在这里记录一下自己学习的过程。
网友评论