package com.example.audiodemo;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* 音频写入文件实现类
*/
public class WavFileWrite {
private String mFilepath;
private int mDataSize = 0;
private DataOutputStream mDataOutputStream;
/**
*
* @param filepath 文件地址
* @param sampleRateInHz 采样率
* @param channels 声道数
* @param bitsPerSample 数据位宽
* @return true 成功 ,false 失败
* @throws IOException
*/
public boolean openFile(String filepath, int sampleRateInHz, int channels, int bitsPerSample) throws IOException {
if (mDataOutputStream != null) {
closeFile();
}
mFilepath = filepath;
mDataSize = 0;
mDataOutputStream = new DataOutputStream(new FileOutputStream(filepath));
return writeHeader(sampleRateInHz, bitsPerSample, channels);
}
public boolean closeFile() throws IOException {
boolean ret = true;
if (mDataOutputStream != null) {
ret = writeDataSize();
mDataOutputStream.close();
mDataOutputStream = null;
}
return ret;
}
/**
*在音频采集的回调中调用该函数写入音频数据
*
* @param buffer 音频二进制原始数据
* @param offset 0
* @param count 音频二进制原始数据的长度 buffer.length
* @return
*/
public boolean writeData(byte[] buffer, int offset, int count) {
if (mDataOutputStream == null) {
return false;
}
try {
mDataOutputStream.write(buffer, offset, count);
mDataSize += count;
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 写入wav头文件信息,根据各个对应的位置以及占多少位写入
*
* @param sampleRateInHz 采样率
* @param channels 声道数
* @param bitsPerSample 数据位宽
* @return true 成功 ,false 失败
*/
private boolean writeHeader(int sampleRateInHz, int channels, int bitsPerSample) {
if (mDataOutputStream == null) {
return false;
}
WavFileHeader header = new WavFileHeader(sampleRateInHz, channels, bitsPerSample);
try {
mDataOutputStream.writeBytes(header.mChunkID);
mDataOutputStream.write(intToByteArray(header.mChunkSize), 0, 4);
mDataOutputStream.writeBytes(header.mFormat);
mDataOutputStream.writeBytes(header.mSubChunk1ID);
mDataOutputStream.write(intToByteArray(header.mSubChunk1Size), 0, 4);
mDataOutputStream.write(shortToByteArray(header.mAudioFormat), 0, 2);
mDataOutputStream.write(shortToByteArray(header.mNumChannel), 0, 2);
mDataOutputStream.write(intToByteArray(header.mSampleRate), 0, 4);
mDataOutputStream.write(intToByteArray(header.mByteRate), 0, 4);
mDataOutputStream.write(shortToByteArray(header.mBlockAlign), 0, 2);
mDataOutputStream.write(shortToByteArray(header.mBitsPerSample), 0, 2);
mDataOutputStream.writeBytes(header.mSubChunk2ID);
mDataOutputStream.write(intToByteArray(header.mSubChunk2Size), 0, 4);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
*写入数据大小(整个wav文件的字节数和存储的二进制原始音频数据的长度)
* @return
*/
private boolean writeDataSize() {
if (mDataOutputStream == null) {
return false;
}
try {
RandomAccessFile wavFile = new RandomAccessFile(mFilepath, "rw");
wavFile.seek(WavFileHeader.WAV_CHUNKSIZE_OFFSET); //写入ChunkSize大小 :整个 wav 文件的字节数
wavFile.write(intToByteArray((mDataSize + WavFileHeader.WAV_CHUNKSIZE_EXCLUDE_DATA)), 0, 4);
wavFile.seek(WavFileHeader.WAV_SUB_CHUNKSIZE2_OFFSET);//写入SubChunk2Size大小:后面存储的二进制原始音频数据的长度
wavFile.write(intToByteArray((mDataSize)), 0, 4);
wavFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
private static byte[] intToByteArray(int data) {
return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(data).array();
}
private static byte[] shortToByteArray(short data) {
return ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(data).array();
}
}
下面结合音频采集的工具类实现采集并将数据写入到wav文件中
package com.example.audiodemo.test;
import android.os.Environment;
import com.example.audiodemo.AudioCapturer;
import com.example.audiodemo.WavFileWrite;
import java.io.IOException;
public class AudioCapturerTest implements AudioCapturer.OnAudioFrameCapturedListener {
private static final String AUDIO_FILE_PATH = "/data/data/com.example.audiodemo/test.wav";
private AudioCapturer mAudioCapturer;
private WavFileWrite mWavFileWrite;
/**
* 开始录音,并将录音写入文件
* @return true 成功, false 失败
*/
public boolean startTest(){
mAudioCapturer = new AudioCapturer();
mWavFileWrite = new WavFileWrite();
mAudioCapturer.setAudioFrameCapturedListener(this);
try {
mWavFileWrite.openFile(AUDIO_FILE_PATH, 44100, 1, 16);
} catch (IOException e) {
e.printStackTrace();
return false;
}
return mAudioCapturer.startCapturer();
}
/**
* 关闭录音,并停止写入文件
* @return true 成功, false 失败
*/
public boolean stopTest(){
mAudioCapturer.stopCapturer();
try {
mWavFileWrite.closeFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
@Override
public void onAudioFrameCaptured(byte[] audioData) {
mWavFileWrite.writeData(audioData, 0, audioData.length);
}
}