fix(publish): stop audio capture on mute, publishing silence in its place#2186
Closed
fperex wants to merge 1 commit into
Closed
fix(publish): stop audio capture on mute, publishing silence in its place#2186fperex wants to merge 1 commit into
fperex wants to merge 1 commit into
Conversation
…lace Muting used to tear the whole audio pipeline down: it stopped the mic track, closed the AudioContext, worklet and AudioEncoder, closed the audio track producer, and cascaded the catalog to drop the audio section entirely. The watcher then had to rebuild its audio subtree (AudioContext, worklet, ring buffer) on every mute and unmute, and the resulting head-of-line contention on the shared WebSocket froze video for a moment. Mute now gates the audio INPUT, not the pipeline. Per source: a microphone track is stopped outright, so the OS releases the device and the recording indicator goes off (that is the point of a mute); screen and file audio is detached from the encoder instead, since stopping a share track would kill the share and force a re-prompt. A silent ConstantSourceNode keeps the worklet pulled, so the encoder keeps publishing true silence on the same clock and the catalog never changes shape. Selecting a source while muted never touches the microphone at all; unmuting acquires it. Also scope the four source-proxy effects to the child effect rather than the root, so switching source tears its proxies down in order instead of leaking a root-scoped writer over the next source.
This was referenced Jul 12, 2026
Collaborator
|
Why make this change? Why publish 128Kb/s or whatever instead of nothing...? DTX will reduce it but yeah.
Fix that then if reinitializing the audio context is expensive. We can cache it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Split out of #2163.
Muting used to tear the whole audio pipeline down. It stopped the mic track, closed the
AudioContext, the worklet and theAudioEncoder, closed the audio track producer, and cascaded the catalog to drop the audio section entirely. Two consequences: every watcher had to rebuild its audio subtree (AudioContext + worklet + ring buffer) on every mute and unmute, and the resulting head-of-line contention on the shared WebSocket froze the video for a moment. Muting your mic should not stutter your video for everyone watching.Mute now gates the audio input, not the pipeline. Per source:
A silent
ConstantSourceNodekeeps the worklet pulled while no input is attached, so the encoder keeps publishing true silence on the same clock and the catalog never changes shape. Selecting a source while muted never touches the microphone at all; unmuting acquires it.Also scopes the four source-proxy effects to the child effect rather than the root, so switching source tears its proxies down in order instead of leaking a root-scoped writer over the next source.
Public API changes: none.
mutedkeeps its type and name; its behavior changes as described (documented in the README and/doc).Test plan:
just js checkgreen. The behavior was proven end-to-end with an ad hoc headless-Chrome run (fake media device via CDP; not a committed test, the repo has no browser-test harness) against the fork's integrated branch, whosejs/tree is byte-identical to these split PRs combined:getUserMediacalls;readyState: "ended");