项目中用的评论回复功能,录制语言时为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);
}
}