Android 录音实现方法、仿微信语音、麦克风录音、发送语音、解决5.0以上BUG

来源:互联网 发布:淘宝客服职责描述 编辑:程序博客网 时间:2024/05/17 04:03

本文修改自:http://www.jianshu.com/p/06eca50ddda4




效果图(注!由于使用的模拟器录制,所以图片中的录音时候话筒上下波动比较小,手机上正常!):

这里写图片描述



使用方法:



录音工具类:AudioRecoderUtils.java,代码如下:

public class AudioRecoderUtils {    //文件路径    private String filePath;    //文件夹路径    private String FolderPath;    private MediaRecorder mMediaRecorder;    private final String TAG = "fan";    public static final int MAX_LENGTH = 1000 * 60 * 10;// 最大录音时长1000*60*10;    private OnAudioStatusUpdateListener audioStatusUpdateListener;    /**     * 文件存储默认sdcard/record     */    public AudioRecoderUtils(){        //默认保存路径为/sdcard/record/下        this(Environment.getExternalStorageDirectory()+"/record/");    }    public AudioRecoderUtils(String filePath) {        File path = new File(filePath);        if(!path.exists())            path.mkdirs();        this.FolderPath = filePath;    }    private long startTime;    private long endTime;    /**     * 开始录音 使用amr格式     *      录音文件     * @return     */    public void startRecord() {        // 开始录音        /* ①Initial:实例化MediaRecorder对象 */        if (mMediaRecorder == null)            mMediaRecorder = new MediaRecorder();        try {            /* ②setAudioSource/setVedioSource */            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置麦克风            /* ②设置音频文件的编码:AAC/AMR_NB/AMR_MB/Default 声音的(波形)的采样 */            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);            /*             * ②设置输出文件的格式:THREE_GPP/MPEG-4/RAW_AMR/Default THREE_GPP(3gp格式             * ,H263视频/ARM音频编码)、MPEG-4、RAW_AMR(只支持音频且音频编码要求为AMR_NB)             */            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);            filePath = FolderPath + TimeUtils.getCurrentTime() + ".amr" ;            /* ③准备 */            mMediaRecorder.setOutputFile(filePath);            mMediaRecorder.setMaxDuration(MAX_LENGTH);            mMediaRecorder.prepare();            /* ④开始 */            mMediaRecorder.start();            // AudioRecord audioRecord.            /* 获取开始时间* */            startTime = System.currentTimeMillis();            updateMicStatus();            Log.e("fan", "startTime" + startTime);        } catch (IllegalStateException e) {            Log.i(TAG, "call startAmr(File mRecAudioFile) failed!" + e.getMessage());        } catch (IOException e) {            Log.i(TAG, "call startAmr(File mRecAudioFile) failed!" + e.getMessage());        }    }    /**     * 停止录音     */    public long stopRecord() {        if (mMediaRecorder == null)            return 0L;        endTime = System.currentTimeMillis();        //有一些网友反应在5.0以上在调用stop的时候会报错,翻阅了一下谷歌文档发现上面确实写的有可能会报错的情况,捕获异常清理一下就行了,感谢大家反馈!        try {            mMediaRecorder.stop();            mMediaRecorder.reset();            mMediaRecorder.release();            mMediaRecorder = null;            audioStatusUpdateListener.onStop(filePath);            filePath = "";        }catch (RuntimeException e){            mMediaRecorder.reset();            mMediaRecorder.release();            mMediaRecorder = null;            File file = new File(filePath);            if (file.exists())                file.delete();            filePath = "";        }        return endTime - startTime;    }    /**     * 取消录音     */    public void cancelRecord(){        try {            mMediaRecorder.stop();            mMediaRecorder.reset();            mMediaRecorder.release();            mMediaRecorder = null;        }catch (RuntimeException e){            mMediaRecorder.reset();            mMediaRecorder.release();            mMediaRecorder = null;        }        File file = new File(filePath);        if (file.exists())            file.delete();        filePath = "";    }    private final Handler mHandler = new Handler();    private Runnable mUpdateMicStatusTimer = new Runnable() {        public void run() {            updateMicStatus();        }    };    private int BASE = 1;    private int SPACE = 100;// 间隔取样时间    public void setOnAudioStatusUpdateListener(OnAudioStatusUpdateListener audioStatusUpdateListener) {        this.audioStatusUpdateListener = audioStatusUpdateListener;    }    /**     * 更新麦克状态     */    private void updateMicStatus() {        if (mMediaRecorder != null) {            double ratio = (double)mMediaRecorder.getMaxAmplitude() / BASE;            double db = 0;// 分贝            if (ratio > 1) {                db = 20 * Math.log10(ratio);                if(null != audioStatusUpdateListener) {                    audioStatusUpdateListener.onUpdate(db,System.currentTimeMillis()-startTime);                }            }            mHandler.postDelayed(mUpdateMicStatusTimer, SPACE);        }    }    public interface OnAudioStatusUpdateListener {        /**         * 录音中...         * @param db 当前声音分贝         * @param time 录音时长         */        public void onUpdate(double db,long time);        /**         * 停止录音         * @param filePath 保存路径         */        public void onStop(String filePath);    }}


使用很简单,主要就是开始录音startRecord()、取消录音cancelRecord()、结束录音stopRecord()和录音监听setOnAudioStatusUpdateListener(),注意,取消录音不保存文件,结束录音会保存文件!


在布局文件中添加一个控件(任意一个都行)

<Button  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:text="按住说话"  android:textColor="@android:color/white"  android:id="@+id/button"  android:background="@color/colorPrimary"   />





Activity中使用:

