feat(moq-mux,moq-srt): PTS-exposing TS Export API + PCR-paced SRT egress#1845
Merged
Conversation
…gress on it `ts::Export::next()` now yields a `moq_mux::container::Frame` instead of bare `Bytes`: each frame's `payload` is the TS packets, stamped with the source `timestamp` and `keyframe` flag so a transport can pace delivery on the media clock. PAT/PMT are no longer emitted as a separate timestamp-less chunk; the muxer buffers them and prepends them to the first media frame, so the leading header inherits a real timestamp and the previous startup double-PSI is gone. The SRT request egress (#1828) now stamps each SRT payload with `anchor + (timestamp - base)` rather than `Instant::now()`. That Instant is the packet origin time feeding SRT's TSBPD, so the receiver reconstructs the inter-frame spacing and a tune-in keyframe burst is released at the media rate instead of all at once, the pacing #1828 deferred. Part of #1839. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The deleted write_psi left its doc comment attached to pick_next_track; replace it with an accurate one. Document that SRT egress paces on the presentation timestamp (the only clock the muxer exposes) while frames transmit in decode order, so B-frame reorder leaves send_at slightly non-monotonic, which is harmless. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kixelated
added a commit
that referenced
this pull request
Jun 21, 2026
#1845 landed PTS-paced SRT egress + a Frame-returning ts::Subscriber::next on dev while this branch moved the egress path out of listen.rs into the new server.rs. Resolution: keep the Server/Request-based listen.rs (run() on top of Server) and port #1845's media-clock pacing into server.rs::serve_subscribe, which now consumes ts::Subscriber's Frame (timestamp + payload) and stamps each SRT payload with the frame's media time instead of Instant::now(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kixelated
pushed a commit
that referenced
this pull request
Jun 21, 2026
dev advanced 3 commits while this PR was open (#1845 PTS-exposing TS Export + PCR-paced SRT egress, #1847 moq-lite-05 wire sync, #1819 always-on hardware encoders). Re-merged dev and reconciled two conflicts: - nix/overlay.nix: kept this PR's cargo+sccache CI direction (dev's tip still carries the crane `moqChecks`; the cargo switch lives on main, #1821). - rs/moq-mux/src/container/ts/export.rs: combined dev's #1845 Frame-returning `Export::next` (PTS/keyframe-stamped) with this PR's generic `catalog::Catalog` trait (main's #1815 mpegts rename). Updated the moq-cli drain helper to read `frame.payload` and refreshed two stale `scte35::Ext` comments. Verified: moq-mux (279), moq-cli, moq-srt tests pass; workspace clippy -D warnings and fmt clean (excluding the crates that need libva/gstreamer system libs unavailable in this sandbox: moq-video/libmoq/moq-boy/moq-gst); JS type-checks and biome clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BQ9o9paZnRLpYRgbyjUwFV
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements step 1 of #1839: an additive media-timing API on
moq_mux::container::ts::Export, and uses it to fix the SRT egress tune-in burst that #1828 explicitly deferred.ts::Exportnow yieldsFrame, notBytesExport::next()/poll_next()returnOption<moq_mux::container::Frame>. Each frame'spayloadholds the TS packets, stamped with the sourcetimestampandkeyframeflag, so a transport can pace delivery on the media clock.durationis alwaysNone(the muxer never tracked it).write_framere-emitted PAT/PMT on the first keyframe (a startup double-PSI). Now step 3 only builds the PSI;write_frameprepends it to the first frame, so the header inherits that frame's real timestamp andtimestampis always valid (noOption). Removed the now-unusedwrite_psi.SRT egress paces on the media clock
serve_requeststamps each SRT payload withanchor + (timestamp - base)instead ofInstant::now(). ThatInstantis the packet's origin time feeding SRT's TSBPD, so the receiver reconstructs the original inter-frame spacing and the tune-in keyframe burst is released at the media rate instead of bursting. OneInstant::now()total (the anchor), no per-packet wall-clock stamps.Why this is the whole SRT fix
SRT already has congestion control and a receiver jitter buffer (TSBPD). The burst wasn't a missing-pacing problem; it was that we fed
Instant::now()as the packet origin time, collapsing all spacing into "simultaneous." Feeding real media time uses TSBPD as designed. The standalone PCR-pacing loop #1839 describes is still needed for the future raw UDP/RTP backends (no TSBPD there), but not for SRT.Notes
Export::next()returningFrameis a breaking moq-mux API change, hence targetingdev.durationwas not removed: it's load-bearing in fmp4 export (trun sample durations) and the consumer's group-advance, and isn't needed forExportto returnFrame(it just setsNone, like the legacy/flv/ts-import paths).moq-cliCLI surface is unchanged (same TS bytes to stdout).Test plan
cargo test -p moq-mux ts::(181 passed) — covers the PSI-buffering change and TS round-tripscargo test -p moq-srtcargo clippy -p moq-mux -p moq-srt -p moq-cli --all-targets(clean)m=requesttune-in no longer bursts the opening GOP (manual, ffmpeg/VLC loopback)Part of #1839; builds on #1828.
(Written by Claude)