streaming

Media streaming and broadcast systems in Go
Log | Files | Refs | README | LICENSE

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 }