Repository navigation
feat(scene): microphones and system audio publish their own Opus tracks - #40
Conversation
Quest-Claim: adcd8b881db6efc1
Each microphone and system-audio source encodes its capture, before gain and mute, as Opus in its nested catalog while it is used: while the mix on program plays it, or while something reads its track. Isolated recording and replay of audio sources read that track. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 43 minutes. View limit details
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. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head 3595a77883c6b0e9df4e3d7982b138839cd2195f against base 6d1b7242cc32910ad12ac3ec73b972ca3ab94730.
No actionable findings identified in this source review. The direction is sound: the studio-specific on-program/subscriber policy wraps the existing upstream encoder and shared capture rather than adding another capture or codec implementation. I traced capture fanout, unique track allocation, use transitions and discontinuities, failure handling, and the recording/replay consumers, including sound-only replay's speed restriction.
Verification limits: GitHub-only inspection of the diff, surrounding source, pinned moq implementation and tests; no build, tests, hardware capture/playback or performance measurements run. quest context could not be run in this GitHub-only review. The current Check job was still running when checked, so this does not establish CI success or validate the reported benchmarks.
There was a problem hiding this comment.
Important
The new microphone/system-audio tracks are local, but replay::targets gates every Of::Source on --connect, so replaying one (or saving its clip) fails offline with a message that does not hold for a local source.
Reviewed changes
- Per-source Opus track:
Audioinrs/moq-scene/src/publish.rsadvertises an Opus rendition from the shared capture input and encodes only while the source is on program (shown or heard) or read by a recording, marking capture gaps and leaving use. - Heard on program:
Program::on_programadds running microphones and system audio that the program mix plays to the set that keeps encoding, alongside shown scene items. - Recording and replay: source tracks flow through the existing
recordlisting;Program::sourcenow exposes an audio rendition, andFeed::replayrestricts sound-only takes to real time. - Docs and quests: README Audio/Replay/Health sections updated, and the
audio-source-tracksquest completed.
Technical details
# Source replay needlessly requires a relay
## Affected sites
- `rs/moq-studio/src/replay.rs:82` — `Some(_) => output()?.source(capture)` short-circuits on `self.output`, which is `Some` only with `--connect`.
- `README.md` (Replay) — "a replay needs `--connect`" generalizes the program's relay requirement to local sources.
## Required outcome
- A local source (camera, microphone, system audio, replay) can be replayed and saved as a clip without a relay: `Program.sources` is a local `Publish` broadcast created in `publish()` regardless of `--connect`, and `Program::source` reads it directly.
- `Of::Program` keeps its existing `output()` gate, since the program's catalog is the published broadcast.
## Suggested approach (optional)
- Use `self.program.source(capture)` for `Of::Source` (the `.with_context(...)` chain already handles `None`) and leave the `output()` closure for `Of::Program`; update the README sentence that generalizes the limitation.big-pickle (free) | 𝕏
Its track is kept in the local broadcast with or without a relay; only the program's past needs one. 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 head c2d45a71d1f0fb32aa3664af8b9962d7e70f96cc against base 8fdb2b2757e0f366de392b0f7e36dcbd3560a3bf, focusing on the changes since my review of 3595a77883c6b0e9df4e3d7982b138839cd2195f and separating the merged base changes.
No new actionable findings. The offline-source replay fix is sound: Engine::targets now reads local source tracks directly from self.program.source(capture), while only Of::Program checks for a relay. The engine creates the local source broadcast and passes its publisher into source context regardless of --connect, so this fixes both replay and clip selection without changing program replay's gate. The README now matches that distinction.
Verification limits: GitHub-only source review of the delta and replay/source initialization paths. No build, tests, hardware capture/playback, or performance measurements run; quest context could not be executed. Author-reported local passes were not independently reproduced. The current Check job was still running when checked.
(Written by review (OpenAI))
There was a problem hiding this comment.
ℹ️ No critical issues — one minor documentation clarity suggestion inline.
Reviewed changes
- Offline source replay:
Engine::targetsnow readsProgram::sourcefor every local source instead of gating onself.output, so cameras, microphones, system audio, and replay sources replay and clip without a relay; onlyOf::Programstill requires--connect. - Explicit LUT refusal: a
Source::Luttarget now fails with a "no picture or sound" message instead of falling through to the local-source path. - Docs: the README and
targetsdoc comment now state that a local source keeps its track without a relay, and only a replay of the program needs--connect.
big-pickle (free) | 𝕏
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A media file's sound publishes its own Opus track through publish::Audio, so an audio-only file's track goes live; a file without sound has no strip. - The own pictures' track opens before the play's clock starts. - Feed::play clears the held picture, and the engine sets the sources on program before drawing, so a restart never shows the last play's end. - The program's shown set includes mask sources; Health lists a source whose picture fails to draw as failed. - The media publish test holds the paused clock at each step, since a decoder on its own thread (Linux) let it jump past the restart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Finishes quest/m0/audio-source-tracks.md.
Problem
Microphones and system audio had no track of their own, so the studio could not record one in its own file or replay it. Cameras, displays, windows, images, and colors already had one (moq-dev/studio#21).
Approach
publish::Audio(rs/moq-scene/src/publish.rs) encodes a source's sound as Opus into its nested catalog underdev.moq.studio, beside the picture sources. It works likepublish::Video: it encodes only while the source is used, which means on program or with its track being read. Leaving use marks a gap. A capture gap re-stamps the next sound, so the track's timeline keeps the gap.Program::on_program(rs/moq-studio/src/engine.rs) adds those sources to the set of sources shown in a scene on air. Only microphones and system audio count as heard. A replay source's track holds its pictures, so its strip on the program mix does not keep it encoding.Driver::listenfeeds the bus and the encoder from the onecapture::Producer(moq-dev/studio#27). It reads each buffer from the capture consumer, after the capture chain and before the strip's gain, mute, and delay. The stall check that consumer did for moq-dev/studio#31 stays in the same loop. If the capture fails, the track ends with that error.--connect, since its track is in the local broadcast; only the program's replay needs a relay.Program::sourcereturns a sound-only target. A take with nothing encoded is refused withTake's reason. A slowed-down replay of sound alone is refused, because it would play nothing.publishesinrs/moq-scene/src/source.rsnow matches every variant explicitly, and its stale doc comment is rewritten.Publish::showis renamedPublish::set_on_program, because "shown" no longer covers sources that are heard.Encoder load: Opus runs on the CPU and holds no GPU encode session. Measured on an Apple M4 in release, encoding 60 s of 48 kHz input through
publish::Audiotook 617 ms for stereo (1.0% of one core) and 326 ms for mono (0.5%). An unused source costs about 5 ms per minute (0.01%). It adds no GPU copies and does not touch frame time.Impact
dev.moq.studiosources, by source name. The track stays local and never reaches a relay.--connect.README.mddocuments all of this.moq_scene::publish::Publish::showis renamedset_on_program. Its only consumer ismoq-studio.Alternatives
encode::Control(capture-backed, encodes on demand and keeps raw history) can encode only while subscribed or all the time. It cannot express "on program or subscribed", it compiles only with thecapturefeature (so default-feature tests could not cover it), and it would encode up to 30 s of held history for a recording that subscribes.encode::Producerbehind the same use rule as video needs no moq change.Program::on_program: the engine tests need a GPU. The rule underneath (Sources::plays) andpublish::Audioare covered in moq-scene.Choices made without asking
Config::from_input, rather than the bus's stereo layout.Follow-ups
None.
Validation
just ci: passes after merging main (quest: settle keyframes; plan a media file source and stinger transitions #39, feat(studio): a recording picks its mix #41, feat(scene): broadcast sources play in sync on the publisher's timestamps #38).cargo clippy --locked -p moq-scene -p moq-studio --all-targets --features moq-scene/capture,moq-studio/capture,moq-studio/openh264 -- -D warnings: clean.publish::tests::an_audio_encodes_while_used(paused clock viakio::clock). It checks that the rendition is listed before anything encodes, that nothing encodes while unused, that sound encodes on program and while read, that the timestamps land on the program clock, that a capture gap stays on the track, that a replay take holds the encoded span, that a take of nothing is refused, and that the track ends cleanly.Review
quest review, round 3)rs/moq-studio/src/replay.rs:82: fixed in c2d45a7. Local sources replay without--connect, and only the program needs a relay.README.md:643: wording suggestion applied in 254d197.(Written by Claude Opus 5.5)