package com.suan.weclient.util.voice;
import android.media.AudioRecord;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import com.suan.weclient.fragment.mass.VoiceFragment;
import org.apache.http.util.ByteArrayBuffer;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by lhk on 3/18/14.
*/
public class RecorderThread implements Runnable {
private AudioRecord audioRecord;
private int bufferSizeInBytes;
private int sampleRateInHz;
private String wavAudioPath;
private RecordListener recordListener;
/*
about record message
*/
public static final int RECORD_ERROR_TOO_LONG = 3;
public static final int RECORD_ERROR_TOO_SHORT = 4;
/*
about record type
*/
public static final int RECORD_TYPE_MASS = 4;
public static final int RECORD_TYPE_CHAT = 5;
private static final int MAX_RECORD_TIME_LENGTH = 60000;
private static final int MIN_RECORD_TIME_LENGTH = 1000;
private long playLength = 0;
private boolean isRecord;
private long recordStartTime = 0;
public RecorderThread(AudioRecord audioRecord,
int bufferSizeInBytes,
int sampleRateInHz, String wavAudioPath, RecordListener recordListener) {
this.audioRecord = audioRecord;
this.bufferSizeInBytes = bufferSizeInBytes;
this.sampleRateInHz = sampleRateInHz;
this.wavAudioPath = wavAudioPath;
this.recordListener = recordListener;
}
public void setRecording(boolean isRecording) {
if (isRecording) {
this.recordStartTime = System.currentTimeMillis();
}
this.isRecord = isRecording;
}
@Override
public void run() {
Looper.prepare();
ByteArrayBuffer byteArrayBuffer = writeDateTOFile();//往文件中写入裸数据
if (System.currentTimeMillis() - recordStartTime > MIN_RECORD_TIME_LENGTH) {
if (byteArrayBuffer != null) {
playLength = System.currentTimeMillis() - recordStartTime;
copyWaveFile(byteArrayBuffer, wavAudioPath);//给裸数据加上头文件
}
} else {
if (recordListener != null) {
recordListener.onRecordError(RECORD_ERROR_TOO_SHORT);
}
}
}
/**
* 这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频,
* 如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的 裸数据进行处理,比如你要做一个爱说话的TOM
* 猫在这里就进行音频的处理,然后重新封装 所以说这样得到的音频比较容易做一些音频的处理。
*/
private ByteArrayBuffer writeDateTOFile() {
// new一个byte数组用来存一些字节数据,大小为缓冲区大小
byte[] audiodata = new byte[bufferSizeInBytes];
ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(6000000);
int readsize = 0;
if (recordListener != null) {
recordListener.onRecordStart(RECORD_TYPE_MASS);
}
while (isRecord == true) {
if (System.currentTimeMillis() - recordStartTime > MAX_RECORD_TIME_LENGTH) {
if (recordListener != null) {
recordListener.onRecordError(RECORD_ERROR_TOO_LONG);
return null;
}
}
readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
if (AudioRecord.ERROR_INVALID_OPERATION != readsize) {
try {
byteArrayBuffer.append(audiodata, 0, audiodata.length);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return byteArrayBuffer;
}
// 这里得到可播放的音频文件
private void copyWaveFile(ByteArrayBuffer byteArrayBuffer, String outFilename) {
FileOutputStream out = null;
long totalAudioLen = 0;
long totalDataLen = totalAudioLen + 36;
long longSampleRate = sampleRateInHz;
int channels = 2;
long byteRate = 16 * sampleRateInHz * channels / 8;
byte[] data = new byte[bufferSizeInBytes];
ByteArrayInputStream in = new ByteArrayInputStream(byteArrayBuffer.toByteArray());
try {
out = new FileOutputStream(outFilename);
totalAudioLen = byteArrayBuffer.toByteArray().length;
totalDataLen = totalAudioLen + 36;
WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
longSampleRate, channels, byteRate);
while (in.read(data) != -1) {
out.write(data);
}
in.close();
out.close();
if (recordListener != null) {
recordListener.onRecordFinish(RECORD_TYPE_MASS, wavAudioPath,playLength);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。
* 为我为啥插入这44个字节,这个还真没深入研究,不过你随便打开一个wav
* 音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有
* 自己特有的头文件。
*/
private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen,
long totalDataLen, long longSampleRate, int channels, long byteRate)
throws IOException {
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) 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);
header[32] = (byte) (2 * 16 / 8); // 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);
out.write(header, 0, 44);
}
public interface RecordListener {
public void onRecordStart(int type);
public void onRecordFinish(int type, String filePath,long playLength);
public void onRecordError(int type);
}
}