Android 多媒体之MediaRecorder MediaP

作者: _SOLID | 来源:发表于2016-03-26 12:47 被阅读3010次

    以前学了很多东西,都没怎么做记录,慢慢的时间长了也就给忘了,当初踩过的坑翻来覆去的踩,由于这些血淋林的教训,所以从现在开始,每次学了新的东西都要来写个博客做个记录总结一下了。

    最近在学习Android多媒体这一块,现在刚好学到了MediaRecorder和MediaPlayer。今天也就介绍下这两个类吧,也有利于以后初学者的学习。

    本文一共分3个部分:第一和第二部分用来介绍这两个类,第3部分做一个录音的小Demo(附源码)

    1.MediaRecorder

    关于MediaRecorder 官网给的解释是

    Used to record audio and video. The recording control is based on a simple state machine

    大致意思就是,这个类是用来去录制音频和视频的。录制基于一种简单的状态机制。
    这个状态机制是什么呢?Google给了一张图

    mediarecorder_state_diagram.gif

    从图中可以看出MediaRecorder 有这么几种状态:
    Initial:初始化。也就是MediaRecorder 刚被创建的时候。在这个时候我们去设置音频或者视频的来源了,可能这个时候就有人问了 音频或者视频的来源是什么意思,举个例子吧,比如当我们在录音的时候,这个声音的来源就可以设置成手机的麦克风。
    Initialized:初始化完成。这里我们已经知道音频或者视频的来源了,在这里我们就可以设置一些输出的属性了,比如输出文件的保存格式,编码什么的。由于水平有限还有很多关于媒体文件属性,我也不是太理解。
    DataSourceConfigured:数据源配置改变。也就是我们改变了一些输出的属性,就会进入到这个状态。
    Prepered:处于这个状态就说明了我们的配置已经完成了,现在就等去录制了。
    Recordeing:这个不用我说也应该明白了。
    Released:资源被释放了。
    Error:录制的时候发生了错误。

    图中已经把状态之间是怎么切换的已经描述的非常清楚了,我也不过多介绍了。

    2.MediaPlayer

    关于MediaPlayer官网给的解释是:

    MediaPlayer class can be used to control playback of audio/video files and streams.

    简单翻译过来就是:这个类是用来去播放音频,视频文件和流文件的。

    他也对应了一个状态图:

    mediaplayer_state_diagram.gif

    其实他的大致流程和MediaRecorder差不多,这里我就略过了。

    你以为到这就结束了吗?肯定不是的,上面的也就为下面我要做的做个铺垫而已,有了上面的基础,后面的肯定就轻松了。

    3.做一个录音的小Demo

    先来看一看效果图吧

    未标题-1.png

    看起来还是很简单吧。
    开始是初始状态,然后是录制状态(中间有个波浪形的自定义控件),在这个状态下会显示当前的录制时长,波浪形控件会显示,最后就是录制完成,可以点击播放了。
    最下面是保存和删除按钮,可以删除当前的录音。PS:保存按钮没有任何实现,录音文件会自动保存。

    知道了这个效果现在就来介绍是怎么做的吧。

    这个小Demo我对MediaRecorder和MediaPlayer做了一下封装,方便以后使用调用方便。

    MediaRecorderHelper代码如下:
    <pre>
    public class MediaRecorderHelper {

    private MediaRecorder mMediaRecorder;
    private String mSavePath;
    private String mCurrentFilePath;
    
    
    public MediaRecorderHelper(String savePath) {
        mSavePath = savePath;
        File file = new File(mSavePath);
        if (!file.exists()) file.mkdirs();
    
    }
    
    
    /**
     * 开始录音
     */
    public void startRecord() {
        try {
            mMediaRecorder = new MediaRecorder();
            File file = new File(mSavePath, generateFileName());
            mCurrentFilePath = file.getAbsolutePath();
            // 设置录音文件的保存位置
            mMediaRecorder.setOutputFile(mCurrentFilePath);
            // 设置录音的来源(从哪里录音)
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            // 设置录音的保存格式
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
            // 设置录音的编码
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            mMediaRecorder.prepare();
            mMediaRecorder.start();
    
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 停止录音
     */
    public void stopAndRelease() {
        if (mMediaRecorder == null) return;
        mMediaRecorder.stop();
        mMediaRecorder.release();
        mMediaRecorder = null;
    }
    
    /***
     * 取消本次录音操作
     */
    public void cancel() {
        this.stopAndRelease();
        if (mCurrentFilePath != null) {
            File file = new File(mCurrentFilePath);
            file.delete();
            mCurrentFilePath = null;
    
    
        }
    }
    
    private String generateFileName() {
        return UUID.randomUUID().toString() + ".amr";
    }
    
    /**
     * 得到录音文件的路径
     *
     * @return
     */
    public String getCurrentFilePath() {
        return mCurrentFilePath;
    }
    

    }

    </pre>
    MediaPlayerHelper代码如下:
    <pre>
    public class MediaPlayerHelper {

    private static MediaPlayer mMediaPlayer;
    private static boolean isPause = false;
    
    public static void playSound(String filePath) {
        playSound(filePath, null);
    }
    
    public static void playSound(String filePath, MediaPlayer.OnCompletionListener onCompletionListener) {
        if (mMediaPlayer == null) {
            mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                @Override
                public boolean onError(MediaPlayer mp, int what, int extra) {
                    mMediaPlayer.reset();
                    return false;
                }
            });
        } else {
            mMediaPlayer.reset();
        }
        try {
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            if (onCompletionListener != null) {
                mMediaPlayer.setOnCompletionListener(onCompletionListener);
            }
    
    
            mMediaPlayer.setDataSource(filePath);
            mMediaPlayer.prepare();
            mMediaPlayer.start();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    
    
    }
    
    /**
     * 暂停播放
     */
    public static void pause() {
        if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
            mMediaPlayer.pause();
            isPause = true;
        }
    }
    
    
    /**
     * 继续播放
     */
    public static void resume() {
        if (mMediaPlayer != null && isPause) {
            mMediaPlayer.start();
            isPause = false;
        }
    }
    
    /**
     * 释放资源
     */
    public static void realese() {
        if (mMediaPlayer != null) {
            mMediaPlayer.release();
            mMediaPlayer = null;
            isPause = true;
        }
    }
    

    }

    </pre>

    这两个类的代码注释的已经非常详细了,我再在这里介绍也就显得有点多余了。如果还是又不懂或者有问题需要提出的,欢迎留言。

    到这里我们的核心东西已经准备好了,现在就剩下一个Activity让我们去实现刚才效果图上的小Demo了。

    我们来分析一下我们的小Demo会有哪些状态:
    1.正常状态,也就是没有录制的状态
    2.录制中
    3.录制完成
    4.播放状态
    5.暂停状态

    对于这几种状态我定义了对应的五个常量来表示。
    <pre>
    private static final int ACTION_NORMAL = 0;
    private static final int ACTION_RECORDING = 1;
    private static final int ACTION_COMMPLETE = 2;
    private static final int ACTION_PLAYING = 3;
    private static final int ACTION_PAUSE = 4;
    </pre>

    在中间的录制按钮在点击的时候,我们要根据当前的状态来进行状态之间的切换:
    依然是附代码,就是这么任性~~~~
    <pre>
    /**
    * 切换ACTION状态
    */
    private void switchActionState() {
    mIsRecorder = false;
    if (mCurrentActionState == ACTION_NORMAL) {
    mCurrentActionState = ACTION_RECORDING;
    mIvAction.setImageResource(R.drawable.pause);

            //开始录音
            mMediaRecorderHelper.startRecord();
            mWaveView.setVisibility(View.VISIBLE);
            mIsRecorder = true;
            //开启计时线程
            mCountTimeThread = new Thread(this);
            mCountTimeThread.start();
    
        } else if (mCurrentActionState == ACTION_RECORDING) {//录制中
            mCurrentActionState = ACTION_COMMPLETE;
            mIvAction.setImageResource(R.drawable.icon_audio_state_uploaded);
            //停止录音
            mMediaRecorderHelper.stopAndRelease();
            mRlBottom.setVisibility(View.VISIBLE);
            mWaveView.setVisibility(View.INVISIBLE);
    
        } else if (mCurrentActionState == ACTION_COMMPLETE) {//录制完成
            mCurrentActionState = ACTION_PLAYING;
            mIvAction.setImageResource(R.drawable.icon_audio_state_uploaded_play);
    
            //播放录音
            MediaPlayerHelper.playSound(mMediaRecorderHelper.getCurrentFilePath(), new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    //当播放完了之后切换到录制完成的状态
                    mCurrentActionState = ACTION_COMMPLETE;
                    mIvAction.setImageResource(R.drawable.icon_audio_state_uploaded);
                }
            });
    
        } else if (mCurrentActionState == ACTION_PLAYING) {//播放中
            mCurrentActionState = ACTION_PAUSE;
            mIvAction.setImageResource(R.drawable.icon_audio_state_uploaded);
            //暂停播放
            MediaPlayerHelper.pause();
        } else if (mCurrentActionState == ACTION_PAUSE) {//暂停
            mCurrentActionState = ACTION_PLAYING;
            mIvAction.setImageResource(R.drawable.icon_audio_state_uploaded_play);
            //继续播放
            MediaPlayerHelper.resume();
        }
    }
    

    </pre>

    上面的就是整个Demo的核心思想。

    需要源码的可以点击下面的链接下载。
    MediaRecorderDemo

    如果在阅读的过程中又发现错误,也欢迎留言纠错。

    相关文章

      网友评论

        本文标题:Android 多媒体之MediaRecorder MediaP

        本文链接:https://www.haomeiwen.com/subject/boqdlttx.html