Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions quest/m0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,15 @@ repository.
- [Studio on macOS with capture granted](/quest/m0/app-macos.md) - camera, screen, and audio capture run on a Mac, not only Linux
- [Studio on Windows](/quest/m0/app-windows.md) - the studio runs on Windows, not only Linux
- [Viewer-side composition](/quest/m0/compose/README.md) - sources as their own tracks plus a layout track, composed by viewers, with a server-composed program as the fallback
- [Worker threads fail loud at startup](/quest/m0/thread-start.md) - a worker that cannot start fails the studio's start instead of logging
- [The program encoder drains](/quest/m0/program-drain.md) - a hardware encoder never loses the program's last frames at exit or on pause
- [Outside edits to the scene file](/quest/m0/outside-edits.md) - autosave reloads or asks instead of overwriting a change made outside the studio
- [Scene editing](/quest/m0/scene-editing.md) - rename and reorder scenes, and resize the canvas while live through a new rendition
- [Broadcast sources play in sync](/quest/m0/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/m0/wayland-sources.md) - portal-picked sources that reopen without the picker
- [Live encode control](/quest/m0/encode-control.md) - simulcast rungs that follow the bandwidth grant, live bitrate and resolution, keyframes on request
- [Health grades source tracks](/quest/m0/health-sources.md) - the Health panel covers each published source track, not only the program
- [Audio sources report stalls](/quest/m0/audio-stall.md) - a dead microphone or system audio reads stalled like a camera
- [Relay failover](/quest/m0/failover.md) - the same epoch on two relays, so a relay failure does not drop the stream
- [Instant replay and DVR](/quest/m0/replay.md) - replays and clips from held groups, and viewer scrubbing through the archive
- [HTML/CSS overlays](/quest/m0/overlays.md) - script-free HTML and CSS graphics through Blitz natively and the DOM in the browser
Expand All @@ -96,10 +101,14 @@ repository.
- [Destinations](/quest/m0/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/m0/multi-canvas.md) - landscape and portrait canvases composite at once from shared sources
- [Guests](/quest/m0/guests.md) - remote guests and phone cameras join through a moq-room link or QR code and appear as sources
- [Guest return feed](/quest/m0/guest-return.md) - guests see the program and hear a mix-minus
- [Guest token refresh](/quest/m0/guest-refresh.md) - a show outlasts the guest link's expiry without new links
- [Audio mixes](/quest/m0/mixes.md) - per-output mixes, meters, monitoring, and sync offsets
- [Audio filters](/quest/m0/audio-filters.md) - per-source noise suppression, gate, compressor, limiter, and plugins, configured from the studio
- [Recording](/quest/m0/recording.md) - each canvas's program, and optionally each source, recorded to disk alongside live outputs
- [Browser sources](/quest/m0/browser-source.md) - web overlays rendered by out-of-process CEF into the compositor through shared GPU textures
- [Browser sources keep a profile](/quest/m0/browser-profile.md) - one persistent profile, so logins survive restarts, and a reload action
- [Browser source popups](/quest/m0/browser-popups.md) - dropdowns and other in-page popups draw and take input
- [Web studio](/quest/m0/web.md) - the full studio in wasm on WebGPU and WebCodecs, served from this repository
- [Virtual camera](/quest/m0/vcam/README.md) - a canvas's program exposed as a system camera on Linux, Windows, and macOS
- [Signing identities are available](/quest/m0/signing.md) - the Apple and Windows code-signing credentials packaging and the macOS camera need
Expand All @@ -112,6 +121,7 @@ repository.
- [moq-audio's filter chain is pinned](/quest/m0/pin-audio-filters.md) - the chain audio filters configure
- [moq-video's browser backends are pinned](/quest/m0/pin-browser-video.md) - the web studio's video slice and browser composition
- [moq-audio's browser backends are pinned](/quest/m0/pin-browser-audio.md) - the web studio's audio slice
- [moq-video's program readback is pinned](/quest/m0/pin-readback.md) - the readback the Linux virtual camera uses

## Related

Expand Down
21 changes: 21 additions & 0 deletions quest/m0/audio-stall.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# [S] Audio sources report stalls

## Goal

A live audio source (a microphone or system audio) that stops delivering
samples reads "stalled" in the Sources panel and Health, as a live camera does
after a second without a picture.

## Plan

Audio capture runs inside the audio bus today, which reports no last-delivery
time per source, so the stall check video sources have cannot see it. The
capture Producer/Consumer split that the audio-capture pin brings gives the
studio its own handle on each capture; read delivery from there rather than
adding a side channel in the bus. Raised on
[#5](https://github.com/moq-dev/studio/pull/5).

## Required

- [moq-audio's capture split is pinned](/quest/m0/pin-audio-capture.md) - the
per-capture handle this reads
19 changes: 19 additions & 0 deletions quest/m0/browser-popups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# [S] Browser source popups

## Goal

In-page popups of a browser source, such as `<select>` dropdowns, draw on the
canvas and take input like the rest of the page, on both the GPU import and
the CPU fallback paths.

## Plan

CEF paints popup widgets separately (`PET_POPUP`) with their own rectangle,
and the helper drops them today; `README.md` states the limitation, and this
quest removes that note. `window.open` and `target="_blank"` stay cancelled:
those are new browsers, not widgets. Raised on
[#8](https://github.com/moq-dev/studio/pull/8).

## Related

- [Browser sources](/quest/m0/browser-source.md) - the macOS and Windows half
24 changes: 24 additions & 0 deletions quest/m0/browser-profile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# [S] Browser sources keep a profile

## Goal

Browser sources share one persistent browser profile, so cookies and logins
(an alert service, a chat widget) survive a restart of the source or the
studio, as in OBS.
Each browser source also has a reload action that restarts its page without
editing the source.

## Plan

Decided 2026-11-02 (maintainer): one shared profile for all browser sources,
not one per source. Each page runs in its own CEF helper process today with a
fresh temporary profile, and two CEF instances cannot share a profile
directory, so sharing it means the helpers share one CEF instance or hand the
profile between them; weigh that against the crash isolation per page that the
helpers give. Keep the profile beside the studio's other per-user state, not
beside the scene file, since the scene file is meant to be shared. Raised on
[#8](https://github.com/moq-dev/studio/pull/8).

## Related

- [Browser sources](/quest/m0/browser-source.md) - the macOS and Windows half
23 changes: 15 additions & 8 deletions quest/m0/compose/layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,18 @@ what it settles on. Until then sources are listed provisionally as
`dev.moq.studio.sources.<name>` in the studio catalog, each a nested hang
catalog (decided 2026-11-02, maintainer; `rs/moq-scene/src/publish.rs`).

Clones and filters travel in the layout, not as tracks: a source's track is
its capture before any filter, and a clone publishes none, so the layout names
the source a clone shows and the filters each source and item applies
(decided 2026-11-02, maintainer).

## Required

- [Audio source tracks](/quest/m0/compose/sources.md) - the audio tracks a layout names
Clones and video filters travel in the layout, not as tracks: a picture
source's track is its capture before any filter, and a clone publishes none,
so the layout names the source a clone shows and the video filters each
source and item applies (decided 2026-11-02, maintainer). Only a video filter
that cannot render the same way in every viewer is baked into a track of its
own. Audio is the other way round: an audio source's track is published after
its audio filters ([Audio source tracks](/quest/m0/compose/sources.md)), so
the layout carries only what is applied after that point, such as gain and
mute, and never names an audio filter for a viewer to apply again. The
picture source tracks are enough to start; audio source tracks join the
layout when they land.

## Related

- [Audio source tracks](/quest/m0/compose/sources.md) - the audio tracks a layout also names once they land
19 changes: 19 additions & 0 deletions quest/m0/guest-refresh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# [M] Guest token refresh

## Goal

A show can outlast `--guest-expiry`: a joined guest's credential is renewed
while they stay in the room, without the host sending a new link and without
the guest reconnecting.

## Plan

A signed guest token cannot be revoked, and the relay ends a session at its
`exp`, which is why links expire today. The studio holds the room key, so it
signs each renewed token, and the token has to reach the connected guest
before `exp` over something the room already provides, such as a track only
that guest may subscribe to; the join page then re-authenticates with it.
Renew over the transport's own re-authentication if moq supports it, or land
that in moq first; do not invent a guest protocol. A host's Remove from scenes
should stop renewal, so the expiry bounds a removed guest again. Raised on
[#10](https://github.com/moq-dev/studio/pull/10).
23 changes: 23 additions & 0 deletions quest/m0/guest-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# [M] Guest return feed

## Goal

Guests in the studio's room see the program and hear a mix-minus, the program
audio without their own voice, so they can follow the show without hearing
themselves back.
The join page plays it.

## Plan

Decided 2026-11-02 (maintainer): guests get a mix-minus, not the full program,
so this waits on audio mixes; video and audio land together. Publish into the
room the studio already owns, under names the room's token scope allows, and
keep it free of the studio's own credentials. One mix-minus per guest grows
with the guest count, so bound it by design (the guest roster is already
bounded to guests the studio signed for). Raised on
[#10](https://github.com/moq-dev/studio/pull/10).

## Required

- [Audio mixes](/quest/m0/mixes.md) - the per-output mixes a mix-minus is
built from
22 changes: 22 additions & 0 deletions quest/m0/health-sources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# [S] Health grades source tracks

## Goal

The Health panel grades each published source track the way it grades the
program's: sent rate, viewers reporting, and the worst grade and latency they
report, so a source someone watches directly is covered too.

## Plan

Source tracks are listed in their own nested catalogs under the studio's
catalog (see `README.md`, Source tracks), and the health sampler reads only
the root renditions today. Viewers report per rendition through `.echo`, so
the per-track table and its causes extend to the source renditions rather than
adding a second path. Keep the table readable when there are many sources, for
example grouped by source. Raised on
[#3](https://github.com/moq-dev/studio/pull/3).

## Related

- [Source tracks](/quest/m0/compose/sources.md) - the audio source tracks this
grades once they land
31 changes: 31 additions & 0 deletions quest/m0/outside-edits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# [S] Outside edits to the scene file

## Goal

Autosave does not silently overwrite a change made to the scene file outside
the studio, by hand or by another studio on the same file, except in the short
window between its last check and its rename, which `README.md` names.
When the studio has nothing unsaved, it reloads the outside change without
asking.
When both sides changed, autosave pauses and the studio asks whether to keep
its own version or take the file's; nothing is written until the user picks.

## Plan

Decided 2026-11-02 (maintainer, follow-up planning after
[#4](https://github.com/moq-dev/studio/pull/4)): the silent reload and the
keep-mine or take-theirs prompt above. Today the last writer wins, which
`README.md` documents; that note goes away with this quest.

- Detect a change by what the studio last wrote or read, not by timing, so the
studio's own atomic rename never reads as an outside edit.
- Check again right before the autosave's rename, not only before its write,
since another studio can write in between. A window remains between that
check and the rename. No lock binds an arbitrary editor, so this is
best-effort; an advisory lock between studios is worth it only if it works
on every platform and removes the studio-to-studio half of the window.
- An outside edit that does not parse is refused like File > Reload refuses
it: the studio keeps its state, says why, and does not overwrite the file
until the user picks.
- The undo history file follows the scene file: a reload already replays or
drops its entries, and "take theirs" goes through that path.
19 changes: 19 additions & 0 deletions quest/m0/pin-readback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# [XS] moq-video's program readback is pinned

## Goal

moq-video exposes its GPU readback (the `render::export` readback route:
staging buffers, row unpadding, the mapping lifecycle) without an encoder,
merged on moq's `main` with a moq-side test, and the `moq` gitlink here
includes it.
Check with `just upgrade-moq` and a search of `moq/rs/moq-video` for a public
readback-only constructor.

## Plan

Decided 2026-11-02 (maintainer, on
[#9](https://github.com/moq-dev/studio/pull/9)): the Linux virtual camera's
readback lives in moq-video, not in a copy here. The readback is private today
and reachable only through an encoder probe. Land the public API in
moq-dev/moq first; no moq quest tracks it yet. Bump the pin in its own PR,
fixing whatever the bump breaks.
16 changes: 16 additions & 0 deletions quest/m0/program-drain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# [XS] The program encoder drains

## Goal

The program's encoder drains its buffered pictures before it stops at exit
and before the studio publishes the gap marker of an on-demand pause, so a
pipelined hardware encoder never loses the program's last frames.

## Plan

Source encoders already drain before they are replaced or their track ends,
and a failed drain aborts the track
([#3](https://github.com/moq-dev/studio/pull/3)). Give the program the same
behaviour through the same path rather than a second one. openh264 buffers
nothing, so prove it on an encoder that does, or with a test double that
holds frames.
5 changes: 3 additions & 2 deletions quest/m0/scene-editing.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

## Goal

In `moq-studio`, scenes can be renamed and reordered, and the canvas can be
resized while live, with no restart.
In `moq-studio`, scenes can be renamed and reordered, the transition's
settings (such as the fade time) can be edited as undoable steps, and the
canvas can be resized while live, with no restart.

## Plan

Expand Down
18 changes: 18 additions & 0 deletions quest/m0/thread-start.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# [XS] Worker threads fail loud at startup

## Goal

A studio worker thread (program, audio, source, autosave) that cannot start,
such as a failed thread spawn or Tokio runtime build, reports that error
instead of logging it and leaving the feature dead. A worker the studio needs
to run fails the studio's start; a source, which starts and restarts while
the studio runs, shows the error as that source's failure in the Sources
panel.

## Plan

`engine::clocked` builds each worker's runtime inside the spawned thread and
only logs a failure, and a failed source thread spawn is logged and dropped,
so the caller never learns of either. Build the runtime before spawning, or
hand the result back, and propagate it to whoever starts the worker. Raised on
[#4](https://github.com/moq-dev/studio/pull/4).
6 changes: 6 additions & 0 deletions quest/m0/vcam/linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@
The studio publishes a canvas's program as a PipeWire video node that
PipeWire-aware apps (browsers and conferencing apps) list as a camera. It
falls back to an existing v4l2loopback device when one is present.
The studio's Devices panel leaves out its own virtual camera, so picking it
cannot feed the program back into itself.

## Required

- [moq-video's program readback is pinned](/quest/m0/pin-readback.md) - the readback the camera reads the program through