Android使用AudioRecord遇到的问题与解决方法
16lz
2022-05-16
问题:
1、android判断是否禁用了录音权限
通过判断分贝值是否大于0,在代码中搜索 volume > 0
2、部分手机在调用 audioRecord.startRecording(); 和audioRecord.stop();方法时会抛出异常,例如联想手机
3、部分手机(例如联想)会抛出java.lang.IllegalStateException: startRecording() called on an uninitialized AudioRecord.
解决方法来源于:http://www.cnblogs.com/mythou/p/3241925.html
原因:
出现上面问题的原因是录音的硬件资源被申请了,但是没有释放,然后你再次申请资源,导致初始化失败。这里需要注意的是不仅仅需要调用Release()方法。还需要把AudioRecord对象置为null,否则还是释放失败。下面是Android 开发网上面的一个对于AudioRecord的释放说明。
Releases the native AudioRecord resources. The object can no longer be used and the reference should be set to null after a call to release()。
解决方法在代码中:
package com.androidleaf.audiorecord;import android.app.ProgressDialog;import android.content.Context;import android.media.AudioFormat;import android.media.AudioRecord;import android.media.MediaRecorder;import android.os.AsyncTask;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import com.hisun.phone.core.voice.Device;import com.todoroo.aacenc.AACEncoder;import com.todoroo.aacenc.AACToM4A;import java.io.DataInputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.RandomAccessFile;import app.jimu.zhiyu.activity.question.AnswerActivity;public class AudioRecordUtils {private final int audioSource = MediaRecorder.AudioSource.MIC;// 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025 private final int sampleRateInHz = 16000; // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道 private final int channelConfig = AudioFormat.CHANNEL_IN_STEREO; // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。 private final int audioFormat = AudioFormat.ENCODING_PCM_16BIT; private int inBufSize = 0;private AudioRecord audioRecord;private AACEncoder encoder = null;private ProgressDialog mProgressDialog = null;private boolean isRecord = false;private Context mContext;/** * 录制的音频文件名称 */private String mAudioRecordFileName;private static final int RECORDED_INIT_DELETE = 0;private static final int RECORDED_COMPLETED_DELETE = 1; private Handler mHandler;/** * 是否可以录音 true 可以录音 */private boolean recordEnable = false;public AudioRecordUtils(Context context,String audioRecordFileName, Handler handler){mContext = context;mAudioRecordFileName = audioRecordFileName; mHandler = handler;initAudioRecord();} /** * 初始化对象 */ private void initAudioRecord(){inBufSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, inBufSize);encoder = new AACEncoder();deleteAllFiles(RECORDED_INIT_DELETE);mProgressDialog = new ProgressDialog(mContext);mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);mProgressDialog.setCanceledOnTouchOutside(false);mProgressDialog.setCancelable(false);mProgressDialog.setTitle("提示");mProgressDialog.setMessage("正在保存录音,请耐心等候......");} /** * 开始录音 */public void startRecord(){new AudioRecordTask().execute();}/** * 暂停录音 */public void pauseRecord(){isRecord = false;}/** * 停止录音 */public void stopRecord(){new AudioEncoderTask().execute();}/** * 重新录制 */public void reRecord(){//重新录制时,删除录音文件夹中的全部文件deleteAllFiles(RECORDED_INIT_DELETE);} private void encodeAudio(){try {//读取录制的pcm音频文件 DataInputStream mDataInputStream = new DataInputStream(new FileInputStream( FileUtils.getPcmFilePath(mAudioRecordFileName)));byte[] b = new byte[(int) new File(FileUtils.getPcmFilePath(mAudioRecordFileName)).length()];mDataInputStream.read(b);//初始化编码配置encoder.init(32000, 2, sampleRateInHz, 16, FileUtils.getAAcFilePath(mAudioRecordFileName));//对二进制代码进行编码 encoder.encode(b); //编码完成 encoder.uninit(); //关闭流 mDataInputStream.close(); try { //将aac文件转码成m4a文件 new AACToM4A().convert(mContext, FileUtils.getAAcFilePath(mAudioRecordFileName), FileUtils.getM4aFilePath(mAudioRecordFileName)); } catch (IOException e) { Log.e("ERROR", "error converting", e); } deleteAllFiles(RECORDED_COMPLETED_DELETE);} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}class AudioRecordTask extends AsyncTask{@Overrideprotected Void doInBackground(Void... params) {// TODO Auto-generated method stubif(audioRecord == null){initAudioRecord();}RandomAccessFile mRandomAccessFile = null;try {mRandomAccessFile = new RandomAccessFile(new File(FileUtils.getPcmFilePath(mAudioRecordFileName)), "rw");byte[] b = new byte[inBufSize/4];//开始录制音频try{// 防止某些手机崩溃,例如联想audioRecord.startRecording();}catch (IllegalStateException e){e.printStackTrace();}//判断是否正在录制isRecord = true; long wait = 0; long maxWait = 10;while(isRecord){ //r是实际读取的数据长度,一般而言r会小于buffersize int r = audioRecord.read(b, 0, b.length); long v = 0; // 将 buffer 内容取出,进行平方和运算 for (int i = 0; i < b.length; i++) { v += b[i] * b[i]; } // 平方和除以数据总长度,得到音量大小。 double mean = v / (double) r; double volume = 10 * Math.log10(mean); wait++; if(wait > maxWait){ wait = 0; Log.d(this.getClass().getName(), "分贝值:" + volume + " " + (volume > 0));if(volume > 0){recordEnable = true;} Message msg = new Message(); msg.what = AnswerActivity.STATUS_PREPARE; Bundle bundle = new Bundle(); bundle.putDouble(Device.VOICE_AMPLITUDE, volume); msg.obj = bundle; mHandler.sendMessage(msg); }//向文件中追加内容mRandomAccessFile.seek(mRandomAccessFile.length());mRandomAccessFile.write(b, 0, b.length); }//停止录制try {// 防止某些手机崩溃,例如联想audioRecord.stop();// 彻底释放资源audioRecord.release();audioRecord = null;}catch (IllegalStateException e){e.printStackTrace();}mRandomAccessFile.close();} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}}class AudioEncoderTask extends AsyncTask{@Overrideprotected void onPreExecute() {// TODO Auto-generated method stubsuper.onPreExecute();if(mProgressDialog != null && !mProgressDialog.isShowing()){//mProgressDialog.show(); Message msg = new Message(); msg.what = 2; mHandler.sendMessage(msg);}}@Overrideprotected Long doInBackground(Void... params) {// TODO Auto-generated method stubencodeAudio();return null;}@Overrideprotected void onPostExecute(Long result) {// TODO Auto-generated method stubsuper.onPostExecute(result);if(mProgressDialog.isShowing()){mProgressDialog.cancel();mProgressDialog.dismiss();}}}/** * 清空音频录制文件夹中的所有文件 * @param isRecorded */public void deleteAllFiles(int isRecorded){ File[] files = new File(FileUtils.getAudioRecordFilePath()).listFiles();switch (isRecorded) {case RECORDED_INIT_DELETE:for(File file: files){ file.delete(); }break;case RECORDED_COMPLETED_DELETE: for(File file: files){ if(!file.getName().equals(mAudioRecordFileName + Constants.M4A_SUFFIX)){ file.delete(); } }break;default:break;}}public boolean isRecordEnable() {return recordEnable;}}
更多相关文章
- Android实现为GridView添加边框效果
- android binder机制之二 Service Manager
- android中使用properties文件配置
- AIDL笔记
- Android(安卓)开发环境准备(Ubuntu)
- 使用本地仓库实现最新版ReactNative集成Android
- Android(安卓)系统分区分析
- ViewPager实现QQ主界面,ViewFlipper实现某些新闻应用,自动播放,很
- NPM 和webpack 的基础使用