完美解决录音权限问题并附上录音代码
来源:互联网 发布:显示毫秒的网络时钟 编辑:程序博客网 时间: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
- 完美解决录音权限问题并附上录音代码
- 解决录音文件丢失问题
- iPhone 录音和播放(解决录音延迟问题)
- iphone录音和播放(解决录音延迟问题)
- iPhone 录音和播放(解决录音延迟问题)
- 录音
- 录音
- 录音
- 录音
- 录音
- 录音
- 录音
- 录音
- 录音
- 录音
- 科大讯飞 无录音权限
- 5.0系统录音权限
- android 权限录音权限检测
- Linux 网络命令
- Activity的4种launchMode
- linux 环境变量
- excel 常用使用技巧 二(数据筛选、条件格式、自动换行、自定义序列、自定义单位、冻结窗格)
- vim配置及插件安装管理(超级详细)
- 完美解决录音权限问题并附上录音代码
- chm 乱码解决办法
- IE浏览器模式和文档模式
- linux hostname 更改机器名
- usermod 命令使用说明
- linux chown 命令
- UIButton
- mysql学习笔记一(数据库管理控制)
- mysql学习笔记二(创建、删除、修改表)