From 270a92cdf3bfeccfba5a548d41793e1d137c9290 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 8 Nov 2026 09:46:19 -0800 Subject: [PATCH] quest: plan playout's move to positioned bus channels Co-Authored-By: Claude Opus 5.5 --- quest/m0/README.md | 2 ++ quest/m0/pin-bus-positioned.md | 20 +++++++++++++ quest/m0/playout-positioned.md | 54 ++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 quest/m0/pin-bus-positioned.md create mode 100644 quest/m0/playout-positioned.md diff --git a/quest/m0/README.md b/quest/m0/README.md index 464469e..63a6cff 100644 --- a/quest/m0/README.md +++ b/quest/m0/README.md @@ -109,6 +109,8 @@ repository. - [moq-audio's browser backends are pinned](/quest/m0/pin-browser-audio.md) - the web studio's audio slice - [moq-audio's source tap is pinned](/quest/m0/pin-audio-tap.md) - the samples clap-to-measure sync times a clap from - [moq-audio's strip pan is pinned](/quest/m0/pin-audio-pan.md) - the bus strip pan the studio's pan sets +- [Playout writes land on positioned bus channels](/quest/m0/playout-positioned.md) - broadcast, media, and replay sound at the bus position its pictures are timed for +- [moq-audio's positioned bus channel is pinned](/quest/m0/pin-bus-positioned.md) - `Bus::positioned`, which playout writes through - [A replayed media file never repeats a timestamp](/quest/m0/media-replay-timestamps.md) - a media source that starts over publishes strictly increasing timestamps, and its flaky test passes every run ## Related diff --git a/quest/m0/pin-bus-positioned.md b/quest/m0/pin-bus-positioned.md new file mode 100644 index 0000000..fe9dbef --- /dev/null +++ b/quest/m0/pin-bus-positioned.md @@ -0,0 +1,20 @@ +# [XS] moq-audio's positioned bus channel is pinned + +## Goal + +The `moq` submodule includes moq-audio's `Bus::positioned`, whose +`bus::Positioned::write(position, data)` plays a write at the bus position it +names, from [moq-dev/moq#8273](https://github.com/moq-dev/moq/pull/8273). That +PR also renamed `Bus::channel`/`bus::Channel` to `Bus::live`/`bus::Live`. + +## Plan + +Planned 2026-11-08 (maintainer, moq's /quest-complete), a follow-up of +moq-dev/moq#8273, which has merged on moq's `main`. + +Advance it with `just upgrade-moq` in its own PR, fixing whatever the new API +breaks here: at least the `Bus::live` rename at every `bus.channel(..)` call. +If [moq-dev/moq#8272](https://github.com/moq-dev/moq/pull/8272) has landed by +then, `moq_mux::timeline` is `moq_mux::sync`, and `playout.rs` follows that +PR's migration notes too. Move no audio onto positioned writes here; that is +[Playout writes land on positioned bus channels](/quest/m0/playout-positioned.md). diff --git a/quest/m0/playout-positioned.md b/quest/m0/playout-positioned.md new file mode 100644 index 0000000..4fb7576 --- /dev/null +++ b/quest/m0/playout-positioned.md @@ -0,0 +1,54 @@ +# [M] Playout writes land on positioned bus channels + +## Goal + +A broadcast, media, or replay source's sound plays at exactly the bus +position its pictures are timed for. `rs/moq-scene`'s playout writes it +through moq-audio's `Bus::positioned`, and its private copy of moq-audio's bus +latency (`BUS_LATENCY`) and of the live ring's pad rule are deleted. + +Non-goals: the `Speaker`'s jitter targeting stays as it is, and live inputs +(microphones, capture, guests) stay on `Bus::live`. + +## Plan + +Planned 2026-11-08 (maintainer, moq's /quest-complete), a follow-up of +[moq-dev/moq#8273](https://github.com/moq-dev/moq/pull/8273), which added +`Bus::positioned` for this consumer. + +Today `playout::Writer` writes into a live `bus::Channel` and keeps track of +when what it wrote runs out, padding silence ahead of a frame so it sounds a +copied 50 ms `BUS_LATENCY` later, the way moq-audio's ring would. Each source +that plays timed audio (`source.rs`'s broadcast, media, and replay paths) +goes through it. + +Decided with the maintainer: + +- ✅ **Studio maps an instant to a bus position** (rejected: an upstream + moq-audio bus clock). `Program::run_audio` (`rs/moq-studio/src/engine.rs`) already advances the bus + sample-exact on the program clock from `start`, so the position a frame + sounds at is `(sounds - start) * rate`. The writer gets the program clock's + `start` and the bus rate through the sources' `Context`. moq-audio's bus + counts frames and has no wall clock, so a clock there would guess timing + only the app knows. +- ✅ **A late frame is trimmed, not dropped** (rejected: drop the whole + frame). `Positioned::write` fails a write any part of which is already + mixed, overlaps earlier audio, or lands past `bus::REACH`. The writer cuts + the frames whose position has passed and writes the rest at its position, + as today's writer does with a late part. + +Recommendations, not settled: + +- Keep consecutive writes contiguous: a frame that starts within the + existing one-millisecond `CONTIGUOUS` stamp rounding of where the last one + ended is written at that end, since a one-frame overlap from rounding fails + the write. +- A frame the writer holds earlier than `REACH` ahead waits until it is in + reach rather than failing. +- Test on the scene's driver-stepped bus, as `a_write_sounds_when_placed` + does: frames written ahead, late, and across a stall sound at the expected + bus positions, sample-exact. + +## Required + +- [moq-audio's positioned bus channel is pinned](/quest/m0/pin-bus-positioned.md) - `Bus::positioned`, which the writer writes through