录音器 AudioRecorder

时间:2023-03-08 20:01:42

实现录音器有两种方式可以选择:

1.AudioRecord(基于字节流录音)
优点:可以实现语音的实时处理,进行边录边播,对音频的实时处理。
缺点:输出的是PCM的语音数据,如果保存成音频文件是不能被播放器播放的。要用到AudioTrack这个去进行处理。

2.MediaRecorder(基于文件录音)
已集成了录音,编码,压缩等,支持少量的音频格式文件。
优点:封装度很高,操作简单
缺点:无法实现实时处理音频,输出的音频格式少。

权限:

<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

AudioRecorder录音工具类代码如下:

package com.example.m_evolution.Utils;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.util.Log; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date; public class AudioRecoderUtils { //文件路径
private String filePath;
//文件夹路径
private String FolderPath; //录音的线程
private Thread mThread; // private MediaRecorder mMediaRecorder;
private AudioRecord audioRecord;
private boolean isRecording;
private int channelConfiguration = AudioFormat.CHANNEL_IN_MONO;
private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
private int sampleRate = 44100;
private int bufferSizeInBytes; private final String TAG = "fan";
public static final int MAX_LENGTH = 1000 * 60 * 10;// 最大录音时长1000*60*10; private OnAudioStatusUpdateListener audioStatusUpdateListener; /**
* 文件存储默认sdcard/record
*/
public AudioRecoderUtils(){ //默认保存路径为/sdcard/record/下
FolderPath = Environment.getExternalStorageDirectory()+"/record/";
bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRate,
channelConfiguration, audioEncoding); // need to be larger than size of a frame audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
sampleRate, channelConfiguration, audioEncoding,
bufferSizeInBytes); //麦克风
} public void startRecord(){
mThread = new Thread(new Runnable() {
@Override
public void run() {
/* 获取开始时间* */
startTime = System.currentTimeMillis();
//设置录制指标
isRecording = true;
//自动更新界面
updateMicStatus();
//设置存储路径
filePath = FolderPath+getCurrentDate("yyyyMMddHHmmss") + ".wav";
File recordingFile = new File(filePath);
OutputStream out = null;
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
audioRecord.startRecording();
byte[] buffer = new byte[bufferSizeInBytes];
int bufferReadResult = 0;
while (isRecording) {
bufferReadResult = audioRecord.read(buffer, 0,
bufferSizeInBytes);
if(bufferReadResult>0){
baos.write(buffer, 0, bufferReadResult);
}
}
Log.i(TAG, "stop recording,file=" + recordingFile.getAbsolutePath());
buffer = baos.toByteArray();
Log.i(TAG, "audio byte len="+buffer.length);
out = new FileOutputStream(recordingFile);
out.write(getWavHeader(buffer.length));
out.write(buffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(baos!=null){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
});
mThread.start();
} public void stopRecord(){
stopRecording();
audioStatusUpdateListener.onStop(filePath);
filePath = "";
} public byte[] getWavHeader(long totalAudioLen){
int mChannels = 1;
long totalDataLen = totalAudioLen + 36;
long longSampleRate = sampleRate;
long byteRate = sampleRate * 2 * mChannels; byte[] header = new byte[44];
header[0] = 'R'; // RIFF/WAVE header
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);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f'; // 'fmt ' chunk
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 16; // 4 bytes: size of 'fmt ' chunk
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 1; // format = 1
header[21] = 0;
header[22] = (byte) mChannels;
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);
header[32] = (byte) (2 * mChannels); // block align
header[33] = 0;
header[34] = 16; // bits per sample
header[35] = 0;
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); return header;
} private long startTime;
private long endTime; public static String getCurrentDate(String pattern) {
SimpleDateFormat formatter = new SimpleDateFormat(pattern);
Date curDate = new Date(System.currentTimeMillis());// 获取当前时间
String timestamp = formatter.format(curDate);
return timestamp;
} public void stopRecording() {
try {
isRecording = false;
audioRecord.stop();
audioRecord.release();
audioRecord = null;
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
sampleRate, channelConfiguration, audioEncoding,
bufferSizeInBytes); //麦克风
} catch (Exception e) {
e.printStackTrace();
}
} private final Handler mHandler = new Handler();
private Runnable mUpdateMicStatusTimer = new Runnable() {
public void run() {
updateMicStatus();
}
}; private int SPACE = 100;//显示时间的间隔时间 public void setOnAudioStatusUpdateListener(OnAudioStatusUpdateListener audioStatusUpdateListener) {
this.audioStatusUpdateListener = audioStatusUpdateListener;
} /**
* 更新麦克状态
*/
private void updateMicStatus() { if (isRecording) {
if(null != audioStatusUpdateListener) {
audioStatusUpdateListener.onUpdate(System.currentTimeMillis()-startTime);
}
mHandler.postDelayed(mUpdateMicStatusTimer, SPACE);
}
} public interface OnAudioStatusUpdateListener {
/**
* 录音中...
* @param db 当前声音分贝
* @param time 录音时长
*/
public void onUpdate(long time); /**
* 停止录音
* @param filePath 保存路径
*/
public void onStop(String filePath);
} }