Plugin version:
^7.0.1
Platform(s):
Android
Current behavior:
When starting speech recognition the first time, the recorder and recognition start correctly. On the second attempt (start → stop → start), the recorder UI does not start and no audio is captured. The plugin reports an error mapped to code 11 (native SpeechRecognizer.ERROR_SERVER_DISCONNECTED) but this error code is not handled in getErrorText. The failure alternates (works on 1st attempt, fails on 2nd, works on 3rd, etc.).
Expected behavior:
Speech recognition should start reliably on each start invocation (start → stop → start) without alternating failures. The plugin should either reuse the SpeechRecognizer connection or recover cleanly so the remote service does not disconnect between quick successive starts.
Steps to reproduce:
- Install the app with
@capacitor-community/speech-recognition on an Android device or emulator running API 35.
- Grant microphone permission if prompted.
- Start speech recognition (e.g.,
SpeechRecognition.start({...}) with partialResults: true, popup: false).
- Let it run, then stop it (user stop or call
SpeechRecognition.stop()).
- Immediately start speech recognition again.
- Observe that the second start often fails and logs an ERROR_SERVER_DISCONNECTED (11). Repeat — behavior alternates.
Related code:
await SpeechRecognition.removeAllListeners();
await SpeechRecognition.addListener('partialResults', data => { /* ... */ });
await SpeechRecognition.addListener('listeningState', data => { /* ... */ });
await SpeechRecognition.start({
language: 'en-US',
maxResults: 1,
partialResults: true,
popup: false
});
// later...
await SpeechRecognition.stop();
Native plugin: the plugin's SpeechRecognition.java lifecycle previously destroyed and recreated the SpeechRecognizer instance on each start/stop cycle. This can cause ERROR_SERVER_DISCONNECTED when the recognition service is unbound/rebound too quickly.
Other information:
- Native error code:
11 = SpeechRecognizer.ERROR_SERVER_DISCONNECTED.
- Observed on Android API 35 (physical device and emulator).
- Behavior: works on odd attempts (1st, 3rd, ...), fails on even attempts (2nd, 4th, ...).
- Likely root cause: destroying/unbinding the
SpeechRecognizer between sessions causes a race with the remote recognition service (Google speech service). Rebinding immediately can result in ERROR_SERVER_DISCONNECTED.
- Local mitigation that reduces the issue frequency:
- Reuse the
SpeechRecognizer instance instead of calling destroy() on every stop. Call stopListening()/cancel() on stop and only destroy() on plugin/activity destroy or when receiving ERROR_SERVER_DISCONNECTED.
- On
onError() if ERROR_SERVER_DISCONNECTED is received, explicitly destroy the recognizer and set it to null to force a fresh create on next start (or attempt a short delay before re-creating).
- Example recommended pattern (pseudo-Java):
// create once (e.g., in load())
if (speechRecognizer == null) {
speechRecognizer = SpeechRecognizer.createSpeechRecognizer(activity);
}
speechRecognizer.setRecognitionListener(listener);
speechRecognizer.startListening(intent);
// on stop
speechRecognizer.stopListening();
speechRecognizer.cancel();
// do not destroy here - reuse the instance
// on error
if (error == SpeechRecognizer.ERROR_SERVER_DISCONNECTED) {
speechRecognizer.destroy();
speechRecognizer = null;
}
- I inspected / modified locally the plugin file:
SpeechRecognition.java
(added logging, added explicit handling to map error 11, and experimented with reusing the recognizer vs destroying on every stop).
If you need full logcat traces, JS console output, or the patch I applied locally (to show the exact changes), I can attach them or open a PR with a recommended fix (reuse recognizer + error-handling + minimal retry/delay).
Capacitor doctor:
💊 Capacitor Doctor 💊
Latest Dependencies:
@capacitor/cli: 7.4.4
@capacitor/core: 7.4.4
@capacitor/android: 7.4.4
@capacitor/ios: 7.4.4
Installed Dependencies:
@capacitor/cli: 7.4.4
@capacitor/ios: 7.4.4
@capacitor/android: 7.4.4
@capacitor/core: 7.4.4
[error] Xcode is not installed
[success] Android looking great! 👌
If helpful, I can prepare a PR that:
- Reuses the
SpeechRecognizer instance (create once).
- Avoids calling
destroy() on normal stop.
- Destroys + recreates only on
ERROR_SERVER_DISCONNECTED or on plugin/activity destroy.
- Adds detailed logging and an optional small delay before recreating when necessary.
Plugin version:
^7.0.1
Platform(s):
Android
Current behavior:
When starting speech recognition the first time, the recorder and recognition start correctly. On the second attempt (start → stop → start), the recorder UI does not start and no audio is captured. The plugin reports an error mapped to code 11 (native
SpeechRecognizer.ERROR_SERVER_DISCONNECTED) but this error code is not handled ingetErrorText. The failure alternates (works on 1st attempt, fails on 2nd, works on 3rd, etc.).Expected behavior:
Speech recognition should start reliably on each start invocation (start → stop → start) without alternating failures. The plugin should either reuse the SpeechRecognizer connection or recover cleanly so the remote service does not disconnect between quick successive starts.
Steps to reproduce:
@capacitor-community/speech-recognitionon an Android device or emulator running API 35.SpeechRecognition.start({...})withpartialResults: true,popup: false).SpeechRecognition.stop()).Related code:
Native plugin: the plugin's SpeechRecognition.java lifecycle previously destroyed and recreated the
SpeechRecognizerinstance on each start/stop cycle. This can causeERROR_SERVER_DISCONNECTEDwhen the recognition service is unbound/rebound too quickly.Other information:
11=SpeechRecognizer.ERROR_SERVER_DISCONNECTED.SpeechRecognizerbetween sessions causes a race with the remote recognition service (Google speech service). Rebinding immediately can result inERROR_SERVER_DISCONNECTED.SpeechRecognizerinstance instead of callingdestroy()on every stop. CallstopListening()/cancel()on stop and onlydestroy()on plugin/activity destroy or when receiving ERROR_SERVER_DISCONNECTED.onError()ifERROR_SERVER_DISCONNECTEDis received, explicitly destroy the recognizer and set it tonullto force a fresh create on next start (or attempt a short delay before re-creating).SpeechRecognition.java
(added logging, added explicit handling to map error 11, and experimented with reusing the recognizer vs destroying on every stop).
If you need full logcat traces, JS console output, or the patch I applied locally (to show the exact changes), I can attach them or open a PR with a recommended fix (reuse recognizer + error-handling + minimal retry/delay).
Capacitor doctor:
If helpful, I can prepare a PR that:
SpeechRecognizerinstance (create once).destroy()on normal stop.ERROR_SERVER_DISCONNECTEDor on plugin/activity destroy.