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
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/*
* Parses an RTP packet
* @param buffer an ArrayBuffer that contains the packet
* @return { type: "rtp", header: {...}, payload: a DataView }
*/
var ParseRtpPacket = buffer => {
// DataView.getFooInt returns big endian numbers by default
let view = new DataView(buffer);
// Standard Header Fields
// https://tools.ietf.org/html/rfc3550#section-5.1
// 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|X| CC |M| PT | sequence number |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | timestamp |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | synchronization source (SSRC) identifier |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | contributing source (CSRC) identifiers |
// | .... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
let header = {};
let offset = 0;
// Note that incrementing the offset happens as close to reading the data as
// possible. This simplifies ensuring that the number of read bytes and the
// offset increment match. Data may be manipulated between when the offset is
// incremented and before the next read.
let byte = view.getUint8(offset);
offset++;
// Version 2 Bit
header.version = (0xc0 & byte) >> 6;
// Padding 1 Bit
header.padding = (0x30 & byte) >> 5;
// Extension 1 Bit
header.extensionsPresent = (0x10 & byte) >> 4 == 1;
// CSRC count 4 Bit
header.csrcCount = 0xf & byte;
byte = view.getUint8(offset);
offset++;
// Marker 1 Bit
header.marker = (0x80 & byte) >> 7;
// Payload Type 7 Bit
header.payloadType = 0x7f & byte;
// Sequence Number 16 Bit
header.sequenceNumber = view.getUint16(offset);
offset += 2;
// Timestamp 32 Bit
header.timestamp = view.getUint32(offset);
offset += 4;
// SSRC 32 Bit
header.ssrc = view.getUint32(offset);
offset += 4;
// CSRC 32 Bit
header.csrcs = [];
for (let c = 0; c < header.csrcCount; c++) {
header.csrcs.push(view.getUint32(offset));
offset += 4;
}
// Extensions
header.extensions = [];
header.extensionPaddingBytes = 0;
header.extensionsTotalLength = 0;
if (header.extensionsPresent) {
// https://tools.ietf.org/html/rfc3550#section-5.3.1
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | defined by profile | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | header extension |
// | .... |
let addExtension = (id, len) =>
header.extensions.push({
id,
data: new DataView(buffer, offset, len),
});
let extensionId = view.getUint16(offset);
offset += 2;
// len is in 32 bit units, not bytes
header.extensionsTotalLength = view.getUint16(offset) * 4;
offset += 2;
// Check for https://tools.ietf.org/html/rfc5285
if (extensionId != 0xbede) {
// No rfc5285
addExtension(extensionId, header.extensionsTotalLength);
offset += header.extensionsTotalLength;
} else {
let expectedEnd = offset + header.extensionsTotalLength;
while (offset < expectedEnd) {
// We only support "one-byte" extension headers ATM
// https://tools.ietf.org/html/rfc5285#section-4.2
// 0
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// | ID | len |
// +-+-+-+-+-+-+-+-+
byte = view.getUint8(offset);
offset++;
// Check for padding which can occur between extensions or at the end
if (byte == 0) {
header.extensionPaddingBytes++;
continue;
}
let id = (byte & 0xf0) >> 4;
// Check for the FORBIDDEN id (15), dun dun dun
if (id == 15) {
// Ignore bytes until until the end of extensions
offset = expectedEnd;
break;
}
// the length of the extention is len + 1
let len = (byte & 0x0f) + 1;
addExtension(id, len);
offset += len;
}
}
}
return { type: "rtp", header, payload: new DataView(buffer, offset) };
};
|