pion/webrtc · error

RTP packet SSRC does not match Ogg track SSRC

Error message

RTP packet SSRC does not match Ogg track SSRC

What it means

errPacketSSRCMismatch is returned by Track.WriteRTP when the RTP packet's SSRC does not match the SSRC the track was created with. Each Ogg track is bound to exactly one RTP synchronization source, so routing packets from a different SSRC would mix streams and corrupt the Opus mapping. This is a per-track input validation error.

Source

Thrown at pkg/media/oggwriter/oggwriter.go:54

	channelMappingFamily255            = 255
	idPageSignature                    = "OpusHead"
	commentPageSignature               = "OpusTags"
	defaultVendor                      = "pion"
	pageHeaderSignature                = "OggS"
	pageHeaderSize                     = 27
	maxOggPageSegments                 = 255
	noGranulePosition                  = ^uint64(0)
	maxUint32Length                    = uint64(1<<32 - 1)
)

var (
	errFileNotOpened        = errors.New("file not opened")
	errOutputNotOpened      = errors.New("output not opened")
	errInvalidNilPacket     = errors.New("invalid nil packet")
	errDuplicateTrackSSRC   = errors.New("duplicate Ogg track SSRC")
	errDuplicateTrackSerial = errors.New("duplicate Ogg track serial")
	errTracksStarted        = errors.New("cannot add Ogg tracks after writing has started")
	errPacketSSRCMismatch   = errors.New("RTP packet SSRC does not match Ogg track SSRC")
	errInvalidOpusPacket    = errors.New("invalid Opus packet")
	errInvalidChannelCount  = errors.New("invalid channel count")
	errInvalidChannelMap    = errors.New("invalid channel mapping")
	errInvalidOpusTags      = errors.New("invalid OpusTags")
)

type pageRewriter interface {
	io.Seeker
	io.WriterAt
}

type writerConfig struct {
	sampleRate     uint32
	channelMapping channelMapping
	pageRewriter   pageRewriter
	opusTags       OpusTags
}

View on GitHub (pinned to 8c25dc09fa)

Solutions

  1. Route each RTP packet to the track matching its SSRC (use a map[uint32]*Track)
  2. Recreate the track with NewTrack(packet.SSRC) when the sender's SSRC legitimately changes
  3. Verify SSRC values at setup match what the RTP session actually delivers

Example fix

// before
track, _ := writer.NewTrack(1111, nil)
err := track.WriteRTP(pktWithSSRC(2222)) // mismatch
// after
tracks := map[uint32]*Track{}
track, _ := writer.NewTrack(1111, nil)
tracks[1111] = track
err := tracks[pkt.SSRC].WriteRTP(pkt)
Defensive patterns

Strategy: try-catch

Validate before calling

func writeIfMine(t *Track, pkt *rtp.Packet) error {
    if pkt.SSRC != t.SSRC() {
        return fmt.Errorf("skip pkt ssrc=%d track ssrc=%d", pkt.SSRC, t.SSRC())
    }
    return t.WriteRTP(pkt)
}

Try / catch

if err := track.WriteRTP(pkt); err != nil {
    if strings.Contains(err.Error(), "SSRC does not match") {
        // route to correct track or drop
    }
}

Prevention

When it happens

Trigger: Calling track.WriteRTP(packet) where packet.SSRC != track's ssrc — e.g. writing a packet with SSRC 2222 to a track created with NewTrack(1111, ...).

Common situations: Renegotiated RTP streams where the sender changed SSRC mid-session; forwarding packets from multiple peers into one track; a bug in a track-routing map keyed by the wrong field; a stream restart with a new random SSRC.

Related errors


AI-assisted analysis of pion/webrtc@8c25dc09fa (2026-09-03). Data as JSON: /api/errors/7fc8a5dc5121e822. Report an issue: GitHub.