Repository navigation
test(interop): the browser publisher sends its tone from a file, not a fake mic - #6647
Conversation
Quest-Claim: 6e26cec9e2bc8bf7
…a fake mic Chromium's fake capture and output devices run on timers that skip a late 10 ms tick. Under CPU starvation Web Audio then splices the captured tone while the capture worklet's sample-count timestamps stay contiguous, so every native subscriber's tone check (added in #6284) reads ~440 Hz at a fraction of its energy. The browser publisher now decodes and loops a generated H.264 + PCM file through <moq-publish>'s file source instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 20 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Adversarial review of the "outside our code" claim, with a standalone headless Chromium page reading the fake microphone (440 Hz WAV) through both
So:
Coverage after this PR: the capture path is still exercised. Local checks on 649c4dd: (Written by Claude Opus 5.5) |
|
Merging 649c4dd with the maintainer's approval. The non-Grok review of this head is clean, every finding is fixed or answered, and the pre-land (Written by Claude Opus 5.5) |
|
Merged (Written by Claude Opus 5.5) |
Quest:
quest/m1/interop-js-tone.md(deleted here).Summary
The scheduled Interop run on 2026-10-23 (run 39958710886) failed
js ->cells on drafts 18, 20, and 22 with "wrong tone: channel 0 carries ~440 Hz, not 440 Hz" at 0.10 to 0.77 of its energy.Cause. The browser publisher captured the tone from Chromium's fake microphone (
--use-file-for-fake-audio-capture) through aMediaStreamAudioSourceNodeand the capture AudioWorklet. Chromium's fake capture and output devices run on timers that skip a 10 ms tick when they wake up late (FakeAudioWorker::DoReadjumps to the next interval instead of catching up). On a runner short of CPU, the captured tone then shifts by a fraction of a period, while the worklet's timestamps, which count rendered samples, stay contiguous. Every subscriber decodes the splice exactly:tone.pysees no gap, only a 440 Hz tone whose phase steps several times inside its 400 ms window, so its Goertzel share drops. The browser subscriber's analyser, which judges a moving window, passed. This is not a decoder or a relay bug, and not the max-age mechanism in moq-dev/moq#6658: the jumps showed up inside the publisher's own capture worklet before encoding, with no timestamp gap anywhere.Why it started on 2026-10-23. Nothing in
js/publishchanged. moq-dev/moq#6284 (every subscriber checks the tone) landed between the passing 2026-10-21 run and the failing one. The splices predate it. The--versions ietfjob runs last, after about 45 minutes of the full matrix, which is when the runner is most loaded. moq-dev/moq#6299 is not involved. Locally I bisected between the two scheduled runs' commits: atdbf06bdcb3, from before the native tone check, 5 of 5 runs passed. At4381af6f07, the failing scheduled run's head, 5 of 5 runs failed the tone, 1 to 9 cells per run.Fix. The browser publisher no longer uses fake devices.
interop.shgenerates a 10 s H.264 and 16-bit PCM.movholding the picture and the tone. The driver serves it, and the page hands it to<moq-publish>'s file source, which decodes it with mediabunny and paces it in real time. The tone check is unchanged. This also exercises the file source end to end in every subscriber. Withoutmedia, the publish role keeps its fake-device path formedia.ts's capture-permission case.Reproduction
just test interop --publishers js --subscribers rust,python,go,cpp,js,js-native-node,js-native-bun,c,gst --versions moq-transport-18,moq-transport-22, pinned to 2 CPUs withtaskset, 5 runs each (18js ->cells per run):4381af6f07(2026-10-23 scheduled head)main(57b0b32bbd)Unpinned, every commit passes. A frame-by-frame phase readout of a failing decode showed a steady offset, then a step of about 300 to 900 us partway through. An instrumented publisher logged the same phase jumps from inside its capture worklet at the matching times. A standalone page reading the fake microphone through both an AudioWorklet and
MediaStreamTrackProcessorshowed jumps on both paths, even with the CPU idle.Decisions made without asking
js/publish's capture. The capture correctly stamps what Web Audio hands it, and a real microphone has a real clock. The fault is Chromium's fake device timers, which we can't change. Publishing a file is a supported<moq-publish>source.serve()in the Playwright harness takes an optional map from path to file, so the driver can serve the generated media beside the built page.Public API and wire impact
None. Test harness only.
Checks
just check: passed.just test interop --all: passed (164 PASS lines).just test interop --all --versions ietf: passed on drafts 14 to 22 (312 PASS lines), after merging main.Follow-ups
🤖 Generated with Claude Code
(Written by Claude Opus 5.5)