2013-09-06 5 views
13

Mam usługę, w której wielokrotnie uruchamiam detektora rozpoznawania mowy, aby umożliwić sesję otwartą dla użytkownika . Klasa zajmuje się również problemem w Jelly Bean, w której generowany jest ERROR_SPEECH_TIMEOUT, jeśli w ciągu 5 sekund nie słychać mowy. Zasadniczo to działa. Jednak jeśli wielokrotnie wywołuję rozpoznawcę.startListening (recogerIntent), to po cichu się nie udaje, o czym świadczy fakt, że funkcja onBeginningOfSpeech() nigdy nie jest wywoływana w tym przypadku. Teraz JEŚLI po prostu nie mówię w ogóle mój handler upływu czasu Jelly Bean ponownie uruchomi słuchacza za każdym razem. Wygląda na to, że kończy się niepowodzeniem po wywołaniu funkcji onResults(), ponieważ słychać było WAS. Po wywołaniu funkcji onResults() wywoływana jest właściwość rozpoznawania.startListening (recognitionerIntent), ale tak jak powiedziałem, nic się nie dzieje. Gdy się zawiedzie, jest losowe i nie ma nic w Logcat, aby wskazać, co to jest problem. Po prostu nie wiem, co jeszcze spróbować. Mam nadzieję, że jeden z was Android eksperci rozpoznawania mowy tam nie widział tego wcześniej ...Wykrywanie mowy w systemie Android: powtarzające się wywoływanie funkcji SpeechRecognizer.startListening() kończy się niepowodzeniem na JB 4.1.2

Minimum: 2,2 docelowa: Testowanie na JB: Android 4.1.2


WIĘCEJ INFO (01/11/13) Aktualizacja 4.3 do mojego HTC One zdecydowanie rozwiązała ten problem. Poniższa usługa rozpoznawania mowy jest teraz niezawodna. Dokładna jest teraz: &. Pracowałem przez co najmniej kilka minut bez błędu. Jeśli chodzi o 4.1.2, to przed aktualizacją do wersji 4.3 wydawało mi się, że działa ona lepiej (czy Google zmieniło coś na końcu?) ... nie wiem, ale nadal brakowałoby niektórych słów wypowiedzianych i od czasu do czasu bezbłędnie, po prostu przestań słuchać (onBeginningOfSpeech() nigdy nie jest wywoływany w tym przypadku). Przypuszczam, że będę musiał ostrzec moich użytkowników o Androidzie 4.1.2 w odniesieniu do tego problemu, ponieważ poszedłem tak daleko, jak mogę w moim kodzie.

