【发布时间】:2015-02-15 23:06:52
【问题描述】:
我已经阅读了类似的主题,但没有找到可以解决我的问题的答案。
我正在编写一个包含 2 个不同 MediaRecorder 的应用程序。一个用于噪声检测,另一个用于记录。我想要做的是 - 当第一个 MediaRecorder 检测到高于 4.0 的噪音水平(我使用 Google 的 SoundMeter 类进行检测)时,它将启动另一个 MediaRecorder 并开始录制。如果声级低于 4.0 持续 10 秒,则停止录制并继续收听。所有这些都是在一个 AsynTask 中完成的,在一个无限的 while(true) 循环中,只有当相应的按钮被点击时才会被破坏。
检测工作正常,但是在录制 MediaRecorder 上调用 start() 时会引发 IllegalStateException。
这里是异步任务:
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;
}
}
这是录音机:
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(); 上抛出异常。
我认为问题在于在这个 while 循环中做所有事情的想法,但我还没有想出更好的想法来实现上述目标。 另外,我尝试了不同的 OutputFormats 和 AudioEncoders,但没有成功。 (参考https://stackoverflow.com/a/23065021/1826152)
另一个可能有用的注意事项是,该文件实际上是在 sdcard 目录中创建的。
我用于开发的手机是 Nexus 5。android manifest 中的权限如下:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
更新:
现在我试图通过创建一个 RecordingHandler 从 while 循环中删除 SoundRecorder 操作。 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;
}
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());
}
}
现在从 Recordinghandler 抛出 IllegalStateException - 在行 soundMeter.start(); 上。
考虑到这个 soundMeter 对象基本上不再在循环中处理,应该消除 while 循环是罪魁祸首的想法。有什么我想念的吗? 问题可能在于多个 MediaRecorder 同时工作吗? 如您所见,现在是 SoundMeter,而不是 SoundRecorder 引发了异常。实际上 - 无论我在 RecordingHandler 中首先放置的 start() 调用,都会引发相同的 IllegalStateException。
这个问题可能与Android: Two instances of Media recorder at same time有关,很遗憾没有答案。
任何进一步的帮助将不胜感激!
【问题讨论】:
-
我只是好奇,缰绳,但你为什么使用
MPEG_4作为录音的输出格式? -
为什么不呢?我也尝试过 THREE_GPP。我应该出于某种原因使用其他东西吗?
-
循环启动和停止媒体记录器不是一个好方法。如果你正确地看这张图developer.android.com/reference/android/media/…,你就会知道为什么
-
我有点意识到这一点,但正如问题中所述 - 我还没有想出更好的解决方案来实现我所追求的目标。我希望检测仅在有噪音时继续运行并记录。把它想象成一个窃听设备。欢迎就如何更好地实现这一目标提出任何建议。另外,如果我每次开始录制时都创建一个新的 SoundRecorder 实例,这到底会是什么问题? @MurtazaHussain
标签: java android android-asynctask mediarecorder android-mediarecorder