package aoiprxkit import ( "encoding/binary" "errors" ) type RTPPacket struct { Version uint8 Padding bool Extension bool CSRCCount uint8 Marker bool PayloadType uint8 SequenceNumber uint16 Timestamp uint32 SSRC uint32 Payload []byte } func ParseRTPPacket(buf []byte) (RTPPacket, error) { if len(buf) < 12 { return RTPPacket{}, errors.New("RTP packet too short") } b0 := buf[0] b1 := buf[1] p := RTPPacket{ Version: b0 >> 6, Padding: (b0 & 0x20) != 0, Extension: (b0 & 0x10) != 0, CSRCCount: b0 & 0x0F, Marker: (b1 & 0x80) != 0, PayloadType: b1 & 0x7F, SequenceNumber: binary.BigEndian.Uint16(buf[2:4]), Timestamp: binary.BigEndian.Uint32(buf[4:8]), SSRC: binary.BigEndian.Uint32(buf[8:12]), } if p.Version != 2 { return RTPPacket{}, errors.New("unsupported RTP version") } headerLen := 12 + int(p.CSRCCount)*4 if len(buf) < headerLen { return RTPPacket{}, errors.New("RTP packet too short for CSRC list") } if p.Extension { if len(buf) < headerLen+4 { return RTPPacket{}, errors.New("RTP packet too short for extension") } extLenWords := int(binary.BigEndian.Uint16(buf[headerLen+2 : headerLen+4])) headerLen += 4 + extLenWords*4 if len(buf) < headerLen { return RTPPacket{}, errors.New("RTP packet too short for full extension") } } payload := buf[headerLen:] if p.Padding { if len(payload) == 0 { return RTPPacket{}, errors.New("RTP packet has invalid padding") } padLen := int(payload[len(payload)-1]) if padLen <= 0 || padLen > len(payload) { return RTPPacket{}, errors.New("RTP packet has invalid pad length") } payload = payload[:len(payload)-padLen] } // ALIASING FIX: copy payload bytes before returning. The caller reuses // the receive buffer on every ReadFromUDP call, so any RTPPacket stored // in the jitter buffer for later delivery would have its Payload slice // silently overwritten by the next incoming packet. p.Payload = append([]byte(nil), payload...) return p, nil }