        //当前布局文件的根layout        final RelativeLayout rl = (RelativeLayout) findViewById(R.id.rl);        mButton = (Button) findViewById(R.id.button);        //PopupWindow的布局文件        final View view = View.inflate(this, R.layout.layout_microphone, null);        final PopupWindowFactory mPop = new PopupWindowFactory(this,view);        //PopupWindow布局文件里面的控件        mImageView = (ImageView) view.findViewById(R.id.iv_recording_icon);        mTextView = (TextView) view.findViewById(R.id.tv_recording_time);        mAudioRecoderUtils = new AudioRecoderUtils();        //录音回调        mAudioRecoderUtils.setOnAudioStatusUpdateListener(new AudioRecoderUtils.OnAudioStatusUpdateListener() {            //录音中....db为声音分贝,time为录音时长            @Override            public void onUpdate(double db, long time) {                //根据分贝值来设置录音时话筒图标的上下波动,下面有讲解                mImageView.getDrawable().setLevel((int) (3000 + 6000 * db / 100));                mTextView.setText(TimeUtils.long2String(time));            }            //录音结束,filePath为保存路径            @Override            public void onStop(String filePath) {                Toast.makeText(MainActivity.this, "录音保存在:" + filePath, Toast.LENGTH_SHORT).show();                mTextView.setText(TimeUtils.long2String(0));            }        });        //Button的touch监听        mButton.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                switch (event.getAction()){                    case MotionEvent.ACTION_DOWN:                        mPop.showAtLocation(rl,Gravity.CENTER,0,0);                        mButton.setText("松开保存");                        mAudioRecoderUtils.startRecord();                        break;                    case MotionEvent.ACTION_UP:                        mAudioRecoderUtils.stopRecord();        //结束录音(保存录音文件)//                        mAudioRecoderUtils.cancelRecord();    //取消录音(不保存录音文件)                        mPop.dismiss();                        mButton.setText("按住说话");                        break;                }                return true;            }        });


OK,就这么简单,demo下载:点击免费下载







下面放一个原作者的封装好的自定义的View,继承自Button,直接放入布局文件后,就可以使用,并封装好了PopupWindow,使用更简单,至于两种方式的好坏看个人需求

效果图:

这里写图片描述


使用:


布局中引入就行了:

<cn.zeffectn.view.recordbutton.view.RecordButton     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:text="录音按钮"     android:id="@+id/button"     android:layout_alignParentTop="true"     android:layout_alignParentLeft="true"     android:layout_alignParentStart="true" />

oK,完了,demo下载:点击免费下载




关于上面的mImageView.getDrawable().setLevel()可以看这篇:http://blog.csdn.net/fan7983377/article/details/51750864





文本所有下载(已上传新Demo,添加6.0权限申请):第一个Demo | 第二个Demo

2 1