{"record":{"id":"4a64f527a44fb835","repo":"pion/webrtc","slug":"duplicate-ogg-track-ssrc","errorCode":null,"errorMessage":"duplicate Ogg track SSRC","messagePattern":"duplicate Ogg track SSRC","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/media/oggwriter/oggwriter.go","lineNumber":51,"sourceCode":"\tchannelMappingFamily0              = 0\n\tchannelMappingFamily1              = 1\n\tchannelMappingFamily2              = 2\n\tchannelMappingFamily255            = 255\n\tidPageSignature                    = \"OpusHead\"\n\tcommentPageSignature               = \"OpusTags\"\n\tdefaultVendor                      = \"pion\"\n\tpageHeaderSignature                = \"OggS\"\n\tpageHeaderSize                     = 27\n\tmaxOggPageSegments                 = 255\n\tnoGranulePosition                  = ^uint64(0)\n\tmaxUint32Length                    = uint64(1<<32 - 1)\n)\n\nvar (\n\terrFileNotOpened        = errors.New(\"file not opened\")\n\terrOutputNotOpened      = errors.New(\"output not opened\")\n\terrInvalidNilPacket     = errors.New(\"invalid nil packet\")\n\terrDuplicateTrackSSRC   = errors.New(\"duplicate Ogg track SSRC\")\n\terrDuplicateTrackSerial = errors.New(\"duplicate Ogg track serial\")\n\terrTracksStarted        = errors.New(\"cannot add Ogg tracks after writing has started\")\n\terrPacketSSRCMismatch   = errors.New(\"RTP packet SSRC does not match Ogg track SSRC\")\n\terrInvalidOpusPacket    = errors.New(\"invalid Opus packet\")\n\terrInvalidChannelCount  = errors.New(\"invalid channel count\")\n\terrInvalidChannelMap    = errors.New(\"invalid channel mapping\")\n\terrInvalidOpusTags      = errors.New(\"invalid OpusTags\")\n)\n\ntype pageRewriter interface {\n\tio.Seeker\n\tio.WriterAt\n}\n\ntype writerConfig struct {\n\tsampleRate     uint32\n\tchannelMapping channelMapping\n\tpageRewriter   pageRewriter","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/pion/webrtc/blob/8c25dc09fa9e7c09aac4309ead88093d760432b0/pkg/media/oggwriter/oggwriter.go#L33-L69","documentation":"errDuplicateTrackSSRC is returned by Writer.NewTrack when a track with the same RTP SSRC already exists in the Ogg writer. Each Ogg logical stream (track) must have a unique SSRC to keep page streams distinguishable on demux.","triggerScenarios":"Calling writer.NewTrack(1111, ...) twice with the same SSRC (oggwriter.go:438 lookup in w.tracks); asserted in oggwriter_test.go:1151 with WithSerial(0x05060708).","commonSituations":"Re-adding the same remote track after a renegotiation, copying track SSRCs from two peers that collided, hardcoding the same SSRC for multiple audio streams.","solutions":["Use a unique SSRC per track; generate one (e.g. random uint32) per NewTrack call","Look up the existing track by SSRC and reuse it instead of creating a new one","If the remote SSRC genuinely changed, remove/close the old track first"],"exampleFix":"// before\nwriter.NewTrack(1111)\nwriter.NewTrack(1111) // errDuplicateTrackSSRC\n// after\nif _, exists := tracks[1111]; !exists {\n    writer.NewTrack(1111)\n}","handlingStrategy":"validation","validationCode":"if ssrc == existingSSRC {\n    return fmt.Errorf(\"SSRC %d already registered as a track\", ssrc)\n}\ntrack, err := writer.NewTrack(ssrc, opts...)","typeGuard":"func ssrcInUse(tracks map[uint32]struct{}, ssrc uint32) bool {\n    _, ok := tracks[ssrc]\n    return ok\n}","tryCatchPattern":"track, err := writer.NewTrack(ssrc, opts...)\nif errors.Is(err, oggwriter.ErrDuplicateTrackSSRC) {\n    // reuse the existing track for this SSRC instead of failing\n}","preventionTips":["Keep a registry of active SSRCs and check before NewTrack","Generate SSRCs randomly per RFC 3550 to avoid collisions","Handle renegotiation by reusing tracks keyed by SSRC"],"tags":["ogg","rtp","ssrc","track","duplicate"],"backgroundTag":"duplicate-ssrc","analyzedSha":"8c25dc09fa9e7c09aac4309ead88093d760432b0","analyzedAt":"2026-09-03T21:56:56.182Z","contentChangedAt":"2026-09-03T21:56:56.182Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}