完美解决录音权限问题并附上录音代码

来源:互联网 发布:显示毫秒的网络时钟 编辑:程序博客网 时间:2024/05/16 19:46
这段时间做一个项目有即时聊天功能,里面有遇到录音权限的问题,百度了个遍判断权限问题,没有好的解决方案,然而自己代码变通了一下,发现问题其实也还好,先附上录音工具
package .view;import android.app.Dialog;import android.content.Context;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.util.Log;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.widget.Button;import android.widget.ImageView;import android.widget.TextView;import com.app.application.AppConfig;import com.app.tool.FToast;import com.nbappdev.aikaopu_personal.R;import com.nbappdev.aikaopu_personal.utils.AudioManager;/** * 自定语音按钮 */public class AudioRecordButton extends Button implements AudioManager.AudioStageListener{    private Dialog mDialog;   //语音对话框    private ImageView mIcon;    private ImageView mVoice;    private TextView mLable;    private Context mContext;    private AudioManager mAudioManager;    private boolean mReady=false;  //开始录制    private boolean isRecording = false;   //是否开始录音    private boolean recordPermissions = true;   //录音权限    private float mTime = 0;   //时间    private static final int MSG_AUDIO_PREPARED = 0X110;    private static final int MSG_VOICE_CHANGE = 0X111;    private static final int MSG_DIALOG_DIMISS = 0X112;    private static final int MSG_VOICE_TIME_OUT = 0X113;    private AudioRecordButtonHandler mHandler = new AudioRecordButtonHandler();    private static final int STATE_NORMAL = 1;    private static final int STATE_RECORDING = 2;    private static final int STATE_WANT_TO_CANCEL = 3;    private int mCurrentState = STATE_NORMAL;    private static final int DISTANCE_Y_CANCEL = 50;    private boolean time_out = false;   //录制超时    private Runnable runnable;    private Handler handler;    private OnFinishedRecordListener onFinishedRecordListener;    public void setOnFinishedRecordListener(OnFinishedRecordListener onFinishedRecordListener) {        this.onFinishedRecordListener = onFinishedRecordListener;    }    public AudioRecordButton(Context context) {        super(context);        this.mContext = context;    }    public AudioRecordButton(final Context context, AttributeSet attrs) {        super(context, attrs);        this.mContext = context;        if( Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){   //判断SD卡是否存在            mAudioManager = AudioManager.getInstance(AppConfig.DIR_AUDIO);            mAudioManager.setOnAudioStageListener(this);            recordPermissions = true;        }else {            FToast.show(mContext,"未发现sd卡,无法使用录音功能");        }    }    private class AudioRecordButtonHandler extends Handler{        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case MSG_AUDIO_PREPARED:                    mTime = 0;                    showRecordingDialog();                    isRecording = true;                    new Thread(mGetVoiceLevelRunnable).start();                    handler = new Handler();                    runnable = new Runnable() {                        @Override                        public void run() {                            mHandler.sendEmptyMessage(MSG_VOICE_TIME_OUT);                        }                    };                    handler.postDelayed(runnable, 61000);                    break;                case MSG_VOICE_CHANGE:                    updateVoiceLevel(mAudioManager.getVoiceLevel(7));                    break;                case MSG_DIALOG_DIMISS:                    mAudioManager.cancel();                    dimissDialog();                    break;                case MSG_VOICE_TIME_OUT:                    time_out = true;                    dimissDialog();                    mAudioManager.release();                    if (onFinishedRecordListener!=null && mReady) {                        if (mTime>60){                            mTime = 60;                        }                        onFinishedRecordListener.onFinishedRecord(mAudioManager.getCurrentFilePath(),(int)mTime);                        FToast.show(mContext, "录制时间不能超过60秒");                    }                    handler.removeCallbacks(runnable);                    reset();                    break;            }        }    };    /**     * 监听屏幕触摸事件     * @param event     * @return     */    @Override    public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        int x = (int) event.getX();        int y = (int) event.getY();        switch (action) {            case MotionEvent.ACTION_DOWN:   //按下                changeDialogState(STATE_RECORDING);                break;            case MotionEvent.ACTION_MOVE:   //移动时                if (isRecording) {                    if (wantToCancel(x, y)) {                        changeDialogState(STATE_WANT_TO_CANCEL);                    }else {                        changeDialogState(STATE_RECORDING);                    }                }                break;            case MotionEvent.ACTION_UP:   //抬起时                if (time_out){                    time_out = false;                    return super.onTouchEvent(event);                }                if (!mReady) {                    reset();                    return super.onTouchEvent(event);                }                if (!isRecording || mTime < 0.6f) {                    tooShort();                    mAudioManager.cancel();                    reset();                    mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS,0);                }else if (mCurrentState == STATE_RECORDING) {                    dimissDialog();                    mAudioManager.release();                    if (onFinishedRecordListener!=null) {                        if (mTime>60){                            mTime =60;                        }                        onFinishedRecordListener.onFinishedRecord(mAudioManager.getCurrentFilePath(),(int)mTime);                    }                    reset();                }else if (mCurrentState == STATE_WANT_TO_CANCEL) {                    mAudioManager.cancel();                    dimissDialog();                    reset();                }                break;        }        return super.onTouchEvent(event);    }    /**     * 改变对话框状态     * @param state     */    private void changeDialogState(int state) {        if (mCurrentState != state) {            mCurrentState = state;            switch (mCurrentState) {                case STATE_NORMAL:                    setBackgroundResource(R.drawable.button_recordnormal);                    setText("按住 说话");                    break;                case STATE_RECORDING:                    setBackgroundResource(R.drawable.button_recording);                    setText("松开 结束");                    if (isRecording) {                        recording();                    }                    break;                case STATE_WANT_TO_CANCEL:                    setBackgroundResource(R.drawable.button_recording);                    setText("松开手指,取消发送");                    wantToCancel();                    break;            }        }    }    private boolean wantToCancel(int x, int y) {        if (x < 0 || x > getWidth()) {    // 判断是否在左边,右边,上边,下边            return true;        }        if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) {            return true;        }        return false;    }    private void reset() {        isRecording = false;        changeDialogState(STATE_NORMAL);        mReady = false;        mTime = 0;    }    /**     * 开始录音     */    public void startRecord(){        if (recordPermissions){            mReady = true;            mAudioManager.prepareAudio();        }    }    @Override    public boolean onPreDraw() {        return false;    }    //*****************************************Diaolog语音对话框********************************//    /**     * 显示语音对话框     */    public void showRecordingDialog() {        mDialog = new Dialog(mContext, R.style.Theme_audioDialog);        LayoutInflater inflater = LayoutInflater.from(mContext);        View view = inflater.inflate(R.layout.voice_dialog, null);        mDialog.setContentView(view);        mIcon = (ImageView) mDialog.findViewById(R.id.dialog_icon);        mVoice = (ImageView) mDialog.findViewById(R.id.dialog_voice);        mLable = (TextView) mDialog.findViewById(R.id.recorder_dialogtext);        mDialog.show();    }    /**     * 设置正在录音时的dialog界面     */    public void recording() {        if (mDialog != null && mDialog.isShowing()) {            mIcon.setVisibility(View.VISIBLE);            mVoice.setVisibility(View.VISIBLE);            mLable.setVisibility(View.VISIBLE);            mIcon.setImageResource(R.drawable.recorder);            mLable.setText("手指上滑,取消发送");        }    }    /**     * 取消录制     */    public void wantToCancel() {        if (mDialog != null && mDialog.isShowing()) {            mIcon.setVisibility(View.VISIBLE);            mVoice.setVisibility(View.GONE);            mLable.setVisibility(View.VISIBLE);            mIcon.setImageResource(R.drawable.cancel);            mLable.setText("松开手指,取消发送");        }    }    /**     * 录制时间过短     */    public void tooShort() {        if (mDialog != null && mDialog.isShowing()) {            mIcon.setVisibility(View.VISIBLE);            mVoice.setVisibility(View.GONE);            mLable.setVisibility(View.VISIBLE);            mIcon.setImageResource(R.drawable.voice_to_short);            mLable.setText("录音时间过短");        }    }    /**     * 隐藏dialog     */    public void dimissDialog() {        if (mDialog != null && mDialog.isShowing()) {            mDialog.dismiss();            mDialog = null;        }    }    public void updateVoiceLevel(int level) {        if (mDialog != null && mDialog.isShowing()) {            int resId = mContext.getResources().getIdentifier("v" + level,                    "drawable", mContext.getPackageName());            mVoice.setImageResource(resId);        }    }    /**     * 开始录制     */    @Override    public void wellPrepared() {        Log.i("触发","准备完成");        mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);    }    /**     * 异步获取音量     */    private Runnable mGetVoiceLevelRunnable = new Runnable() {        @Override        public void run() {            while (isRecording) {                try {                    Thread.sleep(100);                    mTime += 0.1f;                    mHandler.sendEmptyMessage(MSG_VOICE_CHANGE);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    };    /**     * 录制完成回调     */    public interface OnFinishedRecordListener {        void onFinishedRecord(String audioPath,int voice_length);    }}
然后录音管理工具类
<pre name="code" class="java">package .utils;import android.media.AudioFormat;import android.media.AudioRecord;import android.media.MediaRecorder;import android.util.Log;import java.io.File;import java.io.IOException;/** * 语音录制管理类 */public class AudioManager {    private MediaRecorder mRecorder;    private String mDirString;  //文件夹路径    private String mCurrentFilePathString; //当前的详细路径    private static AudioManager mInstance;    public AudioStageListener mListener;    private boolean isPrepared;    // 音频获取源    public static int audioSource = MediaRecorder.AudioSource.MIC;    // 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025    public static int sampleRateInHz = 44100;    // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道    public static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;    // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。    public static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;    // 缓冲区字节大小    public static int bufferSizeInBytes = 0;    public void setOnAudioStageListener(AudioStageListener listener) {        mListener = listener;    }    private AudioManager(String dir) {        mDirString=dir;    }    public static AudioManager getInstance(String dir) {        if (mInstance == null) {            synchronized (AudioManager.class) {                if (mInstance == null) {                    mInstance = new AudioManager(dir);                }            }        }        return mInstance;    }    /**     * 准备开始录制     */    public void prepareAudio() {        try {            isPrepared = false;            File dir = new File(mDirString);            if (!dir.exists()) {                dir.mkdirs();            }            String fileNameString = System.currentTimeMillis()+".m4a";            File file = new File(dir, fileNameString);            mCurrentFilePathString = file.getAbsolutePath();            mRecorder = new MediaRecorder();            // 设置输出文件            mRecorder.setOutputFile(file.getAbsolutePath());            // 设置meidaRecorder的音频源是麦克风            mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);            // 设置文件音频的输出格式为MPEG_4            mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);            // 设置音频的编码格式为AAC            mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);            mRecorder.prepare();            mRecorder.start();            isPrepared = true;            Log.i("调用","开始调用");            if (mListener != null) {                mListener.wellPrepared();            }        } catch (IllegalStateException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    /**     * 获取声音的涨幅     * @param maxLevel     * @return     */    public int getVoiceLevel(int maxLevel) {        if (isPrepared) {            try {                return maxLevel * mRecorder.getMaxAmplitude() / 32768 + 1;            } catch (Exception e) {                e.printStackTrace();            }        }        return 1;    }    /**     * 资源释放     */    public void release() {        try {            if (mRecorder!=null){                mRecorder.stop();                mRecorder.release();                mRecorder = null;            }        }catch (Exception e){            e.printStackTrace();        }    }    public void cancel() {        release();        if (mCurrentFilePathString != null) {            File file = new File(mCurrentFilePathString);            file.delete();            mCurrentFilePathString = null;        }    }    /**     *判断是否有录音权限     * @return     */    public static boolean isHasPermission(){        bufferSizeInBytes = 0;        bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,                channelConfig, audioFormat);        AudioRecord audioRecord =  new AudioRecord(audioSource, sampleRateInHz,                channelConfig, audioFormat, bufferSizeInBytes);        try{            audioRecord.startRecording();        }catch (IllegalStateException e){            e.printStackTrace();        }        Log.i("录音权限","录音权限"+audioRecord.getRecordingState());        if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {            return false;        }        audioRecord.stop();        audioRecord.release();        audioRecord = null;        return true;    }    /**     * 获取当前语音的路径     * @return     */    public String getCurrentFilePath() {        return mCurrentFilePathString;    }    public interface AudioStageListener {        void wellPrepared();    }}
布局文件我就不贴了,开始调用录音之前<pre name="code" class="java">if (AudioManager.isHasPermission()){           down_talk.startRecord();   //开始录音}
判断一下就行了,第一次弄录音功能,代码都是网上找的,然后自己稍微改一下,这个判断其实你只要静态注册了录音权限的话都会返回true的,<span style="font-family: Arial, Helvetica, sans-serif;">这里的作用只是真正录音之前先</span>
<span style="font-family:Arial, Helvetica, sans-serif;">让用户允许录音权限而已,然后执行开始录音,因为第一次肯定会弹起录音权限对话框,所以当你手指离开的时候会调用</span><span style="font-family: Arial, Helvetica, sans-serif;">onTouchEvent的</span><span style="font-family: Arial, Helvetica, sans-serif;">MotionEvent.ACTION_UP事件,这地方</span>
<span style="font-family: Arial, Helvetica, sans-serif;">我判断了很多因素,基本上只会执行走正确流程的录音方式</span>
<pre name="code" class="java">

<pre name="code" class="java">





0 0
原创粉丝点击