1. 程式人生 > >Android 音訊錄製 AudioRecord,MediaRecorder的使用及播放

Android 音訊錄製 AudioRecord,MediaRecorder的使用及播放

  • 增加了許可權的標註
  • 修復 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();
        }


    }