2013-10-12 62 views
1

我正在開發一個Android語音識別應用程序,它利用了Android的AudioRecord類,除了這個缺陷外,一切都很順利。記錄器(AudioRecord的一個實例)在停止後不能再次重新啓動,並且導致GC_CONCURRENT跳入聲明垃圾程序,之後程序退出。我懷疑有一些內存泄漏,但無法擺脫它。爲什麼AudioRecord實例無法在事先停止後重新啓動

下面是我的代碼:

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

回答

1

你可能要檢討你的線程...

上主,它看起來像你這樣做 'recorder.start' & 'recorder.stop'

但是,控制在後臺線程解碼器與「decoder.start ..」,「decoder.end ..」

海事組織,你應該管理所有的控制甲基用於後臺線程的BOTH記錄器和編碼/解碼的ods不執行主線程的啓動/停止記錄,以及線程之間沒有任何通信/協調的背景下的開始/停止解碼。

它是一個更復雜的應用程序,它的工作原理,你可能想看看AudioBoo和在它控制的錄像機/編碼器的東西上面我提到(都在後臺,都在同一個線程)

看audioboo類'FLACRecorder'和'BooRecorder',並且關注這兩個類中的'start/stop'相關方法,以及它們如何與它們各自的線程進行交互。這與線程的使用完全不同,而不是代碼的作用。

OR

這是不太可能,國際海事組織,但有可能是在「獅身人面像」圖書館的一些問題,你是裝的是防止它被稱爲第二次沒有做明確的「卸載','重新加載'循環。您可以在那裏檢查論壇,以查看是否存在兩次調用lib而不卸載,重新加載的問題。

0

請注意,當你stop()你的AudioRecord對象,你也應該打電話release(),否則你將無法重新啓動它。

這可能不是您的整個問題,但肯定會造成問題。

相關問題