WIĘCEJ INFORMACJI (09-17-13) Podobno do HTC dołączy pod koniec września aktualizacja Androida (4.3) (http://www.ubergizmo.com/2013/09/htc-one-to-receive-android-4-3-jelly-bean-update-this-september/). Miejmy nadzieję, że rozwiąże to problem na tym urządzeniu. Problem pozostaje jednak dla moich użytkowników aplikacji z Androidem 4.1.2 i zatrzymanych na tę wersję na jakiś czas. Nadal nie wiem, co zrobić w tych przypadkach i mam nadzieję, że jest to TYLKO wersja Androida z tym problemem. Czy istnieje sposób, aby dowiedzieć się, ile urządzeń pracuje 4.1.2?

WIĘCEJ INFORMACJI (09-15-13) W tym wpisie tutaj: Google voice recognizer doesn't starts on Android 4.x. Autor stwierdza, że ​​widzi ten problem na swoim telefonie HTC One. Mam też HTC, na którym widzę ten problem (Android 4.1.2). Zastanawiam się, czy jest to unikalne dla HTC jeden? (lub dowolne urządzenie z systemem Android 4.1.2) - Nie mogę potwierdzić, ponieważ jest to trudne do przetestowania na wszystkich najnowszych urządzeniach z JB. Autor dalej stwierdza, że ​​jego Nexxus z 4.2.2 działa dobrze. Czy ktoś może mi powiedzieć, na jakim urządzeniu widzą ten problem?

WIĘCEJ INFORMACJI (9-08-13) Aby potwierdzić, że nie ma problemu z moim kodem, przetestowałem to również na Android 2.3.3 i mogłem zadzwonić onResult()> startListening() 25 razy w wiersz. Podczas kierowania na Androida 4.1.2 nigdy nie uda mi się uzyskać 3 lub 4 połączeń. Nie mogę uwierzyć, że nikt inny nie wpadł na ten problem?

public class VoiceRecogService extends Service 
{ 
    protected AudioManager mAudioManager; 
    protected SpeechRecognizer mSpeechRecognizer; 
    protected Intent mSpeechRecognizerIntent; 
    protected RecognitionListener mSpeechRecognizerListner; 
    //protected final Messenger mServerMessenger = new Messenger(new IncomingHandler(this)); 

    protected volatile boolean mIsListening; 
    protected volatile boolean mIsCountDownOn; 

    static final int MSG_RECOGNIZER_START_LISTENING = 1; 
    static final int MSG_RECOGNIZER_CANCEL = 2; 

    private int mBindFlag; 
    private Messenger mServiceMessenger; 

    private Context m_ctx; 

    private Handler mHandler = new Handler(); 
    //private boolean m_bReadyForSpeechReceived = false; 

    @Override 
    public void onCreate() 
    { 
     super.onCreate(); 
     m_ctx = this; 

     mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 

     //do not mute beep when speech listening first kicks off 
     Log.d("TESTING: SPEECH SERVICE: CALL START", "onCreate()"); 
     startListening(false); 
    } 
    private void startListening(boolean bMuteSound){ 
     Log.d("TESTING: SPEECH SERVICE: startListening()", mIsListening? "true":"false"); 
     if (bMuteSound==true && Build.VERSION.SDK_INT >= 16)//Build.VERSION_CODES.JELLY_BEAN) 
     { 
      // turn off beep sound 
      mAudioManager.setStreamMute(AudioManager.STREAM_SYSTEM, true); 
     } 
     if (!mIsListening) 
     { 
      //mSpeechRecognizer.startListening(mSpeechRecognizerIntent); 
      recognizeSpeechDirectly(); 
      mIsListening = true; 

     } 
    } 

    ///////////////////////////////////////////////////////////////////////// 
    /** 
    * lazy initialize the speech recognizer 
    */ 
    private SpeechRecognizer getSpeechRecognizer() 
    { 
     if (mSpeechRecognizer == null) 
     { 
      mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(m_ctx); 
     } 
     return mSpeechRecognizer; 
    } 
    private RecognitionListener getSpeechRecognizerListner() 
    { 
     if (mSpeechRecognizerListner == null) 
     { 
      mSpeechRecognizerListner = new SpeechRecognitionListener(); 
     } 
     return mSpeechRecognizerListner; 
    } 

    private void recognizeSpeechDirectly() 
    { 
     Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 
     recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); 
     // accept partial results if they come 
     recognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true); 

     recognizeSpeechDirectly(m_ctx,recognizerIntent, getSpeechRecognizerListner(), getSpeechRecognizer()); 
    } 
    public static void recognizeSpeechDirectly(Context context, 
               Intent recognizerIntent, 
               RecognitionListener listener, 
               SpeechRecognizer recognizer) 
    { 
     //need to have a calling package for it to work 
     if (!recognizerIntent.hasExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE)) 
     { 
      recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, "com.dummy"); 
     } 

     recognizer.setRecognitionListener(listener); 
     recognizer.startListening(recognizerIntent); 
    } 
    //////////////////////////////////////////////////////////////////////////// 

    public void stop() 
    { 
     if (getSpeechRecognizer() != null) 
     { 
      getSpeechRecognizer().stopListening(); 
      getSpeechRecognizer().cancel(); 
      getSpeechRecognizer().destroy(); 

      mIsListening = false; 
      if (Build.VERSION.SDK_INT >= 16);//Build.VERSION_CODES.JELLY_BEAN) 
       mAudioManager.setStreamMute(AudioManager.STREAM_SYSTEM, false); 
     } 
    } 

    // Count down timer for Jelly Bean work around 
    protected CountDownTimer mNoSpeechCountDown = new CountDownTimer(5000, 5000) 
    { 
     @Override 
     public void onTick(long millisUntilFinished) 
     { 
      // TODO Auto-generated method stub 
     } 
     @Override 
     public void onFinish() 
     { 
      mIsCountDownOn = false; 
      Log.d("TESTING: SPEECH SERVICE: CALL START", "onFinish()"); 
      startListening(true); 
     } 
    }; 

    @Override 
    public void onDestroy() 
    { 
     super.onDestroy(); 

     if (mIsCountDownOn) 
     { 
      mNoSpeechCountDown.cancel(); 
     } 
     if (mSpeechRecognizer != null) 
     { 
      mSpeechRecognizer.destroy(); 
     } 
    } 

    protected class SpeechRecognitionListener implements RecognitionListener 
    { 
     @Override 
     public void onReadyForSpeech(Bundle params) 
     { 
      if (Build.VERSION.SDK_INT >= 16)//Build.VERSION_CODES.JELLY_BEAN) 
      { 
       mIsCountDownOn = true; 
       mNoSpeechCountDown.start(); 
      } 
      Log.d("TESTING: SPEECH SERVICE", "onReadyForSpeech"); 
     } 
     @Override 
     public void onBeginningOfSpeech() 
     { 
      // speech input will be processed, so there is no need for count down anymore 
      if (mIsCountDownOn) 
      { 
       mIsCountDownOn = false; 
       mNoSpeechCountDown.cancel(); 
      }    
     } 
     @Override 
     public void onEndOfSpeech() 
     { 
      Log.d("TESTING: SPEECH SERVICE", "onEndOfSpeech"); 
     } 

     @Override 
     public void onBufferReceived(byte[] buffer) 
     { 
      //Log.d("TESTING: SPEECH SERVICE", buffer + new String(new byte[] {0x63})); 
     } 

     @Override 
     public void onError(int error) 
     { 
      if ((error == SpeechRecognizer.ERROR_NO_MATCH) 
        || (error == SpeechRecognizer.ERROR_SPEECH_TIMEOUT)){ 
       if (mIsCountDownOn) 
       { 
        mIsCountDownOn = false; 
        mNoSpeechCountDown.cancel(); 
       } 
       mIsListening = false; 
       Log.d("TESTING: SPEECH SERVICE: CALL START", "onError()"); 
       startListening(true); 
      } 
     } 

     @Override 
     public void onEvent(int eventType, Bundle params) 
     { 

     } 

     @Override 
     public void onPartialResults(Bundle partialResults) 
     { 

     } 

     @Override 
     public void onResults(Bundle results) 
     { 
      //String str = new String(); 
      //Log.d(TAG, "onResults " + results); 
      ArrayList data = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); 

      //if(data.size() >=1){ 
      // //check for save it: 
      //} 

      for (int i = 0; i < data.size(); i++) 
      { 
       Log.d("TESTING: SPEECH SERVICE", (String)data.get(i)); 
      } 

      //if no "save it" somewhere in there, then continue: 
      if (mIsCountDownOn) 
      { 
       mIsCountDownOn = false; 
      } 
      mIsListening = false; 
      Log.d("TESTING: SPEECH SERVICE: CALL START", "onResults()"); 

      startListening(true); 
     } 
     @Override 
     public void onRmsChanged(float rmsdB) 
     { 

     } 
    } 
    @Override 
    public IBinder onBind(Intent arg0) { 
     // TODO Auto-generated method stub 
     return null; 
    } 
} 
+1

