diff --git a/quest/m2/capture-linux.md b/quest/m2/capture-linux.md index 09c8b56d67c..d6083901346 100644 --- a/quest/m2/capture-linux.md +++ b/quest/m2/capture-linux.md @@ -22,9 +22,10 @@ unimplemented, because xdg-desktop-portal owns source selection: - **Display selection stays picker-driven.** On Wayland a bare `--display` goes to the portal and a non-X11 id is refused. Since #5089 a `Selection` replays its restore token across reopens within one process, but the token is never - exposed, so a new `moq` run always shows the picker. Either the token becomes - persistable (API plus CLI) so a previously-approved source is reused without - the picker, or this stays a documented limitation answered by the X11 path. + exposed, so a new `moq` run always shows the picker. Decided 2026-10-26 + (maintainer): the token becomes persistable (API plus CLI), so a + previously-approved source is reused without the picker. + [Wayland studio sources](/quest/m3/studio/wayland-sources.md) consume it. - **System audio** needs a PipeWire monitor node. `moq_audio::capture::Source::System` exists but is macOS-only and returns `Unsupported` elsewhere. This is independent of the screencast portal. diff --git a/quest/m3/studio/README.md b/quest/m3/studio/README.md index 4b7de4afbee..d4fbb9a9de6 100644 --- a/quest/m3/studio/README.md +++ b/quest/m3/studio/README.md @@ -70,6 +70,10 @@ surface and zero-copy texture import, land before the cut. - [Zero-copy program encode](/quest/m1/studio-gpu/encode.md) - the program reaches the encoder as a GPU surface instead of a CPU readback - [Zero-copy source import](/quest/m1/studio-gpu/import.md) - captured and decoded frames reach the compositor as GPU textures instead of a CPU upload - [Studio on macOS and Windows](/quest/m3/studio/app.md) - the studio runs on macOS and Windows, not only Linux +- [Autosave](/quest/m3/studio/autosave.md) - every edit is written to the scene file, with no save step or quit prompt +- [Scene editing](/quest/m3/studio/scene-editing.md) - rename and reorder scenes, and resize the canvas while live through a new rendition +- [Broadcast sources play in sync](/quest/m3/studio/broadcast-sync.md) - subscribed broadcasts and guests play audio and video on the publisher's timestamps, with `moq play`'s delay +- [Wayland display and window sources](/quest/m3/studio/wayland-sources.md) - portal-picked sources that reopen without the picker - [Destinations](/quest/m3/studio/destinations.md) - RTMP, RTMPS, and WHIP push with per-destination codecs and shared encoders, on a UI-free egress library a hosted service can reuse - [Multiple canvases](/quest/m3/studio/multi-canvas.md) - landscape and portrait canvases composite at once from shared sources - [Guests](/quest/m3/studio/guests.md) - remote guests and phone cameras join through a moq-room link or QR code and appear as sources diff --git a/quest/m3/studio/autosave.md b/quest/m3/studio/autosave.md new file mode 100644 index 00000000000..ba3d5c9b85a --- /dev/null +++ b/quest/m3/studio/autosave.md @@ -0,0 +1,18 @@ +# [S] Studio autosave + +## Goal + +`moq-studio` writes every change to the scene collection to its scene file +shortly after it happens, with no save step and no prompt on quit. A crash +loses at most the edits inside the debounce window. A failed write shows in the +UI rather than being dropped. + +## Plan + +Decided 2026-10-26 (maintainer): autosave, not a dirty flag and a quit prompt. +Debounce bursts such as dragging a slider, flush on quit, and write +atomically (temporary file plus rename) so a crash never leaves a half-written +file. The scene file stays diffable, so an autosave that changes nothing +writes nothing. A scene path that does not exist yet is created by the first +autosave, replacing the guide's "created on the first save" and +**File > Save**. Update `doc/bin/studio.md`. diff --git a/quest/m3/studio/broadcast-sync.md b/quest/m3/studio/broadcast-sync.md new file mode 100644 index 00000000000..c9f1d5ac25a --- /dev/null +++ b/quest/m3/studio/broadcast-sync.md @@ -0,0 +1,34 @@ +# [M] Broadcast sources play in sync + +## Goal + +A subscribed MoQ broadcast in `moq-studio`, guests included, plays its audio +and video on the publisher's timestamps, so lip sync holds through network +jitter and stalls. Today each track plays at its own live edge, so a stall +can leave audio and video apart. + +## Plan + +Decided 2026-10-26 (maintainer): + +- **Scope:** broadcast sources only. Local devices keep the manual + per-source offsets in [Audio mixes](/quest/m3/studio/mixes.md). +- **Delay:** reuse `moq play`'s timing, the `--delay auto` target from + moq-audio's jitter estimate (`rs/moq-audio/src/jitter.rs`, + `doc/concept/audio-jitter.md`), rather than a second algorithm or a manual + setting. As in `moq play`, the estimate is the broadcast's audio track's, + and video follows it rather than keeping its own, so one delay governs the + whole broadcast. A broadcast with no audio keeps video's own short delay. + Show each source's delay in the UI. + +Lift the shared part out of `moq play` into a library both binaries use, +rather than copying it. The video side holds frames until their audio-aligned +time, and a source still repeats its last frame rather than stalling the +canvas. This replaces the live-edge behavior the studio app PR chose, where +replaying a publisher's timestamp gaps pushed audio behind its own video. Here +video waits for audio instead. Update `doc/bin/studio.md`. + +## Related + +- [Audio jitter target](/quest/m1/audio-jitter-target/README.md) - the delay estimate this reuses +- [Guests](/quest/m3/studio/guests.md) - guests are broadcast sources and inherit this diff --git a/quest/m3/studio/scene-editing.md b/quest/m3/studio/scene-editing.md new file mode 100644 index 00000000000..5ad27f7dfe2 --- /dev/null +++ b/quest/m3/studio/scene-editing.md @@ -0,0 +1,22 @@ +# [M] Scene editing + +## Goal + +In `moq-studio`, scenes can be renamed and reordered, and the canvas can be +resized while live, with no restart. + +## Plan + +Decided 2026-10-26 (maintainer): a resize while publishing adds a new video +rendition under a new track name in a catalog update, and viewers switch to +it. A track name never changes what it means (AGENTS.md), so the old track +ends rather than changing resolution mid-stream. The compositor reallocates +its canvas textures and the program encoder restarts on the new size. + +A rename updates every reference to the scene in the collection. Reordering +is the order of the scene file's list. Update +`doc/bin/studio.md`. + +## Related + +- [Multiple canvases](/quest/m3/studio/multi-canvas.md) - canvases of different sizes at once, sharing the resize path diff --git a/quest/m3/studio/wayland-sources.md b/quest/m3/studio/wayland-sources.md new file mode 100644 index 00000000000..ad836613ba6 --- /dev/null +++ b/quest/m3/studio/wayland-sources.md @@ -0,0 +1,30 @@ +# [M] Wayland display and window sources + +## Goal + +On a Wayland desktop, `moq-studio` adds display and window sources through +the xdg-desktop-portal picker. A source the user approved once reopens +without the picker, across restarts of the studio. Today display and window +sources capture only X11 and XWayland. + +## Plan + +Decided 2026-10-26 (maintainer): + +- **Token:** the portal restore token is persisted, which + [Linux capture parity](/quest/m2/capture-linux.md) makes possible in + moq-video. This quest consumes it. +- **Storage:** the token lives in per-machine state (the XDG state directory, + keyed by scene collection and source), never in the scene file, so the scene + file stays portable and diffable. On another machine, or when the portal + rejects the token, the picker shows once and the new token is stored. +- **Scene file:** the scene item records that the source is portal-picked, not + which monitor or window was picked, since only the portal knows that. + +Add the source kinds next to the X11 ones in moq-scene and the Sources panel, +and update `doc/bin/studio.md`, which says display and window sources are +X11-only. + +## Required + +- [Linux capture parity](/quest/m2/capture-linux.md) - the portal restore token becomes persistable