package net.coding.program.message;
import android.media.AudioRecord;
import android.util.Log;
import net.coding.program.common.Global;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.RandomAccessFile;
/**
* Created by Carlos2015 on 2015/8/28.
*/
public class AmrAudioRecorder {
private final static int[] sampleRates = {44100, 22050, 11025, 8000};
// Used only in uncompressed mode
private static final int BUFFER_FRAME_SIZE = 960;
private String outPath;
private int sampleRate;
private int bufferSize;
private AudioRecord audioRecorder;
private State state;
// Number of frames written to file on each output(only in uncompressed
// mode)
private int framePeriod;
private byte[] buffer;
private boolean isAddAmrFileHead;
private boolean isRecording;
private long duration = 0l;
private final Object mLock = new Object();
private String TAG = "AmrAudioRecorder";
private int audioSource;
private int channelConfig;
private int audioFormat;
public AmrAudioRecorder(int audioSource, int channelConfig, int audioFormat, String outPath) {
this.outPath = outPath;
this.audioSource = audioSource;
this.channelConfig = channelConfig;
this.audioFormat = audioFormat;
try {
sampleRate = sampleRates[3];
bufferSize = BUFFER_FRAME_SIZE;
// bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig,
// audioFormat);
bufferSize = 1024 * 2;
if (bufferSize == AudioRecord.ERROR_BAD_VALUE) {
Log.e("AmrAudioRecorder", "bufferSize error");
return;
}
initAudioRecoder(audioSource, channelConfig, audioFormat);
} catch (Exception e) {
Global.errorLog(e);
}
}
private void initAudioRecoder(int audioSource, int channelConfig, int audioFormat) throws Exception {
audioRecorder = new AudioRecord(audioSource, sampleRate, channelConfig, audioFormat, bufferSize);
if (audioRecorder.getState() != AudioRecord.STATE_INITIALIZED)
throw new Exception("AudioRecord initialization failed");
buffer = new byte[bufferSize];
state = State.INITIALIZING;
Log.w("AmrAudioRecorder", "sampleRate=" + sampleRate + ",bufferSize=" + bufferSize);
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
/**
* INITIALIZING : recorder is initializing; READY : recorder has been
* initialized, recorder not yet started RECORDING : recording ERROR :
* reconstruction needed STOPPED: reset needed
*/
public enum State {
INITIALIZING, READY, RECORDING, ERROR, STOPPED
}
public void prepare() {
if (state == State.INITIALIZING) {
if ((audioRecorder.getState() == AudioRecord.STATE_INITIALIZED)
& (outPath != null)) {
File file = new File(outPath).getParentFile();
if (file != null && !file.exists()) {
file.mkdirs();
}
isAddAmrFileHead = true;
duration = 0l;
state = State.READY;
} else {
state = State.ERROR;
}
}
}
private VoiceRecordingCallBack mVoiceRecordingCallBack;
public void setVoiceRecordingCallBack(VoiceRecordingCallBack mVoiceRecordingCallBack) {
this.mVoiceRecordingCallBack = mVoiceRecordingCallBack;
}
public void pause() {
stop();
}
public long getDuration() {
return duration;
}
public void continueRecord() throws Exception {
if (state != State.ERROR) {
initAudioRecoder(audioSource, channelConfig, audioFormat);
state = State.READY;
isAddAmrFileHead = false;
start();
}
}
/**
* Starts the recording, and sets the state to RECORDING. Call after
* prepare().
*/
public void start() {
if (state == State.READY) {
isRecording = true;
audioRecorder.startRecording();
state = State.RECORDING;
new Thread() {
public void run() {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
long startTime = System.currentTimeMillis();
long endTime = 0l;
int len = 0;
synchronized (mLock) {
mLock.notify();
}
while (isRecording && state == AmrAudioRecorder.State.RECORDING && (AudioRecord.ERROR_INVALID_OPERATION != (len = audioRecorder.read(buffer, 0, buffer.length)))) {
endTime = System.currentTimeMillis();
try {
bos.write(buffer, 0, len);
long v = 0;
// 将 buffer 内容取出,进行平方和运算
for (int i = 0; i < len; i++) {
v += buffer[i] * buffer[i];
}
// 平方和除以数据总长度,得到音量大小。
double mean = v / (double) len;
double volume = 10 * Math.log10(mean);
duration += (endTime - startTime);
startTime = endTime;
Log.w(TAG, "duration:" + duration + ",分贝值:" + volume);
if (mVoiceRecordingCallBack != null) {
mVoiceRecordingCallBack.onRecord(duration, volume);
}
if (isRecording) {
// 大概一秒十次
synchronized (mLock) {
try {
mLock.wait(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
try {
byte[] pcm = bos.toByteArray();
// VoiceDenoiseUtils mVoiceDenoiseUtils = new VoiceDenoiseUtils();
// mVoiceDenoiseUtils.initAudioDeNose();
// mVoiceDenoiseUtils.audioDeNose8K(pcm);
// mVoiceDenoiseUtils.exitAudioDeNose();
ByteArrayInputStream bis = new ByteArrayInputStream(pcm);
bos.close();
if (bis.available() != 0) {
byte[] data = AmrUtils.convertToAmr(bis, isAddAmrFileHead);
File f = new File(outPath);
if (!f.exists()) {
f.createNewFile();
}
RandomAccessFile raf = new RandomAccessFile(f, "rw");
if (!isAddAmrFileHead) {
raf.seek(f.length());
}
raf.write(data, 0, data.length);
raf.close();
// if(isAddAmrFileHead){
// FileOutputStream fos = new FileOutputStream(outPath,true);
// Log.w(TAG,"fileSize:"+data.length);
// fos.write(data);
// fos.flush();
// fos.close();
// }else{
// File f = new File(outPath);
// if(!f.exists()){
// f.createNewFile();
// }
// RandomAccessFile raf =new RandomAccessFile(f,"rw");
// raf.seek(f.length());
// raf.write(data,0,data.length);
// raf.close();
//
// }
}
} catch (Exception e) {
Global.errorLog(e);
} finally {
synchronized (mLock) {
mLock.notify();
}
if (audioRecorder != null) {
audioRecorder.stop();
audioRecorder.release();
audioRecorder = null;
}
}
}
}.start();
} else {
Log.e("start()",
"start() called on illegal state");
state = State.ERROR;
}
}
public void stop() {
state = State.STOPPED;
isRecording = false;
synchronized (mLock) {
try {
mLock.wait(1800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public interface VoiceRecordingCallBack {
void onRecord(long duration, double volume);
}
}