我正在开发一个Android语音识别应用程序,它使用Android的AudioRecord类,除了这个缺陷,一切顺利。停止后,记录器(AudioRecord的一个实例)无法再次重新启动,并导致GC_CONCURRENT跳转到声明垃圾,之后程序退出。我怀疑是否有一些内存泄漏,但无法理解它。
以下是我的代码:
package edu.cmu.pocketsphinx.demo;
import static edu.cmu.pocketsphinx.SphinxUtil.syncAssets;
import static edu.cmu.pocketsphinx.sphinxbase.setLogFile;
import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.ToggleButton;
import edu.cmu.pocketsphinx.Config;
import edu.cmu.pocketsphinx.Decoder;
import edu.cmu.pocketsphinx.Hypothesis;
public class PocketSphinxAndroidDemo extends Activity {
private class RecognitionTask
extends AsyncTask<AudioRecord, Void, Hypothesis> {
private final Decoder decoder;
public RecognitionTask() {
File root = null;
try {
root = syncAssets(getApplicationContext(), "models");
} catch (IOException e) {
throw new RuntimeException(e);
}
File rootLog = new File(root.getParentFile(), "pocketsphinx.log");
setLogFile(rootLog.getPath());
Config config = Decoder.defaultConfig();
config.setString("-lm", new File(root, "lm/hub4.5000.DMP").getPath());
config.setString("-hmm", new File(root, "hmm/hub4wsj_sc_8k").getPath());
config.setString("-dict",new File(root, "lm/hub4.5000.dic").getPath());
config.setString("-rawlogdir", root.getPath());
config.setString("-rawlogdir", root.getPath());
config.setFloat("-samprate", SAMPLE_RATE);
config.setInt("-maxhmmpf", 10000);
config.setBoolean("-backtrace", true);
config.setBoolean("-bestpath", false);
config.setBoolean("-remove_noise", false);
decoder = new Decoder(config);
}
protected Hypothesis doInBackground(AudioRecord... recorder) {
int nread;
short[] buf = new short[1024];
decoder.startUtt(null);
while ((nread = recorder[0].read(buf, 0, buf.length)) > 0){
decoder.processRaw(buf, nread, false, false);
}
decoder.endUtt();
return decoder.hyp();
}
protected void onPostExecute(Hypothesis hypothesis) {
if (null != hypothesis)
speechResult.append("\n" + hypothesis.getHypstr());
else
speechResult.append("\n<no speech>");
}
}
private static final int SAMPLE_RATE = 8000;
private static final String TAG="PocketSphinxAndroidDemo";
static {
System.loadLibrary("pocketsphinx_jni");
}
private TextView speechResult;
private AudioRecord recorder;
private RecognitionTask recTask;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
speechResult = (TextView) findViewById(R.id.SpeechResult);
recorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_RECOGNITION,
SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, 204800);
recTask = new RecognitionTask();
}
public void onToggleRecognition(View view) {
Log.i(TAG, "I in ToggleRecognition");
if (!(view instanceof ToggleButton))
return;
if (((ToggleButton) view).isChecked()) {
recorder.startRecording();
recTask.execute(recorder);
} else {
recorder.stop();
}
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("OnDestroy");
recorder.release();
}
}
答案 0 :(得分:1)
您可能想查看自己的帖子......
在Main上,它看起来像你做'recorder.start'和&amp; 'recorder.stop'
但是,您可以使用'decoder.start ..','decoder.end ..'来控制后台线程中的解码器。
IMO,您应该管理BOTH记录器的所有控制方法,并在后台线程中编码/解码,不从主线程执行启动/停止记录,并在后台启动/停止解码,而不需要线程之间的任何通信/协调。
这是一个更复杂的应用程序,它可以工作,您可能需要查看AudioBoo以及它控制上面提到的记录器/编码器的位置(全部在后台,所有在同一个线程中)
请参阅audioboo类'FLACRecorder'和'BooRecorder',并仔细查看这两个类中的'start / stop'相关方法,以及它们如何从各自的线程进行交互。线程的使用与代码的使用完全不同。
或强>
IMO的可能性要小得多,但是你正在加载的'sphinx'库中可能存在一些问题,这些问题会阻止它在没有明确的'卸载','重载'周期的情况下被第二次调用。您可以检查那里的论坛,以查看是否存在调用lib两次而无需卸载,重新加载的问题。
答案 1 :(得分:0)
请注意,当您stop()
AudioRecord
release()
对象时,您还应拨打{{1}},否则您将无法重新启动它。
这可能不是你的整个问题,但肯定会引起问题。