summaryrefslogtreecommitdiff
path: root/vendor/github.com/pion/rtcp/header.go
blob: 055ca18bf22b9532a8b34d75c94cbabbc68e6837 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package rtcp

import (
	"encoding/binary"
)

// PacketType specifies the type of an RTCP packet
type PacketType uint8

// RTCP packet types registered with IANA. See: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-4
const (
	TypeSenderReport              PacketType = 200 // RFC 3550, 6.4.1
	TypeReceiverReport            PacketType = 201 // RFC 3550, 6.4.2
	TypeSourceDescription         PacketType = 202 // RFC 3550, 6.5
	TypeGoodbye                   PacketType = 203 // RFC 3550, 6.6
	TypeApplicationDefined        PacketType = 204 // RFC 3550, 6.7 (unimplemented)
	TypeTransportSpecificFeedback PacketType = 205 // RFC 4585, 6051
	TypePayloadSpecificFeedback   PacketType = 206 // RFC 4585, 6.3

)

// Transport and Payload specific feedback messages overload the count field to act as a message type. those are listed here
const (
	FormatSLI  uint8 = 2
	FormatPLI  uint8 = 1
	FormatFIR  uint8 = 4
	FormatTLN  uint8 = 1
	FormatRRR  uint8 = 5
	FormatREMB uint8 = 15

	//https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-5
	FormatTCC uint8 = 15
)

func (p PacketType) String() string {
	switch p {
	case TypeSenderReport:
		return "SR"
	case TypeReceiverReport:
		return "RR"
	case TypeSourceDescription:
		return "SDES"
	case TypeGoodbye:
		return "BYE"
	case TypeApplicationDefined:
		return "APP"
	case TypeTransportSpecificFeedback:
		return "TSFB"
	case TypePayloadSpecificFeedback:
		return "PSFB"
	default:
		return string(p)
	}
}

const rtpVersion = 2

// A Header is the common header shared by all RTCP packets
type Header struct {
	// If the padding bit is set, this individual RTCP packet contains
	// some additional padding octets at the end which are not part of
	// the control information but are included in the length field.
	Padding bool
	// The number of reception reports, sources contained or FMT in this packet (depending on the Type)
	Count uint8
	// The RTCP packet type for this packet
	Type PacketType
	// The length of this RTCP packet in 32-bit words minus one,
	// including the header and any padding.
	Length uint16
}

const (
	headerLength = 4
	versionShift = 6
	versionMask  = 0x3
	paddingShift = 5
	paddingMask  = 0x1
	countShift   = 0
	countMask    = 0x1f
	countMax     = (1 << 5) - 1
)

// Marshal encodes the Header in binary
func (h Header) Marshal() ([]byte, error) {
	/*
	 *  0                   1                   2                   3
	 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 * |V=2|P|    RC   |   PT=SR=200   |             length            |
	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 */
	rawPacket := make([]byte, headerLength)

	rawPacket[0] |= rtpVersion << versionShift

	if h.Padding {
		rawPacket[0] |= 1 << paddingShift
	}

	if h.Count > 31 {
		return nil, errInvalidHeader
	}
	rawPacket[0] |= h.Count << countShift

	rawPacket[1] = uint8(h.Type)

	binary.BigEndian.PutUint16(rawPacket[2:], h.Length)

	return rawPacket, nil
}

// Unmarshal decodes the Header from binary
func (h *Header) Unmarshal(rawPacket []byte) error {
	if len(rawPacket) < headerLength {
		return errPacketTooShort
	}

	/*
	 *  0                   1                   2                   3
	 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 * |V=2|P|    RC   |      PT       |             length            |
	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	 */

	version := rawPacket[0] >> versionShift & versionMask
	if version != rtpVersion {
		return errBadVersion
	}

	h.Padding = (rawPacket[0] >> paddingShift & paddingMask) > 0
	h.Count = rawPacket[0] >> countShift & countMask

	h.Type = PacketType(rawPacket[1])

	h.Length = binary.BigEndian.Uint16(rawPacket[2:])

	return nil
}