Repository navigation
test(audio-quality): real-microphone baseline for time stretch, from the kixtop playout run - #7679
Conversation
Quest-Claim: c42ac696a6436078
The watch quest's manual proof re-records `relay-mic` with a real microphone, but the recorder always published Chromium's fake capture device. `--mic-broadcast <name>` records a broadcast already publishing on the public relay's anon path instead. Rewrites the quest to what remains: the replay rows re-measured on today's main (unchanged), the nightly browser rows' steady-state stalls as evidence for the manual run, and a Waiting item for that run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kixtop run The manual run on a MacBook Air: Chrome and Safari playing the built-in microphone through the public relay, Chrome also at +40 ms RTT, with the 20 ms and 100 ms groupDuration A/B and the encoder's lag. relay-mic is re-recorded from that microphone and its replay ceilings re-measured. Every row underruns in steady state; replay of the captured arrivals reproduces it, and the cause is the estimator's 0.95 quantile with no concealment, so the quest now waits on a decision about its Goal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The maintainer pulled time stretch into m1 as the Watch quest's fix (2026-11-03), so the 2026-11-03 kixtop measurements become its baseline: - relay-mic-rtt40 replays the real-microphone Chrome row at +40 ms RTT. - player_underruns reads the player's own counter (the stats panel's) in the page probe and the replay, since the output tap files a run-dry re-stall as stalled time; every replay row budgets it as measured, so a time-stretch change shows up deterministically in CI. - The m2 Time stretch quest folds into Watch, with the stretch depth the traces need. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The maintainer asked to copy what WebRTC's NetEq does: accelerate and preemptive expand by removing or repeating whole pitch periods found by autocorrelation, with NetEq's thresholds as the starting point. The Safari +40 ms baseline stays in the quest's Waiting, naming kixtop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Maintainer on #7679, 2026-11-03: "m1 please copy what NetEQ does". A sibling of Watch in the audio jitter target epic, sharing one algorithm and its test vectors. Also drop proto-safe-names' Required link: #7498 merged and deleted catalog-proto-ids.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main still keeps the browser stretch in m2 Time stretch; open #7679 moves it into Watch. Cross-link both, and record the native m1 decision in the epic's boundaries. 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 5 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. CodeRabbit Verify
|
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head 92876c9 against base 7b4f531.
No actionable findings in the measurement checkpoint. The player's underrun counter reaches replay and browser samples, the analyzer grades its rise over the measured window, and replay budgets enforce the new metric while leaving the browser and native ceilings unchanged. The time-stretch work remains future work; the Safari +40 ms baseline is explicitly waiting.
Static GitHub-only review of the replay, recorder, metrics, budgets, traces and quest dependencies. I did not run tests or replays, or independently reproduce the microphone and browser measurements.
There was a problem hiding this comment.
ℹ️ No critical issues — one minor suggestion inline.
Reviewed changes
- New player underrun metric:
probe.tsreadsaudio.out.stats.underrunsintoSample.playerUnderruns,analyze.tsgrades the counter's rise across the window,schema.tsdeclaresMETRICS.player_underruns, andgrade.tsshows it first. Browser rows report it unbudgeted; native rows leave it unset. - Replay counter:
Quantum.underrunsnow carriesAudioRingBuffer.underruns, with a test that one run-dry counts once and a clean trace counts none. The player's stats accumulate the same ring counter across rings, so the replay value has the same meaning. - Real-microphone baseline:
relay-micis re-recorded from a real microphone (ceilings re-measured to target 80 ms and silence 0.001), andrelay-mic-rtt40adds the Chrome +40 ms live row as a deterministic baseline at 7.9 player underruns/min.record.sh --mic-broadcastdocuments how the former is re-recorded. - Quest tree: the m2 Time stretch quest is folded into the m1 Watch quest, which is re-scoped to NetEq-style accelerate/preemptive expand, with the baseline, a Safari waiting item, and the A/V clock requirement carried over.
I replayed all five traces with replay.ts, reduced them with analyze.ts, and graded with grade.ts --enforce: within budget, and the new row reproduces its checked-in values exactly. The js/watch replay tests and the harness analyzer, probe, and CLI tests pass. I also confirmed the new row's 23 player underruns all occur after 52 s, so the 780 ms tune-in spike in target_ms_p95 does not inflate the baseline.
deepseek-v4.1-flash-1017 (free via Pullfrog for OSS) | 𝕏
| --source "$PUBLIC/anon, <moq-publish> in headless Chromium capturing its fake audio device, recorded $DATE" \ | ||
| --description "A browser publisher through the public relay: getUserMedia, the capture worklet, and WebCodecs Opus, with the relay's round trip in between." | ||
| description="A browser publisher through the public relay: getUserMedia, the capture worklet, and WebCodecs Opus, with the relay's round trip in between." | ||
| if [[ -n "$MIC_BROADCAST" ]]; then |
There was a problem hiding this comment.
--mic-broadcast is parsed for every invocation but only read in the relay-mic branch, so --lanes relay-bbb --mic-broadcast foo silently records the fake device instead of failing. Error when the flag is set without relay-mic among LANES, so a hand-run cannot check in a trace that is not the one asked for.
Take #7679's deletion of m2 Time stretch and its epic README text, keeping the Native stretch sentence; repoint Native stretch at Watch. Per the Merge order table, drop edges to quests main finished: moq-crypto (#7702), resume-model-7542, and mesh-fresh-port (#7688). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Works quest/m1/audio-jitter-target/watch.md. This is the measurement checkpoint for the browser's measured playout target. It holds the 2026-11-03 manual run on the maintainer's MacBook Air (
kixtop), a real-microphonerelay-mictrace, and a CI baseline that a time-stretch change will move deterministically. The quest is rewritten to the time-stretch work that closes its Goal.Decisions
Goal (2026-11-03, maintainer): zero underruns after convergence is unreachable at
QUANTILE = 0.95without concealment.Implement here, or land as a checkpoint? I'm landing this as the checkpoint, for three reasons:
Safari +40 ms (2026-11-03, maintainer): ✅ the by-hand Safari baseline moves out of this PR into the quest's Waiting section, on
kixtopwith Network Link Conditioner orsudo dnctl/pfctl, so this checkpoint lands without it.Stretch design (2026-11-03, maintainer): ✅ copy what WebRTC's NetEq does.
watch.md's Plan now mirrors accelerate and preemptive expand: whole pitch periods found by autocorrelation, removed or repeated with a cross-fade. It citestime_stretch.cc/.h,accelerate.cc,preemptive_expand.ccanddecision_logic.cc/.hat WebRTCa057d00e46, with NetEq's thresholds as the starting point:The Plan also records where it must depart from NetEq. NetEq conceals a missing packet with Expand, which is outside this quest, and at NetEq's cadence preemptive expand slows playback by about a quarter at most. That covers the median late frame (11–31%) but not the 38–71% tail, so the tail is decided from replay numbers after the port.
Tree: I folded the m2 Time stretch quest into this one rather than moving it. Moving it would leave a Watch ↔ Time stretch dependency cycle, and folding keeps one quest on this claim. Watch now Requires A/V clock, inherited from Time stretch, and is [L].
Changes
Since the last review on this PR
test/audio-quality/traces/relay-mic-rtt40.jsonis the real-microphone Chrome row at +40 ms RTT (180 s, minimum RTT 47 ms), converted by the README's recipe. It is budgeted exactly as measured: 7.9 player underruns/min.player_underrunsmetric. This is the player's own counter, the one the stats panel shows:audio.out.stats.underrunsin the page probe, andring.underrunsyielded byjs/watch/src/audio/replay.ts.underrunskey read 0.3/min on this row against 7.9 from the player.js/watchreplay counts a single run-dry as one underrun, and a clean trace as none.statssignal.quest/m2/watch-audio-time-stretch.mdis folded intowatch.mdand deleted. Its links in the epic README,av-clock.md,watch-worker.md, and the m1 and m2 indexes now point to Watch.Earlier on this PR
--mic-broadcast <name>forjust test audio-quality-record --lanes relay-micrecords a hand-published broadcast.relay-micis re-recorded from the MacBook Air's built-in microphone through Chrome 156, with its replay ceilings re-measured (target p95 60 → 80 ms, silence 0 → 0.001).Baseline (the 2026-11-03 run)
Setup
<moq-publish>in Chrome 156, capturing the built-in microphone.--host-resolver-rules. Safari can't be redirected that way and negotiated WebSocket, so its rows ran without added RTT.Results
Cause. Replayed, each row's arrivals reproduce its live re-stalls and short quanta almost exactly. Each run-dry is one frame arriving later than the cushion the 0.95 quantile sizes, which happens in about 5% of 500 ms intervals.
Encoder. Lag is p50 0.9 ms and p99 1.1 ms, and drift is under 0.04 ms/s at both group sizes. The moq-dev/moq#3477 lag did not recur.
Replays on this head (
--enforce, within budget)relay-mic-rtt40relay-miclocal-aacrelay-bbbbursty-aacChoices made without asking
rs/moq-audiois suggested as a follow-up rather than added to this Goal.player_underrunsis budgeted only on the deterministic replay rows. Browser ceilings follow the nightly re-measure rule in the budgets note.Review
gpt-6.1-sol, medium effort, head92876c9525501b2fc715eb1cd72380800bdb4cd3againstorigin/main(7b4f531650), round 2 of the current session. 0 findings.17bee77d6a, and earlier rounds on35633722dband25da08bac3, also had 0 findings.Checks
just check origin/mainpasses on the final head: biome, js check and test, markdown, gh, quest, shell, text, toml, nix, justfile.quest check --base origin/mainpasses (577 documents).just test audio-quality --replays --enforceis within budget.@moq/audio-quality's CLI tests time out at 5 s when run bare on a host at load 30+. They pass underquest gate.Suggested next step:
/quest-merge.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)