package rtpfragmented import ( "crypto/rand" "github.com/pion/rtp" ) const ( rtpVersion = 2 defaultPayloadMaxSize = 1450 // 1500 (UDP MTU) - 20 (IP header) - 8 (UDP header) - 12 (RTP header) - 10 (SRTP overhead) ) func randUint32() (uint32, error) { var b [4]byte _, err := rand.Read(b[:]) if err != nil { return 0, err } return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3]), nil } func packetCount(avail, le int) int { n := le / avail if (le % avail) != 0 { n++ } return n } // Encoder is a RTP encoder for codecs with access units that can be fragmented. type Encoder struct { // payload type of packets. PayloadType uint8 // SSRC of packets (optional). // It defaults to a random value. SSRC *uint32 // initial sequence number of packets (optional). // It defaults to a random value. InitialSequenceNumber *uint16 // maximum size of packet payloads (optional). // It defaults to 1450. PayloadMaxSize int sequenceNumber uint16 } // Init initializes the encoder. func (e *Encoder) Init() error { if e.SSRC == nil { v, err := randUint32() if err != nil { return err } e.SSRC = &v } if e.InitialSequenceNumber == nil { v, err := randUint32() if err != nil { return err } v2 := uint16(v) e.InitialSequenceNumber = &v2 } if e.PayloadMaxSize == 0 { e.PayloadMaxSize = defaultPayloadMaxSize } e.sequenceNumber = *e.InitialSequenceNumber return nil } // Encode encodes a frame into RTP packets. func (e *Encoder) Encode(frame []byte) ([]*rtp.Packet, error) { avail := e.PayloadMaxSize le := len(frame) packetCount := packetCount(avail, le) ret := make([]*rtp.Packet, packetCount) pos := 0 le = avail for i := range ret { if i == (packetCount - 1) { le = len(frame[pos:]) } ret[i] = &rtp.Packet{ Header: rtp.Header{ Version: rtpVersion, PayloadType: e.PayloadType, SequenceNumber: e.sequenceNumber, SSRC: *e.SSRC, Marker: (i == packetCount-1), }, Payload: frame[pos : pos+le], } pos += le e.sequenceNumber++ } return ret, nil }