// SPDX-FileCopyrightText: 2023 The Pion community // SPDX-License-Identifier: MIT package rtp import ( "time" ) // Payloader payloads a byte array for use as rtp.Packet payloads type Payloader interface { Payload(mtu uint16, payload []byte) [][]byte } // Packetizer packetizes a payload type Packetizer interface { Packetize(payload []byte, samples uint32) []*Packet GeneratePadding(samples uint32) []*Packet EnableAbsSendTime(value int) SkipSamples(skippedSamples uint32) } type packetizer struct { MTU uint16 PayloadType uint8 SSRC uint32 Payloader Payloader Sequencer Sequencer Timestamp uint32 // Deprecated: will be removed in a future version. ClockRate uint32 extensionNumbers struct { // put extension numbers in here. If they're 0, the extension is disabled (0 is not a legal extension number) AbsSendTime int // http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time } timegen func() time.Time } // NewPacketizer returns a new instance of a Packetizer for a specific payloader func NewPacketizer(mtu uint16, pt uint8, ssrc uint32, payloader Payloader, sequencer Sequencer, clockRate uint32) Packetizer { return &packetizer{ MTU: mtu, PayloadType: pt, SSRC: ssrc, Payloader: payloader, Sequencer: sequencer, Timestamp: globalMathRandomGenerator.Uint32(), ClockRate: clockRate, timegen: time.Now, } } func (p *packetizer) EnableAbsSendTime(value int) { p.extensionNumbers.AbsSendTime = value } // Packetize packetizes the payload of an RTP packet and returns one or more RTP packets func (p *packetizer) Packetize(payload []byte, samples uint32) []*Packet { // Guard against an empty payload if len(payload) == 0 { return nil } payloads := p.Payloader.Payload(p.MTU-12, payload) packets := make([]*Packet, len(payloads)) for i, pp := range payloads { packets[i] = &Packet{ Header: Header{ Version: 2, Padding: false, Extension: false, Marker: i == len(payloads)-1, PayloadType: p.PayloadType, SequenceNumber: p.Sequencer.NextSequenceNumber(), Timestamp: p.Timestamp, // Figure out how to do timestamps SSRC: p.SSRC, CSRC: []uint32{}, }, Payload: pp, } } p.Timestamp += samples if len(packets) != 0 && p.extensionNumbers.AbsSendTime != 0 { sendTime := NewAbsSendTimeExtension(p.timegen()) // apply http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time b, err := sendTime.Marshal() if err != nil { return nil // never happens } err = packets[len(packets)-1].SetExtension(uint8(p.extensionNumbers.AbsSendTime), b) if err != nil { return nil // never happens } } return packets } // GeneratePadding returns required padding-only packages func (p *packetizer) GeneratePadding(samples uint32) []*Packet { // Guard against an empty payload if samples == 0 { return nil } packets := make([]*Packet, samples) for i := 0; i < int(samples); i++ { pp := make([]byte, 255) pp[254] = 255 packets[i] = &Packet{ Header: Header{ Version: 2, Padding: true, Extension: false, Marker: false, PayloadType: p.PayloadType, SequenceNumber: p.Sequencer.NextSequenceNumber(), Timestamp: p.Timestamp, // Use latest timestamp SSRC: p.SSRC, CSRC: []uint32{}, }, Payload: pp, } } return packets } // SkipSamples causes a gap in sample count between Packetize requests so the // RTP payloads produced have a gap in timestamps func (p *packetizer) SkipSamples(skippedSamples uint32) { p.Timestamp += skippedSamples }