Android SpeechRecognizer + LiveKit voice app: mic ownership conflict and TTS self-transcription echo loop


I'm building a voice assistant Android app combining LiveKit (client-sdk-android) for real time communication with a backend agent, and Android's native SpeechRecognizer for on device speech-to-text. I use SpeechRecognizer instead of sending raw audio to a cloud STT service to reduce latency and STT costs.

I ran into two related audio ownership problems and want to check whether better solutions exist than the ones I've settled on.

Problem 1: Mic ownership conflict between LiveKit and SpeechRecognizer

Context, already worked around.

LiveKit's default behavior publishes the local microphone as an audio track using AudioSource.VOICE_COMMUNICATION under AudioManager.MODE_IN_COMMUNICATION. Running SpeechRecognizer, which internally uses AudioSource.VOICE_RECOGNITION, at the same time causes SpeechRecognizer to receive near silence and return ERROR_NO_MATCH.

This is because Android's audio policy treats the VOICE_COMMUNICATION stream as an active call and starves the other concurrent capture request.
Reference: <https://source.android.com/docs/core/audio/concurrent>

I've settled on avoiding this entirely rather than solving the concurrency issue: the app no longer publishes a mic audio track to LiveKit at all. SpeechRecognizer owns the mic exclusively, and the transcribed text is sent to the backend agent as text over LiveKit's data channel or text stream instead of raw audio.

This works and isn't something I'm still looking to change. I'm including it only for context, since it's the same app and the same mic, and it led into problem 2 below.

Problem 2: SpeechRecognizer transcribes the device's own TTS output

This is still open.

The agent's response comes back as TTS audio, played through the phone's loudspeaker. To support the user interrupting the assistant mid response, I originally kept SpeechRecognizer listening continuously, including while TTS was playing.

This causes SpeechRecognizer to pick up and transcribe the TTS audio itself, resulting in garbled hallucinated text that closely resembles what was just spoken, plus repeated false speech detection tones.

The root cause, as I understand it, is that SpeechRecognizer is a black-box API with no exposed AudioRecord or session ID. This means AcousticEchoCanceler, which requires attaching to a capture session you control, can't be applied to it.

This is different from AudioSource.VOICE_COMMUNICATION captures, which get hardware AEC automatically on many devices.

Solutions I'm aware of or considering:

  1. Half-duplex: stop SpeechRecognizer while TTS is playing, restart it once TTS finishes. This removes the echo problem entirely but loses true mid-sentence interruption.

  2. Tap-to-interrupt button: keep SpeechRecognizer off during TTS, as in #1, but add a manual button the user taps to interrupt instead of relying on voice detection during playback.

Question:

For problem 2, is there any other viable approach I haven't listed?

Something short of a full custom AudioRecord + AEC rebuild, but more robust than the button or half duplex options?

Has anyone found a way to make continuous listening during TTS playback reliable with SpeechRecognizer specifically, or is dropping SpeechRecognizer for the "listen during TTS" case unavoidable?

0
Sep 10 at 6:30 AM
User AvatarRobair
#android#audio#speech-recognition#echo-cancellation#livekit

No answer found for this question yet.