項目中用的評論回覆功能,錄製語言時爲pcm格式,然後轉換爲MP3格式:
package zhiji.dajing.com.util;
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 com.jiangdg.lametomp3.LameMp3;
import com.jiangdg.lametomp3.Mp3Recorder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AudioRecoderUtils {
//文件路徑
private String filePath;
//文件夾路徑
private String FolderPath;
AudioRecord audioRecord;
private final String TAG = "AudioRecoderUtils";
public static final int MAX_LENGTH = 1000 * 1000 * 1000 ;// 最大錄音時長
private OnAudioStatusUpdateListener audioStatusUpdateListener;
private String voicePath = Environment.getExternalStorageDirectory()+"/dajing/audio/pcm/";
private String voiceName = TimeUtils.getCurrentTime() + ".pcm";
private boolean isRecording = false;
int nMinBufSize =AudioRecord.getMinBufferSize(16000,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
private double volume;
private ExecutorService mThreadExecutor;
private Handler handler;
static AudioRecoderUtils audioRecoderUtils_p ;
public boolean isTmpConversition;
/**
* 文件存儲默認sdcard/record
*/
public AudioRecoderUtils(){
//默認保存路徑爲/sdcard/record/下
this(Environment.getExternalStorageDirectory()+"/dajing/audio/pcm/");
mThreadExecutor = Executors.newScheduledThreadPool(3);
}
public AudioRecoderUtils(String filePath) {
File path = new File(filePath);
if(!path.exists())
path.mkdirs();
this.FolderPath = filePath;
handler = new Handler();
}
public static AudioRecoderUtils getInstance(){
if (audioRecoderUtils_p == null){
audioRecoderUtils_p = new AudioRecoderUtils();
}
return audioRecoderUtils_p;
}
private long startTime;
private long endTime;
public void startRecord(){
audioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 16000,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, nMinBufSize);
final File file = new File(voicePath);
voiceName = TimeUtils.getCurrentTime() + ".pcm";
final File fileaudio = new File(voicePath + voiceName);
filePath = voicePath + voiceName;
if (fileaudio.exists()) {
fileaudio.delete();
}
if (!file.exists()) {
file.mkdirs();
}
audioRecord.startRecording();
isRecording = true;
startTime = System.currentTimeMillis();
mThreadExecutor.execute(new Runnable() {
@Override
public void run() {
FileOutputStream fos = null;
byte data[] = new byte[nMinBufSize];
try {
fos = new FileOutputStream(fileaudio);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if (null != fos) {
while (isRecording) {
int read = audioRecord.read(data, 0, nMinBufSize);
volume = getVolume(read, data.clone());
handler.post(new Runnable() {
@Override
public void run() {
audioStatusUpdateListener.onUpdate(volume,System.currentTimeMillis()-startTime);
}
});
//返回正確時纔讀取數據
if (AudioRecord.ERROR_INVALID_OPERATION != read) {
try {
fos.write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
private double getVolume(int r, byte[] bytes_pkg) {
int v = 0;
for(int i = 0; i < bytes_pkg.length; i+=2){
int v1 = bytes_pkg[i] & 0xFF;
int v2 = bytes_pkg[i + 1] & 0xFF;
int temp = v1 + (v2 << 8);// 小端
if (temp >= 0x8000) {
temp = 0xffff - temp;
}
v += Math.abs(temp);
}
int tmp_v = v / bytes_pkg.length / 2;
volume = Math.log10(1 + tmp_v) * 10;
return volume;
}
public Long stopRecord() {
isRecording = false;
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
//調用release之後必須置爲null
audioRecord = null;
}
endTime = System.currentTimeMillis();
process();
return endTime - startTime;
}
public static String path;
private File mFile;
public String processPath = voicePath + System.currentTimeMillis() + "process.pcm";
private Timer timer;
private void process() {
mThreadExecutor.execute(new Runnable() {
@Override
public void run() {
mFile = new File(filePath);
try {
FileInputStream ins = new FileInputStream(mFile);
byte[] bbytes = new byte[(int) mFile.length()];
int readBytes = ins.read(bbytes);
ins.close();
Log.i(TAG,"讀取pcm數據流,大小爲:"+readBytes);
//錄音用16K採用,單聲道,16位
//讀取PCM文件到bbytes[]
int count = bbytes.length/2; //16位數組的長度
short[] data = new short[count];
for (int i = 0; i < count; i++) {
data[i] = (short) (bbytes[i * 2] & 0xff | (bbytes[2 * i + 1] & 0xff)<< 8); //需要確認是否是小端模式
}
int num = 0;
float allNum = 0;
for (int i = 0; i < count; i++) {
if (data[i] > 1800) {
allNum = allNum + data[i];
num = num + 1;
}
}
float multiple;
if(allNum==0||num==0){
multiple=6;
}
else{
if (allNum / num < 2500) {
multiple = (float) (32000 / (allNum / num) / 2.5);
}else{
multiple = (float) (32000 / (allNum / num) / 6.5);
}
if (multiple < 1) {
multiple = 1;
}
}
for (int i = 0; i < count; i++) {
if (Math.abs(data[i]) < ((short)32000 / multiple)) {
data[i] = (short) (data[i] * multiple);
}
}
for (int i = 0; i < count; i++) {
bbytes[i * 2] = (byte) (data[i] >> 0);
bbytes[i * 2 + 1] = (byte) (data[i] >> 8); //需要確認是否是小端模式
}
byte[] bbytes8000 = new byte[count];
int j = 0;
for (int i = 0; i < bbytes.length ; i++) {
if((i%4) == 0){
bbytes8000[j] = bbytes[i];
bbytes8000[j+1] = bbytes[i+1];
j+=2;
}
}
// 保存bbytes[]到PCM文件
try {
String finalPath = "";
if (isTmpConversition){
OutputStream out = new FileOutputStream(processPath);
out.write(bbytes8000);
out.close();
finalPath = AmrEncoder.pcm2Amr(processPath, Environment.getExternalStorageDirectory() +
"/dajing/audio/amr/");
}else {
/** 初始化lame庫,配置相關信息
* @param inSampleRate pcm格式音頻採樣率
* @param outChannel pcm格式音頻通道數量
* @param outSampleRate mp3格式音頻採樣率
* @param outBitRate mp3格式音頻比特率
* @param quality mp3格式音頻質量,0~9,最慢最差~最快最好
*/
LameMp3.lameInit(16000,AudioFormat.CHANNEL_IN_MONO,16000, Mp3Recorder.LAME_BITRATE_32,5);
byte[] mp3Bytes = new byte[bbytes.length];
int lameFlush = LameMp3.lameEncode(data,data,data.length,mp3Bytes);
Log.i(TAG,"lame編碼,大小爲:"+ lameFlush);
int flush = LameMp3.lameFlush(mp3Bytes);
Log.i(TAG,"錄製完畢,大小爲:" + flush);
OutputStream mp3Out = null;
String mp3Path = Environment.getExternalStorageDirectory() + "/dajing/audio/mp3/" + System.currentTimeMillis() + ".mp3";
File file = new File(Environment.getExternalStorageDirectory() + "/dajing/audio/mp3/");
if (!file.exists()){
file.mkdirs();
}
try {
mp3Out = new FileOutputStream(mp3Path);
mp3Out.write(mp3Bytes,0,lameFlush );
mp3Out.close();
finalPath = mp3Path;
} catch (Exception e) {
e.printStackTrace();
}
}
String finalPath1 = finalPath;
handler.post(new Runnable() {
@Override
public void run() {
audioStatusUpdateListener.onStop(finalPath1);
}
});
} catch (Exception e) {
e.printStackTrace();
}finally {
LameMp3.lameClose();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private short[] transferByte2Short(byte[] data,int readBytes){
// byte[] 轉 short[],數組長度縮減一半
int shortLen = readBytes / 2;
// 將byte[]數組裝如ByteBuffer緩衝區
ByteBuffer byteBuffer = ByteBuffer.wrap(data, 0, readBytes);
// 將ByteBuffer轉成小端並獲取shortBuffer
ShortBuffer shortBuffer = byteBuffer.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
short[] shortData = new short[shortLen];
shortBuffer.get(shortData, 0, shortLen);
return shortData;
}
/**
* 取消錄音
*/
public void cancelRecord(){
isRecording = false;
try {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}catch (RuntimeException e){
audioRecord.release();
}finally {
audioRecord = null;
}
File file = new File(filePath);
if (file.exists())
file.delete();
filePath = "";
}
public void setOnAudioStatusUpdateListener(OnAudioStatusUpdateListener audioStatusUpdateListener) {
this.audioStatusUpdateListener = audioStatusUpdateListener;
}
/**
* 更新麥克狀態
*/
private void updateMicStatus() {
if (audioRecord != null) {
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
byte data[] = new byte[nMinBufSize];
int read = audioRecord.read(data, 0, nMinBufSize);
volume = getVolume(read, data.clone());
Log.e("reaudioTime","time 3 = " + volume);
double ratio =0.0;
if (volume < 1000 && volume > 0){
ratio = volume / 600;
}else {
ratio = volume / 4000;
}
double db = 0;// 分貝
if (ratio > 1) {
db = 20 * Math.log10(ratio);
if(null != audioStatusUpdateListener) {
double finalDb = db;
handler.post(new Runnable() {
@Override
public void run() {
}
});
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
},100,100);
}
}
public interface OnAudioStatusUpdateListener {
/**
* 錄音中...
* @param db 當前聲音分貝
* @param time 錄音時長
*/
public void onUpdate(double db, long time);
/**
* 停止錄音
* @param filePath 保存路徑
*/
public void onStop(String filePath);
}
}