最近在做一個項目,要求給主副MIC分別錄音,然後再單獨播放主副MIC錄製的音頻文件,再網上找了許久,沒有找到合適的就自己琢磨了一下AudioRecord和AudioTrack,然後曲線救國實現了改功能,以下就是全部代碼了。
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import static java.lang.Daemons.start;
import static java.lang.Daemons.stop;
public class AudioRecoderUtils {
String TAG = "AudioRecoder";
private boolean isRecording = false;
private boolean isPlay = false;
byte[] mBuffer = new byte[10485760];
Handler mHandler = new Handler(Looper.myLooper()) {
};
static int mBufferCount = 0;
AudioRecord audioRecord;
AudioTrack mAudioTrack;
//16K採集率
int frequency = 16000;
//錄音通道--立體音錄音
int channel = AudioFormat.CHANNEL_IN_STEREO;
//16Bit
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
AudioManager mAudioManager;
public AudioRecoderUtils() {
}
public boolean getPlay(){
return isPlay;
}
//停止錄音
public void StopRecord() {
isRecording = false;
if(audioRecord != null){
audioRecord.release();
}
}
private AudioManager.OnAudioFocusChangeListener mAudioFocusChange = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_LOSS:
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
break;
case AudioManager.AUDIOFOCUS_GAIN:
start();
break;
}
}
};
//申請音頻焦點
private void beforePlay(Context context) {
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mAudioManager.requestAudioFocus(mAudioFocusChange, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
//退出釋放
public void releaseAudioManager(){
if (audioRecord != null) {
audioRecord.release();
}
if (mAudioTrack != null) {
mAudioTrack.release();
}
if(mAudioManager != null){
mAudioManager.abandonAudioFocus(mAudioFocusChange);
}
}
//開始錄音
public void StartRecord(Context context) {
new Thread(new Runnable() {
public void run() {
mBufferCount = 0;
isPlay = false;
beforePlay();
int bufferSize = AudioRecord.getMinBufferSize(frequency, channel, audioEncoding);
if (audioRecord != null) {
audioRecord.release();
}
long count = 0;
long start = System.currentTimeMillis();
audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, frequency, channel, audioEncoding, bufferSize);
isRecording = true;
audioRecord.startRecording();
while (isRecording) {
int n = audioRecord.read(mBuffer, mBufferCount, 12000);
if (n > 0) {
mBufferCount += n;
long cc = Math.round(((double) (System.currentTimeMillis() - start)) / 1000.0d);
if (cc != count) {
count = cc;
}
} else if (n < 0) {
}
}
}
}).start();
new Thread(new Runnable() {
public void run() {
savePCM(mBuffer, mBufferCount, "stereo.pcm");
}
}).start();
}
/**
//播放音頻 --- 在這裏把主副MIC錄製的數據單獨提取出來,因爲是用的CHANNEL_IN_STEREO,
//注意,因爲把數據區分出來了所以在new AudioTrack的時候要用CHANNEL_IN_MONO單通道播放
//如果要播放錄製的原音可以就要用CHANNEL_IN_STEREO,直接用
//mAudioTrack.write(mBuffer, 0, mBufferCount);
// mAudioTrack.play();
*/
public void PlayRecord(boolean isLeft) {
if (mAudioTrack != null) {
mAudioTrack.release();
}
isPlay = true;
mAudioTrack = new AudioTrack(3, 16000, 4, 2, mBuffer.length, 0);
if (isLeft) {
new Thread(new Runnable() {
public void run() {
byte[] bsleft = new byte[(mBufferCount / 2)];
int i = 0;
while (i < mBufferCount - 1 && (i / 2) + 1 < mBufferCount / 2) {
bsleft[i / 2] = mBuffer[i];
bsleft[(i / 2) + 1] = mBuffer[i + 1];
i += 4;
}
savePCM(bsleft, bsleft.length, "left.pcm");
if (mAudioTrack != null) {
try {
mAudioTrack.write(bsleft, 0, bsleft.length);
mAudioTrack.play();
} catch (Exception e) {
isPlay = false;
}
} else {
isPlay = false;
}
}
}).start();
} else {
new Thread(new Runnable() {
public void run() {
byte[] bsright = new byte[(mBufferCount / 2)];
int j = 2;
while (j < mBufferCount - 1 && (j / 2) + 1 < mBufferCount / 2) {
bsright[(j / 2) - 1] = mBuffer[j];
bsright[j / 2] = mBuffer[j + 1];
bsright[(j / 2) + 1] = 0;
j += 4;
}
savePCM(bsright, bsright.length, "right.pcm");
if (mAudioTrack != null) {
try {
mAudioTrack.write(bsright, 0, bsright.length);
mAudioTrack.play();
} catch (Exception e) {
}
} else {
}
}
}).start();
}
}
//把錄製的音頻以PCM的格式寫入存儲裏面
public String savePCM(byte[] data, int count, String name) {
Log.d(TAG, "開始寫入 count = " + count);
String str = null;
if (count <= 0) {
return str;
}
try {
File path = new File(Environment.getExternalStorageDirectory() + "/record/");
if (!path.exists())
path.mkdirs();
File fout = new File(Environment.getExternalStorageDirectory() + "/record/" + name);
OutputStream out = new FileOutputStream(fout);
out.write(data, 0, count);
out.close();
Log.d(TAG, "寫入成功");
return fout.getAbsolutePath();
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "寫入失敗");
return str;
}
}
}
PlayRecord可以分別播放左右MIC的錄音音頻,在播放之後自動保存了一個PCM文件在內置存儲裏面,
所以要記得加SD卡存儲權限和錄音權限
<uses-permission android:name="android.permission.RECORD_AUDIO" />
一邊錄音一邊播放
public void StartRecord() {
mBufferCount = 0;
beforePlay(this);
int bufferSize = AudioRecord.getMinBufferSize(frequency, channel, audioEncoding);
audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, frequency, channel, audioEncoding, bufferSize);
mAudioTrack = new AudioTrack(3, frequency, channel, audioEncoding, mBuffer.length, 0);
isRecording = true;
audioRecord.startRecording();
while (isRecording) {
int n = audioRecord.read(mBuffer, mBufferCount, 12000);
mAudioTrack.write(mBuffer, 0, mBuffer.length);
if (n > 0) {
mAudioTrack.play();
mBufferCount += n;
}
}
}