Skip to content

vad: bound barge-in by an outbound echo reference, per session - #71

Draft
jason-shen wants to merge 1 commit into
mainfrom
issue-48
Draft

vad: bound barge-in by an outbound echo reference, per session#71
jason-shen wants to merge 1 commit into
mainfrom
issue-48

Conversation

@jason-shen

Copy link
Copy Markdown
Member

The energy VAD fires barge-in on the agent's own voice wherever nothing in the path runs AEC. Over WebRTC the browser cancels echo before audio reaches the server; over a carrier the returning audio is attenuated but structurally identical to speech, and an RMS-vs-noise-floor test cannot separate the two.

EchoGuard keeps a rolling window of the RMS the sender put on the wire and raises the barge-in threshold to floor x gain x margin while that window is live. The agent silent means a zero bound, so a quiet caller on a clean line is unaffected. The reference is sampled after duck attenuation, so a ducked talkspurt lowers the bound with the audio that produces the echo.

Echo frames no longer feed the adaptive noise floor: learning them would ratchet the ordinary threshold to its cap every time the agent spoke.

The bound is chosen per session rather than per server, because one instance commonly serves browsers and SIP calls at once and the two need opposite answers: a browser barge-in would have to clear the agent's own output level first, for a bound that catches nothing getUserMedia has not already removed. Clients declare a raw path with aec=none on the WHIP URL, which sip-server now sends on every call; pipeline.echo_guard defaults to "auto" and follows it.

Documents aec and the previously undocumented direction parameter in the WHIP protocol reference, and DTX suppressing inbound RTP during playback as a sip-server troubleshooting entry, since it presents as half-duplex media and is not a VAD problem.

Fixes #48

The energy VAD fires barge-in on the agent's own voice wherever nothing in
the path runs AEC. Over WebRTC the browser cancels echo before audio reaches
the server; over a carrier the returning audio is attenuated but structurally
identical to speech, and an RMS-vs-noise-floor test cannot separate the two.

EchoGuard keeps a rolling window of the RMS the sender put on the wire and
raises the barge-in threshold to floor x gain x margin while that window is
live. The agent silent means a zero bound, so a quiet caller on a clean line
is unaffected. The reference is sampled after duck attenuation, so a ducked
talkspurt lowers the bound with the audio that produces the echo.

Echo frames no longer feed the adaptive noise floor: learning them would
ratchet the ordinary threshold to its cap every time the agent spoke.

The bound is chosen per session rather than per server, because one instance
commonly serves browsers and SIP calls at once and the two need opposite
answers: a browser barge-in would have to clear the agent's own output level
first, for a bound that catches nothing getUserMedia has not already removed.
Clients declare a raw path with aec=none on the WHIP URL, which sip-server now
sends on every call; pipeline.echo_guard defaults to "auto" and follows it.

Documents aec and the previously undocumented direction parameter in the WHIP
protocol reference, and DTX suppressing inbound RTP during playback as a
sip-server troubleshooting entry, since it presents as half-duplex media and
is not a VAD problem.

Fixes #48
@jason-shen jason-shen self-assigned this Aug 26, 2026
@jason-shen jason-shen added enhancement New feature or request bug Something isn't working labels Aug 26, 2026
@jason-shen

Copy link
Copy Markdown
Member Author

testing still needed before merging

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

VAD needs an echo reference on the SIP/PCMU path (agent barges on its own voice)

1 participant