Skip to main content

Overview

TrackRemote represents a single inbound source of media. It provides methods to read RTP packets, access track metadata, and handle retransmission (RTX) streams.

Type Definition

type TrackRemote struct {
    mu              sync.RWMutex
    id              string
    streamID        string
    payloadType     PayloadType
    kind            RTPCodecType
    ssrc            SSRC
    rtxSsrc         SSRC
    codec           RTPCodecParameters
    params          RTPParameters
    rid             string
    receiver        *RTPReceiver
    peekedPackets   []*peekedPacket
    audioPlayoutStatsProviders []AudioPlayoutStatsProvider
}

Methods

ID

Returns the unique identifier for this Track. This should be unique for the stream, but doesn’t have to be globally unique. A common example would be ‘audio’ or ‘video’ and StreamID would be ‘desktop’ or ‘webcam’.
func (t *TrackRemote) ID() string
id
string
The track identifier

RID

Gets the RTP Stream ID of this Track. With Simulcast you will have multiple tracks with the same ID, but different RID values. In many cases a TrackRemote will not have an RID, so it is important to assert it is non-zero.
func (t *TrackRemote) RID() string
rid
string
The RTP stream identifier, or empty string if not set

PayloadType

Gets the PayloadType of the track.
func (t *TrackRemote) PayloadType() PayloadType
payloadType
PayloadType
The RTP payload type number

Kind

Gets the Kind of the track (audio or video).
func (t *TrackRemote) Kind() RTPCodecType
kind
RTPCodecType
Either RTPCodecTypeAudio or RTPCodecTypeVideo

StreamID

Returns the group this track belongs to. This must be unique.
func (t *TrackRemote) StreamID() string
streamID
string
The stream identifier

SSRC

Gets the SSRC of the track.
func (t *TrackRemote) SSRC() SSRC
ssrc
SSRC
The synchronization source identifier

Msid

Gets the Msid (Media Stream ID) of the track.
func (t *TrackRemote) Msid() string
msid
string
The media stream ID in format “streamID trackID”

Codec

Gets the Codec of the track.
func (t *TrackRemote) Codec() RTPCodecParameters
codec
RTPCodecParameters
The codec parameters including mime type, clock rate, and format parameters

Read

Reads data from the track.
func (t *TrackRemote) Read(b []byte) (n int, attributes interceptor.Attributes, err error)
b
[]byte
required
Buffer to read RTP packet data into
n
int
Number of bytes read
attributes
interceptor.Attributes
Interceptor attributes associated with the packet
error
error
Returns io.EOF if receiver is closed, or other errors on read failure
This method automatically handles RTX (retransmission) packets if available, transparently merging them into the main stream.

ReadRTP

A convenience method that wraps Read and unmarshals for you.
func (t *TrackRemote) ReadRTP() (*rtp.Packet, interceptor.Attributes, error)
packet
*rtp.Packet
The unmarshaled RTP packet
attributes
interceptor.Attributes
Interceptor attributes
error
error
Returns error if read or unmarshal fails
for {
    packet, attributes, err := track.ReadRTP()
    if err != nil {
        return err
    }
    
    fmt.Printf("Received RTP: SSRC=%d, Seq=%d, Timestamp=%d\n",
        packet.SSRC, packet.SequenceNumber, packet.Timestamp)
    
    // Process packet payload
    processMedia(packet.Payload)
}

SetReadDeadline

Sets the max amount of time the RTP stream will block before returning. 0 is forever.
func (t *TrackRemote) SetReadDeadline(deadline time.Time) error
deadline
time.Time
required
The deadline time. Zero value means no deadline.
error
error
Returns error if setting the deadline fails

RtxSSRC

Returns the RTX SSRC for a track, or 0 if track does not have a separate RTX stream.
func (t *TrackRemote) RtxSSRC() SSRC
rtxSsrc
SSRC
The RTX synchronization source identifier, or 0 if RTX is not enabled

HasRTX

