title: Why is Androids SpeechRecognizer automatically stopping itself
body: <h2>Issue number 1:</h2>
  <p>The following settings are being completely ignored</p>
  <pre><code>        putExtra(
              RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS,
              (5000).toLong()
          )
          putExtra(
              RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS,
              (5000).toLong()
          )
          putExtra(
              RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS,
              (5000).toLong()
          )
  </code></pre>
  <p>I'm not sure what else to say other than these settings do absolutely nothing, regardless of how I set up my logic (see below for my current implementation).</p>
  <h2>Issue number 2:</h2>
  <p><code>onBeginningOfSpeech()</code> is called when no speaking has taken place. Which then causes recognition to stop prematurely (within 800-1500ms) since it will subsequently call <code>onEndOfSpeech()</code> and <code>onError()</code> where the error is <code>ERROR_NO_MATCH</code>
  There are some caveats to this;
  Firstly, this occurs only when the phone HAS an internet connection. In other words, if you were to have downloaded the language packs for offline use and then forced the phone into airplane mode, this issue would not occur. Secondly, in the case where the phone DOES have internet connection, <code>onBeginningOfSpeech()</code> seems to be called when any tiny sound in the background occurs. I.e. In dead silence it will not be called, but if you lightly tap a nearby surface with your finger it will trigger and then cause the issue. &quot;It could hear a pin drop&quot; as they say.
  P.s. This combined with <code>Issue number 1 (see above)</code> make the <code>SpeechRecognizer</code> incredibly difficult to use.</p>
  <h2>Testing for the issues above</h2>
  <p><strong>All issues above have been verified to be happening on a fully functional, non-rooted, pixel 4a device running Android 11.</strong></p>
  <h2>The following is my implementation of speech recognition:</h2>
  <pre><code>object SpeechRecognitionUtil {
      const val logTag = &quot;SpeechRecognitionUtil&quot;
  
      val speechRecognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
          putExtra(
              RecognizerIntent.EXTRA_LANGUAGE_MODEL,
              RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
          )
          putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true)
          putExtra(RecognizerIntent.EXTRA_LANGUAGE, &quot;es-US&quot;)
          putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 20)
          putExtra(
              RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS,
              (5000).toLong()
          )
          putExtra(
              RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS,
              (5000).toLong()
          )
          putExtra(
              RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS,
              (5000).toLong()
          )
      }
  
      fun setupSpeechRecognizer(
          context: Context,
          onError: (Int) -&gt; Unit = {},
          onReadyForSpeech: (Bundle) -&gt; Unit = {},
          onEndOfSpeech: () -&gt; Unit = {},
          onResults: (Bundle) -&gt; Unit = {},
          onEvent: (Bundle) -&gt; Unit = {},
          onPartialResults: (Bundle) -&gt; Unit = {},
          onBufferReceived_: (ByteArray) -&gt; Unit = {},
          onEvent_: (Int, Bundle) -&gt; Unit = { _, _ -&gt; }
      ): SpeechRecognizer? {
          return when {
              SpeechRecognizer.isRecognitionAvailable(context) -&gt; {
                  val speechRecognizer = SpeechRecognizer.createSpeechRecognizer(context)
                  speechRecognizer.setRecognitionListener(SimpleRecognitionListener(
                      onError_ = { code: Int -&gt;
                          onError(code)
                      },
                      onBufferReceived_ = {
                          onBufferReceived_(it)
                      },
                      onReadyForSpeech_ = {
                          onReadyForSpeech(it)
                      },
                      onBeginningOfSpeech_ = {
                      },
                      onEvent_ = { integer: Int, bundle: Bundle -&gt;
                          onEvent_(integer, bundle)
                      },
                      onEndOfSpeech_ = {
                          onEndOfSpeech()
                      },
                      onPartialResults_ = {
                          onPartialResults(it)
                      },
                      onResults_ = {
                          onResults(it)
                      }
                  ))
  
                  speechRecognizer
              }
              else -&gt; {
                  Log.i(&quot;SpeechRecognizer&quot;, &quot;Recognition is NOT available!&quot;)
                  null
              }
          }
      }
  }
  
  fun Bundle.recognizedWords() = getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)
  fun Bundle.confidenceScores() = getFloatArray(SpeechRecognizer.CONFIDENCE_SCORES)
  
  class SimpleRecognitionListener(
      val onReadyForSpeech_: (Bundle) -&gt; Unit = {},
      val onBeginningOfSpeech_: () -&gt; Unit = {},
      val onRmsChanged_: (Float) -&gt; Unit = {},
      val onBufferReceived_: (ByteArray) -&gt; Unit = {},
      val onEndOfSpeech_: () -&gt; Unit = {},
      val onError_: (Int) -&gt; Unit = {},
      val onResults_: (Bundle) -&gt; Unit = {},
      val onPartialResults_: (Bundle) -&gt; Unit = {},
      val onEvent_: (Int, Bundle) -&gt; Unit = { _, _ -&gt; }
  ) : RecognitionListener {
      private var performingSpeechSetup = true
  
      override fun onReadyForSpeech(bundle: Bundle) {
          Log.d(SpeechRecognitionUtil.logTag, &quot;onReadyForSpeech()::Bundle=$bundle&quot;)
          performingSpeechSetup = false
          onReadyForSpeech_(bundle)
      }
  
      override fun onBeginningOfSpeech() {
          Log.d(SpeechRecognitionUtil.logTag, &quot;onBeginningOfSpeech()&quot;)
          onBeginningOfSpeech_()
      }
  
      override fun onRmsChanged(rms: Float) {
  //        Log.i(logTag, &quot;onRmsChanged()::Rms=$rms&quot;)
          onRmsChanged_(rms)
      }
  
      override fun onBufferReceived(byteArray: ByteArray) {
          Log.d(
              SpeechRecognitionUtil.logTag,
              &quot;onBufferReceived()::byteArray=$byteArray, \nwords=&quot;
          )
          onBufferReceived_(byteArray)
      }
  
      override fun onEndOfSpeech() {
          Log.d(SpeechRecognitionUtil.logTag, &quot;onEndOfSpeech()&quot;)
          onEndOfSpeech_()
      }
  
      override fun onError(code: Int) {
          Log.d(SpeechRecognitionUtil.logTag, &quot;onError()::code=$code&quot;)
          if (performingSpeechSetup &amp;&amp; code == SpeechRecognizer.ERROR_NO_MATCH) return
          else {
              onError_(code)
          }
      }
  
      override fun onResults(bundle: Bundle) {
          Log.d(
              SpeechRecognitionUtil.logTag,
              &quot;onResults()::Bundle=$bundle, \n&quot; +
                      &quot;Recognized words=${bundle.recognizedWords()}\n&quot; +
                      &quot;Confidence scores=${bundle.confidenceScores()}&quot;
          )
          onResults_(bundle)
      }
  
      override fun onPartialResults(bundle: Bundle) {
          Log.d(
              SpeechRecognitionUtil.logTag, &quot;onPartialResults()::Bundle=$bundle, \n&quot; +
                      &quot;Recognized words=${bundle.recognizedWords()}&quot;
          )
          onPartialResults_(bundle)
      }
  
      override fun onEvent(event: Int, bundle: Bundle) {
          Log.d(SpeechRecognitionUtil.logTag, &quot;onEvent()::event=$event, \nbundle=$bundle&quot;)
          onEvent_(event, bundle)
      }
  }
  </code></pre>
  <pre><code>class MainVM(app: Application) : AndroidViewModel(app) {
      enum class RecordingState {
          IDLE, RECORDING;
      }
  
  
      private var speechRecognizer: SpeechRecognizer? = null
      private val _recording = MutableLiveData(RecordingState.IDLE)
      val recordingState: LiveData&lt;RecordingState&gt; = _recording
  
      private fun initSpeechRecoginizer() {
          // Destroy old recognizer
          speechRecognizer?.cancel()
          speechRecognizer?.destroy()
          speechRecognizer = null
  
          // Create new recognizer
          speechRecognizer = SpeechRecognitionUtil.setupSpeechRecognizer(getApplication(),
              onPartialResults = { _ -&gt; },
              onEndOfSpeech = {
                  _recording.value = RecordingState.IDLE
              },
              onResults = {},
              onError = {})
      }
  
      fun startRecording() {
          initSpeechRecoginizer()
          speechRecognizer?.let {
              it.startListening(SpeechRecognitionUtil.speechRecognizerIntent)
              _recording.value = RecordingState.RECORDING
          }
      }
  
      fun stopRecording() {
          speechRecognizer?.stopListening()
          _recording.value = RecordingState.IDLE
      }
  
      override fun onCleared() {
          super.onCleared()
          speechRecognizer?.destroy()
          speechRecognizer = null
      }
  }
  </code></pre>
  <pre><code>class MainActivity : ComponentActivity() {
  
      private val logTag = &quot;MainActivity&quot;
  
      @ExperimentalAnimationApi
      @ExperimentalPagerApi
      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
  
          setContent {
              MaterialTheme {
                  ScreenMain()
              }
          }
      }
  
      @Composable
      private fun ScreenMain() {
          val vm = getViewModel&lt;MainVM&gt;()
          val recordingState by vm.recordingState.observeAsState(RecordingState.IDLE)
  
          Box(
              modifier = Modifier
                  .fillMaxSize()
                  .padding(20.dp),
              contentAlignment = Alignment.BottomCenter
          ) {
              Button(modifier = Modifier
                  .fillMaxWidth(1f)
                  .height(50.dp),
                  onClick = {
                      when (recordingState) {
                          RecordingState.IDLE -&gt; {
                              vm.startRecording()
                          }
                          RecordingState.RECORDING -&gt; {
                              vm.stopRecording()
                          }
                      }
                  }) {
                  val textString = when (recordingState) {
                      RecordingState.RECORDING -&gt; {
                          &quot;Stop Recording&quot;
                      }
                      RecordingState.IDLE -&gt; {
                          &quot;Start Recording&quot;
                      }
                  }
                  Text(textString)
              }
          }
      }
  }
  </code></pre>
  <p>Manifest:</p>
  <pre><code>&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
      package=&quot;some.example.app&quot;&gt;
  
      &lt;queries&gt;
          &lt;intent&gt;
              &lt;action android:name=&quot;android.speech.RecognitionService&quot; /&gt;
          &lt;/intent&gt;
      &lt;/queries&gt;
  
      &lt;uses-permission android:name=&quot;android.permission.INTERNET&quot; /&gt;
      &lt;uses-permission android:name=&quot;android.permission.ACCESS_NETWORK_STATE&quot; /&gt;
      &lt;uses-permission android:name=&quot;android.permission.ACCESS_WIFI_STATE&quot; /&gt;
      &lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot; /&gt;
      &lt;uses-permission android:name=&quot;android.permission.MANAGE_EXTERNAL_STORAGE&quot; /&gt;
      &lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot; /&gt;
      &lt;uses-permission android:name=&quot;android.permission.RECORD_AUDIO&quot; /&gt;
  
      &lt;application
          android:allowBackup=&quot;false&quot;
          android:icon=&quot;@mipmap/ic_launcher&quot;
          android:label=&quot;EXAMPLE&quot;
          android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;
          android:supportsRtl=&quot;true&quot;
          android:theme=&quot;@style/Theme.Example&quot;&gt;
          &lt;activity
              android:name=&quot;.MainActivity&quot;
              android:exported=&quot;true&quot;&gt;
              &lt;intent-filter&gt;
                  &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;
  
                  &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
              &lt;/intent-filter&gt;
          &lt;/activity&gt;
      &lt;/application&gt;
  
  &lt;/manifest&gt;
  </code></pre>
  <p>I left an issue with Google on their issue tracker (here: <a href="https://issuetracker.google.com/issues/197284982" rel="nofollow noreferrer">https://issuetracker.google.com/issues/197284982</a>) , if you have had any trouble with SpeechRecognizer in the past I urge you to upvote/star it and even leave a comment if you could. Thank you.</p>