Skip to content

feat(studio)!: moq-studio, moq-scene, and a moq-audio program bus - #6797

Merged
kixelated merged 23 commits into
mainfrom
quest/m3/studio/app
Oct 26, 2026
Merged

kixelated merged 23 commits into
mainfrom
quest/m3/studio/app

Conversation

@kixelated

@kixelated kixelated commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

Works on quest/m3/studio/app.md and rewrites it to the remaining work: running the studio on macOS and Windows. The GPU work moves to a new m1 epic, quest/m1/studio-gpu/ (zero-copy program encode and zero-copy source import), so moq-video's GPU encode and import API changes land before the cut.

Problem

The studio epic needs its first consumer: a native app that composes scenes on the GPU and goes live over MoQ. It also needs the UI-free crate (rs/moq-scene) and moq-audio's program bus that later quests build on.

Approach

  • moq-audio::bus (default bus feature, pure Rust): Bus mixes Channels into one interleaved f32 feed, read on the caller's clock.
    • Each channel is resampled and drift-corrected by fixed-resample, and remixed to the bus layout.
    • Strip (gain with a per-block ramp, mute, level meter) is caller-owned, so controls outlive a source restart.
    • Channel::write refuses a NaN or infinite sample, which would poison the whole mix through any gain.
    • Bus::capture (with capture) feeds a microphone or system audio into the bus until the device fails or stops, returning its error.
  • rs/moq-scene (new, publish = false):
    • Collection is a versioned TOML scene file with deny_unknown_fields. An unknown version or a dangling reference fails loudly, and the file never holds credentials.
    • source::Sources runs camera, display, window, microphone, and system-audio capture (behind capture), image, color, and subscribed-broadcast sources. Pictures go to a one-slot mailbox and sound goes to the bus. Editing a source restarts only that source. A broadcast source restarts a rendition only when the track its catalog entry resolves to changes, and fails on a catalog whose renditions all live in another broadcast.
    • Compositor draws preview and program into textures on the caller's wgpu device. It handles cut and fade, blends straight alpha in gamma space, and repeats a stalled source's last picture. A picture it cannot draw is reported through Compositor::error.
    • Readback is a pooled, non-blocking program copy for encoders that cannot take a GPU surface. A full pool drops frames rather than queuing them.
  • rs/moq-studio (new binary, publish = false):
    • eframe and egui_dock UI on one wgpu device (WgpuSetup::Existing), with preview and program registered as native egui textures, so neither is read back for display.
    • Docked panels: Preview, Program (Cut, Fade), Scenes, Items, Sources, Devices (pickers), Audio (gain, mute, meters), and Output (relay, viewers, readback and encode stats).
    • A program-clock thread draws the canvas. An audio thread reads the bus sample-exactly on the same clock. An encode thread reads the program back and encodes H.264, only while the video track is wanted, with a discontinuity on pause and a cut on resume. The canvas keeps drawing after the encoder stops.
    • Opus audio publishes alongside the video under --broadcast with a minted epoch. Both are stamped on the catalog's clock, so its advertised wall time is when the program drew them. Broadcast sources subscribe over the same connection.
    • The Sources panel shows a source as failed with the reason, whether its driver or the compositor failed it.

Impact

  • Breaking: moq_audio::encode::Level (capture feature) is now moq_audio::Level. Migrate by changing the import path. Noted in rs/moq-audio/MIGRATE.md.
  • New: moq_audio::bus::{Bus, Channel, Strip, Config, Capture} behind the default-on bus feature (adds the fixed-resample dependency).
  • New unpublished crates moq-scene and moq-studio. No wire changes.
  • CI: just rs render-sw (nightly) also runs the moq-scene compositor tests and a moq-studio end-to-end test on lavapipe. The capture lint and test pass now covers moq-scene and moq-studio.

Tests

  • moq-audio bus: mixing, gain ramp, mute, layout and rate conversion, a stalled source, a dropped channel, the meters, and refusing non-finite samples. benches/bus.rs sweeps the mix over 1, 4, and 16 channels at 48 kHz and resampled 44.1 kHz (about 3.4 us per channel per 10 ms block, linear).
  • moq-scene: the collection format (round trip, handwritten file, wrong version, unknown fields, dangling references, an unencodable canvas) source sync and restart behavior, a broadcast source switching renditions on a catalog update, following a stable rendition ID to a replacement track, and refusing a catalog of foreign renditions. GPU tests on lavapipe cover placement and order, hidden items, alpha, fade progress, cut, stalled-source repeat, an edited source dropping its old picture, a picture past the texture limit reporting why, and readback depth.
  • moq-studio: the program reaches a test relay and decodes as the composed color, with audio alongside (lavapipe + openh264).

