Skip to content

feat: relative broadcast paths for cross-broadcast catalog renditions#1371

Draft
kixelated wants to merge 2 commits into
devfrom
catalog-broadcast-override
Draft

feat: relative broadcast paths for cross-broadcast catalog renditions#1371
kixelated wants to merge 2 commits into
devfrom
catalog-broadcast-override

Conversation

@kixelated

@kixelated kixelated commented May 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Rewritten from scratch against dev (the original main-based implementation predated the moq-mux catalog machinery and the js/watch rework) and now hooked up end to end on the consumer side.

A rendition in a hang catalog can set an optional broadcast field: a path relative to the broadcast that served the catalog (e.g. "../source"), pointing at the broadcast that actually publishes the track. A transcoder can then publish a sidecar catalog that adds new renditions while pointing unchanged ones at the original broadcast, instead of re-publishing those bytes.

Schema / path math

  • moq-net: new PathRelative type (trims slashes, drops . segments, preserves ..; serde only, never on the announce/subscribe wire) and Path::resolve with excess-.. clamping. Mirrored in @moq/net as Path.normalizeRelative / Path.resolve so both sides agree byte-for-byte.
  • hang / @moq/hang: optional broadcast field on VideoConfig and AudioConfig (skipped when unset, so existing catalogs are byte-identical).

Consumer wiring (the new part)

  • moq-mux: new Source type bundling the catalog BroadcastConsumer with optional (OriginConsumer, path) context, built via Source::new(broadcast).with_origin(origin, path). All exporters (fmp4, mkv, ts, flv, h264, h265) now take impl Into<Source>; a bare BroadcastConsumer still compiles via From but fails with a clear Error::MissingOrigin if a catalog actually references another broadcast. The shared ExportSource resolves the reference and fetches the broadcast via OriginConsumer::request_broadcast (announced broadcasts resolve immediately; OriginDynamic handlers serve the rest). Self-references and empty resolutions reuse the catalog broadcast instead of opening a duplicate subscription.
  • moq-cli subscribe, moq-srt egress, and moq-hls pass their origin through, so all three honor cross-broadcast renditions.
  • @moq/watch: Broadcast.trackBroadcast(effect, rel) resolves the reference against the broadcast name and consumes the resolved path on the same connection, caching one subscription per referenced broadcast (shared across renditions, gated on the same reload/announced logic). Wired into the audio + video decoder and MSE pipelines.

Public API changes

  • New: moq_net::{PathRelative, PathRelativeOwned}, moq_net::Path::resolve, moq_mux::Source, moq_mux::Error::MissingOrigin, hang::catalog::{VideoConfig,AudioConfig}::broadcast, @moq/net Path.resolve/Path.normalizeRelative, @moq/hang RelativeBroadcastSchema, @moq/watch Broadcast.trackBroadcast.
  • Breaking (hence dev): moq-mux exporter constructors and moq_hls::Broadcaster::new now take impl Into<Source> (source-compatible for callers passing a BroadcastConsumer by value); moq-cli's Subscribe::new likewise; catalog format gains an optional field.

Not covered (follow-ups)

  • moq-ffi (and the py/swift/kt/go wrappers) and moq-gst/moq-rtc consume tracks from a bare BroadcastConsumer and don't resolve references yet; they need origin context plumbed the same way.
  • The Rust client origin only resolves referenced broadcasts that are announced (or served by a dynamic handler); there's no client-side "subscribe by arbitrary path" fallback like conn.consume(path) in JS.
  • Pre-existing on dev: Cargo.lock is stale w.r.t. the nvidia-video-codec-sdk git dep (cargo metadata --locked fails before this PR too); left untouched here.

Test plan

  • PathRelative normalization + Path::resolve unit tests (Rust and JS mirrors)
  • Catalog serde round-trip: field deserializes, None stays off the wire, empty string normalizes (Rust hang + @moq/hang zod)
  • moq_mux::Source unit tests: no-override, missing-origin error, self-reference reuse, override resolving through a live origin
  • just check (full Rust + JS suites, clippy, fmt, rustdoc, biome)
  • Manual end-to-end: publish room/source, publish a sidecar catalog with broadcast: "../source", verify @moq/watch and moq subscribe pull the track from the source broadcast

(Written by Claude Fable 5)

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This change adds an optional per-rendition broadcast reference to audio and video configs and implements path utilities to normalize and resolve relative broadcast strings. Runtime code (Broadcast.trackBroadcast and updated decoder/MSE codepaths) now resolves and caches override broadcasts and falls back to the catalog broadcast when absent or self-referential. Importers populate the new field as None by default. Rust and JS tests exercise normalization, resolution, serialization, and subscription behavior.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
Title check ✅ Passed The title accurately summarizes the main change: relative broadcast paths for cross-broadcast catalog renditions.
Description check ✅ Passed The description is clearly about the same cross-broadcast rendition and path-resolution changes shown in the diff.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch catalog-broadcast-override

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.

@kixelated kixelated marked this pull request as draft May 5, 2026 16:07
@kixelated kixelated marked this pull request as ready for review May 23, 2026 17:58
@kixelated kixelated marked this pull request as draft June 16, 2026 19:53
A hang catalog rendition can now set an optional `broadcast` field, a
path relative to the broadcast that served the catalog (e.g. "../source"),
pointing at the broadcast that actually publishes the track. A transcoder
can then publish a sidecar catalog that adds new renditions while pointing
unchanged ones at the original broadcast instead of re-publishing the bytes.

- moq-net: new PathRelative type (normalized, ".."-capable, serde-only) and
  Path::resolve. Mirrored in @moq/net as Path.normalizeRelative/Path.resolve.
- hang / @moq/hang: optional `broadcast` field on VideoConfig and AudioConfig.
- moq-mux: new Source type bundling the catalog BroadcastConsumer with
  optional (OriginConsumer, path) context. Exporters take `impl Into<Source>`
  (bare BroadcastConsumer still works via From) and the shared ExportSource
  resolves per-rendition references via OriginConsumer::request_broadcast.
- moq-cli subscribe, moq-srt egress, and moq-hls pass their origin through.
- @moq/watch: Broadcast.trackBroadcast() resolves the reference against the
  broadcast name and consumes the resolved path on the same connection,
  caching one subscription per referenced broadcast; wired into the audio and
  video decoder and MSE pipelines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kixelated kixelated force-pushed the catalog-broadcast-override branch from be48c4c to 87b2f9b Compare July 2, 2026 04:07
@kixelated kixelated changed the title hang: cross-broadcast track references in renditions feat: relative broadcast paths for cross-broadcast catalog renditions Jul 2, 2026
@kixelated kixelated changed the base branch from main to dev July 2, 2026 04:08
@kixelated kixelated closed this Jul 2, 2026
@kixelated kixelated reopened this Jul 2, 2026
…-917897

# Conflicts:
#	js/watch/src/broadcast.ts
#	rs/moq-cli/src/main.rs
#	rs/moq-cli/src/subscribe.rs
#	rs/moq-hls/src/export/mod.rs
#	rs/moq-hls/src/export/rendition.rs
#	rs/moq-mux/src/codec/h264/export.rs
#	rs/moq-mux/src/container/fmp4/export.rs
#	rs/moq-mux/src/container/mkv/export.rs
#	rs/moq-mux/src/lib.rs
#	rs/moq-srt/src/ts.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant