Skip to content

feat(android): AudioRecorder input preset option (androidInputPreset) - #1210

Open
lpmv wants to merge 1 commit into
software-mansion:mainfrom
lpmv:feat/android-recorder-input-preset
Open

feat(android): AudioRecorder input preset option (androidInputPreset)#1210
lpmv wants to merge 1 commit into
software-mansion:mainfrom
lpmv:feat/android-recorder-input-preset

Conversation

@lpmv

@lpmv lpmv commented Aug 2, 2026

Copy link
Copy Markdown

Why

The Oboe input stream builder in AndroidAudioRecorder::openAudioStream never calls setInputPreset, so every capture stream runs on Oboe's implicit default, InputPreset::VoiceRecognition — the speech-recognition preprocessing chain, which applies no acoustic echo cancellation. For duplex voice apps (playing TTS/voice through the same device while recording, VoIP-style — the use case asked about in #670), that makes Android capture echo-raw, while the equivalent iOS setup gets AEC from the voiceChat session mode.

What

An optional constructor option on AudioRecorder:

const recorder = new AudioRecorder({ androidInputPreset: 'voiceCommunication' });

mapped to Oboe's InputPreset on the capture stream builder. voiceCommunication engages the platform AEC/NS chain — the Android twin of iOS voiceChat.

  • Backwards compatible: when the option is omitted (or names an unknown preset) no setInputPreset call is made, so existing behavior is preserved exactly.
  • iOS ignores the option (its input chain is selected by the AVAudioSession mode); the host object comment says so.
  • Presets exposed: generic, camcorder, voiceRecognition, voiceCommunication, unprocessed, voicePerformance.

Notes

We measured the difference in a duplex probe (1024-sample pcm16 frames at 24 kHz, speaker playback at full volume while recording): on iOS under voiceChat the played audio re-enters the mic at +1.9 dB over the room floor; Android capture through the current builder has no platform AEC path at all. Happy to adjust the option's shape (e.g. a general AudioRecorderOptions bag was chosen so future per-platform stream options have a home).

The Oboe input stream builder never calls setInputPreset, so every capture
stream runs on Oboe's implicit default, InputPreset::VoiceRecognition - the
speech-recognition preprocessing chain, which applies no acoustic echo
cancellation. For duplex voice apps (playing audio through the same device
while recording, VoIP-style) that makes Android capture echo-raw, while the
equivalent iOS setup gets AEC from the voiceChat session mode.

This adds an optional constructor option to AudioRecorder:

  new AudioRecorder({ androidInputPreset: 'voiceCommunication' })

mapping to Oboe's InputPreset on the capture stream builder. When the option
is omitted (or names an unknown preset) no setInputPreset call is made, so
existing behavior is preserved exactly. iOS ignores the option; its input
chain is selected by the AVAudioSession mode instead.

Presets exposed: generic, camcorder, voiceRecognition, voiceCommunication,
unprocessed, voicePerformance.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant