blob: 9b5a83515f4c54ddcd0e78d0ebff3ab7f9ca576f [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000011#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <assert.h>
14#include <math.h> // ceil
15#include <string.h> // memcpy
niklase@google.com470e71d2011-07-07 08:21:25 +000016
sprang73a93e82015-09-14 12:50:39 -070017#include "webrtc/base/checks.h"
18#include "webrtc/base/logging.h"
19#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
danilchapb8b6fbb2015-12-10 05:05:27 -080020#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
sprang73a93e82015-09-14 12:50:39 -070021
niklase@google.com470e71d2011-07-07 08:21:25 +000022namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000023
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +000024namespace RTCPUtility {
asapersson@webrtc.org2dd31342014-10-29 12:42:30 +000025
26NackStats::NackStats()
27 : max_sequence_number_(0),
28 requests_(0),
29 unique_requests_(0) {}
30
31NackStats::~NackStats() {}
32
33void NackStats::ReportRequest(uint16_t sequence_number) {
34 if (requests_ == 0 ||
35 webrtc::IsNewerSequenceNumber(sequence_number, max_sequence_number_)) {
36 max_sequence_number_ = sequence_number;
37 ++unique_requests_;
38 }
39 ++requests_;
40}
41
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +000042uint32_t MidNtp(uint32_t ntp_sec, uint32_t ntp_frac) {
43 return (ntp_sec << 16) + (ntp_frac >> 16);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +000044}
danilchap6a6f0892015-12-10 12:39:08 -080045} // namespace RTCPUtility
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +000046
47// RTCPParserV2 : currently read only
pbos@webrtc.org2f446732013-04-08 11:08:41 +000048RTCPUtility::RTCPParserV2::RTCPParserV2(const uint8_t* rtcpData,
niklase@google.com470e71d2011-07-07 08:21:25 +000049 size_t rtcpDataLength,
50 bool rtcpReducedSizeEnable)
pwestin@webrtc.orgaafa5a32012-01-17 07:07:37 +000051 : _ptrRTCPDataBegin(rtcpData),
52 _RTCPReducedSizeEnable(rtcpReducedSizeEnable),
53 _ptrRTCPDataEnd(rtcpData + rtcpDataLength),
54 _validPacket(false),
55 _ptrRTCPData(rtcpData),
56 _ptrRTCPBlockEnd(NULL),
Erik Språng242e22b2015-05-11 10:17:43 +020057 _state(ParseState::State_TopLevel),
pwestin@webrtc.orgaafa5a32012-01-17 07:07:37 +000058 _numberOfBlocks(0),
Erik Språng6b8d3552015-09-24 15:06:57 +020059 num_skipped_blocks_(0),
Erik Språng242e22b2015-05-11 10:17:43 +020060 _packetType(RTCPPacketTypes::kInvalid) {
pwestin@webrtc.orgaafa5a32012-01-17 07:07:37 +000061 Validate();
niklase@google.com470e71d2011-07-07 08:21:25 +000062}
63
pwestin@webrtc.orgaafa5a32012-01-17 07:07:37 +000064RTCPUtility::RTCPParserV2::~RTCPParserV2() {
niklase@google.com470e71d2011-07-07 08:21:25 +000065}
66
67ptrdiff_t
68RTCPUtility::RTCPParserV2::LengthLeft() const
69{
70 return (_ptrRTCPDataEnd- _ptrRTCPData);
71}
72
73RTCPUtility::RTCPPacketTypes
74RTCPUtility::RTCPParserV2::PacketType() const
75{
76 return _packetType;
77}
78
79const RTCPUtility::RTCPPacket&
80RTCPUtility::RTCPParserV2::Packet() const
81{
82 return _packet;
83}
84
Erik Språng6b8d3552015-09-24 15:06:57 +020085rtcp::RtcpPacket* RTCPUtility::RTCPParserV2::ReleaseRtcpPacket() {
86 return rtcp_packet_.release();
87}
niklase@google.com470e71d2011-07-07 08:21:25 +000088RTCPUtility::RTCPPacketTypes
89RTCPUtility::RTCPParserV2::Begin()
90{
91 _ptrRTCPData = _ptrRTCPDataBegin;
92
93 return Iterate();
94}
95
96RTCPUtility::RTCPPacketTypes
97RTCPUtility::RTCPParserV2::Iterate()
98{
99 // Reset packet type
Erik Språng242e22b2015-05-11 10:17:43 +0200100 _packetType = RTCPPacketTypes::kInvalid;
niklase@google.com470e71d2011-07-07 08:21:25 +0000101
102 if (IsValid())
103 {
104 switch (_state)
105 {
Erik Språng242e22b2015-05-11 10:17:43 +0200106 case ParseState::State_TopLevel:
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 IterateTopLevel();
108 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200109 case ParseState::State_ReportBlockItem:
niklase@google.com470e71d2011-07-07 08:21:25 +0000110 IterateReportBlockItem();
111 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200112 case ParseState::State_SDESChunk:
niklase@google.com470e71d2011-07-07 08:21:25 +0000113 IterateSDESChunk();
114 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200115 case ParseState::State_BYEItem:
niklase@google.com470e71d2011-07-07 08:21:25 +0000116 IterateBYEItem();
117 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200118 case ParseState::State_ExtendedJitterItem:
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000119 IterateExtendedJitterItem();
120 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200121 case ParseState::State_RTPFB_NACKItem:
niklase@google.com470e71d2011-07-07 08:21:25 +0000122 IterateNACKItem();
123 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200124 case ParseState::State_RTPFB_TMMBRItem:
niklase@google.com470e71d2011-07-07 08:21:25 +0000125 IterateTMMBRItem();
126 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200127 case ParseState::State_RTPFB_TMMBNItem:
niklase@google.com470e71d2011-07-07 08:21:25 +0000128 IterateTMMBNItem();
129 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200130 case ParseState::State_PSFB_SLIItem:
niklase@google.com470e71d2011-07-07 08:21:25 +0000131 IterateSLIItem();
132 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200133 case ParseState::State_PSFB_RPSIItem:
niklase@google.com470e71d2011-07-07 08:21:25 +0000134 IterateRPSIItem();
135 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200136 case ParseState::State_PSFB_FIRItem:
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 IterateFIRItem();
138 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200139 case ParseState::State_PSFB_AppItem:
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000140 IteratePsfbAppItem();
141 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200142 case ParseState::State_PSFB_REMBItem:
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000143 IteratePsfbREMBItem();
144 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200145 case ParseState::State_XRItem:
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000146 IterateXrItem();
147 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200148 case ParseState::State_XR_DLLRItem:
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000149 IterateXrDlrrItem();
150 break;
Erik Språng242e22b2015-05-11 10:17:43 +0200151 case ParseState::State_AppItem:
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 IterateAppItem();
153 break;
154 default:
Erik Språng6b8d3552015-09-24 15:06:57 +0200155 RTC_NOTREACHED() << "Invalid state!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 break;
157 }
158 }
159 return _packetType;
160}
161
162void
163RTCPUtility::RTCPParserV2::IterateTopLevel()
164{
165 for (;;)
166 {
sprang73a93e82015-09-14 12:50:39 -0700167 RtcpCommonHeader header;
168 if (_ptrRTCPDataEnd <= _ptrRTCPData)
169 return;
niklase@google.com470e71d2011-07-07 08:21:25 +0000170
sprang73a93e82015-09-14 12:50:39 -0700171 if (!RtcpParseCommonHeader(_ptrRTCPData, _ptrRTCPDataEnd - _ptrRTCPData,
172 &header)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000173 return;
174 }
sprang73a93e82015-09-14 12:50:39 -0700175 _ptrRTCPBlockEnd = _ptrRTCPData + header.BlockSize();
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 if (_ptrRTCPBlockEnd > _ptrRTCPDataEnd)
177 {
Erik Språng6b8d3552015-09-24 15:06:57 +0200178 ++num_skipped_blocks_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000179 return;
180 }
181
sprang73a93e82015-09-14 12:50:39 -0700182 switch (header.packet_type) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000183 case PT_SR:
184 {
185 // number of Report blocks
sprang73a93e82015-09-14 12:50:39 -0700186 _numberOfBlocks = header.count_or_format;
niklase@google.com470e71d2011-07-07 08:21:25 +0000187 ParseSR();
188 return;
189 }
190 case PT_RR:
191 {
192 // number of Report blocks
sprang73a93e82015-09-14 12:50:39 -0700193 _numberOfBlocks = header.count_or_format;
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 ParseRR();
195 return;
196 }
197 case PT_SDES:
198 {
199 // number of SDES blocks
sprang73a93e82015-09-14 12:50:39 -0700200 _numberOfBlocks = header.count_or_format;
niklase@google.com470e71d2011-07-07 08:21:25 +0000201 const bool ok = ParseSDES();
202 if (!ok)
203 {
204 // Nothing supported found, continue to next block!
205 break;
206 }
207 return;
208 }
209 case PT_BYE:
210 {
sprang73a93e82015-09-14 12:50:39 -0700211 _numberOfBlocks = header.count_or_format;
niklase@google.com470e71d2011-07-07 08:21:25 +0000212 const bool ok = ParseBYE();
213 if (!ok)
214 {
215 // Nothing supported found, continue to next block!
216 break;
217 }
218 return;
219 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000220 case PT_IJ:
221 {
222 // number of Report blocks
sprang73a93e82015-09-14 12:50:39 -0700223 _numberOfBlocks = header.count_or_format;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000224 ParseIJ();
225 return;
226 }
Erik Språng6b8d3552015-09-24 15:06:57 +0200227 case PT_RTPFB:
228 FALLTHROUGH();
niklase@google.com470e71d2011-07-07 08:21:25 +0000229 case PT_PSFB:
230 {
Erik Språng6b8d3552015-09-24 15:06:57 +0200231 if (!ParseFBCommon(header)) {
232 // Nothing supported found, continue to next block!
danilchap50da1d32016-03-10 13:13:52 -0800233 EndCurrentBlock();
Erik Språng6b8d3552015-09-24 15:06:57 +0200234 break;
235 }
236 return;
niklase@google.com470e71d2011-07-07 08:21:25 +0000237 }
238 case PT_APP:
239 {
240 const bool ok = ParseAPP(header);
241 if (!ok)
242 {
243 // Nothing supported found, continue to next block!
244 break;
245 }
246 return;
247 }
248 case PT_XR:
249 {
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000250 const bool ok = ParseXr();
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 if (!ok)
252 {
253 // Nothing supported found, continue to next block!
254 break;
255 }
256 return;
257 }
258 default:
259 // Not supported! Skip!
Erik Språng6b8d3552015-09-24 15:06:57 +0200260 ++num_skipped_blocks_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000261 EndCurrentBlock();
262 break;
263 }
264 }
265}
266
267void
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000268RTCPUtility::RTCPParserV2::IterateXrItem()
269{
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000270 const bool success = ParseXrItem();
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000271 if (!success)
272 {
273 Iterate();
274 }
275}
276
277void
278RTCPUtility::RTCPParserV2::IterateXrDlrrItem()
279{
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000280 const bool success = ParseXrDlrrItem();
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000281 if (!success)
282 {
283 Iterate();
284 }
285}
286
287void
niklase@google.com470e71d2011-07-07 08:21:25 +0000288RTCPUtility::RTCPParserV2::IterateReportBlockItem()
289{
290 const bool success = ParseReportBlockItem();
291 if (!success)
292 {
293 Iterate();
294 }
295}
296
297void
298RTCPUtility::RTCPParserV2::IterateSDESChunk()
299{
300 const bool success = ParseSDESChunk();
301 if (!success)
302 {
303 Iterate();
304 }
305}
306
307void
308RTCPUtility::RTCPParserV2::IterateBYEItem()
309{
310 const bool success = ParseBYEItem();
311 if (!success)
312 {
313 Iterate();
314 }
315}
316
317void
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000318RTCPUtility::RTCPParserV2::IterateExtendedJitterItem()
319{
320 const bool success = ParseIJItem();
321 if (!success)
322 {
323 Iterate();
324 }
325}
326
327void
niklase@google.com470e71d2011-07-07 08:21:25 +0000328RTCPUtility::RTCPParserV2::IterateNACKItem()
329{
330 const bool success = ParseNACKItem();
331 if (!success)
332 {
333 Iterate();
334 }
335}
336
337void
338RTCPUtility::RTCPParserV2::IterateTMMBRItem()
339{
340 const bool success = ParseTMMBRItem();
341 if (!success)
342 {
343 Iterate();
344 }
345}
346
347void
348RTCPUtility::RTCPParserV2::IterateTMMBNItem()
349{
350 const bool success = ParseTMMBNItem();
351 if (!success)
352 {
353 Iterate();
354 }
355}
356
357void
358RTCPUtility::RTCPParserV2::IterateSLIItem()
359{
360 const bool success = ParseSLIItem();
361 if (!success)
362 {
363 Iterate();
364 }
365}
366
367void
368RTCPUtility::RTCPParserV2::IterateRPSIItem()
369{
370 const bool success = ParseRPSIItem();
371 if (!success)
372 {
373 Iterate();
374 }
375}
376
377void
378RTCPUtility::RTCPParserV2::IterateFIRItem()
379{
380 const bool success = ParseFIRItem();
381 if (!success)
382 {
383 Iterate();
384 }
385}
386
387void
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000388RTCPUtility::RTCPParserV2::IteratePsfbAppItem()
389{
390 const bool success = ParsePsfbAppItem();
391 if (!success)
392 {
393 Iterate();
394 }
395}
396
397void
398RTCPUtility::RTCPParserV2::IteratePsfbREMBItem()
399{
400 const bool success = ParsePsfbREMBItem();
401 if (!success)
402 {
403 Iterate();
404 }
405}
406
407void
niklase@google.com470e71d2011-07-07 08:21:25 +0000408RTCPUtility::RTCPParserV2::IterateAppItem()
409{
410 const bool success = ParseAPPItem();
411 if (!success)
412 {
413 Iterate();
414 }
415}
416
417void
418RTCPUtility::RTCPParserV2::Validate()
419{
sprang73a93e82015-09-14 12:50:39 -0700420 if (_ptrRTCPData == nullptr)
421 return; // NOT VALID
niklase@google.com470e71d2011-07-07 08:21:25 +0000422
sprang73a93e82015-09-14 12:50:39 -0700423 RtcpCommonHeader header;
424 if (_ptrRTCPDataEnd <= _ptrRTCPDataBegin)
425 return; // NOT VALID
niklase@google.com470e71d2011-07-07 08:21:25 +0000426
sprang73a93e82015-09-14 12:50:39 -0700427 if (!RtcpParseCommonHeader(_ptrRTCPDataBegin,
428 _ptrRTCPDataEnd - _ptrRTCPDataBegin, &header))
429 return; // NOT VALID!
niklase@google.com470e71d2011-07-07 08:21:25 +0000430
431 // * if (!reducedSize) : first packet must be RR or SR.
432 //
433 // * The padding bit (P) should be zero for the first packet of a
434 // compound RTCP packet because padding should only be applied,
435 // if it is needed, to the last packet. (NOT CHECKED!)
436 //
437 // * The length fields of the individual RTCP packets must add up
438 // to the overall length of the compound RTCP packet as
439 // received. This is a fairly strong check. (NOT CHECKED!)
440
441 if (!_RTCPReducedSizeEnable)
442 {
sprang73a93e82015-09-14 12:50:39 -0700443 if ((header.packet_type != PT_SR) && (header.packet_type != PT_RR)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000444 return; // NOT VALID
445 }
446 }
447
448 _validPacket = true;
449}
450
451bool
452RTCPUtility::RTCPParserV2::IsValid() const
453{
454 return _validPacket;
455}
456
457void
458RTCPUtility::RTCPParserV2::EndCurrentBlock()
459{
460 _ptrRTCPData = _ptrRTCPBlockEnd;
461}
462
sprang73a93e82015-09-14 12:50:39 -0700463// 0 1 2 3
464// 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
465// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
466// |V=2|P| IC | PT | length |
467// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
468//
469// Common header for all RTCP packets, 4 octets.
470
471bool RTCPUtility::RtcpParseCommonHeader(const uint8_t* packet,
472 size_t size_bytes,
473 RtcpCommonHeader* parsed_header) {
henrikg91d6ede2015-09-17 00:24:34 -0700474 RTC_DCHECK(parsed_header != nullptr);
sprang73a93e82015-09-14 12:50:39 -0700475 if (size_bytes < RtcpCommonHeader::kHeaderSizeBytes) {
476 LOG(LS_WARNING) << "Too little data (" << size_bytes << " byte"
477 << (size_bytes != 1 ? "s" : "")
478 << ") remaining in buffer to parse RTCP header (4 bytes).";
479 return false;
480 }
481
482 const uint8_t kRtcpVersion = 2;
483 uint8_t version = packet[0] >> 6;
484 if (version != kRtcpVersion) {
485 LOG(LS_WARNING) << "Invalid RTCP header: Version must be "
486 << static_cast<int>(kRtcpVersion) << " but was "
487 << static_cast<int>(version);
488 return false;
489 }
490
491 bool has_padding = (packet[0] & 0x20) != 0;
492 uint8_t format = packet[0] & 0x1F;
493 uint8_t packet_type = packet[1];
494 size_t packet_size_words =
495 ByteReader<uint16_t>::ReadBigEndian(&packet[2]) + 1;
496
497 if (size_bytes < packet_size_words * 4) {
498 LOG(LS_WARNING) << "Buffer too small (" << size_bytes
499 << " bytes) to fit an RtcpPacket of " << packet_size_words
500 << " 32bit words.";
501 return false;
502 }
503
504 size_t payload_size = packet_size_words * 4;
505 size_t padding_bytes = 0;
506 if (has_padding) {
507 if (payload_size <= RtcpCommonHeader::kHeaderSizeBytes) {
508 LOG(LS_WARNING) << "Invalid RTCP header: Padding bit set but 0 payload "
509 "size specified.";
510 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 }
512
sprang73a93e82015-09-14 12:50:39 -0700513 padding_bytes = packet[payload_size - 1];
514 if (RtcpCommonHeader::kHeaderSizeBytes + padding_bytes > payload_size) {
515 LOG(LS_WARNING) << "Invalid RTCP header: Too many padding bytes ("
516 << padding_bytes << ") for a packet size of "
517 << payload_size << "bytes.";
518 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000519 }
sprang73a93e82015-09-14 12:50:39 -0700520 payload_size -= padding_bytes;
521 }
522 payload_size -= RtcpCommonHeader::kHeaderSizeBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000523
sprang73a93e82015-09-14 12:50:39 -0700524 parsed_header->version = kRtcpVersion;
525 parsed_header->count_or_format = format;
526 parsed_header->packet_type = packet_type;
527 parsed_header->payload_size_bytes = payload_size;
528 parsed_header->padding_bytes = padding_bytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000529
sprang73a93e82015-09-14 12:50:39 -0700530 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000531}
532
533bool
534RTCPUtility::RTCPParserV2::ParseRR()
535{
536 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
537
538 if (length < 8)
539 {
540 return false;
541 }
542
543
544 _ptrRTCPData += 4; // Skip header
545
Erik Språng242e22b2015-05-11 10:17:43 +0200546 _packetType = RTCPPacketTypes::kRr;
niklase@google.com470e71d2011-07-07 08:21:25 +0000547
548 _packet.RR.SenderSSRC = *_ptrRTCPData++ << 24;
549 _packet.RR.SenderSSRC += *_ptrRTCPData++ << 16;
550 _packet.RR.SenderSSRC += *_ptrRTCPData++ << 8;
551 _packet.RR.SenderSSRC += *_ptrRTCPData++;
552
553 _packet.RR.NumberOfReportBlocks = _numberOfBlocks;
554
555 // State transition
Erik Språng242e22b2015-05-11 10:17:43 +0200556 _state = ParseState::State_ReportBlockItem;
niklase@google.com470e71d2011-07-07 08:21:25 +0000557
558 return true;
559}
560
561bool
562RTCPUtility::RTCPParserV2::ParseSR()
563{
564 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
565
566 if (length < 28)
567 {
568 EndCurrentBlock();
569 return false;
570 }
571
572 _ptrRTCPData += 4; // Skip header
573
Erik Språng242e22b2015-05-11 10:17:43 +0200574 _packetType = RTCPPacketTypes::kSr;
niklase@google.com470e71d2011-07-07 08:21:25 +0000575
576 _packet.SR.SenderSSRC = *_ptrRTCPData++ << 24;
577 _packet.SR.SenderSSRC += *_ptrRTCPData++ << 16;
578 _packet.SR.SenderSSRC += *_ptrRTCPData++ << 8;
579 _packet.SR.SenderSSRC += *_ptrRTCPData++;
580
581 _packet.SR.NTPMostSignificant = *_ptrRTCPData++ << 24;
582 _packet.SR.NTPMostSignificant += *_ptrRTCPData++ << 16;
583 _packet.SR.NTPMostSignificant += *_ptrRTCPData++ << 8;
584 _packet.SR.NTPMostSignificant += *_ptrRTCPData++;
585
586 _packet.SR.NTPLeastSignificant = *_ptrRTCPData++ << 24;
587 _packet.SR.NTPLeastSignificant += *_ptrRTCPData++ << 16;
588 _packet.SR.NTPLeastSignificant += *_ptrRTCPData++ << 8;
589 _packet.SR.NTPLeastSignificant += *_ptrRTCPData++;
590
591 _packet.SR.RTPTimestamp = *_ptrRTCPData++ << 24;
592 _packet.SR.RTPTimestamp += *_ptrRTCPData++ << 16;
593 _packet.SR.RTPTimestamp += *_ptrRTCPData++ << 8;
594 _packet.SR.RTPTimestamp += *_ptrRTCPData++;
595
596 _packet.SR.SenderPacketCount = *_ptrRTCPData++ << 24;
597 _packet.SR.SenderPacketCount += *_ptrRTCPData++ << 16;
598 _packet.SR.SenderPacketCount += *_ptrRTCPData++ << 8;
599 _packet.SR.SenderPacketCount += *_ptrRTCPData++;
600
601 _packet.SR.SenderOctetCount = *_ptrRTCPData++ << 24;
602 _packet.SR.SenderOctetCount += *_ptrRTCPData++ << 16;
603 _packet.SR.SenderOctetCount += *_ptrRTCPData++ << 8;
604 _packet.SR.SenderOctetCount += *_ptrRTCPData++;
605
606 _packet.SR.NumberOfReportBlocks = _numberOfBlocks;
607
608 // State transition
609 if(_numberOfBlocks != 0)
610 {
Erik Språng242e22b2015-05-11 10:17:43 +0200611 _state = ParseState::State_ReportBlockItem;
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 }else
613 {
614 // don't go to state report block item if 0 report blocks
Erik Språng242e22b2015-05-11 10:17:43 +0200615 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000616 EndCurrentBlock();
617 }
618 return true;
619}
620
621bool
622RTCPUtility::RTCPParserV2::ParseReportBlockItem()
623{
624 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
625
626 if (length < 24 || _numberOfBlocks <= 0)
627 {
Erik Språng242e22b2015-05-11 10:17:43 +0200628 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000629
630 EndCurrentBlock();
631 return false;
632 }
633 _packet.ReportBlockItem.SSRC = *_ptrRTCPData++ << 24;
634 _packet.ReportBlockItem.SSRC += *_ptrRTCPData++ << 16;
635 _packet.ReportBlockItem.SSRC += *_ptrRTCPData++ << 8;
636 _packet.ReportBlockItem.SSRC += *_ptrRTCPData++;
637
638 _packet.ReportBlockItem.FractionLost = *_ptrRTCPData++;
639
640 _packet.ReportBlockItem.CumulativeNumOfPacketsLost = *_ptrRTCPData++ << 16;
641 _packet.ReportBlockItem.CumulativeNumOfPacketsLost += *_ptrRTCPData++ << 8;
642 _packet.ReportBlockItem.CumulativeNumOfPacketsLost += *_ptrRTCPData++;
643
644 _packet.ReportBlockItem.ExtendedHighestSequenceNumber = *_ptrRTCPData++ << 24;
645 _packet.ReportBlockItem.ExtendedHighestSequenceNumber += *_ptrRTCPData++ << 16;
646 _packet.ReportBlockItem.ExtendedHighestSequenceNumber += *_ptrRTCPData++ << 8;
647 _packet.ReportBlockItem.ExtendedHighestSequenceNumber += *_ptrRTCPData++;
648
649 _packet.ReportBlockItem.Jitter = *_ptrRTCPData++ << 24;
650 _packet.ReportBlockItem.Jitter += *_ptrRTCPData++ << 16;
651 _packet.ReportBlockItem.Jitter += *_ptrRTCPData++ << 8;
652 _packet.ReportBlockItem.Jitter += *_ptrRTCPData++;
653
654 _packet.ReportBlockItem.LastSR = *_ptrRTCPData++ << 24;
655 _packet.ReportBlockItem.LastSR += *_ptrRTCPData++ << 16;
656 _packet.ReportBlockItem.LastSR += *_ptrRTCPData++ << 8;
657 _packet.ReportBlockItem.LastSR += *_ptrRTCPData++;
658
659 _packet.ReportBlockItem.DelayLastSR = *_ptrRTCPData++ << 24;
660 _packet.ReportBlockItem.DelayLastSR += *_ptrRTCPData++ << 16;
661 _packet.ReportBlockItem.DelayLastSR += *_ptrRTCPData++ << 8;
662 _packet.ReportBlockItem.DelayLastSR += *_ptrRTCPData++;
663
664 _numberOfBlocks--;
Erik Språng242e22b2015-05-11 10:17:43 +0200665 _packetType = RTCPPacketTypes::kReportBlockItem;
niklase@google.com470e71d2011-07-07 08:21:25 +0000666 return true;
667}
668
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000669/* From RFC 5450: Transmission Time Offsets in RTP Streams.
670 0 1 2 3
671 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
672 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
673 hdr |V=2|P| RC | PT=IJ=195 | length |
674 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
675 | inter-arrival jitter |
676 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
677 . .
678 . .
679 . .
680 | inter-arrival jitter |
681 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
682*/
683
684bool
685RTCPUtility::RTCPParserV2::ParseIJ()
686{
687 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
688
689 if (length < 4)
690 {
691 return false;
692 }
693
694 _ptrRTCPData += 4; // Skip header
695
Erik Språng242e22b2015-05-11 10:17:43 +0200696 _packetType = RTCPPacketTypes::kExtendedIj;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000697
698 // State transition
Erik Språng242e22b2015-05-11 10:17:43 +0200699 _state = ParseState::State_ExtendedJitterItem;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000700 return true;
701}
702
703bool
704RTCPUtility::RTCPParserV2::ParseIJItem()
705{
706 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
707
708 if (length < 4 || _numberOfBlocks <= 0)
709 {
Erik Språng242e22b2015-05-11 10:17:43 +0200710 _state = ParseState::State_TopLevel;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000711 EndCurrentBlock();
712 return false;
713 }
714
715 _packet.ExtendedJitterReportItem.Jitter = *_ptrRTCPData++ << 24;
716 _packet.ExtendedJitterReportItem.Jitter += *_ptrRTCPData++ << 16;
717 _packet.ExtendedJitterReportItem.Jitter += *_ptrRTCPData++ << 8;
718 _packet.ExtendedJitterReportItem.Jitter += *_ptrRTCPData++;
719
720 _numberOfBlocks--;
Erik Språng242e22b2015-05-11 10:17:43 +0200721 _packetType = RTCPPacketTypes::kExtendedIjItem;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000722 return true;
723}
724
niklase@google.com470e71d2011-07-07 08:21:25 +0000725bool
726RTCPUtility::RTCPParserV2::ParseSDES()
727{
728 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
729
730 if (length < 8)
731 {
Erik Språng242e22b2015-05-11 10:17:43 +0200732 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000733
734 EndCurrentBlock();
735 return false;
736 }
737 _ptrRTCPData += 4; // Skip header
738
Erik Språng242e22b2015-05-11 10:17:43 +0200739 _state = ParseState::State_SDESChunk;
740 _packetType = RTCPPacketTypes::kSdes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000741 return true;
742}
743
744bool
745RTCPUtility::RTCPParserV2::ParseSDESChunk()
746{
747 if(_numberOfBlocks <= 0)
748 {
Erik Språng242e22b2015-05-11 10:17:43 +0200749 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000750
751 EndCurrentBlock();
752 return false;
753 }
754 _numberOfBlocks--;
755
756 // Find CName item in a SDES chunk.
757 while (_ptrRTCPData < _ptrRTCPBlockEnd)
758 {
759 const ptrdiff_t dataLen = _ptrRTCPBlockEnd - _ptrRTCPData;
760 if (dataLen < 4)
761 {
Erik Språng242e22b2015-05-11 10:17:43 +0200762 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000763
764 EndCurrentBlock();
765 return false;
766 }
767
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000768 uint32_t SSRC = *_ptrRTCPData++ << 24;
niklase@google.com470e71d2011-07-07 08:21:25 +0000769 SSRC += *_ptrRTCPData++ << 16;
770 SSRC += *_ptrRTCPData++ << 8;
771 SSRC += *_ptrRTCPData++;
772
773 const bool foundCname = ParseSDESItem();
774 if (foundCname)
775 {
776 _packet.CName.SenderSSRC = SSRC; // Add SSRC
777 return true;
778 }
779 }
Erik Språng242e22b2015-05-11 10:17:43 +0200780 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000781
782 EndCurrentBlock();
783 return false;
784}
785
786bool
787RTCPUtility::RTCPParserV2::ParseSDESItem()
788{
789 // Find CName
790 // Only the CNAME item is mandatory. RFC 3550 page 46
791 bool foundCName = false;
792
793 size_t itemOctetsRead = 0;
794 while (_ptrRTCPData < _ptrRTCPBlockEnd)
795 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000796 const uint8_t tag = *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000797 ++itemOctetsRead;
798
799 if (tag == 0)
800 {
801 // End tag! 4 oct aligned
802 while ((itemOctetsRead++ % 4) != 0)
803 {
804 ++_ptrRTCPData;
805 }
806 return foundCName;
807 }
808
809 if (_ptrRTCPData < _ptrRTCPBlockEnd)
810 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000811 const uint8_t len = *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000812 ++itemOctetsRead;
813
814 if (tag == 1)
815 {
816 // CNAME
817
818 // Sanity
819 if ((_ptrRTCPData + len) >= _ptrRTCPBlockEnd)
820 {
Erik Språng242e22b2015-05-11 10:17:43 +0200821 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000822
823 EndCurrentBlock();
824 return false;
825 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000826 uint8_t i = 0;
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000827 for (; i < len; ++i)
niklase@google.com470e71d2011-07-07 08:21:25 +0000828 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000829 const uint8_t c = _ptrRTCPData[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000830 if ((c < ' ') || (c > '{') || (c == '%') || (c == '\\'))
831 {
832 // Illegal char
Erik Språng242e22b2015-05-11 10:17:43 +0200833 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000834
835 EndCurrentBlock();
836 return false;
837 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000838 _packet.CName.CName[i] = c;
839 }
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000840 // Make sure we are null terminated.
841 _packet.CName.CName[i] = 0;
Erik Språng242e22b2015-05-11 10:17:43 +0200842 _packetType = RTCPPacketTypes::kSdesChunk;
niklase@google.com470e71d2011-07-07 08:21:25 +0000843
844 foundCName = true;
845 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000846 _ptrRTCPData += len;
847 itemOctetsRead += len;
848 }
849 }
850
851 // No end tag found!
Erik Språng242e22b2015-05-11 10:17:43 +0200852 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000853
854 EndCurrentBlock();
855 return false;
856}
857
858bool
859RTCPUtility::RTCPParserV2::ParseBYE()
860{
861 _ptrRTCPData += 4; // Skip header
862
Erik Språng242e22b2015-05-11 10:17:43 +0200863 _state = ParseState::State_BYEItem;
niklase@google.com470e71d2011-07-07 08:21:25 +0000864
865 return ParseBYEItem();
866}
867
868bool
869RTCPUtility::RTCPParserV2::ParseBYEItem()
870{
871 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
872 if (length < 4 || _numberOfBlocks == 0)
873 {
Erik Språng242e22b2015-05-11 10:17:43 +0200874 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000875
876 EndCurrentBlock();
877 return false;
878 }
879
Erik Språng242e22b2015-05-11 10:17:43 +0200880 _packetType = RTCPPacketTypes::kBye;
niklase@google.com470e71d2011-07-07 08:21:25 +0000881
882 _packet.BYE.SenderSSRC = *_ptrRTCPData++ << 24;
883 _packet.BYE.SenderSSRC += *_ptrRTCPData++ << 16;
884 _packet.BYE.SenderSSRC += *_ptrRTCPData++ << 8;
885 _packet.BYE.SenderSSRC += *_ptrRTCPData++;
886
887 // we can have several CSRCs attached
888
889 // sanity
890 if(length >= 4*_numberOfBlocks)
891 {
892 _ptrRTCPData += (_numberOfBlocks -1)*4;
893 }
894 _numberOfBlocks = 0;
895
896 return true;
897}
898/*
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000899 0 1 2 3
niklase@google.com470e71d2011-07-07 08:21:25 +0000900 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
901 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
902 |V=2|P|reserved | PT=XR=207 | length |
903 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
904 | SSRC |
905 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
906 : report blocks :
907 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
908*/
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000909bool RTCPUtility::RTCPParserV2::ParseXr()
niklase@google.com470e71d2011-07-07 08:21:25 +0000910{
911 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
niklase@google.com470e71d2011-07-07 08:21:25 +0000912 if (length < 8)
913 {
914 EndCurrentBlock();
915 return false;
916 }
917
918 _ptrRTCPData += 4; // Skip header
919
920 _packet.XR.OriginatorSSRC = *_ptrRTCPData++ << 24;
921 _packet.XR.OriginatorSSRC += *_ptrRTCPData++ << 16;
922 _packet.XR.OriginatorSSRC += *_ptrRTCPData++ << 8;
923 _packet.XR.OriginatorSSRC += *_ptrRTCPData++;
924
Erik Språng242e22b2015-05-11 10:17:43 +0200925 _packetType = RTCPPacketTypes::kXrHeader;
926 _state = ParseState::State_XRItem;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000927 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000928}
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000929
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000930/* Extended report block format (RFC 3611).
931 BT: block type.
932 block length: length of report block in 32-bits words minus one (including
933 the header).
niklase@google.com470e71d2011-07-07 08:21:25 +0000934 0 1 2 3
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000935 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
niklase@google.com470e71d2011-07-07 08:21:25 +0000936 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
937 | BT | type-specific | block length |
938 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
939 : type-specific block contents :
940 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
941*/
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000942bool RTCPUtility::RTCPParserV2::ParseXrItem() {
943 const int kBlockHeaderLengthInBytes = 4;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000944 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000945 if (length < kBlockHeaderLengthInBytes) {
Erik Språng242e22b2015-05-11 10:17:43 +0200946 _state = ParseState::State_TopLevel;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000947 EndCurrentBlock();
948 return false;
949 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000950
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000951 uint8_t block_type = *_ptrRTCPData++;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000952 _ptrRTCPData++; // Ignore reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +0000953
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000954 uint16_t block_length_in_4bytes = *_ptrRTCPData++ << 8;
955 block_length_in_4bytes += *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000956
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000957 switch (block_type) {
958 case kBtReceiverReferenceTime:
959 return ParseXrReceiverReferenceTimeItem(block_length_in_4bytes);
960 case kBtDlrr:
961 return ParseXrDlrr(block_length_in_4bytes);
962 case kBtVoipMetric:
963 return ParseXrVoipMetricItem(block_length_in_4bytes);
964 default:
965 return ParseXrUnsupportedBlockType(block_length_in_4bytes);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000966 }
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000967}
968
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000969/* Receiver Reference Time Report Block.
970 0 1 2 3
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000971 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
972 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
973 | BT=4 | reserved | block length = 2 |
974 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
975 | NTP timestamp, most significant word |
976 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
977 | NTP timestamp, least significant word |
978 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
979*/
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000980bool RTCPUtility::RTCPParserV2::ParseXrReceiverReferenceTimeItem(
981 int block_length_4bytes) {
982 const int kBlockLengthIn4Bytes = 2;
983 const int kBlockLengthInBytes = kBlockLengthIn4Bytes * 4;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000984 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000985 if (block_length_4bytes != kBlockLengthIn4Bytes ||
986 length < kBlockLengthInBytes) {
Erik Språng242e22b2015-05-11 10:17:43 +0200987 _state = ParseState::State_TopLevel;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000988 EndCurrentBlock();
989 return false;
990 }
991
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000992 _packet.XRReceiverReferenceTimeItem.NTPMostSignificant = *_ptrRTCPData++<<24;
993 _packet.XRReceiverReferenceTimeItem.NTPMostSignificant+= *_ptrRTCPData++<<16;
994 _packet.XRReceiverReferenceTimeItem.NTPMostSignificant+= *_ptrRTCPData++<<8;
995 _packet.XRReceiverReferenceTimeItem.NTPMostSignificant+= *_ptrRTCPData++;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000996
asapersson@webrtc.org38599512013-11-12 08:08:26 +0000997 _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant = *_ptrRTCPData++<<24;
998 _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant+= *_ptrRTCPData++<<16;
999 _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant+= *_ptrRTCPData++<<8;
1000 _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant+= *_ptrRTCPData++;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001001
Erik Språng242e22b2015-05-11 10:17:43 +02001002 _packetType = RTCPPacketTypes::kXrReceiverReferenceTime;
1003 _state = ParseState::State_XRItem;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001004 return true;
1005}
1006
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001007/* DLRR Report Block.
1008 0 1 2 3
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001009 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
1010 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1011 | BT=5 | reserved | block length |
1012 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1013 | SSRC_1 (SSRC of first receiver) | sub-
1014 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
1015 | last RR (LRR) | 1
1016 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1017 | delay since last RR (DLRR) |
1018 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1019 | SSRC_2 (SSRC of second receiver) | sub-
1020 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
1021 : ... : 2
1022 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1023*/
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001024bool RTCPUtility::RTCPParserV2::ParseXrDlrr(int block_length_4bytes) {
1025 const int kSubBlockLengthIn4Bytes = 3;
1026 if (block_length_4bytes < 0 ||
1027 (block_length_4bytes % kSubBlockLengthIn4Bytes) != 0) {
Erik Språng242e22b2015-05-11 10:17:43 +02001028 _state = ParseState::State_TopLevel;
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001029 EndCurrentBlock();
1030 return false;
1031 }
Erik Språng242e22b2015-05-11 10:17:43 +02001032 _packetType = RTCPPacketTypes::kXrDlrrReportBlock;
1033 _state = ParseState::State_XR_DLLRItem;
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001034 _numberOfBlocks = block_length_4bytes / kSubBlockLengthIn4Bytes;
1035 return true;
1036}
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001037
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001038bool RTCPUtility::RTCPParserV2::ParseXrDlrrItem() {
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001039 if (_numberOfBlocks == 0) {
Erik Språng242e22b2015-05-11 10:17:43 +02001040 _state = ParseState::State_XRItem;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001041 return false;
1042 }
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001043 const int kSubBlockLengthInBytes = 12;
1044 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1045 if (length < kSubBlockLengthInBytes) {
Erik Språng242e22b2015-05-11 10:17:43 +02001046 _state = ParseState::State_TopLevel;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001047 EndCurrentBlock();
1048 return false;
1049 }
1050
1051 _packet.XRDLRRReportBlockItem.SSRC = *_ptrRTCPData++ << 24;
1052 _packet.XRDLRRReportBlockItem.SSRC += *_ptrRTCPData++ << 16;
1053 _packet.XRDLRRReportBlockItem.SSRC += *_ptrRTCPData++ << 8;
1054 _packet.XRDLRRReportBlockItem.SSRC += *_ptrRTCPData++;
1055
1056 _packet.XRDLRRReportBlockItem.LastRR = *_ptrRTCPData++ << 24;
1057 _packet.XRDLRRReportBlockItem.LastRR += *_ptrRTCPData++ << 16;
1058 _packet.XRDLRRReportBlockItem.LastRR += *_ptrRTCPData++ << 8;
1059 _packet.XRDLRRReportBlockItem.LastRR += *_ptrRTCPData++;
1060
1061 _packet.XRDLRRReportBlockItem.DelayLastRR = *_ptrRTCPData++ << 24;
1062 _packet.XRDLRRReportBlockItem.DelayLastRR += *_ptrRTCPData++ << 16;
1063 _packet.XRDLRRReportBlockItem.DelayLastRR += *_ptrRTCPData++ << 8;
1064 _packet.XRDLRRReportBlockItem.DelayLastRR += *_ptrRTCPData++;
1065
Erik Språng242e22b2015-05-11 10:17:43 +02001066 _packetType = RTCPPacketTypes::kXrDlrrReportBlockItem;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001067 --_numberOfBlocks;
Erik Språng242e22b2015-05-11 10:17:43 +02001068 _state = ParseState::State_XR_DLLRItem;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001069 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001070}
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001071/* VoIP Metrics Report Block.
1072 0 1 2 3
niklase@google.com470e71d2011-07-07 08:21:25 +00001073 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
1074 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1075 | BT=7 | reserved | block length = 8 |
1076 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1077 | SSRC of source |
1078 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1079 | loss rate | discard rate | burst density | gap density |
1080 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1081 | burst duration | gap duration |
1082 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1083 | round trip delay | end system delay |
1084 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1085 | signal level | noise level | RERL | Gmin |
1086 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1087 | R factor | ext. R factor | MOS-LQ | MOS-CQ |
1088 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1089 | RX config | reserved | JB nominal |
1090 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1091 | JB maximum | JB abs max |
1092 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1093*/
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001094
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001095bool RTCPUtility::RTCPParserV2::ParseXrVoipMetricItem(int block_length_4bytes) {
1096 const int kBlockLengthIn4Bytes = 8;
1097 const int kBlockLengthInBytes = kBlockLengthIn4Bytes * 4;
1098 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1099 if (block_length_4bytes != kBlockLengthIn4Bytes ||
1100 length < kBlockLengthInBytes) {
Erik Språng242e22b2015-05-11 10:17:43 +02001101 _state = ParseState::State_TopLevel;
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001102 EndCurrentBlock();
1103 return false;
1104 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001105
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001106 _packet.XRVOIPMetricItem.SSRC = *_ptrRTCPData++ << 24;
1107 _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++ << 16;
1108 _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++ << 8;
1109 _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001110
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001111 _packet.XRVOIPMetricItem.lossRate = *_ptrRTCPData++;
1112 _packet.XRVOIPMetricItem.discardRate = *_ptrRTCPData++;
1113 _packet.XRVOIPMetricItem.burstDensity = *_ptrRTCPData++;
1114 _packet.XRVOIPMetricItem.gapDensity = *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001115
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001116 _packet.XRVOIPMetricItem.burstDuration = *_ptrRTCPData++ << 8;
1117 _packet.XRVOIPMetricItem.burstDuration += *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001118
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001119 _packet.XRVOIPMetricItem.gapDuration = *_ptrRTCPData++ << 8;
1120 _packet.XRVOIPMetricItem.gapDuration += *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001121
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001122 _packet.XRVOIPMetricItem.roundTripDelay = *_ptrRTCPData++ << 8;
1123 _packet.XRVOIPMetricItem.roundTripDelay += *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001124
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001125 _packet.XRVOIPMetricItem.endSystemDelay = *_ptrRTCPData++ << 8;
1126 _packet.XRVOIPMetricItem.endSystemDelay += *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001127
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001128 _packet.XRVOIPMetricItem.signalLevel = *_ptrRTCPData++;
1129 _packet.XRVOIPMetricItem.noiseLevel = *_ptrRTCPData++;
1130 _packet.XRVOIPMetricItem.RERL = *_ptrRTCPData++;
1131 _packet.XRVOIPMetricItem.Gmin = *_ptrRTCPData++;
1132 _packet.XRVOIPMetricItem.Rfactor = *_ptrRTCPData++;
1133 _packet.XRVOIPMetricItem.extRfactor = *_ptrRTCPData++;
1134 _packet.XRVOIPMetricItem.MOSLQ = *_ptrRTCPData++;
1135 _packet.XRVOIPMetricItem.MOSCQ = *_ptrRTCPData++;
1136 _packet.XRVOIPMetricItem.RXconfig = *_ptrRTCPData++;
1137 _ptrRTCPData++; // skip reserved
niklase@google.com470e71d2011-07-07 08:21:25 +00001138
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001139 _packet.XRVOIPMetricItem.JBnominal = *_ptrRTCPData++ << 8;
1140 _packet.XRVOIPMetricItem.JBnominal += *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001141
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001142 _packet.XRVOIPMetricItem.JBmax = *_ptrRTCPData++ << 8;
1143 _packet.XRVOIPMetricItem.JBmax += *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001144
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001145 _packet.XRVOIPMetricItem.JBabsMax = *_ptrRTCPData++ << 8;
1146 _packet.XRVOIPMetricItem.JBabsMax += *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001147
Erik Språng242e22b2015-05-11 10:17:43 +02001148 _packetType = RTCPPacketTypes::kXrVoipMetric;
1149 _state = ParseState::State_XRItem;
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001150 return true;
1151}
niklase@google.com470e71d2011-07-07 08:21:25 +00001152
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001153bool RTCPUtility::RTCPParserV2::ParseXrUnsupportedBlockType(
1154 int block_length_4bytes) {
1155 const int32_t kBlockLengthInBytes = block_length_4bytes * 4;
1156 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1157 if (length < kBlockLengthInBytes) {
Erik Språng242e22b2015-05-11 10:17:43 +02001158 _state = ParseState::State_TopLevel;
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001159 EndCurrentBlock();
1160 return false;
1161 }
1162 // Skip block.
1163 _ptrRTCPData += kBlockLengthInBytes;
Erik Språng242e22b2015-05-11 10:17:43 +02001164 _state = ParseState::State_XRItem;
asapersson@webrtc.org38599512013-11-12 08:08:26 +00001165 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001166}
1167
sprang73a93e82015-09-14 12:50:39 -07001168bool RTCPUtility::RTCPParserV2::ParseFBCommon(const RtcpCommonHeader& header) {
Erik Språng6b8d3552015-09-24 15:06:57 +02001169 RTC_CHECK((header.packet_type == PT_RTPFB) ||
1170 (header.packet_type == PT_PSFB)); // Parser logic check
niklase@google.com470e71d2011-07-07 08:21:25 +00001171
1172 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1173
Erik Språng6b8d3552015-09-24 15:06:57 +02001174 // 4 * 3, RFC4585 section 6.1
1175 if (length < 12) {
1176 LOG(LS_WARNING)
1177 << "Invalid RTCP packet: Too little data (" << length
1178 << " bytes) left in buffer to parse a 12 byte RTPFB/PSFB message.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001179 return false;
1180 }
1181
1182 _ptrRTCPData += 4; // Skip RTCP header
1183
Erik Språng6b8d3552015-09-24 15:06:57 +02001184 uint32_t senderSSRC = ByteReader<uint32_t>::ReadBigEndian(_ptrRTCPData);
1185 _ptrRTCPData += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00001186
Erik Språng6b8d3552015-09-24 15:06:57 +02001187 uint32_t mediaSSRC = ByteReader<uint32_t>::ReadBigEndian(_ptrRTCPData);
1188 _ptrRTCPData += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00001189
sprang73a93e82015-09-14 12:50:39 -07001190 if (header.packet_type == PT_RTPFB) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001191 // Transport layer feedback
1192
sprang73a93e82015-09-14 12:50:39 -07001193 switch (header.count_or_format) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 case 1:
1195 {
1196 // NACK
Erik Språng242e22b2015-05-11 10:17:43 +02001197 _packetType = RTCPPacketTypes::kRtpfbNack;
niklase@google.com470e71d2011-07-07 08:21:25 +00001198 _packet.NACK.SenderSSRC = senderSSRC;
1199 _packet.NACK.MediaSSRC = mediaSSRC;
1200
Erik Språng242e22b2015-05-11 10:17:43 +02001201 _state = ParseState::State_RTPFB_NACKItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001202
1203 return true;
1204 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001205 case 3:
1206 {
1207 // TMMBR
Erik Språng242e22b2015-05-11 10:17:43 +02001208 _packetType = RTCPPacketTypes::kRtpfbTmmbr;
niklase@google.com470e71d2011-07-07 08:21:25 +00001209 _packet.TMMBR.SenderSSRC = senderSSRC;
1210 _packet.TMMBR.MediaSSRC = mediaSSRC;
1211
Erik Språng242e22b2015-05-11 10:17:43 +02001212 _state = ParseState::State_RTPFB_TMMBRItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001213
1214 return true;
1215 }
1216 case 4:
1217 {
1218 // TMMBN
Erik Språng242e22b2015-05-11 10:17:43 +02001219 _packetType = RTCPPacketTypes::kRtpfbTmmbn;
niklase@google.com470e71d2011-07-07 08:21:25 +00001220 _packet.TMMBN.SenderSSRC = senderSSRC;
1221 _packet.TMMBN.MediaSSRC = mediaSSRC;
1222
Erik Språng242e22b2015-05-11 10:17:43 +02001223 _state = ParseState::State_RTPFB_TMMBNItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001224
1225 return true;
1226 }
1227 case 5:
1228 {
1229 // RTCP-SR-REQ Rapid Synchronisation of RTP Flows
1230 // draft-perkins-avt-rapid-rtp-sync-03.txt
1231 // trigger a new RTCP SR
Erik Språng242e22b2015-05-11 10:17:43 +02001232 _packetType = RTCPPacketTypes::kRtpfbSrReq;
niklase@google.com470e71d2011-07-07 08:21:25 +00001233
1234 // Note: No state transition, SR REQ is empty!
1235 return true;
1236 }
Erik Språng6b8d3552015-09-24 15:06:57 +02001237 case 15: {
Erik Språng6b8d3552015-09-24 15:06:57 +02001238 rtcp_packet_ =
1239 rtcp::TransportFeedback::ParseFrom(_ptrRTCPData - 12, length);
1240 // Since we parse the whole packet here, keep the TopLevel state and
1241 // just end the current block.
sprang49f9cdb2015-10-01 03:06:57 -07001242 EndCurrentBlock();
Erik Språng6b8d3552015-09-24 15:06:57 +02001243 if (rtcp_packet_.get()) {
sprang49f9cdb2015-10-01 03:06:57 -07001244 _packetType = RTCPPacketTypes::kTransportFeedback;
Erik Språng6b8d3552015-09-24 15:06:57 +02001245 return true;
1246 }
1247 break;
1248 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001249 default:
1250 break;
1251 }
Erik Språng6b8d3552015-09-24 15:06:57 +02001252 // Unsupported RTPFB message. Skip and move to next block.
1253 ++num_skipped_blocks_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001254 return false;
sprang73a93e82015-09-14 12:50:39 -07001255 } else if (header.packet_type == PT_PSFB) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001256 // Payload specific feedback
sprang73a93e82015-09-14 12:50:39 -07001257 switch (header.count_or_format) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001258 case 1:
1259 // PLI
Erik Språng242e22b2015-05-11 10:17:43 +02001260 _packetType = RTCPPacketTypes::kPsfbPli;
niklase@google.com470e71d2011-07-07 08:21:25 +00001261 _packet.PLI.SenderSSRC = senderSSRC;
1262 _packet.PLI.MediaSSRC = mediaSSRC;
1263
1264 // Note: No state transition, PLI FCI is empty!
1265 return true;
1266 case 2:
1267 // SLI
Erik Språng242e22b2015-05-11 10:17:43 +02001268 _packetType = RTCPPacketTypes::kPsfbSli;
niklase@google.com470e71d2011-07-07 08:21:25 +00001269 _packet.SLI.SenderSSRC = senderSSRC;
1270 _packet.SLI.MediaSSRC = mediaSSRC;
1271
Erik Språng242e22b2015-05-11 10:17:43 +02001272 _state = ParseState::State_PSFB_SLIItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001273
1274 return true;
1275 case 3:
Erik Språng242e22b2015-05-11 10:17:43 +02001276 _packetType = RTCPPacketTypes::kPsfbRpsi;
niklase@google.com470e71d2011-07-07 08:21:25 +00001277 _packet.RPSI.SenderSSRC = senderSSRC;
1278 _packet.RPSI.MediaSSRC = mediaSSRC;
1279
Erik Språng242e22b2015-05-11 10:17:43 +02001280 _state = ParseState::State_PSFB_RPSIItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001281 return true;
1282 case 4:
1283 // FIR
Erik Språng242e22b2015-05-11 10:17:43 +02001284 _packetType = RTCPPacketTypes::kPsfbFir;
niklase@google.com470e71d2011-07-07 08:21:25 +00001285 _packet.FIR.SenderSSRC = senderSSRC;
1286 _packet.FIR.MediaSSRC = mediaSSRC;
1287
Erik Språng242e22b2015-05-11 10:17:43 +02001288 _state = ParseState::State_PSFB_FIRItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001289 return true;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001290 case 15:
Erik Språng242e22b2015-05-11 10:17:43 +02001291 _packetType = RTCPPacketTypes::kPsfbApp;
asapersson@webrtc.orga7689702012-04-19 07:01:29 +00001292 _packet.PSFBAPP.SenderSSRC = senderSSRC;
1293 _packet.PSFBAPP.MediaSSRC = mediaSSRC;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001294
Erik Språng242e22b2015-05-11 10:17:43 +02001295 _state = ParseState::State_PSFB_AppItem;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001296 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001297 default:
1298 break;
1299 }
1300
niklase@google.com470e71d2011-07-07 08:21:25 +00001301 return false;
1302 }
1303 else
1304 {
Erik Språng6b8d3552015-09-24 15:06:57 +02001305 RTC_NOTREACHED();
niklase@google.com470e71d2011-07-07 08:21:25 +00001306 return false;
1307 }
1308}
1309
asapersson@webrtc.orga8260062014-05-20 09:53:51 +00001310bool RTCPUtility::RTCPParserV2::ParseRPSIItem() {
1311
1312 // RFC 4585 6.3.3. Reference Picture Selection Indication (RPSI).
1313 //
1314 // 0 1 2 3
1315 // 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
1316 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1317 // | PB |0| Payload Type| Native RPSI bit string |
1318 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1319 // | defined per codec ... | Padding (0) |
1320 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
niklase@google.com470e71d2011-07-07 08:21:25 +00001321
1322 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1323
asapersson@webrtc.orga8260062014-05-20 09:53:51 +00001324 if (length < 4) {
Erik Språng242e22b2015-05-11 10:17:43 +02001325 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001326
1327 EndCurrentBlock();
1328 return false;
1329 }
asapersson@webrtc.orga8260062014-05-20 09:53:51 +00001330 if (length > 2 + RTCP_RPSI_DATA_SIZE) {
Erik Språng242e22b2015-05-11 10:17:43 +02001331 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001332
1333 EndCurrentBlock();
1334 return false;
1335 }
1336
niklase@google.com470e71d2011-07-07 08:21:25 +00001337
asapersson@webrtc.orga8260062014-05-20 09:53:51 +00001338 uint8_t padding_bits = *_ptrRTCPData++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001339 _packet.RPSI.PayloadType = *_ptrRTCPData++;
1340
danilchap90a13512016-04-11 10:05:02 -07001341 if (padding_bits > static_cast<uint16_t>(length - 2) * 8) {
1342 _state = ParseState::State_TopLevel;
1343
1344 EndCurrentBlock();
1345 return false;
1346 }
1347
1348 _packetType = RTCPPacketTypes::kPsfbRpsiItem;
1349
asapersson@webrtc.orga8260062014-05-20 09:53:51 +00001350 memcpy(_packet.RPSI.NativeBitString, _ptrRTCPData, length - 2);
1351 _ptrRTCPData += length - 2;
niklase@google.com470e71d2011-07-07 08:21:25 +00001352
asapersson@webrtc.orga8260062014-05-20 09:53:51 +00001353 _packet.RPSI.NumberOfValidBits =
1354 static_cast<uint16_t>(length - 2) * 8 - padding_bits;
niklase@google.com470e71d2011-07-07 08:21:25 +00001355 return true;
1356}
1357
1358bool
1359RTCPUtility::RTCPParserV2::ParseNACKItem()
1360{
1361 // RFC 4585 6.2.1. Generic NACK
1362
1363 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1364
1365 if (length < 4)
1366 {
Erik Språng242e22b2015-05-11 10:17:43 +02001367 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001368
1369 EndCurrentBlock();
1370 return false;
1371 }
1372
Erik Språng242e22b2015-05-11 10:17:43 +02001373 _packetType = RTCPPacketTypes::kRtpfbNackItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001374
1375 _packet.NACKItem.PacketID = *_ptrRTCPData++ << 8;
1376 _packet.NACKItem.PacketID += *_ptrRTCPData++;
1377
1378 _packet.NACKItem.BitMask = *_ptrRTCPData++ << 8;
1379 _packet.NACKItem.BitMask += *_ptrRTCPData++;
1380
1381 return true;
1382}
1383
1384bool
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001385RTCPUtility::RTCPParserV2::ParsePsfbAppItem()
1386{
1387 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1388
1389 if (length < 4)
1390 {
Erik Språng242e22b2015-05-11 10:17:43 +02001391 _state = ParseState::State_TopLevel;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001392
1393 EndCurrentBlock();
1394 return false;
1395 }
1396 if(*_ptrRTCPData++ != 'R')
1397 {
Erik Språng242e22b2015-05-11 10:17:43 +02001398 _state = ParseState::State_TopLevel;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001399
1400 EndCurrentBlock();
1401 return false;
1402 }
1403 if(*_ptrRTCPData++ != 'E')
1404 {
Erik Språng242e22b2015-05-11 10:17:43 +02001405 _state = ParseState::State_TopLevel;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001406
1407 EndCurrentBlock();
1408 return false;
1409 }
1410 if(*_ptrRTCPData++ != 'M')
1411 {
Erik Språng242e22b2015-05-11 10:17:43 +02001412 _state = ParseState::State_TopLevel;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001413
1414 EndCurrentBlock();
1415 return false;
1416 }
1417 if(*_ptrRTCPData++ != 'B')
1418 {
Erik Språng242e22b2015-05-11 10:17:43 +02001419 _state = ParseState::State_TopLevel;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001420
1421 EndCurrentBlock();
1422 return false;
1423 }
Erik Språng242e22b2015-05-11 10:17:43 +02001424 _packetType = RTCPPacketTypes::kPsfbRemb;
1425 _state = ParseState::State_PSFB_REMBItem;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001426 return true;
1427}
asapersson@webrtc.orga7689702012-04-19 07:01:29 +00001428
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001429bool
1430RTCPUtility::RTCPParserV2::ParsePsfbREMBItem()
1431{
1432 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1433
1434 if (length < 4)
1435 {
Erik Språng242e22b2015-05-11 10:17:43 +02001436 _state = ParseState::State_TopLevel;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001437
1438 EndCurrentBlock();
1439 return false;
1440 }
1441
asapersson@webrtc.orga7689702012-04-19 07:01:29 +00001442 _packet.REMBItem.NumberOfSSRCs = *_ptrRTCPData++;
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001443 const uint8_t brExp = (_ptrRTCPData[0] >> 2) & 0x3F;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001444
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001445 uint32_t brMantissa = (_ptrRTCPData[0] & 0x03) << 16;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001446 brMantissa += (_ptrRTCPData[1] << 8);
1447 brMantissa += (_ptrRTCPData[2]);
1448
1449 _ptrRTCPData += 3; // Fwd read data
asapersson@webrtc.orga7689702012-04-19 07:01:29 +00001450 _packet.REMBItem.BitRate = (brMantissa << brExp);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001451
asapersson@webrtc.orga7689702012-04-19 07:01:29 +00001452 const ptrdiff_t length_ssrcs = _ptrRTCPBlockEnd - _ptrRTCPData;
1453 if (length_ssrcs < 4 * _packet.REMBItem.NumberOfSSRCs)
1454 {
Erik Språng242e22b2015-05-11 10:17:43 +02001455 _state = ParseState::State_TopLevel;
asapersson@webrtc.orga7689702012-04-19 07:01:29 +00001456
1457 EndCurrentBlock();
1458 return false;
1459 }
1460
Erik Språng242e22b2015-05-11 10:17:43 +02001461 _packetType = RTCPPacketTypes::kPsfbRembItem;
asapersson@webrtc.orga7689702012-04-19 07:01:29 +00001462
1463 for (int i = 0; i < _packet.REMBItem.NumberOfSSRCs; i++)
1464 {
1465 _packet.REMBItem.SSRCs[i] = *_ptrRTCPData++ << 24;
1466 _packet.REMBItem.SSRCs[i] += *_ptrRTCPData++ << 16;
1467 _packet.REMBItem.SSRCs[i] += *_ptrRTCPData++ << 8;
1468 _packet.REMBItem.SSRCs[i] += *_ptrRTCPData++;
1469 }
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001470 return true;
1471}
1472
1473bool
niklase@google.com470e71d2011-07-07 08:21:25 +00001474RTCPUtility::RTCPParserV2::ParseTMMBRItem()
1475{
1476 // RFC 5104 4.2.1. Temporary Maximum Media Stream Bit Rate Request (TMMBR)
1477
1478 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1479
1480 if (length < 8)
1481 {
Erik Språng242e22b2015-05-11 10:17:43 +02001482 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001483
1484 EndCurrentBlock();
1485 return false;
1486 }
1487
Erik Språng242e22b2015-05-11 10:17:43 +02001488 _packetType = RTCPPacketTypes::kRtpfbTmmbrItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001489
1490 _packet.TMMBRItem.SSRC = *_ptrRTCPData++ << 24;
1491 _packet.TMMBRItem.SSRC += *_ptrRTCPData++ << 16;
1492 _packet.TMMBRItem.SSRC += *_ptrRTCPData++ << 8;
1493 _packet.TMMBRItem.SSRC += *_ptrRTCPData++;
1494
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001495 uint8_t mxtbrExp = (_ptrRTCPData[0] >> 2) & 0x3F;
niklase@google.com470e71d2011-07-07 08:21:25 +00001496
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001497 uint32_t mxtbrMantissa = (_ptrRTCPData[0] & 0x03) << 15;
niklase@google.com470e71d2011-07-07 08:21:25 +00001498 mxtbrMantissa += (_ptrRTCPData[1] << 7);
1499 mxtbrMantissa += (_ptrRTCPData[2] >> 1) & 0x7F;
1500
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001501 uint32_t measuredOH = (_ptrRTCPData[2] & 0x01) << 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00001502 measuredOH += _ptrRTCPData[3];
1503
1504 _ptrRTCPData += 4; // Fwd read data
1505
1506 _packet.TMMBRItem.MaxTotalMediaBitRate = ((mxtbrMantissa << mxtbrExp) / 1000);
1507 _packet.TMMBRItem.MeasuredOverhead = measuredOH;
1508
1509 return true;
1510}
1511
1512bool
1513RTCPUtility::RTCPParserV2::ParseTMMBNItem()
1514{
1515 // RFC 5104 4.2.2. Temporary Maximum Media Stream Bit Rate Notification (TMMBN)
1516
1517 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1518
1519 if (length < 8)
1520 {
Erik Språng242e22b2015-05-11 10:17:43 +02001521 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001522
1523 EndCurrentBlock();
1524 return false;
1525 }
1526
Erik Språng242e22b2015-05-11 10:17:43 +02001527 _packetType = RTCPPacketTypes::kRtpfbTmmbnItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001528
1529 _packet.TMMBNItem.SSRC = *_ptrRTCPData++ << 24;
1530 _packet.TMMBNItem.SSRC += *_ptrRTCPData++ << 16;
1531 _packet.TMMBNItem.SSRC += *_ptrRTCPData++ << 8;
1532 _packet.TMMBNItem.SSRC += *_ptrRTCPData++;
1533
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001534 uint8_t mxtbrExp = (_ptrRTCPData[0] >> 2) & 0x3F;
niklase@google.com470e71d2011-07-07 08:21:25 +00001535
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001536 uint32_t mxtbrMantissa = (_ptrRTCPData[0] & 0x03) << 15;
niklase@google.com470e71d2011-07-07 08:21:25 +00001537 mxtbrMantissa += (_ptrRTCPData[1] << 7);
1538 mxtbrMantissa += (_ptrRTCPData[2] >> 1) & 0x7F;
1539
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001540 uint32_t measuredOH = (_ptrRTCPData[2] & 0x01) << 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00001541 measuredOH += _ptrRTCPData[3];
1542
1543 _ptrRTCPData += 4; // Fwd read data
1544
1545 _packet.TMMBNItem.MaxTotalMediaBitRate = ((mxtbrMantissa << mxtbrExp) / 1000);
1546 _packet.TMMBNItem.MeasuredOverhead = measuredOH;
1547
1548 return true;
1549}
1550
1551bool
1552RTCPUtility::RTCPParserV2::ParseSLIItem()
1553{
1554 // RFC 5104 6.3.2. Slice Loss Indication (SLI)
1555 /*
1556 0 1 2 3
1557 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
1558 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1559 | First | Number | PictureID |
1560 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1561 */
1562
1563 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1564
1565 if (length < 4)
1566 {
Erik Språng242e22b2015-05-11 10:17:43 +02001567 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001568
1569 EndCurrentBlock();
1570 return false;
1571 }
Erik Språng242e22b2015-05-11 10:17:43 +02001572 _packetType = RTCPPacketTypes::kPsfbSliItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001573
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001574 uint32_t buffer;
niklase@google.com470e71d2011-07-07 08:21:25 +00001575 buffer = *_ptrRTCPData++ << 24;
1576 buffer += *_ptrRTCPData++ << 16;
1577 buffer += *_ptrRTCPData++ << 8;
1578 buffer += *_ptrRTCPData++;
1579
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001580 _packet.SLIItem.FirstMB = uint16_t((buffer>>19) & 0x1fff);
1581 _packet.SLIItem.NumberOfMB = uint16_t((buffer>>6) & 0x1fff);
1582 _packet.SLIItem.PictureId = uint8_t(buffer & 0x3f);
niklase@google.com470e71d2011-07-07 08:21:25 +00001583
1584 return true;
1585}
1586
1587bool
1588RTCPUtility::RTCPParserV2::ParseFIRItem()
1589{
1590 // RFC 5104 4.3.1. Full Intra Request (FIR)
1591
1592 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1593
1594 if (length < 8)
1595 {
Erik Språng242e22b2015-05-11 10:17:43 +02001596 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001597
1598 EndCurrentBlock();
1599 return false;
1600 }
1601
Erik Språng242e22b2015-05-11 10:17:43 +02001602 _packetType = RTCPPacketTypes::kPsfbFirItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001603
1604 _packet.FIRItem.SSRC = *_ptrRTCPData++ << 24;
1605 _packet.FIRItem.SSRC += *_ptrRTCPData++ << 16;
1606 _packet.FIRItem.SSRC += *_ptrRTCPData++ << 8;
1607 _packet.FIRItem.SSRC += *_ptrRTCPData++;
1608
1609 _packet.FIRItem.CommandSequenceNumber = *_ptrRTCPData++;
1610 _ptrRTCPData += 3; // Skip "Reserved" bytes.
1611 return true;
1612}
1613
sprang73a93e82015-09-14 12:50:39 -07001614bool RTCPUtility::RTCPParserV2::ParseAPP(const RtcpCommonHeader& header) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001615 ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1616
1617 if (length < 12) // 4 * 3, RFC 3550 6.7 APP: Application-Defined RTCP Packet
1618 {
1619 EndCurrentBlock();
1620 return false;
1621 }
1622
1623 _ptrRTCPData += 4; // Skip RTCP header
1624
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001625 uint32_t senderSSRC = *_ptrRTCPData++ << 24;
niklase@google.com470e71d2011-07-07 08:21:25 +00001626 senderSSRC += *_ptrRTCPData++ << 16;
1627 senderSSRC += *_ptrRTCPData++ << 8;
1628 senderSSRC += *_ptrRTCPData++;
1629
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001630 uint32_t name = *_ptrRTCPData++ << 24;
niklase@google.com470e71d2011-07-07 08:21:25 +00001631 name += *_ptrRTCPData++ << 16;
1632 name += *_ptrRTCPData++ << 8;
1633 name += *_ptrRTCPData++;
1634
1635 length = _ptrRTCPBlockEnd - _ptrRTCPData;
1636
Erik Språng242e22b2015-05-11 10:17:43 +02001637 _packetType = RTCPPacketTypes::kApp;
niklase@google.com470e71d2011-07-07 08:21:25 +00001638
sprang73a93e82015-09-14 12:50:39 -07001639 _packet.APP.SubType = header.count_or_format;
niklase@google.com470e71d2011-07-07 08:21:25 +00001640 _packet.APP.Name = name;
1641
Erik Språng242e22b2015-05-11 10:17:43 +02001642 _state = ParseState::State_AppItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001643 return true;
1644}
1645
1646bool
1647RTCPUtility::RTCPParserV2::ParseAPPItem()
1648{
1649 const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
1650 if (length < 4)
1651 {
Erik Språng242e22b2015-05-11 10:17:43 +02001652 _state = ParseState::State_TopLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001653
1654 EndCurrentBlock();
1655 return false;
1656 }
Erik Språng242e22b2015-05-11 10:17:43 +02001657 _packetType = RTCPPacketTypes::kAppItem;
niklase@google.com470e71d2011-07-07 08:21:25 +00001658
1659 if(length > kRtcpAppCode_DATA_SIZE)
1660 {
1661 memcpy(_packet.APP.Data, _ptrRTCPData, kRtcpAppCode_DATA_SIZE);
1662 _packet.APP.Size = kRtcpAppCode_DATA_SIZE;
1663 _ptrRTCPData += kRtcpAppCode_DATA_SIZE;
1664 }else
1665 {
1666 memcpy(_packet.APP.Data, _ptrRTCPData, length);
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001667 _packet.APP.Size = (uint16_t)length;
niklase@google.com470e71d2011-07-07 08:21:25 +00001668 _ptrRTCPData += length;
1669 }
1670 return true;
1671}
1672
Erik Språng6b8d3552015-09-24 15:06:57 +02001673size_t RTCPUtility::RTCPParserV2::NumSkippedBlocks() const {
1674 return num_skipped_blocks_;
1675}
1676
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001677RTCPUtility::RTCPPacketIterator::RTCPPacketIterator(uint8_t* rtcpData,
pwestin@webrtc.orgaafa5a32012-01-17 07:07:37 +00001678 size_t rtcpDataLength)
1679 : _ptrBegin(rtcpData),
1680 _ptrEnd(rtcpData + rtcpDataLength),
1681 _ptrBlock(NULL) {
1682 memset(&_header, 0, sizeof(_header));
niklase@google.com470e71d2011-07-07 08:21:25 +00001683}
1684
pwestin@webrtc.orgaafa5a32012-01-17 07:07:37 +00001685RTCPUtility::RTCPPacketIterator::~RTCPPacketIterator() {
niklase@google.com470e71d2011-07-07 08:21:25 +00001686}
1687
sprang73a93e82015-09-14 12:50:39 -07001688const RTCPUtility::RtcpCommonHeader* RTCPUtility::RTCPPacketIterator::Begin() {
niklase@google.com470e71d2011-07-07 08:21:25 +00001689 _ptrBlock = _ptrBegin;
1690
1691 return Iterate();
1692}
1693
sprang73a93e82015-09-14 12:50:39 -07001694const RTCPUtility::RtcpCommonHeader*
1695RTCPUtility::RTCPPacketIterator::Iterate() {
1696 if ((_ptrEnd <= _ptrBlock) ||
1697 !RtcpParseCommonHeader(_ptrBlock, _ptrEnd - _ptrBlock, &_header)) {
1698 _ptrBlock = nullptr;
1699 return nullptr;
1700 }
1701 _ptrBlock += _header.BlockSize();
niklase@google.com470e71d2011-07-07 08:21:25 +00001702
sprang73a93e82015-09-14 12:50:39 -07001703 if (_ptrBlock > _ptrEnd) {
1704 _ptrBlock = nullptr;
1705 return nullptr;
1706 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001707
sprang73a93e82015-09-14 12:50:39 -07001708 return &_header;
niklase@google.com470e71d2011-07-07 08:21:25 +00001709}
1710
sprang73a93e82015-09-14 12:50:39 -07001711const RTCPUtility::RtcpCommonHeader*
1712RTCPUtility::RTCPPacketIterator::Current() {
niklase@google.com470e71d2011-07-07 08:21:25 +00001713 if (!_ptrBlock)
1714 {
1715 return NULL;
1716 }
1717
1718 return &_header;
1719}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001720} // namespace webrtc