1. 程式人生 > >Android使用MediaRecorder實現錄音及播放

Android使用MediaRecorder實現錄音及播放

  現在專案中有使用到音視訊相關技術,在參考了網上各種大牛的資料及根據自己專案實際情況(相容安卓6.0以上版本動態許可權管理等),
  把聲音錄製及播放相關程式碼做個記錄。
public class MediaRecorderActivity extends BaseActivity {
    private Button start_tv;
    private ListView listView;
    //執行緒操作
    private ExecutorService mExecutorService;
    //錄音API
    private MediaRecorder mMediaRecorder;
    //錄音開始時間與結束時間
private long startTime, endTime; //錄音所儲存的檔案 private File mAudioFile; //檔案列表資料 private List<FileBean> dataList; //錄音檔案資料列表介面卡 private AudioAdapter mAudioAdapter; //錄音檔案儲存位置 private String mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/audio/"
; //當前是否正在播放 private volatile boolean isPlaying; //播放音訊檔案API private MediaPlayer mediaPlayer; //使用Handler更新UI執行緒 private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case
Constant.RECORD_SUCCESS: //錄音成功,展示資料 if (null == mAudioAdapter) { mAudioAdapter = new AudioAdapter(MediaRecorderActivity.this, dataList, R.layout.file_item_layout); } listView.setAdapter(mAudioAdapter); break; //錄音失敗 case Constant.RECORD_FAIL: showToastMsg(getString(R.string.record_fail)); break; //錄音時間太短 case Constant.RECORD_TOO_SHORT: showToastMsg(getString(R.string.time_too_short)); break; case Constant.PLAY_COMPLETION: showToastMsg(getString(R.string.play_over)); break; case Constant.PLAY_ERROR: showToastMsg(getString(R.string.play_error)); break; } } }; @Override protected void setWindowView() { setContentView(R.layout.activity_record); //錄音及播放要使用單執行緒操作 mExecutorService = Executors.newSingleThreadExecutor(); dataList = new ArrayList<>(); } @Override protected void initViews() { this.start_tv = (Button) findViewById(R.id.start_tv); this.listView = (ListView) findViewById(R.id.listview); } @Override protected void initEvents() { //類似微信等應用按住說話進行錄音,所以用OnTouch事件 this.start_tv.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { switch (motionEvent.getAction()) { //按下操作 case MotionEvent.ACTION_DOWN: //安卓6.0以上錄音相應許可權處理 if (Build.VERSION.SDK_INT > 22) { permissionForM(); } else { startRecord(); } break; //鬆開操作 case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: stopRecord(); break; } //對OnTouch事件做了處理,返回true return true; } }); //點選播放對應的錄音檔案 this.listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { //使用MediaPlayer播放聲音檔案 startPlay(dataList.get(i).getFile()); } }); } /** * @description 開始進行錄音 * @author ldm * @time 2017/2/9 9:18 */ private void startRecord() { start_tv.setText(R.string.stop_by_up); start_tv.setBackgroundResource(R.drawable.bg_gray_round); //非同步任務執行錄音操作 mExecutorService.submit(new Runnable() { @Override public void run() { //播放前釋放資源 releaseRecorder(); //執行錄音操作 recordOperation(); } }); } /** * @description 錄音失敗處理 * @author ldm * @time 2017/2/9 9:35 */ private void recordFail() { mAudioFile = null; mHandler.sendEmptyMessage(Constant.RECORD_FAIL); } /** * @description 錄音操作 * @author ldm * @time 2017/2/9 9:34 */ private void recordOperation() { //建立MediaRecorder物件 mMediaRecorder = new MediaRecorder(); //建立錄音檔案,.m4a為MPEG-4音訊標準的檔案的副檔名 mAudioFile = new File(mFilePath + System.currentTimeMillis() + ".m4a"); //建立父資料夾 mAudioFile.getParentFile().mkdirs(); try { //建立檔案 mAudioFile.createNewFile(); //配置mMediaRecorder相應引數 //從麥克風採集聲音資料 mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); //設定儲存檔案格式為MP4 mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); //設定取樣頻率,44100是所有安卓裝置都支援的頻率,頻率越高,音質越好,當然檔案越大 mMediaRecorder.setAudioSamplingRate(44100); //設定聲音資料編碼格式,音訊通用格式是AAC mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); //設定編碼頻率 mMediaRecorder.setAudioEncodingBitRate(96000); //設定錄音儲存的檔案 mMediaRecorder.setOutputFile(mAudioFile.getAbsolutePath()); //開始錄音 mMediaRecorder.prepare(); mMediaRecorder.start(); //記錄開始錄音時間 startTime = System.currentTimeMillis(); } catch (Exception e) { e.printStackTrace(); recordFail(); } } /** * @description 結束錄音操作 * @author ldm * @time 2017/2/9 9:18 */ private void stopRecord() { start_tv.setText(R.string.speak_by_press); start_tv.setBackgroundResource(R.drawable.bg_white_round); //停止錄音 mMediaRecorder.stop(); //記錄停止時間 endTime = System.currentTimeMillis(); //錄音時間處理,比如只有大於2秒的錄音才算成功 int time = (int) ((endTime - startTime) / 1000); if (time >= 3) { //錄音成功,新增資料 FileBean bean = new FileBean(); bean.setFile(mAudioFile); bean.setFileLength(time); dataList.add(bean); //錄音成功,發Message mHandler.sendEmptyMessage(Constant.RECORD_SUCCESS); } else { mAudioFile = null; mHandler.sendEmptyMessage(Constant.RECORD_TOO_SHORT); } //錄音完成釋放資源 releaseRecorder(); } /** * @description 翻放錄音相關資源 * @author ldm * @time 2017/2/9 9:33 */ private void releaseRecorder() { if (null != mMediaRecorder) { mMediaRecorder.release(); mMediaRecorder = null; } } @Override public void onClick(View view) { } @Override protected void onDestroy() { super.onDestroy(); //頁面銷燬,執行緒要關閉 mExecutorService.shutdownNow(); } /*******6.0以上版本手機許可權處理***************************/ /** * @description 相容手機6.0許可權管理 * @author ldm * @time 2016/5/24 14:59 */ private void permissionForM() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE}, Constant.PERMISSIONS_REQUEST_FOR_AUDIO); } else { startRecord(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == Constant.PERMISSIONS_REQUEST_FOR_AUDIO) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { startRecord(); } return; } super.onRequestPermissionsResult(requestCode, permissions, grantResults); } /** * @description 播放音訊 * @author ldm * @time 2017/2/9 16:54 */ private void playAudio(final File mFile) { if (null != mFile && !isPlaying) { isPlaying = true; mExecutorService.submit(new Runnable() { @Override public void run() { startPlay(mFile); } }); } } /** * @description 開始播放音訊檔案 * @author ldm * @time 2017/2/9 16:56 */ private void startPlay(File mFile) { try { //初始化播放器 mediaPlayer = new MediaPlayer(); //設定播放音訊資料檔案 mediaPlayer.setDataSource(mFile.getAbsolutePath()); //設定播放監聽事件 mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mediaPlayer) { //播放完成 playEndOrFail(true); } }); //播放發生錯誤監聽事件 mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mediaPlayer, int i, int i1) { playEndOrFail(false); return true; } }); //播放器音量配置 mediaPlayer.setVolume(1, 1); //是否迴圈播放 mediaPlayer.setLooping(false); //準備及播放 mediaPlayer.prepare(); mediaPlayer.start(); } catch (IOException e) { e.printStackTrace(); //播放失敗正理 playEndOrFail(false); } } /** * @description 停止播放或播放失敗處理 * @author ldm * @time 2017/2/9 16:58 */ private void playEndOrFail(boolean isEnd) { isPlaying = false; if (isEnd) { mHandler.sendEmptyMessage(Constant.PLAY_COMPLETION); } else { mHandler.sendEmptyMessage(Constant.PLAY_ERROR); } if (null != mediaPlayer) { mediaPlayer.setOnCompletionListener(null); mediaPlayer.setOnErrorListener(null); mediaPlayer.stop(); mediaPlayer.reset(); mediaPlayer.release(); mediaPlayer = null; } } }

頁面佈局

<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin">

    <Button
            android:id="@+id/start_tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="開始錄音"
            android:textSize="16sp"
            />

    <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:divider="#d1d1d1"
            android:dividerHeight="1dp"
            android:scrollbars="none"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"></ListView>

</LinearLayout>

對應資原始檔strings.xml:

<resources>
    <string name="app_name">mediarecorder</string>
    <string name="record_fail">錄音失敗</string>
    <string name="time_too_short">時間太短,請重新錄音</string>
    <string name="play_over">播放完成</string>
    <string name="play_error">抱歉,播放發生異常</string>
    <string name="stop_by_up">鬆開停止錄音</string>
    <string name="speak_by_press">按住說話</string>
    <string name="start_record">開始錄音</string>
    <string name="stop_record">停止錄音</string>
</resources>

錄音相關許可權 :

<!--SD卡許可權-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!--錄音許可權-->
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>