Skip to main content
Producing a track involves writing media data to a moqt.TrackWriter, which manages the creation of groups and frames for transmission. moqt.TrackWriter is responsible for handling the track’s lifecycle, including opening and closing groups. moqt.TrackWriter is created when being subscribed to a track from the peer on the session. Created moqt.TrackWriter is then routed via the session’s moqt.TrackMux and can be used to publish media data.

Handle Track Subscriptions

When the other side (client or server) subscribes to a broadcast path, the registered moqt.TrackHandler is invoked to serve the subscription. The handler receives a moqt.TrackWriter and is responsible for sending the appropriate track data for the requested track name.

Handle Track Subscriptions

Create a Group

To start a new group within a track, use TrackWriter.OpenGroup method. This creates a new group with an automatically incremented sequence number and returns a moqt.GroupWriter for writing frames to that group. For explicit sequence control, use TrackWriter.OpenGroupAt method with a specific moqt.GroupSequence.
Note: Context and BackpressureOpenGroup/OpenGroupAt take a context.Context as their first argument. The group is opened on a fresh QUIC stream; when the peer’s concurrent-stream limit (MAX_STREAMS) is reached, the call blocks — applying flow-control backpressure — until a stream is granted or the context is done (either the passed context or the track’s lifetime context, which is monitored internally). Pass context.Background() to bound the open to the track’s lifetime, or a context with timeout to drop a group under pressure rather than wait.
Note: Group OrderingGroups are supposed to be produced in order, with each group having a unique increasing sequence number and then consumed in order by the subscriber. However, groups not in order can be created, but this may lead to complications in playback and synchronization.
Note: Sequence Number 0Sequence number 0 has a special meaning: it is reserved for special identifiers like “Latest Available Group” or “Final Group”, and does not represent a real group.

Write Frames

To add media data to a group, use GroupWriter.WriteFrame method. Each frame represents a chunk of media data (audio, video, etc.) to be sent as part of the group.

Frame Creation

Create frames with moqt.NewFrame(capacity), reuse the buffer with Reset, and append payload via Write or by manipulating Body() when needed.
Frames are reused for efficiency; clone with frame.Clone() when you need to retain a copy after the next write.
Relays MUST NOT combine, split, or otherwise modify object payloads.
— MOQT WG1

Finalize a Group

To finalize a group and indicate that no more frames will be sent, call GroupWriter.Close method.

Cancel Group Writing

To cancel a group and stop sending frames, call GroupWriter.CancelWrite method with an error code.

Stop a Track

To stop a track and indicate that no more groups will exist, call TrackWriter.Close method.
To abort a track and indicate that no more groups will exist due to an error, call TrackWriter.CloseWithError method with an error code.
  • Subscribe Error Code: The subscribe error code is used to indicate the reason for closing the track subscription. It helps the publisher understand why the subscription finished.
If any groups belong to the track, they will be closed automatically with an error code moqt.PublishAbortedErrorCode when the track is closed. This ensures that all resources are released properly and no data is lost.

Track Info

A subscriber can ask about a track’s immutable publisher properties — priority, ordering preference, max latency, and timescale — via Session.TrackInfo, without subscribing to it. By default, TrackMux answers TRACK_INFO requests with zero-valued properties (zero priority, unordered, no retention, DefaultTimescale). To advertise real properties, implement TrackInfoProvider on your TrackHandler:
TRACK_INFO is intentionally out-of-band from the catalog: catalog fields (msf.Track) describe content, while PublishInfo carries transport scheduling hints, and the two live in different layers by design — msf.Track has no Priority/Ordered fields to source them from. The TrackInfoProvider type assertion runs against the handler registered with mux.Publish for the broadcast path — not against the per-track handler passed to RegisterTrack. msf.Broadcast does not implement TrackInfoProvider itself, so publishing one directly means every track reports the default zero-valued properties. To supply real ones, embed *msf.Broadcast in your own type and implement TrackInfo on it, then publish that type instead of the *msf.Broadcast value:
msf.Track has spec-defined TargetLatency/Timescale fields that already carry the same meaning as PublishInfo.MaxLatency/Timescale, so a wrapper can forward those straight from the catalog. Priority/Ordered have no catalog equivalent to source from — they are tracked in issue #420 as a possible future vendor extension to the catalog.

Footnotes

  1. IETF Draft - The Media Over QUIC Transport (moqtransport) ↩