我正在编写一个应用程序,其中包含两个不同的MediaRecorder。一个用于噪声检测,另一个用于录音。我想做的是 - 当第一个MediaRecorder检测到噪声水平高于4.0(我使用Google的SoundMeter类进行检测)时,它会启动另一个MediaRecorder并开始录制。如果声音水平保持在4.0以下10秒钟,则停止录制并继续监听。所有这些都在AsynTask中完成,在无限while(true)循环中完成,只有在单击相应按钮时才会中断。
检测工作正常,但是当开始录制MediaRecorder时,会抛出IllegalStateException异常。
这是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();
处抛出。
我认为问题在于试图在这个while循环中完成所有操作的想法,但我还没有想出更好的实现前述目标的方法。此外,我尝试了不同的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"/>
更新:
我尝试通过创建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());
}
}
现在 IllegalStateException 是从 Recordinghandler 抛出的,位于
soundMeter.start();
这一行。
考虑到这个 soundMeter 对象基本上不再在循环中处理,应该排除 while 循环是罪魁祸首的可能性。我是否遗漏了什么?问题可能是同时有多个 MediaRecorder 工作所导致的吗?如您所见,现在抛出异常的是 SoundMeter,而不是 SoundRecorder。实际上,RecordingHandler 中无论我先放置哪个 start()
调用,都会抛出相同的 IllegalStateException。这个问题可能与Android: Two instances of Media recorder at same time相关,但遗憾的是该问题没有答案。
非常感谢您提供的任何进一步帮助!
MPEG_4
作为音频录制的输出格式? - tolgap