MediaRecorder.start () бросает IllegalStateException

Я прочитал похожие темы и не нашел ответа, который бы разрешил мою проблему.

Я пишу приложение с двумя различными MediaRecorders. Один для обнаружения шума и еще один для записи. То, что я хочу сделать, – когда первый MediaRecorder обнаруживает уровни шума выше 4.0 (я использую класс SoundMeter от Google), он инициирует другой MediaRecorder и начнет запись. Если уровни звука остаются ниже 4.0 в течение 10 секунд, прекратите запись и продолжайте слушать. Все это делается в AsynTask, в бесконечном цикле while (true), который будет разбит, только если нажать соответствующую кнопку.

Обнаружение работает нормально, но исключение IllegalStateException вызывается, когда на запись MediaRecorder вызывается start ().

Вот AsyncTask:

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; } } 

И вот SoundRecorder:

 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; } } } 

Исключение mRecorder.start(); на mRecorder.start(); ,

Я думаю, что проблема заключается в идее делать все в этом цикле, но я не придумал лучшего представления о достижении намеченной цели. Кроме того, я пробовал разные OutputFormats и AudioEncoders без успеха. (Ссылка на https://stackoverflow.com/a/23065021/1826152 )

Другим примечанием, которое может быть полезно, является тот факт, что файл фактически создан в каталоге sdcard.

Телефон, который я использую для разработки, – Nexus 5. Разрешения в манифесте android следующие:

 <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

Обновить:

Прямо сейчас я попытался удалить операции SoundRecorder из цикла while, создав RecordingHandler. Новый код для doInBackground () выглядит следующим образом:

  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; } в  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 следующий:

 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()); } } в 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()); } } 

Теперь исключение IllegalStateException выбрано из Recordinghandler – на строке soundMeter.start(); , Учитывая, что этот объект soundMeter в основном не обрабатывается в цикле, должен устранить хотя бы то, что цикл while был виновником. Есть что-то, чего я не хватает? Может ли проблема заключаться в одновременном использовании нескольких MediaRecorders? Как вы можете видеть, теперь SoundMeter, а не SoundRecorder, бросает исключение. Фактически – какой бы вызов start() я помещал сначала в RecordingHandler, выбрасывает одно и то же исключение IllegalStateException.

Вопрос может быть связан с Android: два экземпляра медиа-рекордера одновременно , у которых, к сожалению, нет ответов.

Любая дополнительная помощь будет принята с благодарностью!

Ладно, похоже, я взломал проблему. Кажется, что проблема заключается в одновременном использовании нескольких экземпляров MediaRecorder. То, что я сделал, было то, что теперь я не использую отдельные классы для обнаружения и записи, так что теперь записывающее устройство делает свое собственное обнаружение.

Сначала я запускаю встроенный SoundMeter, который прослушивает до тех пор, пока он не получит вход по уровню 4.0. Затем я останавливаю исходный SoundMeter и создаю новый SoundMeter (с другим выходным каталогом), который начинает запись и запись до тех пор, пока уровни не будут ниже 4.0 для apprixamtely 10 секунд. Затем второй SoundMeter останавливается, и фоновая задача может снова запустить исходный SoundMeter.

Вот код, который решил мою проблему, AsyncTask:

  protected Object doInBackground(Object[] params) { int i = 0; soundMeter = new SoundMeter(); RecordingHandler recordingHandler = null; try { soundMeter.start("/dev/null"); } 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){ soundMeter.stop(); recordingHandler = new RecordingHandler(deviceId); currentlyRecording = true; recordingHandler.run(); } else if(!currentlyRecording && !soundMeter.isRunning()){ try { soundMeter.start("/dev/null"); } catch (IOException e) { Log.e("error", e.getMessage()); } } } return null; } } в  protected Object doInBackground(Object[] params) { int i = 0; soundMeter = new SoundMeter(); RecordingHandler recordingHandler = null; try { soundMeter.start("/dev/null"); } 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){ soundMeter.stop(); recordingHandler = new RecordingHandler(deviceId); currentlyRecording = true; recordingHandler.run(); } else if(!currentlyRecording && !soundMeter.isRunning()){ try { soundMeter.start("/dev/null"); } catch (IOException e) { Log.e("error", e.getMessage()); } } } return null; } } 

И RecordingHandler.run ():

 @Override public void run() { int i = 0; try { soundMeter.start(getFileNameString()); } catch (IOException e) { Log.e("error", e.getMessage()); } while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { Log.e("error", e.getMessage()); } if(isKilled){ break; } if(soundMeter.getAmplitudeEMA() < 4.0){ i++; if(i > 10){ break; } } else { i = 0; } } soundMeter.stop(); EavesDrop.currentlyRecording = false; } в @Override public void run() { int i = 0; try { soundMeter.start(getFileNameString()); } catch (IOException e) { Log.e("error", e.getMessage()); } while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { Log.e("error", e.getMessage()); } if(isKilled){ break; } if(soundMeter.getAmplitudeEMA() < 4.0){ i++; if(i > 10){ break; } } else { i = 0; } } soundMeter.stop(); EavesDrop.currentlyRecording = false; } 

Документация по адресу http://developer.android.com/reference/android/media/MediaRecorder.html , по документации метода release (), говорит о том, что несколько экземпляров не поддерживаются на некоторых устройствах. Таким образом, это может быть проблема, связанная с конкретным устройством.