Skip to content

Barge-in with headphones - #6

Merged
ssethia2 merged 3 commits into
mainfrom
ss/barge-in-aec
Jun 15, 2026
Merged

Barge-in with headphones#6
ssethia2 merged 3 commits into
mainfrom
ss/barge-in-aec

Conversation

@ssethia2

Copy link
Copy Markdown
Owner

Barge-in in duplex mode with speakers

ssethia2 added 3 commits June 14, 2026 21:30
WebRTC APM won't build on macOS (Linux-only prctl.h), so use speexdsp's EchoCanceller
— cross-platform (Mac + Pi), optional dep (falls back to the half-duplex gate if the
system lib is absent).

- voice_aec.py: canceller factory + pure helpers (16k resample, 10ms reframing),
  env-tunable echo tail (ARIA_AEC_TAIL). speexdsp is optional via available().
- voice_live.py: AEC mode default when speexdsp present — mic stays open, each 10ms
  frame echo-cancelled against the matching played reference, so you can talk over her
  without her hearing herself. --duplex (headphones, raw) and --no-aec (gate) fallbacks.
  Render references captured in the player; render_q cleared on barge-in.
- tests for the pure helpers (192 total pass). Acoustic quality is manual-test only.

Assisted-by: Claude Code (Opus 4.8)
She kept hearing herself because the previous design ran mic and speaker as SEPARATE
streams and paired them through a queue — variable/empty reference, so speexdsp's
adaptive filter never converged and echo leaked.

Collapse to ONE duplex sd.Stream at 16 kHz: each callback plays one frame and captures
one frame in lockstep, giving a constant aligned mic↔speaker delay the echo canceller can
actually learn. Gemini's 24 kHz output is resampled to 16 kHz for playback (and reused as
the cancellation reference). Gate (--no-aec) and headphone (--duplex) paths preserved.

Assisted-by: Claude Code (Opus 4.8)
The speexdsp binding exposes only EchoCanceller, not the residual-suppression
preprocessor, so it leaks enough echo to self-trigger Gemini's VAD (she answers
herself). Demote it to an opt-in --aec experiment. Default is now the half-duplex
gate (mutes mic while she speaks → no self-loop, no barge-in); --duplex (headphones)
gives true barge-in. Real speaker barge-in needs OS/WebRTC-grade AEC (browser
getUserMedia in the eventual app, or WebRTC APM on the Pi).

Assisted-by: Claude Code (Opus 4.8)
@ssethia2
ssethia2 merged commit 745942d into main Jun 15, 2026
1 check passed
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