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
- Route each RTP packet to the track matching its SSRC (use a map[uint32]*Track)
- Recreate the track with NewTrack(packet.SSRC) when the sender's SSRC legitimately changes
- 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
- Dispatch packets by SSRC through a map[uint32]Track
- Handle SSRC changes (RTP renegotiation) by creating a new track
- Log and drop foreign-SSRC packets instead of guessing
- Verify SSRC configuration matches the actual RTP session
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
- duplicate Ogg track SSRC
- duplicate Ogg track serial
- stream is nil
- bad header signature
- bad opus tags signature
AI-assisted analysis of pion/webrtc@8c25dc09fa (2026-09-03).
Data as JSON: /api/errors/7fc8a5dc5121e822.
Report an issue: GitHub.