// 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 // put extension numbers in here. If they're 0, the extension is disabled (0 is not a legal extension number) extensionNumbers struct { 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, } } // WithSSRC sets the SSRC for the Packetizer. func WithSSRC(ssrc uint32) func(*packetizer) { return func(p *packetizer) { p.SSRC = ssrc } } // WithPayloadType sets the PayloadType for the Packetizer. func WithPayloadType(pt uint8) func(*packetizer) { return func(p *packetizer) { p.PayloadType = pt } } // WithTimestamp sets the initial Timestamp for the Packetizer. func WithTimestamp(timestamp uint32) func(*packetizer) { return func(p *packetizer) { p.Timestamp = timestamp } } // PacketizerOption is a function that configures a RTP Packetizer. type PacketizerOption func(*packetizer) // NewPacketizerWithOptions returns a new instance of a Packetizer with the given options. func NewPacketizerWithOptions( mtu uint16, payloader Payloader, sequencer Sequencer, clockRate uint32, options ...PacketizerOption, ) Packetizer { packetizerInstance := &packetizer{ MTU: mtu, Payloader: payloader, Sequencer: sequencer, Timestamp: globalMathRandomGenerator.Uint32(), ClockRate: clockRate, timegen: time.Now, } for _, option := range options { option(packetizerInstance) } return packetizerInstance } 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) // nolint: gosec // G115 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 }