Repository navigation
fix(watch): cache audio support across unmute - #7248
Conversation
Quest-Claim: c5f3cb43fbccce56
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Quest-Claim: 7e8400ce34632c2b
Audio and video Sources now probe rendition support through a shared SupportProbe that owns the probe race, the per-rendition config-keyed cache, pending, and the NotSupportedError. Audio gains video's cache and an out.error, and the unsupported indicator reports an audio-only broadcast it cannot play. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Maintainer decision (2026-10-31, /quest-plan of the 10-31 follow-ups): keep this PR and rescope it after moq-dev/moq#7359 lands. Merge main, drop (Written by Claude Opus 5.5) |
…d29f664aa66 # Conflicts: # js/watch/src/audio/decoder.test.ts # js/watch/src/audio/source.test.ts
Drop support-cache.ts in favour of #7359's shared supportCacheKey. Keep the audio decoderConfigKey tag, the mute/unmute tests, and the bench. Finish the audio-support-cache quest and size its now childless push-to-talk epic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 3689fc1
No actionable bugs found. The audio key covers the decoder/probe inputs while allowing mute, jitter and bitrate metadata to reuse the verdict; cached selection still publishes the current metadata. Reusing the shared SupportProbe is simpler than maintaining a separate audio cache. The included #7359 extraction also preserves cancellation, cache pruning and unsupported-error handling on inspection. Keep the documented #7359-first landing order.
Verification: static inspection of code, tests and benchmark wiring, including an independent shared-probe/source/UI pass. Builds, tests, browser playback and benchmarks were not run; the reported performance measurements were not independently reproduced.
(Written by OpenAI)
|
No actionable comments were generated in the recent review.
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
This is stacked on #7359 and merges its head, so the diff against main also carries #7359's shared SupportProbe refactor; the audio-specific parts are the decoderConfigKey tag, the mute/unmute tests, and the bench.
- Shared
SupportProbe(from #7359) —js/watch/src/support-probe.tsowns the race against an unsettled probe, the per-supported-function, per-rendition config-keyed cache,pending, and aNotSupportedErrorerror; video and audioSourceboth delegate to it and expose itserror. - Audio support cache —
audio/config.tsaddsdecoderConfigKeyandaudio/decoder.tstags the moduleDecoder.supportedwith it, so metadata-only catalog changes (mute/unmute,enabled,jitter,bitrate) reuse the cached verdict while a decoder-relevant field (codec,container,description,sampleRate,numberOfChannels) re-probes. - Audio
out.error—Audio.Source.Outgains a public, additiveerror(reflected inapi/index.api.md), andunsupported-indicatornow reports an audio-only broadcast it cannot decode, deferring to video whenever a video catalog exists. - Tests and bench — mute/unmute source and decoder tests assert a single probe across the cycle and the AudioContext suspend/resume;
audio/supported.test.tscountsisConfigSupported;js/watch/bench/support.ts(just js audio-support-bench, added tosh/gh/nightly.sh) sweeps rendition count in the nightly series.
I verified the load-bearing behavior end to end: SupportProbe.run's early if (!supported) return; cannot strand pending=true (the effect.set cleanup drains on every rerun/close before the next run body), a torn-down probe's late result cannot reach publish/error (the race resolves undefined on abort, guarded by effect.abort.aborted), and decoderConfigKey covers every field the audio supported probe reads, so no false cache hit is possible. The watch tests for the changed files pass locally.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
# Conflicts: # js/watch/src/audio/source.test.ts # js/watch/src/ui/components/unsupported-indicator.test.ts # js/watch/src/ui/components/unsupported-indicator.ts
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
This run covers the delta since the prior pullfrog review at 3689fc104: a merge of main after #7359 landed, which moves the shared SupportProbe refactor and the audio out.error/unsupported-indicator work into the base and leaves the diff against main as only the audio-specific parts.
- Merged
mainafter #7359 landed — the branch'ssupport-probe.ts, videoSource/decoder/config, and audioSource/unsupported-indicatorchanges are now inherited frommain, so the PR's diff againstmainshrank to the audiodecoderConfigKeytag, the mute/unmute tests, the bench, and the quest cleanup. - Adopted
main'syieldNow()inaudio/source.test.ts— the localtickhelper is replaced by the injected-clock helper; the mute/unmute test itself is unchanged. - Picked up
main's AAC/warmupdecoder.test.tsadditions — they coexist with the PR'ssupportProbesmock and the AudioContext suspend/resume assertions. - Finished the quest bookkeeping —
quest/m1/push-to-talk/README.mdis now[M]with itsRequiredsection removed, and no references to the deletedaudio-support-cache.mdremain anywhere.
The audio-specific code is byte-identical to the approved revision, and the merge resolution matches main's landed #7359 code. decoderConfigKey remains a superset of every field the probe reads, so no false cache hit is possible. Ran bun test src/audio/source.test.ts (15 pass) and bun test src/audio/decoder.test.ts (56 pass) locally; audio/supported.test.ts cannot run here because its import graph reaches @moq/libav.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Completes
quest/m1/push-to-talk/audio-support-cache.md(deleted here).Builds on moq-dev/moq#7359, which has landed. The diff against main is now only the audio-specific changes.
Problem
On every catalog change, including a push-to-talk mute or unmute, audio rendition selection asked the decoder again whether the codec is supported. So on unmute the AudioContext could resume only after a support check of a few milliseconds, even though frames were already arriving. Video already caches its verdicts.
Approach
moq-dev/moq#7359 moved the per-rendition support cache into a shared
SupportProbe. That probe keys each verdict by the probe'ssupportCacheKey, or by the full config when the probe sets none. This PR adds only what is specific to audio:audio/config.tsaddsdecoderConfigKey, the JSON ofdecoderConfig. The built-inDecoder.supportedis tagged with it, the same way video's decoder is. As a result,enabled,jitter,bitrate, label and other metadata updates reuse the cached verdict. A change to a field the decoder uses still probes again.audio/source.test.ts: mute and unmute make one probe, publish the new metadata, and keep the rendition held. AsampleRatechange probes again.audio/decoder.test.ts: the same AudioContext suspends once drained and resumes on unmute, with one support probe in total.audio/supported.test.ts: the real libav/WebCodecs probe makes oneisConfigSupportedquery across mute and unmute.js/watch/bench/support.ts(just js audio-support-bench, in the nightly JS series) measures catalog updates against rendition count.Impact
quest/m1/push-to-talk/README.mdhas no children left, so it is now sized[M]and is the epic's remaining work.Validation
quest gate nix develop --command just ci origin/mainpasses on c727535 (check/test js, markdown, gh, quest, shell, toml, nix, justfile, workers, large_files).bun watch/bench/support.ts: after warmup, no new probes for 1, 8 or 32 renditions over 20 and 200 updates.Decisions
support-cache.tsand keep only the audiodecoderConfigKeytag, the mute/unmute tests, and the bench. ✅ Done.unsupported-indicatorconflicts took main's landed feat(watch): one support probe for audio and video #7359 version.audio/source.test.tstook main'syieldNowhelper in place of the localtickand kept this PR's mute/unmute test.sampleRatecase covers the key.Follow-ups
None.
Review
quest review --base origin/main: Codex, gpt-6.1-sol, medium effort, round 1 on head c727535 (after merging main, so the diff shows only the audio changes). No findings.Automated reviews on the previous head 3689fc1 (OpenAI review, Pullfrog, CodeRabbit) reported no actionable findings.
🤖 Generated with Claude Code
(Written by Claude Opus 5.5)