ktoś ma jakieś pomysły na ten temat? całkowicie utknąłem tutaj ... – Mike6679

+0

Mam DROID RAZR HD z wersją 4.1.2 i już mam taki sam problem. –

Odpowiedz

1

spróbuje użyć pojedynczą instancję z SpeechRecognizer, nie ma potrzeby, aby odtworzyć go na stop() metody. Zadzwoń pod numer getSpeechRecognizer() w onCreate() i zapomnij o tym. Ale nie zapomnij zniszczyć metodą onDestroy().

+0

To jest właśnie powód, dla którego mi się nie udało po 3 lub 4 cyklach. Po zniszczeniu rozpoznawacza i ponownym jego odtworzeniu za każdym razem, gdy działa niezawodnie. –

1

Aby obejść ten problem, użyłem CountDownTimer do wywoływania przyrostowego cancel i startListening.

_timer = new CountDownTimer(300000000, 1000){ 
    @Override 
    public void onTick(long millisUntilFinished){ 
     if(!_processingSpeech){ 
      _mSpeechRecognizer.cancel(); 
      _mSpeechRecognizer.startListening(_mSpeechRecognizerIntent); 
     } 
    } 

    @Override 
    public void onFinish(){ 
     setUpTimer(); 
    } 
}; 
_processingSpeech = false; 
_timer.start(); 

użyłem logiczną processingSpeech w metodach RecognitionListener, aby upewnić się, że nie anulować i ponownie uruchomić, a ja trafiałem/wejście przetwarzania.

Daj mi znać, jeśli to Ci pomoże lub potrzebujesz więcej informacji. Powodzenia!

+0

To nie działa dla mnie. Utrzymuje kanał odsłuchowy otwarty, tak, jednak odkrywam, że wiele słów, o których mówię, nie jest w ogóle rozpoznawanych, więc dokładność bardzo cierpi. Prawdopodobnie z powodu anulowania i ponownego uruchamiania rozpoznawania mowy w każdej sekundzie. Nigdy wcześniej nie miałem problemu z dokładnością w wersjach Androida <4.1.2. Być może nie implementuję twojego rozwiązania poprawnie ... w którym momencie ustawiasz _processingSpeech = true? - Robię to w onBeginningOfSpeech(), a następnie po przetworzeniu bieżącego fragmentu mowy ustawię _processingSpeech = false. – Mike6679