Review round (/quest-iterate)

  • Codex: --connect failed from the binary because the QUIC client was built outside the runtime; fixed. A failed or stopped output dropped its tracks unfinished (viewers saw Dropped); it now aborts with the cause or finishes. Bus benchmark added. Declined: a poll-based source driver (its capture and decode inputs are async-only, and the sibling media crates use select! the same way) and a compositor bench (lavapipe timing is not meaningful; the GPU quests count readback and upload instead).
  • OpenAI review: a broadcast source now follows catalog updates, and the compositor forgets an edited source's last picture. Both fixed.
  • Second OpenAI review: a metadata-only catalog update (such as a jitter estimate) no longer restarts a broadcast rendition. Fixed.
  • Third round (on 551bef62f3), fixed in b206186024:
    • OpenAI: compare the track a rendition resolves to, not its catalog ID, since the JS publisher repoints a stable ID at a new track on a codec change.
    • Codex: stamp program media on the catalog's clock.
    • CodeRabbit: keep drawing after the encoder exits; refuse (rather than zero) non-finite PCM; qualify the scene file's sharing claim; leave Windows system audio to the Windows capture quest. The capture backoff finding is moot: the retry is gone (below).
    • Declined with reasons on the threads: preserving publisher timestamp gaps in broadcast audio (Codex; the studio plays each source at its live edge, so the stall already played as silence), playing on with one rendition when the other fails (CodeRabbit; a quiet degrade), scoping the AGENTS.md doc-sync row, tokio::select! in moq-scene, and hoisting bytemuck.
  • Merge round: main merged in for a quest/m1/README.md conflict. Codex then noted that pipewire advertised Wayland screen capture the scene sources never reach; the claim is corrected in 39277bb6a0 (PipeWire cameras and audio; display and window are X11 and XWayland only), and a portal-backed source is a follow-up.
  • Second merge round: the queue failed main's new Nightly bench coverage test, so moq-audio's bus bench now runs in the rust-extra leg. Codex: an Items pick whose source was removed or reloaded away added a dangling item; fixed in 98fb1be6f8.
  • Maintainer decision (2026-10-25), no silent runtime fallbacks, applied to what this PR adds: Bus::capture no longer reopens a failed device with backoff, a catalog of only foreign renditions fails the source instead of playing nothing, and a picture the compositor cannot draw shows as a failed source instead of only a log line. GPU import and export paths are in the stacked moq-dev/moq#6805 and moq-dev/moq#6806.

Alternatives

  • Zero-copy GPU encode in this PR. Each backend (NVENC Vulkan slot, VAAPI DMA-BUF, VideoToolbox IOSurface, D3D11) needs an exportable program texture below wgpu. That is a separate, independently landable step, now quest/m1/studio-gpu/encode.md.
  • JSON or RON for the scene file. TOML diffs and hand-edits best, and the workspace already depends on it.
  • egui 0.37: egui_dock 0.21 pins egui 0.36.

Decisions

