/* NAME rtp.go - provides a data structure intended to encapsulate the properties of an rtp packet and also functions to allow manipulation of these packets. DESCRIPTION See Readme.md AUTHOR Saxon A. Nelson-Milton LICENSE rtp.go is Copyright (C) 2018 the Australian Ocean Lab (AusOcean) It is free software: you can redistribute it and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with revid in gpl.txt. If not, see [GNU licenses](http://www.gnu.org/licenses). */ /* See https://tools.ietf.org/html/rfc6184 and https://tools.ietf.org/html/rfc3550 for rtp-h264 and rtp standards. */ package rtp import ( "encoding/binary" ) const ( rtpVer = 2 // Version of RTP that this package is compatible with. defaultHeadSize = 12 // Header size of an rtp packet. defPayloadSize = sendSize // Default payload size for the rtp packet. defPktSize = defaultHeadSize + defPayloadSize // Default packet size is header size + payload size. optionalFieldIdx = 12 // This is the idx of optional fields including CSRC and extension header in an RTP packet. ) // Pkt provides fields consistent with RFC3550 definition of an rtp packet // The padding indicator does not need to be set manually, only the padding length type Pkt struct { V uint8 // Version (currently 2). p bool // Padding indicator (0 => padding, 1 => padding). X bool // Extension header indicator. CC uint8 // CSRC count. M bool // Marker bit. PT uint8 // Packet type. SN uint16 // Synch number. TS uint32 // Timestamp. SSRC uint32 // Synchronisation source identifier. CSRC [][4]byte // Contributing source identifier. Extension ExtensionHeader // Header extension. Payload []byte // Payload data. Padding []byte // No of bytes of padding. } // ExtensionHeader header provides fields for an RTP packet extension header. type ExtensionHeader struct { ID uint16 Header [][4]byte } // Bytes provides a byte slice of the packet func (p *Pkt) Bytes(buf []byte) []byte { // Calculate the required length for the RTP packet. headerExtensionLen := 0 if p.X { headerExtensionLen = int(4 + 4*len(p.Extension.Header)) } requiredPktLen := defaultHeadSize + int(4*p.CC) + headerExtensionLen + len(p.Payload) + len(p.Padding) // Create new space if no buffer is given, or it doesn't have sufficient capacity. if buf == nil || requiredPktLen > cap(buf) { buf = make([]byte, requiredPktLen, defPktSize) } buf = buf[:requiredPktLen] // Start encoding fields into the buffer. buf[0] = p.V<<6 | asByte(p.p)<<5 | asByte(p.X)<<4 | p.CC buf[1] = asByte(p.M)<<7 | p.PT binary.BigEndian.PutUint16(buf[2:4], p.SN) binary.BigEndian.PutUint32(buf[4:8], p.TS) binary.BigEndian.PutUint32(buf[8:12], p.SSRC) // If there is a CSRC count, add the CSRC to the buffer. if p.CC != 0 { if p.CC != uint8(len(p.CSRC)) { panic("CSRC count in RTP packet is incorrect") } for i := 0; i < int(p.CC); i++ { copy(buf[12+i*4:], p.CSRC[i][:]) } } // This is our current index for writing to the buffer. idx := int(12 + 4*p.CC) // If there is an extension field, add this to the buffer. if p.X { binary.BigEndian.PutUint16(buf[idx:idx+2], p.Extension.ID) idx += 2 binary.BigEndian.PutUint16(buf[idx:idx+2], uint16(len(p.Extension.Header))) idx += 2 for i := 0; i < len(p.Extension.Header); i++ { copy(buf[idx+i*4:], p.Extension.Header[i][:]) } idx += len(p.Extension.Header) * 4 } // If there is payload, add to the buffer. if p.Payload != nil { copy(buf[idx:], p.Payload) idx += len(p.Payload) } // Finally, if there is padding, add to the buffer. if p.Padding != nil { copy(buf[idx:], p.Padding) } return buf } func asByte(b bool) byte { if b { return 0x01 } return 0x00 }