Android Speech Recognition: Calling SpeechRecognizer.startListening () again does not work on JB 4.1.2

I have a service in which I start listening to a voice alert several times, so I can have an open session so that the user can talk. The class also handles the problem in Bean Jelly, where ERROR_SPEECH_TIMEOUT is called if speech is not heard in 5 seconds. So basically it works. However, if I repeatedly call the recognition function .startListening (recognition element), it silently fails, as evidenced by the fact that onBeginningOfSpeech () is never called in this case. Now, if I just don’t speak at all, my timewelly Bean handler will restart the listener every time without fail. It seems to only fail after onResults () is called because the speech WAS heard. After calling onResults (), recognition recognition .startListening (identizerIntent) is definitely called, but, as I said, nothing happens. When it fails, it is random, and there is nothing in Logcat to indicate what the problem is. I just don't know what else to try. I hope one of you, speech recognition specialists in Android have seen this before ...

Minimum: 2.2 Purpose: Testing on JB: Android 4.1.2




FURTHER INFORMATION (11-01-13) Update 4.3 for my HTC One definitely solved this problem. Now my speech recognition service is reliable and accurate. I missed at least a few minutes without errors. As for 4.1.2, before I upgraded to 4.3, it seemed to work better (did Google change anything at their end?) ... I don’t know, but he would still have missed some words spoken and sometimes without errors, just stop listening (onBeginningOfSpeech () in this case is never called). I suppose I just need to warn my users about Android 4.1.2 regarding this issue, because I got to my code.

FURTHER INFORMATION (09-17-13) Presumably, at the end of September, HTC will update Android (4.3) ( http://www.ubergizmo.com/2013/09/htc-one-to-receive-android-4-3 -jelly-bean-update-this-september / ). We hope that this problem will be fixed on this device. The problem remains, although for my users, applications that are running Android 4.1.2 have been stuck in this version for some time. I still don’t know what to do in these cases, and I hope this is the only version of Android with this problem. Is there a way to find out how many devices are running 4.1.2?

MORE INFO (09-15-13) In this post here: Google voice recognizer does not start on Android 4.x. The author’s statement said that he sees this issue on his HTC. I also have HTC, which I see in this problem (Android 4.1.2). I wonder if this is unique to HTC? (or any device running Android 4.1.2). I can’t confirm, since it is difficult to verify on all the latest devices running JB. The author further claims that his Nexxus with 4.2.2 works fine. Can someone tell me on which device they see this problem?

FURTHER INFORMATION (9-08-13) Just to confirm that there are no problems with my code, I also tested this on Android 2.3.3 and I managed to call onResult ()> startListening () 25 times in a row. When targeting Android 4.1.2, I can never go through 3 or 4 calls. I can’t believe that no one else has encountered this 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; } } 
+13
android listener service speech-recognition
Sep 06 '13 at 4:45
source share
4 answers

I'm on Android 4.4 KitKat on a Nexus 5, and it has the same problem. I think this is more likely an Android bug because I have not seen anyone with a clean solution.
This solution is similar to Andrew_CS solution, but I think it actually allows for better recognition. Andrews solution constantly starts and stops the recognizer, and you have to monitor the state of things, for example, if you process speech or not. This new / work -around solution basically does the following:

  • As soon as onResults is called and our results are processed, we start the timer.
  • If everything works fine, onReadyForSpeech will be called, and we can cancel our timer.
  • If something does not work properly, our timer ends, and we restart the speech recognizer and start the timer again.
  • Make sure you also cancel the timer in the OnDestroy method.

Please let me know if you find an even better way, but right now it works very well. If we really prove that this is an Android bug, I would like someone to submit it to 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(); } 
+7
Nov 28 '13 at 3:19
source share

You can use:

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

This code will force the service to listen for a long time.

+2
Jul 24 '15 at 7:27
source share

Try to use one instance of SpeechRecognizer , there is no need to recreate it using the stop () method. Call getSpeechRecognizer () in onCreate () and forget about it. But don't forget to kill in the onDestroy () method.

+1
Sep 19 '13 at 20:35
source share

To get around this problem, I used CountDownTimer to gradually call the cancel and start Listening.

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

I used the Speech logical processing in the RecognitionListener methods to make sure that I did not cancel and restart while I received / processed the input.

Let me know if this helps you, or if you need more information. Good luck

+1
Sep 28 '13 at 21:33
source share



All Articles