Settled with the maintainer (/quest-iterate, recommendations accepted):

  1. ✅ Ship CPU readback now, zero-copy later. Every program frame is read back for the encoder (counted in the Output panel). The GPU work is split out of app.md (maintainer, 2026-10-25) into a new m1 epic, quest/m1/studio-gpu/README.md, so moq-video's GPU encode and import API changes land before the cut:

    • encode.md [L]: the program reaches the encoder as a GPU surface on NVENC (Vulkan slot), VideoToolbox (IOSurface CVPixelBuffer), and Media Foundation (shared D3D11), exported in moq-video or moq-scene. The slot is shaped so VA-API and AMD Vulkan Video can take it later without an API change.
    • import.md [M]: moq-video's renderer reports import or upload per frame, and captured and decoded frames reach the compositor as imported textures on Linux (DMA-BUF) and Apple (Metal), with uploads counted. The renderer already imports both; the gaps are that report, moq-scene not enabling pipewire, and no upload counter.
    • Placement: the epic is in quest/m1/README.md Required right after the API audit, and both quests lead quest/m3/studio/README.md Required. A dated Plan note in quest/m1/README.md and the studio README records why they are in m1.
    • Nothing in the epic requires m2 or m3 work, including app.md: each path is tested on its own platform's CI, NVENC by just rs gpu. No m2 quest moved. AMD Vulkan Video encode (vulkan-encode.md), Intel VA-API on an external Vulkan image (vaapi-vulkan-import.md), and Direct3D11 render import (render-d3d11.md) stay in m2 as Related follow-ups, as the m1 README already defers them; until they land, those backends take the counted CPU path.
    • app.md is retitled "Studio on macOS and Windows" and holds only the platform runs.
  2. ✅ Quest alignment. Nine studio quests that only needed the app to exist are unblocked: destinations, multi-canvas, guests, mixes, audio filters, recording, browser source, Linux vcam, and web video. Packaging and the macOS and Windows vcams still require app.md for the platform runs; none of them needs the GPU quests.

  3. ✅ Every audio source is always in the program mix, whatever scene is live, muted per source, until the audio mixes quest owns routing. OBS ties scene-local audio to the active scene.

  4. ✅ TOML scene file, version 1. Audio gain and mute live in a separate [audio.<name>] table, so editing them never restarts a source. A canvas change takes a restart.

  5. ✅ capture stays opt-in for moq-studio, as for moq-cli, because ALSA links at build time on Linux. A default build has image, color, and broadcast sources only. Revisit in packaging.

  6. ✅ No silent runtime fallbacks (maintainer, 2026-10-25): a path that cannot run is an error at setup or on use, never a quiet degrade with strikes or retries. Consequence here: an unplugged microphone fails its source with the reason, and the user re-adds or edits it to reopen, as with a camera.

Chosen without asking:

  • Strip::set_gain panics on a negative or non-finite gain, like Duration::from_secs_f32, instead of silently keeping the old one. Collection::validate refuses such a gain from a scene file, so only a caller bug reaches it.
  • Channel::write refuses non-finite samples with Error::Unsupported rather than replacing them with silence, per "fail loud on malformed input".
  • A compositor draw failure keeps the source's last good picture on the canvas while the Sources panel shows it as failed.

Follow-ups

  • app.md (rewritten): running the studio on macOS and Windows. Only Linux was built and run here.
  • quest/m1/studio-gpu/encode.md (new): the program reaches the encoder as a GPU surface instead of a CPU readback.
  • quest/m1/studio-gpu/import.md (new): sources reach the compositor as imported GPU textures, with uploads counted.
  • A portal-backed display and window source for Wayland, keeping the portal selection and restore token with the scene item (overlaps quest/m2/capture-linux.md).
  • m2 follow-ups that extend these to more backends already exist: vulkan-encode.md, vaapi-vulkan-import.md, render-d3d11.md.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 8 commits October 25, 2026 09:21
Quest-Claim: 9bb42c9a3f0daa9f
Adds the UI-free half of moq-studio: a versioned TOML scene collection,
live sources (capture, image, color, subscribed broadcast), a compositor
with preview, program, cut, and fade, and a pooled program readback.
Adds moq-audio's program bus with per-source strips, and moves Level to
the crate root so the bus and capture share it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One wgpu device serves the sources, the compositor, and the window. A
program clock draws the canvas and mixes the bus, and the program is read
back and encoded only while a viewer watches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…emains

Adds doc/bin/studio.md, the repository map and AGENTS.md rows, and the
moq-audio migration note for Level. The app quest now holds only the
zero-copy program encode and the macOS and Windows runs, and the studio
quests that only needed the app are unblocked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… frame

The canvas is black until a source delivers its first picture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title The studio app feat(studio)!: moq-studio, moq-scene, and a moq-audio program bus Oct 25, 2026
kixelated and others added 4 commits October 25, 2026 10:59
Collection::validate already refuses a negative or non-finite gain from a
scene file, so only a caller bug reaches Strip::set_gain; fail loud there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
app.md keeps only the macOS and Windows runs. Zero-copy program encode and
zero-copy source import become quest/m2/studio-gpu, ranked at the top of m2
and first in the studio epic, with a dated note in m1 and the studio README
that they drive moq-video improvements ahead of the cut without gating it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review October 25, 2026 18:12
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Walkthrough

