Я прочитал похожие темы и не нашел ответа, который бы разрешил мою проблему.
Я пишу приложение с двумя различными 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 (), говорит о том, что несколько экземпляров не поддерживаются на некоторых устройствах. Таким образом, это может быть проблема, связанная с конкретным устройством.