手机端录音,保存录音文件
1、录音、存储相关权限申请
2、编写录音工具类,主要是开始录音、停止录音、传递录音数据的方法
a、新建一个buffer类,缓冲数据
public class ByteRingBuffer {
private byte[] m_buffer = null;
private int m_head = 0;
private int m_tail = 0;
public ByteRingBuffer()
{
this(262144);
}
public ByteRingBuffer(int bufSiz)
{
this.m_buffer = new byte[bufSiz + 1];
this.m_head = 0;
this.m_tail = 0;
}
public boolean isFull()
{
return (this.m_tail + 1) % this.m_buffer.length == this.m_head;
}
public boolean isEmpty()
{
return this.m_tail == this.m_head;
}
public void clear()
{
this.m_head = (this.m_tail = 0);
}
public int getCapaSize()
{
return this.m_buffer.length - 1;
}
public int getBusySize()
{
if (this.m_head <= this.m_tail) {
return this.m_tail - this.m_head;
}
return this.m_buffer.length - (this.m_head - this.m_tail);
}
public int getFreeSize()
{
return this.m_buffer.length - getBusySize() - 1;
}
public boolean put(byte[] buff, int offset, int size)
{
if ((buff == null) || (offset + size > buff.length)) {
return false;
}
if (getFreeSize() < size) {
return false;
}
int num_cpy = size;
if (this.m_tail + num_cpy > this.m_buffer.length) {
num_cpy = this.m_buffer.length - this.m_tail;
}
System.arraycopy(buff, offset, this.m_buffer, this.m_tail, num_cpy);
if (size - num_cpy > 0) {
System.arraycopy(buff, offset + num_cpy, this.m_buffer, 0, size - num_cpy);
}
this.m_tail = ((this.m_tail + size) % this.m_buffer.length);
return true;
}
public boolean get(byte[] buff, int offset, int size)
{
if ((buff == null) || (offset + size > buff.length)) {
return false;
}
if (getBusySize() < size) {
return false;
}
int num_cpy = size;
if (this.m_head + num_cpy > this.m_buffer.length) {
num_cpy = this.m_buffer.length - this.m_head;
}
System.arraycopy(this.m_buffer, this.m_head, buff, offset, num_cpy);
if (size - num_cpy > 0) {
System.arraycopy(this.m_buffer, 0, buff, offset + num_cpy, size - num_cpy);
}
this.m_head = ((this.m_head + size) % this.m_buffer.length);
return true;
}
}
b、新建录音工具类
AudioRecorder
音频相关参数设置
bufferSize = AudioTrack.getMinBufferSize(16000,AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 16000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, BufferSize);
开始录音
public synchronized void startRecord(IRecordCallback callback){
mCallback = callback;
if (mAudioRecord == null) {
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 16000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, BufferSize);
}
isRecord = true;
mAudioRecord.startRecording();
recordOutBuff = new byte[BufferSize];
recordThread = new Thread(){
@Override
public void run() {
while(isRecord){
int recordRet = mAudioRecord.read(recordOutBuff, 0, recordOutBuff.length);
if (recordRet != 0) {
// 持续的音频数据
saveRecordData(recordOutBuff);
}
}
}
};
recordThread.start();
}
public void saveRecordData(byte data[]) {
byte mByteBuffer[] = new byte[AUDIO_FRAME_DATA_LENGTH];
mRingBuffer.put(data, 0, data.length);
if (mRingBuffer.getBusySize() >= AUDIO_FRAME_DATA_LENGTH) {
mRingBuffer.get(mByteBuffer, 0, AUDIO_FRAME_DATA_LENGTH);
if(null != mCallback){
mCallback.onAudioInputData(mByteBuffer);
}
}
}
停止录音,释放资源
public synchronized void stopRecord(){
if(isRecord) {
try {
isRecord = false;
recordThread.join();
} catch (Exception e) {
}
if (mAudioRecord != null) {
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
}
}
}
完整的工具类:
public class AudioRecorder {
private static final String TAG = "AudioRecorder";
private int BufferSize = 0;
private IRecordCallback mCallback;
private ByteRingBuffer mRingBuffer;
//每一帧数据的长度
private static final int AUDIO_FRAME_DATA_LENGTH = 1280;
private boolean isRecord = false;
//录音工具录
private AudioRecord mAudioRecord;
private Thread recordThread;
private byte[] recordOutBuff;
public AudioRecorder(){
mRingBuffer = new ByteRingBuffer();
BufferSize = AudioTrack.getMinBufferSize(16000,AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 16000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, BufferSize);
}
/**
* 录音
* @param callback
*/
public synchronized void startRecord(IRecordCallback callback){
Log.v(TAG, "startRecord ");
mCallback = callback;
if (mAudioRecord == null) {
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 16000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, BufferSize);
}
isRecord = true;
mAudioRecord.startRecording();
recordOutBuff = new byte[BufferSize];
recordThread = new Thread(){
@Override
public void run() {
while(isRecord){
int recordRet = mAudioRecord.read(recordOutBuff, 0, recordOutBuff.length);
if (recordRet != 0) {
saveRecordData(recordOutBuff);
}
}
}
};
recordThread.start();
}
/**
*
*/
public void saveRecordData(byte data[]) {
byte mByteBuffer[] = new byte[AUDIO_FRAME_DATA_LENGTH];
mRingBuffer.put(data, 0, data.length);
if (mRingBuffer.getBusySize() >= AUDIO_FRAME_DATA_LENGTH) {
mRingBuffer.get(mByteBuffer, 0, AUDIO_FRAME_DATA_LENGTH);
if(null != mCallback){
mCallback.onAudioInputData(mByteBuffer);
}
}
}
/**
* 停止录音
*/
public synchronized void stopRecord(){
Log.v(TAG, "stopRecord ");
if(isRecord) {
try {
isRecord = false;
recordThread.join();
} catch (Exception e) {
}
if (mAudioRecord != null) {
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
}
}
}
}
调用方法:
AudioRecorder audioRecorder = new AudioRecorder();
audioRecorder.startRecord(callback);
回调CallBack里面定义接口
onAudioInputData(byte[] byte);传递录音数据
可以在此回调方法里面,保存录音数据或直接将录音数据传递给服务端
如保存到文件:
// 创建文件,保存数据
public void createFile(String fileDir, String fileName) {
synchronized (lock) {
if (null != fileName) {
try {
File dir = new File(fileDir);
if (!dir.exists()) {
dir.mkdir();
}
//保存录音文件
File file = new File(fileDir + "/" + fileName + ".pcm");
file.createNewFile();
Log.d(TAG, "createFile file path = " + file.getPath());
fileOutputStream = new FileOutputStream(file);
} catch (Exception e) {
e.printStackTrace();
fileOutputStream = null;
}
}
}
}
// 停止录音时关闭读写
public void closeFile() {
synchronized (lock) {
if (null != fileOutputStream) {
try {
fileOutputStream.flush();
fileOutputStream.close();
fileOutputStream = null;
} catch (Exception e) {
e.printStackTrace();
} finally {
fileOutputStream = null;
}
}
}
}
写入文件:在回调方法里面写入,开始录音后,会持续写入文件
@Override
public void onAudioInputData(byte[] data) {
//录音数据定入文件
synchronized (lock) {
try {
//音频写入文件
if (null != fileOutputStream) {
fileOutputStream.write(data, 0, data.length);
}
} catch (Exception e) {
Log.e(TAG, "----录音异常");
}
}
}
停止录音后,可以根据文件名获取文件