+0

Wierzę, że ustawiłem go na false po onResults i po onError i ustawiłem go na true w onBegginingOfSpeech. Możesz spróbować zalogować się przy każdej metodzie w SpeechRecognitionListener, aby zobaczyć, jaka jest zmienna i czy jest ona resetowana podczas próby przetworzenia danych wejściowych. Słyszałem również, że na początku wyniki są dokładne na poziomie 70%. –

+0

Tak, mam dokładnie to samo. Kod konsekwentnie pomija słowa. Twoja praca wymaga poważnego trafienia, czegoś, czego po prostu nie mogę poświęcić. Dostaję co najmniej 90 - 95% dokładności z moim kodem działającym w wersjach Androida <4.1.2. Twój kod wydaje się bardziej skłonny do pominięcia pojedynczych słów w przeciwieństwie do fraz i myślę, że jest to spowodowane tym, że restartujesz słuchanie * co * sekundy zamiast tylko w onError() lubOnResults(). Wszelkie przemyślenia na temat poprawy dokładności? – Mike6679

7

Jestem na Androidzie 4.4 KitKat na Nexusie 5 i ma ten sam problem. Myślę, że to prawdopodobnie błąd Androida, ponieważ nie widziałem nikogo, kto ma czyste rozwiązanie.
To rozwiązanie jest podobne do rozwiązania Andrew_CS, ale myślę, że to faktycznie pozwala na lepsze rozpoznanie. Rozwiązanie Andrews stale uruchamia i zatrzymuje urządzenie rozpoznające, a Ty musisz śledzić stan rzeczy, na przykład podczas przetwarzania mowy. To nowe rozwiązanie/praca w zasadzie to robi:

  • Po wywołaniu funkcji onResults i przetworzeniu wyników, uruchamiamy zegar.
  • Jeśli wszystko działa poprawnie, zostanie wywołany program OnStudiesForSpeech, a my możemy anulować nasz licznik czasu.
  • Jeśli coś nie działa poprawnie, nasz zegar się kończy, a my uruchomimy ponownie rozpoznawanie mowy i ponownie uruchomimy zegar.
  • Upewnij się również, że anulujesz timer w swojej metodzie OnDestroy.

Proszę dać mi znać, jeśli znajdziesz jeszcze lepszy sposób, ale na razie wygląda to dobrze. Jeśli uda nam się udowodnić, że jest to błąd Androida, bardzo chciałbym, aby ktoś przesłał go do Google.

  @Override 
     public void onReadyForSpeech(Bundle params) { 
      Log.d("Speech", "onReadyForSpeech: Cancel Timer"); 
      if(mTimer != null) { 
       mTimer.cancel(); 
      } 
     } 


     @Override 
     public void onResults(Bundle results) { 
      //If the timer is available, cancel it so it doesn't interrupt our result processing 
      if(mTimer != null){ 
       mTimer.cancel(); 
      } 
      Log.d("Speech", "onResults"); 
      //Start processing data 
      ArrayList<String> strlist = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); 
      for (int i = 0; i < strlist.size();i++) { 
       Log.d("Speech", "YOU SAID: " + strlist.get(i)); 
      } 
      //Start listening again 
      Log.d("Speech", "onResults: Start Listening"); 
      mSpeechRecognizer.startListening(mRecognizerIntent); 
      //Start a timer in case OnReadyForSpeech is never called back (Android Bug?) 
      Log.d("Speech", "onResults: Start a timer"); 
      if(mTimer == null) { 
       mTimer = new CountDownTimer(2000, 500) { 
        @Override 
        public void onTick(long l) { 
        } 

        @Override 
        public void onFinish() { 
         Log.d("Speech", "Timer.onFinish: Timer Finished, Restart recognizer"); 
         mSpeechRecognizer.cancel(); 
         mSpeechRecognizer.startListening(mRecognizerIntent); 
        } 
       }; 
      } 
      mTimer.start(); 
     } 
+0

Tutaj jest problem, który został zarejestrowany w Google, które podobałoby się niektórym gwiazdom, więc pewnego dnia zostanie naprawiony. https://code.google.com/p/android/issues/detail?id=179293 – Matthew

2

Można użyć:

intent.putExtra("android.speech.extra.DICTATION_MODE", true); 

Ten kod make serwis słuchać długo.

Powiązane problemy