Android 音訊錄製 AudioRecord,MediaRecorder的使用及播放
阿新 • • 發佈:2019-02-14
- 增加了許可權的標註
- 修復 AudioRecord錄製的音訊播放時沒反應的問題。
- 整理出完整程式碼並上傳到GitHub上。
AudioRecord和MediaRecorder兩種都可以錄製音訊,MediaRecorder已實現大量的封裝,操作起來更加簡單,
而AudioRecord使用起來更加靈活,能實現更多的功能。
1.AudioRecord(基於位元組流錄音)
優點:可以實現語音的實時處理,進行邊錄邊播,對音訊的實時處理。
缺點:輸出的是PCM的語音資料,如果儲存成音訊檔案是不能被播放器播放的。要用到AudioTrack這個去進行處理。
2.MediaRecorder(基於檔案錄音)
已集成了錄音,編碼,壓縮等,支援少量的音訊格式檔案。
優點:封裝度很高,操作簡單
缺點:無法實現實時處理音訊,輸出的音訊格式少。
- 首先將許可權加上
<!-- 允許程序錄制音訊-->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 寫SD卡許可權-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- AudioRecord的功能實現:
開始錄音程式碼實現
/**
* 開始錄音
*
* @return
*/
private boolean dostart() {
try {
//記錄開始錄音時間
startRecorderTime = System.currentTimeMillis();
//建立錄音檔案
mAudioRecordFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/recorderdemo/" + System.currentTimeMillis() + ".pcm" );
if (!mAudioRecordFile.getParentFile().exists()) {
mAudioRecordFile.getParentFile().mkdirs();
mAudioRecordFile.createNewFile();
}
//建立檔案輸出流
mFileOutputStream = new FileOutputStream(mAudioRecordFile);
//配置AudioRecord
int audioSource = MediaRecorder.AudioSource.MIC;
//所有android系統都支援
int sampleRate = 44100;
//單聲道輸入
int channelConfig = AudioFormat.CHANNEL_IN_MONO;
//PCM_16是所有android系統都支援的
int autioFormat = AudioFormat.ENCODING_PCM_16BIT;
//計算AudioRecord內部buffer最小
int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, autioFormat);
//buffer不能小於最低要求,也不能小於我們每次我們讀取的大小。
mAudioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, autioFormat, Math.max(minBufferSize, BUFFER_SIZE));
//開始錄音
mAudioRecord.startRecording();
//迴圈讀取資料,寫入輸出流中
while (mIsRecording) {
//只要還在錄音就一直讀取
int read = mAudioRecord.read(mBuffer, 0, BUFFER_SIZE);
if (read <= 0) {
return false;
} else {
mFileOutputStream.write(mBuffer, 0, read);
}
}
//退出迴圈,停止錄音,釋放資源
stopRecorder();
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if (mAudioRecord != null) {
mAudioRecord.release();
}
}
return true;
}
停止錄音程式碼實現
/**
* 停止錄音
* @return
*/
private boolean doStop() {
//停止錄音,關閉檔案輸出流
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
Log.i("Tag8", "go here");
//記錄結束時間,統計錄音時長
stopRecorderTime = System.currentTimeMillis();
//大於3秒算成功,在主執行緒更新UI
final int send = (int) (stopRecorderTime - startRecorderTime) / 1000;
if (send > 3) {
mHandler.post(new Runnable() {
@Override
public void run() {
tv_stream_msg.setText("錄音成功:" + send + "秒");
bt_stream_recorder.setText("開始錄音");
Log.i("Tag8", "go there");
}
});
} else {
recorderFail();
return false;
}
return true;
}
播放音訊檔案程式碼實現
/**
* 播放音訊檔案
*
* @param audioFile
*/
private void doPlay(File audioFile) {
if (audioFile != null) {
Log.i("Tag8", "go there");
//配置播放器
//音樂型別,揚聲器播放
int streamType = AudioManager.STREAM_MUSIC;
//錄音時採用的取樣頻率,所以播放時同樣的取樣頻率
int sampleRate = 44100;
//單聲道,和錄音時設定的一樣
int channelConfig = AudioFormat.CHANNEL_OUT_MONO;
//錄音時使用16bit,所以播放時同樣採用該方式
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
//流模式
int mode = AudioTrack.MODE_STREAM;
//計算最小buffer大小
int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
//構造AudioTrack 不能小於AudioTrack的最低要求,也不能小於我們每次讀的大小
AudioTrack audioTrack = new AudioTrack(streamType, sampleRate, channelConfig, audioFormat,
Math.max(minBufferSize, BUFFER_SIZE), mode);
audioTrack.play();
//從檔案流讀資料
FileInputStream inputStream = null;
try {
//迴圈讀資料,寫到播放器去播放
inputStream = new FileInputStream(audioFile);
//迴圈讀資料,寫到播放器去播放
int read;
//只要沒讀完,迴圈播放
while ((read = inputStream.read(mBuffer)) > 0) {
Log.i("Tag8", "read:" + read);
int ret = audioTrack.write(mBuffer, 0, read);
//檢查write的返回值,處理錯誤
switch (ret) {
case AudioTrack.ERROR_INVALID_OPERATION:
case AudioTrack.ERROR_BAD_VALUE:
case AudioManager.ERROR_DEAD_OBJECT:
playFail();
return;
default:
break;
}
}
//播放結束
audioTrack.stop();
} catch (Exception e) {
e.printStackTrace();
//讀取失敗
playFail();
} finally {
mIsPlaying = false;
//關閉檔案輸入流
if (inputStream != null) {
closeStream(inputStream);
}
//播放器釋放
resetQuietly(audioTrack);
}
//迴圈讀資料,寫到播放器去播放
//錯誤處理,防止閃退
}
}
釋放資原始碼
@Override
protected void onDestroy() {
super.onDestroy();
if (mExecutorService != null) {
mExecutorService.shutdownNow();
}
if (mAudioRecord != null) {
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
}
}
- MediaRecord錄製音訊
啟動錄音程式碼實現
/**
* 啟動錄音
*
* @return
*/
private boolean doStart() {
try {
//建立MediaRecorder
mMediaRecorder = new MediaRecorder();
//建立錄音檔案
mRecorderFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/recorderdemo/" + System.currentTimeMillis() + ".m4a");
if (!mRecorderFile.getParentFile().exists()) mRecorderFile.getParentFile().mkdirs();
mRecorderFile.createNewFile();
//配置MediaRecorder
//從麥克風採集
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//儲存檔案為MP4格式
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
//所有android系統都支援的適中取樣的頻率
mMediaRecorder.setAudioSamplingRate(44100);
//通用的AAC編碼格式
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
//設定音質頻率
mMediaRecorder.setAudioEncodingBitRate(96000);
//設定檔案錄音的位置
mMediaRecorder.setOutputFile(mRecorderFile.getAbsolutePath());
//開始錄音
mMediaRecorder.prepare();
mMediaRecorder.start();
startRecorderTime = System.currentTimeMillis();
} catch (Exception e) {
Toast.makeText(MediaRecordActivity.this, "錄音失敗,請重試", Toast.LENGTH_SHORT).show();
return false;
}
//記錄開始錄音時間,用於統計時長,小於3秒中,錄音不傳送
return true;
}
結束錄音程式碼實現
/**
* 關閉錄音
*
* @return
*/
private boolean doStop() {
try {
mMediaRecorder.stop();
stopRecorderTime = System.currentTimeMillis();
final int second = (int) (stopRecorderTime - startRecorderTime) / 1000;
//按住時間小於3秒鐘,算作錄取失敗,不進行傳送
if (second < 3) return false;
mHander.post(new Runnable() {
@Override
public void run() {
tv_sendmsg.setText("錄製成功:" + second + "秒");
}
});
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
播放音訊程式碼實現
/**
* 播放音訊檔案
* @param audioFile
*/
private void doPlay(File audioFile) {
try {
//配置播放器 MediaPlayer
mediaPlayer = new MediaPlayer();
//設定聲音檔案
mediaPlayer.setDataSource(audioFile.getAbsolutePath());
//配置音量,中等音量
mediaPlayer.setVolume(1,1);
//播放是否迴圈
mediaPlayer.setLooping(false);
//設定監聽回撥 播放完畢
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
stopPlayer();
}
});
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
stopPlayer();
Toast.makeText(MediaRecordActivity.this,"播放失敗",Toast.LENGTH_SHORT).show();
return true;
}
});
//設定播放
mediaPlayer.prepare();
mediaPlayer.start();
//異常處理,防止閃退
} catch (Exception e) {
e.printStackTrace();
stopPlayer();
}
}