Feature Request
When building a full-duplex voice assistant (mic capture + TTS playback at the same
time), enabling androidInputPreset: 'voiceCommunication' on the AudioRecorder alone
was not enough to get working acoustic echo cancellation on Android. Our STT kept
transcribing the assistant's own TTS playback.
The missing piece: the output stream (AudioPlayer.cpp) is opened without any
Usage, which defaults to USAGE_MEDIA. On many devices, the platform AEC chain
engaged by the VOICE_COMMUNICATION input preset only references the
voice-communication output path and media-stream playback leaks into the microphone
uncancelled.
Adding two lines to the output stream builder fixed it completely:
// AudioPlayer.cpp — openAudioStream()
builder.setSharingMode(SharingMode::Exclusive)
->setFormat(AudioFormat::Float)
// ...existing config...
->setUsage(Usage::VoiceCommunication) // ← added
->setContentType(ContentType::Speech) // ← added
// ...
Environment
react-native-audio-api 1.0.0-nightly-f8b57cd-20260825
- React Native 0.86.2 / Expo SDK 57, physical Android device (loudspeaker, no headphones)
- Capture:
AudioRecorder with { androidInputPreset: 'voiceCommunication', iosVoiceProcessing: true }
- Playback:
AudioContext playing TTS PCM buffers
- Use case: streaming STT (websocket ASR) while speaking TTS replies (barge-in style interaction)
Symptom before the patch
- Speech-to-text transcribed the assistant's own spoken replies as if they were user input
- Token-overlap heuristics and LLM-based intent filtering reduced but never eliminated
the self-echo turns
- Verified the input preset reaches Oboe correctly (
setInputPreset(VoiceCommunication)
present in openAudioStream()), so the gap was on the output/reference side
After the patch
- Self-echo eliminated at DSP level (zero phantom transcripts during playback)
- Real barge-in (user talking over the reply) works reliably
- No audio-routing regressions on our test device: playback still comes out of the
loudspeaker as before
Suggestions
- Library behavior: consider applying
Usage::VoiceCommunication (+ ContentType::Speech)
to the output stream automatically when an active recorder uses
androidInputPreset: 'voiceCommunication' or expose an option for it.
- Docs (
next → AudioRecorder): the full-duplex section recommends
androidInputPreset: 'voiceCommunication' + iosVoiceProcessing: true, but doesn't
mention that the playback side must also sit on the voice-communication path for
Android AEC to reference it.
Feature Request
When building a full-duplex voice assistant (mic capture + TTS playback at the same
time), enabling
androidInputPreset: 'voiceCommunication'on theAudioRecorderalonewas not enough to get working acoustic echo cancellation on Android. Our STT kept
transcribing the assistant's own TTS playback.
The missing piece: the output stream (
AudioPlayer.cpp) is opened without anyUsage, which defaults toUSAGE_MEDIA. On many devices, the platform AEC chainengaged by the
VOICE_COMMUNICATIONinput preset only references thevoice-communication output path and media-stream playback leaks into the microphone
uncancelled.
Adding two lines to the output stream builder fixed it completely:
Environment
react-native-audio-api1.0.0-nightly-f8b57cd-20260825AudioRecorderwith{ androidInputPreset: 'voiceCommunication', iosVoiceProcessing: true }AudioContextplaying TTS PCM buffersSymptom before the patch
the self-echo turns
setInputPreset(VoiceCommunication)present in
openAudioStream()), so the gap was on the output/reference sideAfter the patch
loudspeaker as before
Suggestions
Usage::VoiceCommunication(+ContentType::Speech)to the output stream automatically when an active recorder uses
androidInputPreset: 'voiceCommunication'or expose an option for it.next→ AudioRecorder): the full-duplex section recommendsandroidInputPreset: 'voiceCommunication'+iosVoiceProcessing: true, but doesn'tmention that the playback side must also sit on the voice-communication path for
Android AEC to reference it.