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.
Overview
Overview
Handle Track Subscriptions
When the other side (client or server) subscribes to a broadcast path, the registeredmoqt.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, useTrackWriter.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 Backpressure
OpenGroup/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, useGroupWriter.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 withmoqt.NewFrame(capacity), reuse the buffer with Reset, and append payload via Write or by manipulating Body() when needed.
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, callGroupWriter.Close method.
Cancel Group Writing
To cancel a group and stop sending frames, callGroupWriter.CancelWrite method with an error code.
Stop a Track
To stop a track and indicate that no more groups will exist, callTrackWriter.Close method.
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.
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 — viaSession.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:
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.