Line data Source code
1 : /*
2 : * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
12 :
13 : #include <string.h>
14 :
15 : #include "webrtc/base/logging.h"
16 : #include "webrtc/modules/rtp_rtcp/include/rtp_cvo.h"
17 : #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
18 :
19 : namespace webrtc {
20 :
21 0 : RtpData* NullObjectRtpData() {
22 0 : static NullRtpData null_rtp_data;
23 0 : return &null_rtp_data;
24 : }
25 :
26 0 : RtpFeedback* NullObjectRtpFeedback() {
27 0 : static NullRtpFeedback null_rtp_feedback;
28 0 : return &null_rtp_feedback;
29 : }
30 :
31 0 : ReceiveStatistics* NullObjectReceiveStatistics() {
32 0 : static NullReceiveStatistics null_receive_statistics;
33 0 : return &null_receive_statistics;
34 : }
35 :
36 : namespace RtpUtility {
37 :
38 : enum {
39 : kRtcpExpectedVersion = 2,
40 : kRtcpMinHeaderLength = 4,
41 : kRtcpMinParseLength = 8,
42 :
43 : kRtpExpectedVersion = 2,
44 : kRtpMinParseLength = 12
45 : };
46 :
47 : /*
48 : * Misc utility routines
49 : */
50 :
51 : #if defined(_WIN32)
52 : bool StringCompare(const char* str1, const char* str2,
53 : const uint32_t length) {
54 : return _strnicmp(str1, str2, length) == 0;
55 : }
56 : #elif defined(WEBRTC_LINUX) || defined(WEBRTC_BSD) || defined(WEBRTC_MAC)
57 0 : bool StringCompare(const char* str1, const char* str2,
58 : const uint32_t length) {
59 0 : return strncasecmp(str1, str2, length) == 0;
60 : }
61 : #endif
62 :
63 0 : size_t Word32Align(size_t size) {
64 0 : uint32_t remainder = size % 4;
65 0 : if (remainder != 0)
66 0 : return size + 4 - remainder;
67 0 : return size;
68 : }
69 :
70 0 : RtpHeaderParser::RtpHeaderParser(const uint8_t* rtpData,
71 0 : const size_t rtpDataLength)
72 : : _ptrRTPDataBegin(rtpData),
73 0 : _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) {
74 0 : }
75 :
76 0 : RtpHeaderParser::~RtpHeaderParser() {
77 0 : }
78 :
79 0 : bool RtpHeaderParser::RTCP() const {
80 : // 72 to 76 is reserved for RTP
81 : // 77 to 79 is not reserver but they are not assigned we will block them
82 : // for RTCP 200 SR == marker bit + 72
83 : // for RTCP 204 APP == marker bit + 76
84 : /*
85 : * RTCP
86 : *
87 : * FIR full INTRA-frame request 192 [RFC2032] supported
88 : * NACK negative acknowledgement 193 [RFC2032]
89 : * IJ Extended inter-arrival jitter report 195 [RFC-ietf-avt-rtp-toff
90 : * set-07.txt] http://tools.ietf.org/html/draft-ietf-avt-rtp-toffset-07
91 : * SR sender report 200 [RFC3551] supported
92 : * RR receiver report 201 [RFC3551] supported
93 : * SDES source description 202 [RFC3551] supported
94 : * BYE goodbye 203 [RFC3551] supported
95 : * APP application-defined 204 [RFC3551] ignored
96 : * RTPFB Transport layer FB message 205 [RFC4585] supported
97 : * PSFB Payload-specific FB message 206 [RFC4585] supported
98 : * XR extended report 207 [RFC3611] supported
99 : */
100 :
101 : /* 205 RFC 5104
102 : * FMT 1 NACK supported
103 : * FMT 2 reserved
104 : * FMT 3 TMMBR supported
105 : * FMT 4 TMMBN supported
106 : */
107 :
108 : /* 206 RFC 5104
109 : * FMT 1: Picture Loss Indication (PLI) supported
110 : * FMT 2: Slice Lost Indication (SLI)
111 : * FMT 3: Reference Picture Selection Indication (RPSI)
112 : * FMT 4: Full Intra Request (FIR) Command supported
113 : * FMT 5: Temporal-Spatial Trade-off Request (TSTR)
114 : * FMT 6: Temporal-Spatial Trade-off Notification (TSTN)
115 : * FMT 7: Video Back Channel Message (VBCM)
116 : * FMT 15: Application layer FB message
117 : */
118 :
119 0 : const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
120 0 : if (length < kRtcpMinHeaderLength) {
121 0 : return false;
122 : }
123 :
124 0 : const uint8_t V = _ptrRTPDataBegin[0] >> 6;
125 0 : if (V != kRtcpExpectedVersion) {
126 0 : return false;
127 : }
128 :
129 0 : const uint8_t payloadType = _ptrRTPDataBegin[1];
130 0 : switch (payloadType) {
131 : case 192:
132 0 : return true;
133 : case 193:
134 : // not supported
135 : // pass through and check for a potential RTP packet
136 0 : return false;
137 : case 195:
138 : case 200:
139 : case 201:
140 : case 202:
141 : case 203:
142 : case 204:
143 : case 205:
144 : case 206:
145 : case 207:
146 0 : return true;
147 : default:
148 0 : return false;
149 : }
150 : }
151 :
152 0 : bool RtpHeaderParser::ParseRtcp(RTPHeader* header) const {
153 0 : assert(header != NULL);
154 :
155 0 : const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
156 0 : if (length < kRtcpMinParseLength) {
157 0 : return false;
158 : }
159 :
160 0 : const uint8_t V = _ptrRTPDataBegin[0] >> 6;
161 0 : if (V != kRtcpExpectedVersion) {
162 0 : return false;
163 : }
164 :
165 0 : const uint8_t PT = _ptrRTPDataBegin[1];
166 0 : const size_t len = (_ptrRTPDataBegin[2] << 8) + _ptrRTPDataBegin[3];
167 0 : const uint8_t* ptr = &_ptrRTPDataBegin[4];
168 :
169 0 : uint32_t SSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
170 0 : ptr += 4;
171 :
172 0 : header->payloadType = PT;
173 0 : header->ssrc = SSRC;
174 0 : header->headerLength = 4 + (len << 2);
175 0 : if (header->headerLength > static_cast<size_t>(length)) {
176 0 : return false;
177 : }
178 :
179 0 : return true;
180 : }
181 :
182 0 : bool RtpHeaderParser::Parse(RTPHeader* header,
183 : RtpHeaderExtensionMap* ptrExtensionMap) const {
184 0 : const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
185 0 : if (length < kRtpMinParseLength) {
186 0 : return false;
187 : }
188 :
189 : // Version
190 0 : const uint8_t V = _ptrRTPDataBegin[0] >> 6;
191 : // Padding
192 0 : const bool P = ((_ptrRTPDataBegin[0] & 0x20) == 0) ? false : true;
193 : // eXtension
194 0 : const bool X = ((_ptrRTPDataBegin[0] & 0x10) == 0) ? false : true;
195 0 : const uint8_t CC = _ptrRTPDataBegin[0] & 0x0f;
196 0 : const bool M = ((_ptrRTPDataBegin[1] & 0x80) == 0) ? false : true;
197 :
198 0 : const uint8_t PT = _ptrRTPDataBegin[1] & 0x7f;
199 :
200 0 : const uint16_t sequenceNumber = (_ptrRTPDataBegin[2] << 8) +
201 0 : _ptrRTPDataBegin[3];
202 :
203 0 : const uint8_t* ptr = &_ptrRTPDataBegin[4];
204 :
205 0 : uint32_t RTPTimestamp = ByteReader<uint32_t>::ReadBigEndian(ptr);
206 0 : ptr += 4;
207 :
208 0 : uint32_t SSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
209 0 : ptr += 4;
210 :
211 0 : if (V != kRtpExpectedVersion) {
212 0 : return false;
213 : }
214 :
215 0 : header->markerBit = M;
216 0 : header->payloadType = PT;
217 0 : header->sequenceNumber = sequenceNumber;
218 0 : header->timestamp = RTPTimestamp;
219 0 : header->ssrc = SSRC;
220 0 : header->numCSRCs = CC;
221 0 : header->paddingLength = P ? *(_ptrRTPDataEnd - 1) : 0;
222 :
223 : // 12 == sizeof(RFC rtp header) == kRtpMinParseLength, each CSRC=4 bytes
224 0 : header->headerLength = 12 + (CC * 4);
225 : // not a full validation, just safety against underflow. Padding must
226 : // start after the header. We can have 0 payload bytes left, note.
227 0 : if (header->paddingLength + header->headerLength > (size_t) length) {
228 0 : return false;
229 : }
230 :
231 0 : for (uint8_t i = 0; i < CC; ++i) {
232 0 : uint32_t CSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
233 0 : ptr += 4;
234 0 : header->arrOfCSRCs[i] = CSRC;
235 : }
236 0 : assert((ptr - _ptrRTPDataBegin) == (ptrdiff_t) header->headerLength);
237 :
238 : // If in effect, MAY be omitted for those packets for which the offset
239 : // is zero.
240 0 : header->extension.hasTransmissionTimeOffset = false;
241 0 : header->extension.transmissionTimeOffset = 0;
242 :
243 : // May not be present in packet.
244 0 : header->extension.hasAbsoluteSendTime = false;
245 0 : header->extension.absoluteSendTime = 0;
246 :
247 : // May not be present in packet.
248 0 : header->extension.hasAudioLevel = false;
249 0 : header->extension.voiceActivity = false;
250 0 : header->extension.audioLevel = 0;
251 :
252 : // May not be present in packet.
253 0 : header->extension.hasVideoRotation = false;
254 0 : header->extension.videoRotation = kVideoRotation_0;
255 :
256 : // May not be present in packet.
257 0 : header->extension.hasRID = false;
258 0 : header->extension.rid = NULL;
259 :
260 : // May not be present in packet.
261 0 : header->extension.playout_delay.min_ms = -1;
262 0 : header->extension.playout_delay.max_ms = -1;
263 :
264 0 : if (X) {
265 : /* RTP header extension, RFC 3550.
266 : 0 1 2 3
267 : 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
268 : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
269 : | defined by profile | length |
270 : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
271 : | header extension |
272 : | .... |
273 : */
274 : // earlier test ensures we have at least paddingLength bytes left
275 0 : const ptrdiff_t remain = (_ptrRTPDataEnd - ptr) - header->paddingLength;
276 0 : if (remain < 4) { // minimum header extension length = 32 bits
277 0 : return false;
278 : }
279 :
280 0 : header->headerLength += 4;
281 :
282 0 : uint16_t definedByProfile = ByteReader<uint16_t>::ReadBigEndian(ptr);
283 0 : ptr += 2;
284 :
285 : // in 32 bit words
286 0 : size_t XLen = ByteReader<uint16_t>::ReadBigEndian(ptr);
287 0 : ptr += 2;
288 0 : XLen *= 4; // in bytes
289 :
290 0 : if (static_cast<size_t>(remain) < (4 + XLen)) {
291 0 : return false;
292 : }
293 0 : if (definedByProfile == kRtpOneByteHeaderExtensionId) {
294 0 : const uint8_t* ptrRTPDataExtensionEnd = ptr + XLen;
295 : ParseOneByteExtensionHeader(header,
296 : ptrExtensionMap,
297 : ptrRTPDataExtensionEnd,
298 0 : ptr);
299 : }
300 0 : header->headerLength += XLen;
301 : }
302 0 : if (header->headerLength + header->paddingLength >
303 0 : static_cast<size_t>(length))
304 0 : return false;
305 0 : return true;
306 : }
307 :
308 0 : void RtpHeaderParser::ParseOneByteExtensionHeader(
309 : RTPHeader* header,
310 : const RtpHeaderExtensionMap* ptrExtensionMap,
311 : const uint8_t* ptrRTPDataExtensionEnd,
312 : const uint8_t* ptr) const {
313 0 : if (!ptrExtensionMap) {
314 0 : return;
315 : }
316 :
317 0 : while (ptrRTPDataExtensionEnd - ptr > 0) {
318 : // 0
319 : // 0 1 2 3 4 5 6 7
320 : // +-+-+-+-+-+-+-+-+
321 : // | ID | len |
322 : // +-+-+-+-+-+-+-+-+
323 :
324 : // Note that 'len' is the header extension element length, which is the
325 : // number of bytes - 1.
326 0 : const int id = (*ptr & 0xf0) >> 4;
327 0 : const int len = (*ptr & 0x0f);
328 0 : if (ptr + len + 1 > ptrRTPDataExtensionEnd) {
329 0 : LOG(LS_WARNING)
330 0 : << "RTP extension header length out of bounds. Terminate parsing.";
331 0 : return;
332 : }
333 0 : ptr++;
334 :
335 0 : if (id == 0) {
336 : // Padding byte, skip ignoring len.
337 0 : continue;
338 : }
339 :
340 0 : if (id == 15) {
341 0 : LOG(LS_VERBOSE)
342 0 : << "RTP extension header 15 encountered. Terminate parsing.";
343 0 : return;
344 : }
345 :
346 0 : if (ptrRTPDataExtensionEnd - ptr < (len + 1)) {
347 0 : LOG(LS_WARNING) << "Incorrect one-byte extension len: " << (len + 1)
348 0 : << ", bytes left in buffer: "
349 0 : << (ptrRTPDataExtensionEnd - ptr);
350 0 : return;
351 : }
352 :
353 0 : RTPExtensionType type = ptrExtensionMap->GetType(id);
354 0 : if (type == RtpHeaderExtensionMap::kInvalidType) {
355 : // If we encounter an unknown extension, just skip over it.
356 : // Mozilla - we reuse the parse for demux, without registering extensions.
357 : // Reduce log-spam by switching to VERBOSE
358 0 : LOG(LS_VERBOSE) << "Failed to find extension id: " << id;
359 : } else {
360 0 : switch (type) {
361 : case kRtpExtensionTransmissionTimeOffset: {
362 0 : if (len != 2) {
363 0 : LOG(LS_WARNING) << "Incorrect transmission time offset len: "
364 0 : << len;
365 0 : return;
366 : }
367 : // 0 1 2 3
368 : // 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
369 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
370 : // | ID | len=2 | transmission offset |
371 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372 :
373 0 : header->extension.transmissionTimeOffset =
374 0 : ByteReader<int32_t, 3>::ReadBigEndian(ptr);
375 0 : header->extension.hasTransmissionTimeOffset = true;
376 0 : break;
377 : }
378 : case kRtpExtensionAudioLevel: {
379 0 : if (len != 0) {
380 0 : LOG(LS_WARNING) << "Incorrect audio level len: " << len;
381 0 : return;
382 : }
383 : // 0 1
384 : // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
385 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
386 : // | ID | len=0 |V| level |
387 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
388 : //
389 0 : header->extension.audioLevel = ptr[0] & 0x7f;
390 0 : header->extension.voiceActivity = (ptr[0] & 0x80) != 0;
391 0 : header->extension.hasAudioLevel = true;
392 0 : break;
393 : }
394 : case kRtpExtensionAbsoluteSendTime: {
395 0 : if (len != 2) {
396 0 : LOG(LS_WARNING) << "Incorrect absolute send time len: " << len;
397 0 : return;
398 : }
399 : // 0 1 2 3
400 : // 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
401 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
402 : // | ID | len=2 | absolute send time |
403 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
404 :
405 0 : header->extension.absoluteSendTime =
406 0 : ByteReader<uint32_t, 3>::ReadBigEndian(ptr);
407 0 : header->extension.hasAbsoluteSendTime = true;
408 0 : break;
409 : }
410 : case kRtpExtensionVideoRotation: {
411 0 : if (len != 0) {
412 0 : LOG(LS_WARNING)
413 0 : << "Incorrect coordination of video coordination len: " << len;
414 0 : return;
415 : }
416 : // 0 1
417 : // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
418 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
419 : // | ID | len=0 |0 0 0 0 C F R R|
420 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
421 0 : header->extension.hasVideoRotation = true;
422 0 : header->extension.videoRotation =
423 0 : ConvertCVOByteToVideoRotation(ptr[0]);
424 0 : break;
425 : }
426 : case kRtpExtensionTransportSequenceNumber: {
427 0 : if (len != 1) {
428 0 : LOG(LS_WARNING) << "Incorrect transport sequence number len: "
429 0 : << len;
430 0 : return;
431 : }
432 : // 0 1 2
433 : // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
434 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435 : // | ID | L=1 |transport wide sequence number |
436 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
437 :
438 0 : uint16_t sequence_number = ptr[0] << 8;
439 0 : sequence_number += ptr[1];
440 0 : header->extension.transportSequenceNumber = sequence_number;
441 0 : header->extension.hasTransportSequenceNumber = true;
442 0 : break;
443 : }
444 : case kRtpExtensionPlayoutDelay: {
445 0 : if (len != 2) {
446 0 : LOG(LS_WARNING) << "Incorrect playout delay len: " << len;
447 0 : return;
448 : }
449 : // 0 1 2 3
450 : // 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
451 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
452 : // | ID | len=2 | MIN delay | MAX delay |
453 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
454 :
455 0 : int min_playout_delay = (ptr[0] << 4) | ((ptr[1] >> 4) & 0xf);
456 0 : int max_playout_delay = ((ptr[1] & 0xf) << 8) | ptr[2];
457 0 : header->extension.playout_delay.min_ms =
458 0 : min_playout_delay * kPlayoutDelayGranularityMs;
459 0 : header->extension.playout_delay.max_ms =
460 0 : max_playout_delay * kPlayoutDelayGranularityMs;
461 0 : break;
462 : }
463 : case kRtpExtensionRtpStreamId: {
464 : // 0 1 2
465 : // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
466 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
467 : // | ID | L=? |UTF-8 RID value...... |...
468 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
469 :
470 : // As per RFC 5285 section 4.2, len is the length of the header data
471 : // - 1. E.G. a len of 0 indicates a header data length of 1
472 0 : if ( &ptr[len + 1] > ptrRTPDataExtensionEnd ) {
473 0 : LOG(LS_WARNING) << "Extension RtpStreamId data length " << (len + 1)
474 0 : << " is longer than remaining input parse buffer "
475 0 : << static_cast<size_t>(ptrRTPDataExtensionEnd - ptr);
476 0 : return;
477 : }
478 :
479 0 : header->extension.rid.reset(new char[len + 2]);
480 0 : memcpy(header->extension.rid.get(), ptr, len + 1);
481 0 : header->extension.rid.get()[len + 1] = '\0';
482 0 : header->extension.hasRID = true;
483 0 : break;
484 : }
485 : default:
486 : case kRtpExtensionNone:
487 : case kRtpExtensionNumberOfExtensions: {
488 0 : RTC_NOTREACHED() << "Invalid extension type: " << type;
489 0 : return;
490 : }
491 : }
492 : }
493 0 : ptr += (len + 1);
494 : }
495 : }
496 :
497 : } // namespace RtpUtility
498 : } // namespace webrtc
|