The change adds an audio bus, a scene library with GPU composition and readback, and the MoQ Studio desktop application. Studio can edit scene collections, preview and program scenes, manage sources and audio, and optionally publish to a relay. The change also adds build and test wiring, Studio documentation, and updated GPU and cross-platform quest plans.

Priority: Normal

Merge Risk: Moderate · up to 551be

A decode error on one video or audio rendition of a broadcast source stops that source's other rendition until the publisher restarts. An output failure can also freeze the local studio window. Fix both before merging; the remaining items are minor.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 55.45% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 202 functions across 16 files. (19 skippe… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly identifies the three primary changes: the new studio application, scene crate, and audio program bus.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The pull request description directly describes the new moq-audio bus, moq-scene crate, moq-studio application, documentation and quest changes, GPU work split, breaking API change, tests, and remaini…
Full details: Description check

Explanation

The pull request description directly describes the new moq-audio bus, moq-scene crate, moq-studio application, documentation and quest changes, GPU work split, breaking API change, tests, and remaining platform work. It is clearly related to the changeset.

Full details: Docstring Coverage

Explanation

Docstring coverage is 55.45% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 202 functions across 16 files. (19 skipped: 19 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
✨ Simplify code
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-26T00:16:11.510632Z 4b96152 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: c9a4ffd

Two actionable findings:

  • P2 — Follow catalog updates within a broadcast (rs/moq-scene/src/source.rs:295–306). Only the first catalog is read. Joining while a camera is disabled means enabling it never starts video; switching codecs/tracks likewise leaves the original subscription frozen or ended until the broadcast restarts. Keep polling catalogs and rebuild affected consumers. Test enabling and track replacement without changing broadcast epoch.
  • P2 — Clear cached pictures when replacing a source (rs/moq-scene/src/compositor.rs:431–438). Sources restart when their configuration changes, but GPU layers survive by name alone. Replacing a visible source with an offline broadcast or missing image therefore keeps the previous source's picture on program indefinitely. Invalidate its layer when feed identity changes, while retaining last-frame behavior for the same stalled feed.

Overall direction is sound: separating scene composition from the UI, bounded readback, and caller-owned audio controls keep the implementation understandable.

Verification: static inspection of scene/source lifecycle, composition, audio bus, publisher integration and build wiring. No tests or GPU execution performed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c9a4ffd1c5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread rs/moq-studio/src/main.rs
Comment on lines +179 to +184
pub async fn run(self) {
let status = self.status.clone();
let result = tokio::select! {
_ = status.unused() => return,
result = self.produce() => result,
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Expose a poll-based source driver using kio primitives

rs/AGENTS.md requires new library logic to expose poll_* operations with async helpers and specifically directs libraries away from Tokio select!. The new source driver instead implements cancellation and production entirely through async futures here and another tokio::select! in broadcast, leaving no poll interface for callers that drive the UI-free scene library synchronously. Implement the driver state machine with kio primitives and make run its async wrapper.

AGENTS.md reference: rs/AGENTS.md:L21-L24

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declining. The driver composes moq-video's capture and decode consumers and moq-audio's capture, which are async-only today; a poll state machine here would have to pin and poll those futures inside kio::wait, the pattern rs/AGENTS.md names a smell. tokio::select! over them matches the sibling media crates (moq-video capture and decode, moq-audio capture). Poll APIs belong in those crates first, and moq-scene can follow once they exist.

(Written by Claude Opus 5.5)

Comment thread rs/moq-studio/src/engine.rs Outdated
Comment thread rs/moq-audio/src/bus.rs
Comment on lines +215 to +216
for entry in entries.iter_mut() {
entry.cons.read_interleaved(scratch, false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add benchmarks for the new real-time media paths

The new mixer performs resampling, gain processing, metering, and summation for every channel on each audio tick, alongside a new per-frame compositor and readback path. Searching the repository's benchmark code and Cargo manifests finds no benchmark exercising these additions; the supplied tests establish correctness but do not measure whether these paths meet their real-time budgets as source and item counts grow. Root AGENTS.md requires benchmarks for performance-sensitive changes, so add measured coverage for these paths before landing.

AGENTS.md reference: AGENTS.md:L53-L53

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partly fixed in b299e60009: rs/moq-audio/benches/bus.rs sweeps the bus over 1, 4, and 16 channels, at 48 kHz and resampled 44.1 kHz (about 3.4 us per channel per 10 ms block here, linear). Declining a compositor and readback bench for now: their cost is GPU time, and the only GPU in CI is lavapipe, whose timings say nothing about real hardware. The zero-copy encode and import quests (quest/m1/studio-gpu/) count readback and upload in the studio's stats, which is where that cost is tracked.

(Written by Claude Opus 5.5)

kixelated and others added 4 commits October 25, 2026 11:23
moq-video's GPU encode and import API changes land before the cut. The m1
quests are scoped to the API shape and the backends provable now (NVENC,
VideoToolbox, Media Foundation, DMA-BUF, Metal); AMD Vulkan encode, Intel
VA-API import, and Direct3D11 render import stay m2 follow-ups.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- moq-studio enters its runtime before building the QUIC client, which
  refused to start outside one, so --connect works from the binary.
- A failed video or audio output aborts its track with the cause instead of
  dropping it unfinished, and a clean stop finishes the video.
- A broadcast source follows catalog updates, switching a rendition when a
  better one appears instead of keeping the first catalog's choice.
- The compositor forgets an edited source's last picture, so a replaced
  source never shows the old one's frame.
- A criterion bench sweeps the program bus over channel count and resampling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Reply to the automated OpenAI review of c9a4ffd:

  • Follow catalog updates: fixed in b299e60009. A broadcast source keeps reading its catalog and restarts only the video or audio rendition whose pick changed; a rendition that ends waits for the next update. Covered by a_broadcast_follows_its_catalog.
  • Clear cached pictures when replacing a source: fixed in b299e60009. A compositor layer remembers its source and is dropped when the source is edited, so a replacement shows nothing until it has its own picture, while a stalled unchanged source still repeats its last one. Covered in a_stalled_source_repeats_its_last_picture (lavapipe).

(Written by Claude Opus 5.5)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 428a7565b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +389 to +391
while let Some(read) = consumer.read().await? {
if let moq_audio::decode::Read::Frame(frame) = read {
channel.write(&frame.data)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve timestamp gaps when feeding broadcast audio

When a broadcast delivers buffered audio containing a timestamp hole, this loop discards both the Read::Gap event and each frame's timestamp, then appends the PCM on either side contiguously. moq_audio::decode::Consumer::read returns available samples without pacing them, and the bus only buffers sample data, so silence is not inserted merely because the publisher's timeline contains a gap. For example, packets delivered together after a network stall can have their missing interval compressed away, shifting the source's audio relative to its video. Map decoded timestamps onto the program timeline and preserve gaps before writing samples to the bus.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declining. The studio plays every broadcast at its live edge, not on the publisher's timeline: a picture shows the moment it decodes (one-slot mailbox), and audio goes through the bus's bounded ring on the program clock. During a stall the bus already plays silence for that source in real time, so the hole is heard while it happens. Replaying the publisher's timeline after the burst would insert that hole a second time, putting the audio behind the live edge and behind its own video, which is already showing the newest frame. A burst of late audio is bounded by the bus's buffer (50 ms target, 200 ms capacity, trimmed back by its overflow correction). Timeline-accurate A/V sync per source would need a jitter buffer for video too, which belongs with the per-source sync work rather than here. The comment in play_audio now says this in b206186024.

(Written by Claude Opus 5.5)

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: 428a756

Both earlier findings are fixed: broadcast catalog updates are followed, and changed source definitions invalidate cached pictures.

P2 — Preserve playback across metadata-only catalog updates (rs/moq-scene/src/source.rs:329–332, likewise 317–320). Comparing entire rendition configurations recreates the decoder and audio bus channel when only jitter, delay, or descriptive metadata changes. Publisher estimates can republish once per second; each restart discards buffered audio and rejoins at Start::Latest, introducing discontinuities despite unchanged media. Compare playback identity/decoder-relevant fields separately and add a jitter-only update regression test.

The independently reported timestamp-gap loss #6797 (comment) also remains relevant; no duplicate comment added.

Direction remains sound. Runtime initialization and explicit producer aborts address the corresponding independent findings; the bus benchmark adds useful coverage.

Verification: static comparison against c9a4ffd and source/test inspection, accounting for merged base changes. Tests and benchmarks were not run.

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: b206186

The resolved-track comparison finding is fixed: Reference::track(config, id) now controls rebinding, with a regression covering stable-ID replacement. Metadata-only updates still preserve playback.

The shared catalog clock, continued preview rendering after encoder failure, explicit source errors and non-finite PCM rejection are sensible improvements. No new actionable bugs found in this update.

The earlier timestamp-gap concern #6797 (comment) is unchanged, not fixed; the author explicitly chooses arrival-clock playback and defers timeline-accurate source synchronization.

Verification: static comparison against 551bef6 and surrounding code/tests, accounting for base advancement. Tests, GPU execution and benchmarks were not run.

@kixelated

Copy link
Copy Markdown
Collaborator Author

Landing b206186024 through the merge queue (squash).

  • CI 11/11 green on this head; OpenAI and CodeRabbit found nothing new, and Codex gave a thumbs-up.
  • quest check --base origin/main passes on the head (505 documents ok).
  • Three declined threads stay open with their replies: the poll-based source driver and compositor bench (Codex), and preserving publisher timestamp gaps in broadcast audio (Codex). The queue does not require resolved conversations.
  • Stacked moq-dev/moq#6805 and moq-dev/moq#6806 will be retargeted to main after this lands.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 25, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 25, 2026
# Conflicts:
#	quest/m1/README.md

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3b598fe099

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread rs/moq-scene/src/source.rs
…ture

Display and window sources map to moq-video's X11 capture, so a Wayland
screen or window is unreachable until a portal-backed source exists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Re-landing after the queue dropped it for a quest/m1/README.md conflict with main.

  • Merged main in (kept both dated m1 Plan notes), then cargo clippy -D warnings (default and capture) and cargo test for moq-audio, moq-scene, and moq-studio pass locally against the new main, which dropped moq-net exports in moq-dev/moq#6744.
  • Codex on the merge head: pipewire advertised Wayland screen capture that scene sources never reach. Fixed the claim in 39277bb6a0; a portal-backed source is a follow-up.
  • quest check --base origin/main passes (555 documents ok). Landing 39277bb6a0.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 25, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 25, 2026
Also registers moq-audio's bus bench in the rust-extra Nightly leg, which
main's bench coverage test now requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: 4b96152

No new actionable bugs found in the PR-specific update. Registering moq-audio's bus benchmark in the rust-extra Nightly invocation is a focused coverage fix: the named target exists, uses Criterion, and its required bus feature is enabled by default. The merged benchmark-coverage check now includes it.

The studio/audio implementation and previously fixed resolved-track rebinding are unchanged. The timestamp-gap concern #6797 (comment) remains intentionally unchanged, not fixed; arrival-clock playback is still the chosen design.

Verification: static base-aware comparison against the last published review and intervening equivalent merges, plus Nightly registration, target manifest and benchmark inspection. No builds, tests, benchmarks or GPU execution performed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b96152401

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread rs/moq-studio/src/ui.rs
A pick held across removing its source, or reloading a collection without
it, added a dangling item that failed every later save.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: 98fb1be

The independent stale-source selection finding #6797 (comment) is fixed: the Items panel clears a selection absent from the current video-capable sources before it can be inserted. The same state lock covers validation and insertion, so source removal or reload cannot interleave between them.

No new actionable bugs found. Reusing the existing eligible-source list is a simple, focused fix. Earlier resolved-track fixes and the intentionally deferred timestamp-gap behavior are unchanged.

Verification: static inspection of the four-line delta and surrounding add/remove/reload flow against 4b96152; base unchanged. No regression test was added in this delta, and no tests, builds or GUI execution were run.

@kixelated

Copy link
Copy Markdown
Collaborator Author

Re-landing after the queue failed test gh on main's new Nightly bench coverage test.

  • Merged main in again (another quest/m1/README.md Plan-note conflict, both kept) and registered moq-audio's bus bench in the rust-extra Nightly leg; just gh test passes locally.
  • Codex: an Items pick whose source was removed or reloaded away added a dangling item. Fixed in 98fb1be6f8; the OpenAI review of that head found nothing new.
  • clippy (default and capture) and tests for moq-audio, moq-scene, and moq-studio pass against this main; quest check passes (556 documents ok). Landing 98fb1be6f8.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 26, 2026
Merged via the queue into main with commit 88e1a94 Oct 26, 2026
10 checks passed
@kixelated
kixelated deleted the quest/m3/studio/app branch October 26, 2026 02:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant