Consume a Track
Consuming a track involves reading media data from a moqt.TrackReader, which provides access to groups and frames as they are received. This is typically done by the subscriber or receiver.
moqt.TrackReader is created when calling (moqt.Session).Subscribe method.
Overview
// Create a new session
// This differs from if it is client-side or server-side
var sess *moqt.Session
var config *moqt.TrackConfig
tr, err := sess.Subscribe("/broadcast_path", "track_name", config)
if err != nil {
// Handle error
return
}
defer tr.Close()
for {
gr, err := tr.AcceptGroup(context.Background())
if err != nil {
// Handle error
return
}
go func(gr *moqt.GroupReader) { // Read frames in parallel
defer gr.Close()
frame := moqt.NewFrame(0)
for {
if err := gr.ReadFrame(frame); err != nil {
// End of group or error
break
}
// Process the frame
// The raw payload data can be accessed with frame.Body()
}
}(gr)
}Subscribe to a Track
By subscribing to a track, a moqt.TrackReader is created, allowing the receiver to read media data from the track.
Accept a Group
To receive the next available group from a track, use (moqt.TrackReader).AcceptGroup method. This returns a moqt.GroupReader for reading frames from the group.
var tr *moqt.TrackReader
ctx := context.Background()
group, err := tr.AcceptGroup(ctx)
if err != nil {
// End of track or error
return
}
defer group.Close() // Always close when doneRead Frames
To read frames from a group, use (moqt.GroupReader).ReadFrame method. Each call decodes the next frame in the group into the internal moqt.Frame object. The frame is reused for each call. To cache the frame data, you have to clone it via (moqt.Frame).Clone before reading the next frame.
var group *moqt.GroupReader
frame := moqt.NewFrame(0) // Reuse the buffer
for {
if err := group.ReadFrame(frame); err != nil {
// End of group or error
break
}
// Process the frame using frame.Body()
}Iterate Frames
Instead of a loop with ReadFrame, you can use (moqt.GroupReader).Frames to get a lazy iterator. Reuse a buffer to minimize allocations; the iterator populates it on each yield.
frame := moqt.NewFrame(0)
for f := range group.Frames(frame) {
// f == frame; process payload in place
}Clone Frame
To clone a frame, use (moqt.Frame).Clone method. This creates a deep copy of the frame, including its data, allowing you to retain the frame data even after reading the next frame.
frame := moqt.NewFrame(0)
_ = group.ReadFrame(frame)
clone := frame.Clone()Copy and Cache Frame Data
To copy the frame data into a provided buffer, use (moqt.Frame).WriteTo method, implementing the io.WriterTo interface. It is useful for efficiently caching the frame data.
frame := moqt.NewFrame(0)
_ = group.ReadFrame(frame)
buf := bytes.NewBuffer(nil)
io.Copy(buf, frame) // or frame.WriteTo(buf)Cancel Group Reading
To cancel a group and stop receiving frames, call (moqt.GroupReader).CancelRead method with an error code.
var group *moqt.GroupReader
var code moqt.GroupErrorCode
group.CancelRead(code)- Group Error Code: The group error code is used to indicate the reason for canceling the group reading. It helps the sender understand why the group was canceled.
Unsubscribe from a Track
To unsubscribe from a track and stop receiving any further groups or frames with no errors, call (moqt.TrackReader).Close method.
var tr *moqt.TrackReader
tr.Close()To stop receiving any further groups or frames due to an error, call (moqt.TrackReader).CloseWithError method with an error code.
var tr *moqt.TrackReader
var code moqt.SubscribeErrorCode
tr.CloseWithError(code)- Subscribe Error Code: The subscribe error code is used to indicate the reason for closing the track subscription. It helps the subscriber understand why the subscription was terminated.
If any groups belong to the track, they will be closed automatically with an error code moqt.SubscribeCanceledErrorCode when the track is closed. This ensures that all resources are released properly and no unexpected behavior occurs.