Skip to content

refactor(moq-net): broadcasts own tracks own groups own frames via inherited Arc<Info>#1900

Merged
kixelated merged 2 commits into
devfrom
claude/kind-allen-bff7c0
Jun 24, 2026
Merged

refactor(moq-net): broadcasts own tracks own groups own frames via inherited Arc<Info>#1900
kixelated merged 2 commits into
devfrom
claude/kind-allen-bff7c0

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Makes the moq-net model a strict ownership chain: a child is born only from its parent's create_*, and each level inherits its parent's Arc<Info> so properties (notably the track timescale) are inherited rather than passed piecemeal.

Ownership: children are born only from parents

  • TrackProducer::new and TrackRequest::new are now pub(crate). The only public ways to mint a track are BroadcastProducer::create_track / reserve_track, or a dynamic TrackRequest.
  • BroadcastProducer::insert_track is removed. Its one production user, the IETF PUBLISH path in ietf/subscriber.rs, now start_announces the broadcast first and then create_tracks the track from it (so the track is genuinely born from its broadcast), undoing the announce on the error paths.
  • Standalone BroadcastInfo::produce() is kept, as agreed. Origin-owned broadcasts (Arc<OriginInfo>) remain a deliberate follow-up.

Inherited Arc<Info> chain

  • BroadcastProducer / BroadcastConsumer / BroadcastDynamic hold Arc<BroadcastInfo>, threaded into every track via create_track / reserve_track / TrackRequest::accept. Exposed as TrackProducer::broadcast().
  • TrackState holds Option<Arc<TrackInfo>>; each group inherits a shared Arc<TrackInfo> clone (replacing the copied-out Option<Timescale>), and GroupProducer::timescale() reads through it.
  • GroupProducer / GroupConsumer hold Arc<GroupInfo>, threaded into every frame. Exposed as FrameProducer::group().

Rename

GroupGroupInfo and FrameFrameInfo, matching the existing BroadcastInfo / TrackInfo convention. The wire types lite::Group / ietf::Group are unchanged.

Cascade

The only breakage anywhere in the workspace was test-site callers of the now-private constructors (moq-mux ×3 files, moq-json, moq-native test) and qualified moq_net::Group/Frame refs (moq-mux, hang). No production code outside moq-net needed changes. Test sites were migrated to create_track (via a throwaway broadcast helper) and the renamed types.

Public API changes (breaking, targets dev)

  • Group renamed to GroupInfo; Frame renamed to FrameInfo.
  • TrackProducer::new, TrackRequest::new demoted to pub(crate).
  • BroadcastProducer::insert_track removed.
  • BroadcastProducer/Consumer/Dynamic now carry Arc<BroadcastInfo>; GroupProducer/Consumer carry Arc<GroupInfo>; FrameProducer carries Arc<GroupInfo>.
  • New: TrackProducer::broadcast(), FrameProducer::group().

Testing

  • cargo test -p moq-net → 398 lib + 4 doctests pass.
  • 62 moq-native loopback broadcast tests pass — validates the IETF publish reshape end-to-end.
  • moq-mux / moq-json / hang / moq-relay libs pass.
  • cargo build --workspace --all-targets, clippy, and cargo fmt --check (nix toolchain) all clean.

Cross-package sync (follow-up)

  • js/net mirror (broadcast.ts / track.ts / group.ts) and doc/concept are not in this PR; they're the tracked follow-up.
  • Arc<OriginInfo> (origins owning broadcasts) intentionally deferred.

🤖 Generated with Claude Code

(Written by Claude)

kixelated and others added 2 commits June 23, 2026 23:25
…herited Arc<Info>

Make the model a strict ownership chain: a child is born only from its
parent's `create_*`, and each level inherits its parent's `Arc<Info>` so
properties (notably the track timescale) are inherited rather than passed
piecemeal.

Ownership:
- `TrackProducer::new` and `TrackRequest::new` are now `pub(crate)`. The
  public ways to mint a track are `BroadcastProducer::create_track` /
  `reserve_track`, or a dynamic `TrackRequest`.
- `BroadcastProducer::insert_track` is removed. The one production user (the
  IETF PUBLISH path) now announces the broadcast first, then `create_track`s
  the track from it, undoing the announce on the error paths.
- Standalone `BroadcastInfo::produce()` is kept (origin-owned broadcasts are
  still a follow-up, like `Arc<OriginInfo>`).

Inherited Arc chain:
- `BroadcastProducer`/`Consumer`/`Dynamic` hold `Arc<BroadcastInfo>`, threaded
  into each track (`TrackProducer::broadcast()`).
- `TrackState` holds `Option<Arc<TrackInfo>>`; each group inherits a shared
  `Arc<TrackInfo>` (replacing the copied-out `Option<Timescale>`), and
  `GroupProducer::timescale()` reads through it.
- `GroupProducer`/`Consumer` hold `Arc<GroupInfo>`, threaded into each frame
  (`FrameProducer::group()`).

Rename `Group` -> `GroupInfo` and `Frame` -> `FrameInfo` to match the existing
`BroadcastInfo`/`TrackInfo` convention (the wire `lite::Group`/`ietf::Group`
are unchanged).

Breaking change, targets `dev`. js/net mirror + doc/concept are a follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… Arc

These three info structs are small all-scalar values, so an Arc is overkill:
make them `Copy` and inherit them by value down the chain. Only `BroadcastInfo`
(which holds an `OriginList` Vec) stays behind an `Arc`.

The info accessors (`TrackSubscriber::info`, `FrameProducer::group`, the
Group Deref, etc.) still hand out `&T` references, so the internal storage can
move back to `Arc<T>` later without a breaking change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kixelated kixelated enabled auto-merge (squash) June 24, 2026 06:58
@kixelated kixelated merged commit fa5406a into dev Jun 24, 2026
1 check passed
@kixelated kixelated deleted the claude/kind-allen-bff7c0 branch June 24, 2026 06:58
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