rtp.go (7289B)
1 // Package rtp implements the Real-Time Transport Protocol as 2 // specified in RFC 3550. 3 package rtp 4 5 import ( 6 "encoding/binary" 7 "errors" 8 "fmt" 9 "math/rand" 10 ) 11 12 // Packet represents a single RTP data packet. 13 type Packet struct { 14 // Header is the RTP fixed header present at the beginning of 15 // every packet. 16 Header Header 17 // Payload contains the raw bytes, excluding the header, 18 // transported in a packet. 19 Payload []byte 20 } 21 22 // Header represents the "Fixed Header" specified in RFC 3550 section 5.1. 23 type Header struct { 24 // Version specifies the version of RTP used in the Packet. 25 // In practice, the only version in use is VersionRFC3550. 26 Version uint8 27 28 // TODO(otl): do we store padding bytes? how many? 29 padding bool 30 31 // Marker indicates the marker bit is set. The payload type 32 // determines how this value is interpreted. 33 Marker bool 34 35 // Type specifies the format of the payload transported in the Packet. 36 // In general, each type has its own IETF RFC specifying how the payload is encoded. 37 // For example, PayloadMP2T is detailed in RFC 2250. 38 Type PayloadType 39 40 // Sequence is a monotonically incremented number used by 41 // receivers to manage packet loss. The first packet's Sequence 42 // should be randomly assigned, then incremented by one for each 43 // RTP packet transmitted. 44 Sequence uint16 45 46 // Timestamp is the instant sampled of the first byte of the packet. 47 // The first packet in a session should have a randomly assigned 48 // timestamp. Subsequent timestamps are calculated according to a 49 // monotonically incrementing clock. The clock frequency, and how the 50 // timestamp should be interpreted, is dictated by the payload type. For 51 // instance, the Timestamp field of RTP packets with MPEG payloads 52 // represents the number of ticks of a 90KHz clock. Timestamps of GSM 53 // audio RTP packets represent ticks of a 8KHz clock. 54 Timestamp uint32 55 56 // SyncSource identifies the synchronisation source of the RTP 57 // session. It should be randomly assigned at the start of a 58 // session and remain unchanged throughout to prevent 59 // collisions with other sessions. 60 SyncSource uint32 61 62 // ContribSource lists a maximum of 15 contribution sources 63 // used to generate the payload. For example, a RTP session for 64 // audio transport may list each SyncSource in ContribSource. 65 ContribSource []uint32 66 67 // Extension is an optional field which may be used by certain 68 // payloads to transmit extra information. The RTP specification 69 // discourages the use of Extension. Instead it recommendeds to 70 // store extra information in leading bytes of the payload. 71 Extension *Extension 72 } 73 74 const ( 75 versionPreSpec uint8 = 0 76 VersionDraft uint8 = 1 << 6 77 VersionRFC3550 = 1 << 7 78 ) 79 80 type PayloadType uint8 81 82 const ( 83 PayloadL16Stereo PayloadType = 10 84 PayloadL16Mono PayloadType = 11 85 PayloadMP2T PayloadType = 33 86 // ... 87 ) 88 89 // DynamicPayloadType returns a randomly generated PayloadType from 90 // the range of allowed values for payloads with non-static PayloadType 91 // values. For example, transporting text and JPEG XS with RTP requires 92 // the use of a dynamic payload type. 93 func DynamicPayloadType() PayloadType { 94 floor := 96 95 ceil := 127 96 return PayloadType(floor + rand.Intn(ceil-floor)) 97 } 98 99 func (t PayloadType) String() string { 100 if t >= 96 && t <= 127 { 101 return "dynamic" 102 } 103 switch t { 104 case PayloadMP2T: 105 return "MP2T" 106 case PayloadL16Stereo, PayloadL16Mono: 107 return fmt.Sprintf("%d", t) 108 } 109 return "unknown" 110 } 111 112 const ( 113 ClockMP2T = 90000 // 90KHz 114 ClockPCMAudio = 44100 // 44.1KHz 115 ClockText = 1000 // 1KHz 116 ) 117 118 type Extension struct { 119 Profile [2]byte 120 Data []byte 121 } 122 123 var ErrNoPayload = errors.New("no payload") 124 125 // minHeaderLength is the minimum number of bytes in a packet header. 126 // It is calculated from the sum of the following components: 127 // - 1 byte (version, padding, extension, contrib count) 128 // - 1 byte (marker + type) 129 // - 2 bytes (sequence) 130 // - 4 bytes (timestamp) 131 // - 4 bytes (sync source) 132 const minHeaderLength = 12 133 134 func Unmarshal(data []byte, p *Packet) error { 135 if len(data) < minHeaderLength { 136 return fmt.Errorf("need at least %d bytes, have %d", minHeaderLength, len(data)) 137 } else if len(data) == minHeaderLength { 138 return ErrNoPayload 139 } 140 141 p.Header.Version = uint8(data[0] & 0b11000000) 142 p.Header.padding = data[0]&0b00100000 > 0 143 hasExtension := data[0]&0b00010000 > 0 144 // extension bit, ignore til later, 0b00010000 145 cc := data[0] & 0b00001111 146 if cc > 0 { 147 p.Header.ContribSource = make([]uint32, cc) 148 } 149 150 // m t t t t t t t 151 p.Header.Marker = data[1]&0x80 > 0 152 p.Header.Type = PayloadType(data[1] & 0x7f) 153 154 p.Header.Sequence = binary.BigEndian.Uint16(data[2:4]) 155 p.Header.Timestamp = binary.BigEndian.Uint32(data[4:8]) 156 p.Header.SyncSource = binary.BigEndian.Uint32(data[8:12]) 157 158 // throw away unmarshalled bytes 159 data = data[minHeaderLength:] 160 161 if hasExtension { 162 if len(data) < 4 { 163 return fmt.Errorf("header extension: %d bytes after header, need %d", len(data), 4) 164 } 165 ext := &Extension{} 166 copy(ext.Profile[:], data[:2]) 167 length := int(binary.BigEndian.Uint16(data[2:4])) 168 if len(data) < length { 169 return fmt.Errorf("header extension: reports length %d bytes, only have %d", length, len(data)) 170 } 171 if length > 0 { 172 ext.Data = data[4 : 4+length] 173 data = data[4+length:] 174 } else { 175 data = data[4:] 176 } 177 p.Header.Extension = ext 178 } 179 180 need := len(p.Header.ContribSource) * 4 // uint32 count * 4 for number of bytes needed 181 if len(data) < need { 182 return fmt.Errorf("contribution sources: need %d bytes, only have %d", need, len(data)) 183 } 184 var n int 185 for i := range p.Header.ContribSource { 186 p.Header.ContribSource[i] = binary.BigEndian.Uint32(data[n : n+4]) 187 n += 4 188 } 189 190 if len(data[n:]) == 0 { 191 return ErrNoPayload 192 } 193 p.Payload = data[n:] 194 return nil 195 } 196 197 const maxContribCount = 0x0f // max 4-bit integer 198 199 func Marshal(p *Packet) ([]byte, error) { 200 if p.Header.Version > VersionRFC3550 { 201 return nil, fmt.Errorf("bad version %v", p.Header.Version) 202 } 203 buf := make([]byte, minHeaderLength) 204 buf[0] |= p.Header.Version 205 if p.Header.padding { 206 buf[0] |= 0b00100000 207 } 208 if p.Header.Extension != nil { 209 buf[0] |= 0b00010000 210 } 211 if len(p.Header.ContribSource) > maxContribCount { 212 return nil, fmt.Errorf("contribution source count %d greater than max %d", len(p.Header.ContribSource), maxContribCount) 213 } 214 buf[0] |= uint8(len(p.Header.ContribSource)) 215 216 if p.Header.Marker { 217 buf[1] |= 0b10000000 218 } 219 220 if p.Header.Type > 0x7f { 221 return nil, fmt.Errorf("payload type %s (%d) greater than max %d", p.Header.Type, p.Header.Type, 0x7f) 222 } 223 buf[1] |= byte(p.Header.Type) 224 225 binary.BigEndian.PutUint16(buf[2:4], p.Header.Sequence) 226 binary.BigEndian.PutUint32(buf[4:8], p.Header.Timestamp) 227 binary.BigEndian.PutUint32(buf[8:12], p.Header.SyncSource) 228 229 if p.Header.Extension != nil { 230 buf = append(buf, p.Header.Extension.Profile[:]...) 231 if len(p.Header.Extension.Data) > 0xffff { // max uint16 232 return buf, fmt.Errorf("extension data length %d greater than max %d", len(p.Header.Extension.Data), 0xffff) 233 } 234 buf = binary.BigEndian.AppendUint16(buf, uint16(len(p.Header.Extension.Data))) 235 buf = append(buf, p.Header.Extension.Data...) 236 } 237 238 for _, src := range p.Header.ContribSource { 239 buf = binary.BigEndian.AppendUint32(buf, src) 240 } 241 242 return append(buf, p.Payload...), nil 243 }