title: Android Speech Speech Recognition: Repeated Calling of SpeechRecognizer.startListening() fails on JB 4.1.2
body: <p>I have a service where I'm kicking off a speech recognition listener repeatedly so I can have an open ended session for the user to speak. The class also handles the issue in Jelly Bean where a ERROR_SPEECH_TIMEOUT is thrown if no speech is heard in 5 seconds. So basically this works. However if I repeatedly call recognizer.startListening(recognizerIntent) , it silently fails as evidenced by the fact that onBeginningOfSpeech() is never called in this case. Now IF I just do not talk at all my Jelly Bean timeout handler will restart the listener every time without fail. It seems to only fail after onResults() is called because speech WAS heard. After onResults() is called, recognizer.startListening(recognizerIntent) is definitely called, but like I said, nothing happens.   When it fails it is random and there is nothing in Logcat to indicate what the issue is. I just don't know what else to try. Hopefully one of you Android Speech recognition experts out there has seen this before...</p>
  
  <p>Minimum: 2.2
  Target: Testing on JB : Android 4.1.2</p>
  
  <hr>
  
  <p>MORE INFO (11-01-13)
  The 4.3 Update to my HTC One has definitely addressed this issue. My Speech recognition service below is now reliable &amp; accurate. I has run  for at least few minutes without error. As for 4.1.2, before my update to 4.3 it seemed to have been working  better (did Google change anything on their end?)...I don't know, but it still would miss some words spoken and occasionally without error, just stop listening (onBeginningOfSpeech() is never called in this case). I suppose I will just have to warn my users about Android 4.1.2 with regards to this issue because I have gone as far as I can go in my code. </p>
  
  <p>MORE INFO (09-17-13)
  Supposedly, there is an Android update (4.3) coming to HTC ones at the end of September (<a href="http://www.ubergizmo.com/2013/09/htc-one-to-receive-android-4-3-jelly-bean-update-this-september/" rel="nofollow noreferrer">http://www.ubergizmo.com/2013/09/htc-one-to-receive-android-4-3-jelly-bean-update-this-september/</a>). So hopefully that will address this issue on that device. The issue remains though for my app users that are running Android 4.1.2 and stuck on that version for a while. I still don't know what to do in those cases, and hopefully that is the ONLY Android version with this issue. Is there any way to find out how many devices are running 4.1.2??  </p>
  
  <p>MORE INFO (09-15-13)
  In this post here: <a href="https://stackoverflow.com/questions/17592333/google-voice-recognizer-doesnt-starts-on-android-4-x?noredirect=1#comment27730909_17592333">Google voice recognizer doesn&#39;t starts on Android 4.x</a>. The author state states that he is seeing this issue on his HTC one. I also have an HTC one that I'm seeing this issue on (Android 4.1.2) . I wonder if this is unique to the HTC one? (or any device running Android 4.1.2) - I can't confirm as its difficult to test on all the latest devices running JB. The author further states that his Nexxus with 4.2.2 works fine. Can anyone tell me on what device they see this issue?</p>
  
  <p>MORE INFO (9-08-13)
  Just to confirm there is no issue with my code, I also tested this on Android 2.3.3 and I was able to call onResult() > startListening() 25 times in a row. When targeting Android 4.1.2 I'm never able to get past 3 or 4 calls. I can't believe no one else has run into this issue?</p>
  
  <pre><code>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 &amp;&amp; Build.VERSION.SDK_INT &gt;= 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 &gt;= 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 &gt;= 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() &gt;=1){
               //  //check for save it:
               //}
  
               for (int i = 0; i &lt; 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;
      }
  }
  </code></pre>