Skip to content

fix(voice): music and the radio no longer eat your voice - #4460

Merged
janlauber merged 1 commit into
mainfrom
claude/voice-over-music
Nov 6, 2026
Merged

janlauber merged 1 commit into
mainfrom
claude/voice-over-music

Conversation

@janlauber

Copy link
Copy Markdown
Member

Voices sounded over-cancelled while music, the radio or a video played. Noise cancellation was not the cause: Chrome's echo canceller was.

echoCancellation: true is Chrome-wide echo cancellation. Its reference is the output device, so music counted as echo, and the canceller suppressed the rider's voice under it, on headphones too.

The change

  • Capture asks for echoCancellation: 'remote-only', so only audio an element plays counts as echo.
  • Voices reach the speakers through WebAudio, which remote-only does not see. Each voice's element now plays a copy at ECHO_REFERENCE (0.2, 14 dB under the graph), on the same output. It goes to 0 at fader 0 and while Away.
  • A share stays out, because it is music. A handheld and a mic test keep true.

createMediaElementSource was the obvious way to avoid a second copy. It does not work: WebMediaPlayerMS has no audio provider, so the element keeps playing.

Numbers

Raw capture through the real model and gate, speech at −26 dBFS. With --mute-audio, true cancels nothing, so the "before" rows put music in the same canceller's reference through a remote track under remote-only.

Case PESQ-WB STOI First 80 ms of a word
No music 4.40 0.999 −0.3 dB
Headphones, music in the reference 1.58 0.815 −7.2
Headphones, music 12 dB quieter 3.02 0.944 −4.4
Speakers at −30 dBFS, music in the reference 1.24 0.516 −14.4
Speakers at −30 dBFS, music out of it 3.06 0.973 0.1
Speakers, a song in the reference 1.37 0.702 −47.7
Speakers, a song out of it 1.38 0.852 3.8

Crew echo in a real call through LiveKit: a second rider's mic carries the first rider's voice at −26 dBFS. Without the copy it goes back at −24 dBFS. With the copy it reaches −56 dBFS within 10 s and stays between −56 and −81. The element-volume sweep is in docs/RESEARCH.md §22.6: 0.2 cancels, 0.1 cancels nothing.

Regression, real call, at the listener against #4433: quiet 4.04 → 4.07, fan 3.19 → 3.20, bike 2.72 → 2.71. One quiet run scored 3.22 with 0.58 % concealment. Two reruns scored 4.07 with none, so I read that one as a stall.

What it costs

  • A song on speakers now leaks into the call at about −31 dBFS, because a singer is speech to the model. Instrumental music does not.
  • Each voice has a second copy 14 dB down, which ripples its level by about 2 dB at most.
  • A mic test keeps true, so it can sound worse over music than the call does.

Not verified

  • true with music on real speakers. Reproducing it needs sound out of the Mac, so the before rows use the same canceller by another route.
  • How the copy sounds. Nobody has listened to it, and its delay against the graph is unmeasured.
  • A rider talking over the crew on speakers.

Chrome's echo canceller took everything the browser plays as echo, so it
suppressed the rider's voice under music, on headphones too. It now hears
crew voices only: capture asks for `remote-only`, and each voice's element
plays a copy at 0.2 so the canceller still has it.

Changelog: Your voice stays clear while music, the radio or a video plays. On speakers, a song's singer can now reach your crew faintly; headphones avoid that.
@janlauber
janlauber merged commit 61c3da8 into main Nov 6, 2026
5 checks passed
@janlauber
janlauber deleted the claude/voice-over-music branch November 6, 2026 23:22
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