Returns true if the track has a separate RTX stream.
func (t *TrackRemote) HasRTX() bool
hasRtx
bool
True if RTX is enabled for this track

Usage Examples

Basic Track Handling

peerConnection.OnTrack(func(track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
    fmt.Printf("Track started:\n")
    fmt.Printf("  ID: %s\n", track.ID())
    fmt.Printf("  Stream ID: %s\n", track.StreamID())
    fmt.Printf("  Kind: %s\n", track.Kind())
    fmt.Printf("  SSRC: %d\n", track.SSRC())
    fmt.Printf("  Codec: %s\n", track.Codec().MimeType)
    
    for {
        packet, _, err := track.ReadRTP()
        if err != nil {
            return
        }
        
        // Process RTP packet
        fmt.Printf("RTP: %d bytes\n", len(packet.Payload))
    }
})

Saving Track to File

peerConnection.OnTrack(func(track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
    codec := track.Codec()
    
    if codec.MimeType != webrtc.MimeTypeVP8 {
        return
    }
    
    // Create output file
    file, err := os.Create("output.ivf")
    if err != nil {
        panic(err)
    }
    defer file.Close()
    
    // Write IVF header
    ivfWriter, err := ivfwriter.New(file, codec.ClockRate)
    if err != nil {
        panic(err)
    }
    
    // Read and save packets
    for {
        packet, _, err := track.ReadRTP()
        if err != nil {
            return
        }
        
        if err := ivfWriter.WriteRTP(packet); err != nil {
            return
        }
    }
})

Handling Simulcast Tracks

peerConnection.OnTrack(func(track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
    rid := track.RID()
    
    if rid != "" {
        fmt.Printf("Simulcast track with RID: %s\n", rid)
    }
    
    // Get all simulcast tracks
    tracks := receiver.Tracks()
    fmt.Printf("Total tracks in receiver: %d\n", len(tracks))
    
    for _, t := range tracks {
        fmt.Printf("  RID: %s, SSRC: %d\n", t.RID(), t.SSRC())
    }
})

Checking RTX Support

peerConnection.OnTrack(func(track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
    if track.HasRTX() {
        fmt.Printf("Track has RTX support\n")
        fmt.Printf("Main SSRC: %d\n", track.SSRC())
        fmt.Printf("RTX SSRC: %d\n", track.RtxSSRC())
    } else {
        fmt.Printf("No RTX support\n")
    }
    
    for {
        packet, attributes, err := track.ReadRTP()
        if err != nil {
            return
        }
        
        // Check if this packet was retransmitted
        if rtxSsrc, ok := attributes.Get(webrtc.AttributeRtxSsrc).(uint32); ok {
            fmt.Printf("Retransmitted packet from SSRC %d\n", rtxSsrc)
        }
    }
})

Setting Read Timeout

peerConnection.OnTrack(func(track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
    // Set 5 second timeout
    deadline := time.Now().Add(5 * time.Second)
    if err := track.SetReadDeadline(deadline); err != nil {
        panic(err)
    }
    
    packet, _, err := track.ReadRTP()
    if err != nil {
        if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
            fmt.Println("Read timeout")
        }
        return
    }
    
    // Clear deadline
    track.SetReadDeadline(time.Time{})
})

Forwarding Track to Another Peer

// Receive track from one peer
peerConnection1.OnTrack(func(remoteTrack *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
    // Create local track to forward
    localTrack, err := webrtc.NewTrackLocalStaticRTP(
        remoteTrack.Codec().RTPCodecCapability,
        remoteTrack.ID(),
        remoteTrack.StreamID(),
    )
    if err != nil {
        panic(err)
    }
    
    // Add to second peer connection
    _, err = peerConnection2.AddTrack(localTrack)
    if err != nil {
        panic(err)
    }
    
    // Forward packets
    for {
        packet, _, err := remoteTrack.ReadRTP()
        if err != nil {
            return
        }
        
        if err := localTrack.WriteRTP(packet); err != nil {
            return
        }
    }
})

See Also

Build docs developers (and LLMs) love