Android 音视频开发:使用AudioRecord采集音频PCM并保存
Posted 学杰杰杰杰.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 音视频开发:使用AudioRecord采集音频PCM并保存相关的知识,希望对你有一定的参考价值。
一. AudioRecord API详解
AudioRecord是安卓系统提供的用于实现录音的功能类。
根据官方文档:
AndioRecord类的主要功能就是让各自JAVA应用能够管理音频资源,以便它们通过这个类录制硬件设备收集的声音。录音过程,应用需要做的就是调用三个类方法中的一个获取声音数据。
1. read(byte[],int,int)
2. read(short[],int,int)
3. read(ByteBuffer,int)
无论使用哪一个方法,都需要预先设定一个buffer用于存储还没有来得及被读取的数据。这个buffer的大小可以在构造AudioRecord对象的时候指定,一旦确定大小,声音数据从音频硬件中被读出,一次读取的数据大小不能超过该buffer的容量。
实现android录音的流程为:
- 构造一个AudioRecord对象,其中需要的最小录音缓存buffer大小可以通过getMinBufferSize方法得到,如果buffer容量过小,会导致对象构造失败。
- 初始化一个buffer,该buffer大于等于AudioRecord对象用于写声音数据的buffer大小。
- 开始录音。
- 创建一个数据流,一边从AudioRecord中读取声音数据到初始化的buffer,一边将buffer中数据导入数据流。
- 关闭数据流。
- 停止录音。
二. 使用AudioRecord实现录音,并生成.wav文件
2.1 创建一个AudioRecord对象
首先要声明一些全局的变量参数:
private AudioRecord audioRecord = null; //声明AudioRecord对象
private int recordBufSize = 0; //声明recordBuffer的大小字段
获取buffer的大小,并创建AudioRecord:
public void createAudioRecord(){
recordBufSize = AudioRecord.getMinBufferSize(frequency,channelConfiguration,EncodingBitRate); //audioRecord能接收的最小的buffer大小
audioRecord = new AudioRecord(MediaRecord.Audiosource.MIC,frequency,channelConfiguration,EncodingBitRate,recordBufSize);
}
2.2 初始化一个buffer
byte data[] = new byte[recordBufSize];
2.3 开始录音
audioRecord.startRecording();
isRecording = true;
2.4 创建一个数据流,一边从AudioRecord中读取声音数据到初始化的buffer,一边将buffer中数据导入数据流
FileOutputStream os = null;
try{
os = new FileOutputStream(filename);
}catch(FileNotFoundException e){
e.printStackTrace();
}
if(null != os)
{
while(isRecording){
read = audioRecord.read(data,0,recordBufSize);
//如果读取音频数据没有出现错误,就将数据写入到文件
if(AudioRecord.ERROR_INVALID_OPERATION != read){
try{
os.write(data)
}catch(IOException e){
e.printStackTrace();
}
}
}
try{
os.close();
}catch(IOException e){
e.printStackTrace();
}
}
2.5 关闭数据流
修改标志位:isRecording为false,上面的while循环就自动停止了,数据流也就停止流动了,Stream也就被关闭了。
isRecording = false;
2.6 停止录音
停止录音之后,注意要释放资源。
if(null != audioRecord){
audioRecord.stop();
audioRecord.release();
audioRecord = null;
recordingThread = null;
}
最后:添加权限WRITE_EXTERNAL_STORAGE、RECORD_AUDIO
三. 注意事项
按照上述流程录制出的音频文件是无法直接进行播放的raw文件,如果想要放入播放器中进行播放,需要加入文件头。
添加wave文件头的代码如下:
public class PcmToWavUtil {
/**
* 缓存的音频大小
*/
private int mBufferSize;
/**
* 采样率
*/
private int mSampleRate;
/**
* 声道数
*/
private int mChannel;
/**
* @param sampleRate sample rate、采样率
* @param channel channel、声道
* @param encoding Audio data format、音频格式
*/
PcmToWavUtil(int sampleRate, int channel, int encoding) {
this.mSampleRate = sampleRate;
this.mChannel = channel;
this.mBufferSize = AudioRecord.getMinBufferSize(mSampleRate, mChannel, encoding);
}
/**
* pcm文件转wav文件
*
* @param inFilename 源文件路径
* @param outFilename 目标文件路径
*/
public void pcmToWav(String inFilename, String outFilename) {
FileInputStream in;
FileOutputStream out;
long totalAudioLen;
long totalDataLen;
long longSampleRate = mSampleRate;
int channels = mChannel == AudioFormat.CHANNEL_IN_MONO ? 1 : 2;
long byteRate = 16 * mSampleRate * channels / 8;
byte[] data = new byte[mBufferSize];
try {
in = new FileInputStream(inFilename);
out = new FileOutputStream(outFilename);
totalAudioLen = in.getChannel().size();
totalDataLen = totalAudioLen + 36;
writeWaveFileHeader(out, totalAudioLen, totalDataLen,
longSampleRate, channels, byteRate);
while (in.read(data) != -1) {
out.write(data);
}
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 加入wav文件头
*/
private void writeWaveFileHeader(FileOutputStream out, long totalAudioLen,
long totalDataLen, long longSampleRate, int channels, long byteRate)
throws IOException {
byte[] header = new byte[44];
// RIFF/WAVE header
header[0] = \'R\';
header[1] = \'I\';
header[2] = \'F\';
header[3] = \'F\';
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 8) & 0xff);
header[6] = (byte) ((totalDataLen >> 16) & 0xff);
header[7] = (byte) ((totalDataLen >> 24) & 0xff);
//WAVE
header[8] = \'W\';
header[9] = \'A\';
header[10] = \'V\';
header[11] = \'E\';
// \'fmt \' chunk
header[12] = \'f\';
header[13] = \'m\';
header[14] = \'t\';
header[15] = \' \';
// 4 bytes: size of \'fmt \' chunk
header[16] = 16;
header[17] = 0;
header[18] = 0;
header[19] = 0;
// format = 1
header[20] = 1;
header[21] = 0;
header[22] = (byte) channels;
header[23] = 0;
header[24] = (byte) (longSampleRate & 0xff);
header[25] = (byte) ((longSampleRate >> 8) & 0xff);
header[26] = (byte) ((longSampleRate >> 16) & 0xff);
header[27] = (byte) ((longSampleRate >> 24) & 0xff);
header[28] = (byte) (byteRate & 0xff);
header[29] = (byte) ((byteRate >> 8) & 0xff);
header[30] = (byte) ((byteRate >> 16) & 0xff);
header[31] = (byte) ((byteRate >> 24) & 0xff);
// block align
header[32] = (byte) (2 * 16 / 8);
header[33] = 0;
// bits per sample
header[34] = 16;
header[35] = 0;
//data
header[36] = \'d\';
header[37] = \'a\';
header[38] = \'t\';
header[39] = \'a\';
header[40] = (byte) (totalAudioLen & 0xff);
header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
out.write(header, 0, 44);
}
}
四. MediaRecorder和AudioRecord
Andorid SDK提供了两套音视频采集的API,分别为MediaRecorder和AudioRecord,前者是一个更加上层的API,它可以直接把手机麦克风录入的音频数据进行压缩编码(如AMR、MP3等)并存成文件,而后者更接近底层,能够更加自由灵活的控制,可以得到原始的一帧帧PCM音频数据。如果想要简单的做一个录音机,录制成可以播放的音频文件,则推举使用MediaRecord,而如果想要对音频做进一步处理、或者采用第三方的编码库进行压缩、以及网络传输等应用,则建议使用AudioRecord。其实MediaRecord底层也是调用了AudioRecord与Android Framework层的AudioFlinger进行交互的。直播中实时采集音频自然要有AudioRecord。
五. 源码
http://github.com/renhui/Audi...
以上是关于Android 音视频开发:使用AudioRecord采集音频PCM并保存的主要内容,如果未能解决你的问题,请参考以下文章
Android 音视频开发:使用 Camera API 采集视频数据