MediaRecorder.start() throwing IllegalStateException
我读过类似的文章,但没有找到可以解决我的问题的答案。
我正在用2个不同的MediaRecorder编写一个应用程序。一个用于噪声检测,另一个用于记录。我想做的是-当第一个MediaRecorder检测到高于4.0的噪声水平时(我正在使用Google的SoundMeter类进行检测),它将启动另一个MediaRecorder并开始录制。如果声级在4.0以下保持10秒钟,请停止录音并继续收听。所有这一切都是在AsynTask中完成的,而无休止的while(true)循环只有在单击相应按钮时才会中断。
检测正常,但是在记录MediaRecorder上调用start()时抛出IllegalStateException。
这是AsyncTask:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | private class NoiseDetection extends AsyncTask { double currentSoundInputLevel; @Override protected Object doInBackground(Object[] params) { int i = 0; soundMeter = new SoundMeter(); try { soundMeter.start(); } catch (IOException e) { Log.e("error", e.getMessage()); } while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { Log.e("error", e.getMessage()); } if(isCancelled()){ soundMeter.stop(); if(currentlyRecording) { soundRecorder.stop(); } break; } currentSoundInputLevel = soundMeter.getAmplitudeEMA(); if(!currentlyRecording && currentSoundInputLevel > 4.0){ soundRecorder = new SoundRecorder(); try { soundRecorder.start(getFileNameString()); currentlyRecording = true; } catch (IOException e) { Log.e("error", e.getMessage()); } } else if(currentlyRecording && currentSoundInputLevel < 4.0) { i++; if(i > 10) { soundRecorder.stop(); } } } return null; } } |
这是录音机:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class SoundRecorder { private MediaRecorder mRecorder = null; public void start(String fileName) throws IOException { if (mRecorder == null) { mRecorder = new MediaRecorder(); mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); mRecorder.setOutputFile(Environment.getExternalStorageDirectory().getPath() +"/" + fileName); mRecorder.prepare(); mRecorder.start(); } } public void stop() { if (mRecorder != null) { mRecorder.stop(); mRecorder.release(); mRecorder = null; } } } |
在
我认为问题在于在while循环中进行所有操作的想法,但是我还没有提出实现上述目标的更好的想法。
另外,我尝试了不同的OutputFormats和AudioEncoders,但没有成功。 (参考https://stackoverflow.com/a/23065021/1826152)
另一个可能有用的注释是,该文件实际上是在sdcard目录中创建的。
我用于开发的手机是Nexus5。Android清单中的权限如下:
1 2 | <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> |
更新:
现在,我尝试通过创建RecordingHandler从while循环中删除SoundRecorder操作。 doInBackground()的新代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | protected Object doInBackground(Object[] params) { int i = 0; soundMeter = new SoundMeter(); RecordingHandler recordingHandler = null; try { soundMeter.start(); } catch (IOException e) { Log.e("error", e.getMessage()); } while(true){ if(isCancelled()){ soundMeter.stop(); if(currentlyRecording && recordingHandler != null){ recordingHandler.kill(); } break; } try { Thread.sleep(1000); } catch (InterruptedException e) { Log.e("error", e.getMessage()); } if(!currentlyRecording && soundMeter.getAmplitudeEMA() > 4.0){ recordingHandler = new RecordingHandler(deviceId); currentlyRecording = true; recordingHandler.run(); } } return null; } |
和RecordingHandler本身是以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | public class RecordingHandler implements Runnable { SoundRecorder soundRecorder; SoundMeter soundMeter; String deviceID; boolean isKilled = false; public RecordingHandler(String deviceID){ this.soundRecorder = new SoundRecorder(); this.soundMeter = new SoundMeter(); this.deviceID = deviceID; } @Override public void run() { int i = 0; try { soundMeter.start(); soundRecorder.start(getFileNameString()); } catch (IOException e) { Log.e("error", e.getMessage()); } while(true){ if(isKilled){ break; } if(soundMeter.getAmplitudeEMA() < 4.0){ i++; if(i > 10){ break; } } else { i = 0; } } soundMeter.stop(); soundRecorder.stop(); EavesDrop.currentlyRecording = false; } public void kill(){ this.isKilled = true; } private String getFileNameString() { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); return deviceID +"_" + sdf.format(new Date()); } } |
现在,从Recordinghandler抛出IllegalStateException-在行
考虑到此soundMeter对象基本上不再在循环中处理,因此应消除while循环是罪魁祸首的原因。有什么我想念的吗?问题可能出在多个MediaRecorder同时工作吗?如您所见,引发异常的是SoundMeter,而不是SoundRecorder。实际上,无论我首先在RecordingHandler中放置的哪个
该问题可能与Android有关:一次同时有两个Media Recorder实例,不幸的是没有答案。
我们将不胜感激!