/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" #include #include // ceil #include // memcpy #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" namespace webrtc { namespace RTCPUtility { NackStats::NackStats() : max_sequence_number_(0), requests_(0), unique_requests_(0) {} NackStats::~NackStats() {} void NackStats::ReportRequest(uint16_t sequence_number) { if (requests_ == 0 || webrtc::IsNewerSequenceNumber(sequence_number, max_sequence_number_)) { max_sequence_number_ = sequence_number; ++unique_requests_; } ++requests_; } uint32_t MidNtp(uint32_t ntp_sec, uint32_t ntp_frac) { return (ntp_sec << 16) + (ntp_frac >> 16); } } // namespace RTCPUtility // RTCPParserV2 : currently read only RTCPUtility::RTCPParserV2::RTCPParserV2(const uint8_t* rtcpData, size_t rtcpDataLength, bool rtcpReducedSizeEnable) : _ptrRTCPDataBegin(rtcpData), _RTCPReducedSizeEnable(rtcpReducedSizeEnable), _ptrRTCPDataEnd(rtcpData + rtcpDataLength), _validPacket(false), _ptrRTCPData(rtcpData), _ptrRTCPBlockEnd(NULL), _state(ParseState::State_TopLevel), _numberOfBlocks(0), num_skipped_blocks_(0), _packetType(RTCPPacketTypes::kInvalid) { Validate(); } RTCPUtility::RTCPParserV2::~RTCPParserV2() { } ptrdiff_t RTCPUtility::RTCPParserV2::LengthLeft() const { return (_ptrRTCPDataEnd- _ptrRTCPData); } RTCPUtility::RTCPPacketTypes RTCPUtility::RTCPParserV2::PacketType() const { return _packetType; } const RTCPUtility::RTCPPacket& RTCPUtility::RTCPParserV2::Packet() const { return _packet; } rtcp::RtcpPacket* RTCPUtility::RTCPParserV2::ReleaseRtcpPacket() { return rtcp_packet_.release(); } RTCPUtility::RTCPPacketTypes RTCPUtility::RTCPParserV2::Begin() { _ptrRTCPData = _ptrRTCPDataBegin; return Iterate(); } RTCPUtility::RTCPPacketTypes RTCPUtility::RTCPParserV2::Iterate() { // Reset packet type _packetType = RTCPPacketTypes::kInvalid; if (IsValid()) { switch (_state) { case ParseState::State_TopLevel: IterateTopLevel(); break; case ParseState::State_ReportBlockItem: IterateReportBlockItem(); break; case ParseState::State_SDESChunk: IterateSDESChunk(); break; case ParseState::State_BYEItem: IterateBYEItem(); break; case ParseState::State_ExtendedJitterItem: IterateExtendedJitterItem(); break; case ParseState::State_RTPFB_NACKItem: IterateNACKItem(); break; case ParseState::State_RTPFB_TMMBRItem: IterateTMMBRItem(); break; case ParseState::State_RTPFB_TMMBNItem: IterateTMMBNItem(); break; case ParseState::State_PSFB_SLIItem: IterateSLIItem(); break; case ParseState::State_PSFB_RPSIItem: IterateRPSIItem(); break; case ParseState::State_PSFB_FIRItem: IterateFIRItem(); break; case ParseState::State_PSFB_AppItem: IteratePsfbAppItem(); break; case ParseState::State_PSFB_REMBItem: IteratePsfbREMBItem(); break; case ParseState::State_XRItem: IterateXrItem(); break; case ParseState::State_XR_DLLRItem: IterateXrDlrrItem(); break; case ParseState::State_AppItem: IterateAppItem(); break; default: RTC_NOTREACHED() << "Invalid state!"; break; } } return _packetType; } void RTCPUtility::RTCPParserV2::IterateTopLevel() { for (;;) { RtcpCommonHeader header; if (_ptrRTCPDataEnd <= _ptrRTCPData) return; if (!RtcpParseCommonHeader(_ptrRTCPData, _ptrRTCPDataEnd - _ptrRTCPData, &header)) { return; } _ptrRTCPBlockEnd = _ptrRTCPData + header.BlockSize(); if (_ptrRTCPBlockEnd > _ptrRTCPDataEnd) { ++num_skipped_blocks_; return; } switch (header.packet_type) { case PT_SR: { // number of Report blocks _numberOfBlocks = header.count_or_format; ParseSR(); return; } case PT_RR: { // number of Report blocks _numberOfBlocks = header.count_or_format; ParseRR(); return; } case PT_SDES: { // number of SDES blocks _numberOfBlocks = header.count_or_format; const bool ok = ParseSDES(); if (!ok) { // Nothing supported found, continue to next block! break; } return; } case PT_BYE: { _numberOfBlocks = header.count_or_format; const bool ok = ParseBYE(); if (!ok) { // Nothing supported found, continue to next block! break; } return; } case PT_IJ: { // number of Report blocks _numberOfBlocks = header.count_or_format; ParseIJ(); return; } case PT_RTPFB: FALLTHROUGH(); case PT_PSFB: { if (!ParseFBCommon(header)) { // Nothing supported found, continue to next block! break; } return; } case PT_APP: { const bool ok = ParseAPP(header); if (!ok) { // Nothing supported found, continue to next block! break; } return; } case PT_XR: { const bool ok = ParseXr(); if (!ok) { // Nothing supported found, continue to next block! break; } return; } default: // Not supported! Skip! ++num_skipped_blocks_; EndCurrentBlock(); break; } } } void RTCPUtility::RTCPParserV2::IterateXrItem() { const bool success = ParseXrItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateXrDlrrItem() { const bool success = ParseXrDlrrItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateReportBlockItem() { const bool success = ParseReportBlockItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateSDESChunk() { const bool success = ParseSDESChunk(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateBYEItem() { const bool success = ParseBYEItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateExtendedJitterItem() { const bool success = ParseIJItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateNACKItem() { const bool success = ParseNACKItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateTMMBRItem() { const bool success = ParseTMMBRItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateTMMBNItem() { const bool success = ParseTMMBNItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateSLIItem() { const bool success = ParseSLIItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateRPSIItem() { const bool success = ParseRPSIItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateFIRItem() { const bool success = ParseFIRItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IteratePsfbAppItem() { const bool success = ParsePsfbAppItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IteratePsfbREMBItem() { const bool success = ParsePsfbREMBItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::IterateAppItem() { const bool success = ParseAPPItem(); if (!success) { Iterate(); } } void RTCPUtility::RTCPParserV2::Validate() { if (_ptrRTCPData == nullptr) return; // NOT VALID RtcpCommonHeader header; if (_ptrRTCPDataEnd <= _ptrRTCPDataBegin) return; // NOT VALID if (!RtcpParseCommonHeader(_ptrRTCPDataBegin, _ptrRTCPDataEnd - _ptrRTCPDataBegin, &header)) return; // NOT VALID! // * if (!reducedSize) : first packet must be RR or SR. // // * The padding bit (P) should be zero for the first packet of a // compound RTCP packet because padding should only be applied, // if it is needed, to the last packet. (NOT CHECKED!) // // * The length fields of the individual RTCP packets must add up // to the overall length of the compound RTCP packet as // received. This is a fairly strong check. (NOT CHECKED!) if (!_RTCPReducedSizeEnable) { if ((header.packet_type != PT_SR) && (header.packet_type != PT_RR)) { return; // NOT VALID } } _validPacket = true; } bool RTCPUtility::RTCPParserV2::IsValid() const { return _validPacket; } void RTCPUtility::RTCPParserV2::EndCurrentBlock() { _ptrRTCPData = _ptrRTCPBlockEnd; } // 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| IC | PT | length | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // // Common header for all RTCP packets, 4 octets. bool RTCPUtility::RtcpParseCommonHeader(const uint8_t* packet, size_t size_bytes, RtcpCommonHeader* parsed_header) { RTC_DCHECK(parsed_header != nullptr); if (size_bytes < RtcpCommonHeader::kHeaderSizeBytes) { LOG(LS_WARNING) << "Too little data (" << size_bytes << " byte" << (size_bytes != 1 ? "s" : "") << ") remaining in buffer to parse RTCP header (4 bytes)."; return false; } const uint8_t kRtcpVersion = 2; uint8_t version = packet[0] >> 6; if (version != kRtcpVersion) { LOG(LS_WARNING) << "Invalid RTCP header: Version must be " << static_cast(kRtcpVersion) << " but was " << static_cast(version); return false; } bool has_padding = (packet[0] & 0x20) != 0; uint8_t format = packet[0] & 0x1F; uint8_t packet_type = packet[1]; size_t packet_size_words = ByteReader::ReadBigEndian(&packet[2]) + 1; if (size_bytes < packet_size_words * 4) { LOG(LS_WARNING) << "Buffer too small (" << size_bytes << " bytes) to fit an RtcpPacket of " << packet_size_words << " 32bit words."; return false; } size_t payload_size = packet_size_words * 4; size_t padding_bytes = 0; if (has_padding) { if (payload_size <= RtcpCommonHeader::kHeaderSizeBytes) { LOG(LS_WARNING) << "Invalid RTCP header: Padding bit set but 0 payload " "size specified."; return false; } padding_bytes = packet[payload_size - 1]; if (RtcpCommonHeader::kHeaderSizeBytes + padding_bytes > payload_size) { LOG(LS_WARNING) << "Invalid RTCP header: Too many padding bytes (" << padding_bytes << ") for a packet size of " << payload_size << "bytes."; return false; } payload_size -= padding_bytes; } payload_size -= RtcpCommonHeader::kHeaderSizeBytes; parsed_header->version = kRtcpVersion; parsed_header->count_or_format = format; parsed_header->packet_type = packet_type; parsed_header->payload_size_bytes = payload_size; parsed_header->padding_bytes = padding_bytes; return true; } bool RTCPUtility::RTCPParserV2::ParseRR() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 8) { return false; } _ptrRTCPData += 4; // Skip header _packetType = RTCPPacketTypes::kRr; _packet.RR.SenderSSRC = *_ptrRTCPData++ << 24; _packet.RR.SenderSSRC += *_ptrRTCPData++ << 16; _packet.RR.SenderSSRC += *_ptrRTCPData++ << 8; _packet.RR.SenderSSRC += *_ptrRTCPData++; _packet.RR.NumberOfReportBlocks = _numberOfBlocks; // State transition _state = ParseState::State_ReportBlockItem; return true; } bool RTCPUtility::RTCPParserV2::ParseSR() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 28) { EndCurrentBlock(); return false; } _ptrRTCPData += 4; // Skip header _packetType = RTCPPacketTypes::kSr; _packet.SR.SenderSSRC = *_ptrRTCPData++ << 24; _packet.SR.SenderSSRC += *_ptrRTCPData++ << 16; _packet.SR.SenderSSRC += *_ptrRTCPData++ << 8; _packet.SR.SenderSSRC += *_ptrRTCPData++; _packet.SR.NTPMostSignificant = *_ptrRTCPData++ << 24; _packet.SR.NTPMostSignificant += *_ptrRTCPData++ << 16; _packet.SR.NTPMostSignificant += *_ptrRTCPData++ << 8; _packet.SR.NTPMostSignificant += *_ptrRTCPData++; _packet.SR.NTPLeastSignificant = *_ptrRTCPData++ << 24; _packet.SR.NTPLeastSignificant += *_ptrRTCPData++ << 16; _packet.SR.NTPLeastSignificant += *_ptrRTCPData++ << 8; _packet.SR.NTPLeastSignificant += *_ptrRTCPData++; _packet.SR.RTPTimestamp = *_ptrRTCPData++ << 24; _packet.SR.RTPTimestamp += *_ptrRTCPData++ << 16; _packet.SR.RTPTimestamp += *_ptrRTCPData++ << 8; _packet.SR.RTPTimestamp += *_ptrRTCPData++; _packet.SR.SenderPacketCount = *_ptrRTCPData++ << 24; _packet.SR.SenderPacketCount += *_ptrRTCPData++ << 16; _packet.SR.SenderPacketCount += *_ptrRTCPData++ << 8; _packet.SR.SenderPacketCount += *_ptrRTCPData++; _packet.SR.SenderOctetCount = *_ptrRTCPData++ << 24; _packet.SR.SenderOctetCount += *_ptrRTCPData++ << 16; _packet.SR.SenderOctetCount += *_ptrRTCPData++ << 8; _packet.SR.SenderOctetCount += *_ptrRTCPData++; _packet.SR.NumberOfReportBlocks = _numberOfBlocks; // State transition if(_numberOfBlocks != 0) { _state = ParseState::State_ReportBlockItem; }else { // don't go to state report block item if 0 report blocks _state = ParseState::State_TopLevel; EndCurrentBlock(); } return true; } bool RTCPUtility::RTCPParserV2::ParseReportBlockItem() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 24 || _numberOfBlocks <= 0) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packet.ReportBlockItem.SSRC = *_ptrRTCPData++ << 24; _packet.ReportBlockItem.SSRC += *_ptrRTCPData++ << 16; _packet.ReportBlockItem.SSRC += *_ptrRTCPData++ << 8; _packet.ReportBlockItem.SSRC += *_ptrRTCPData++; _packet.ReportBlockItem.FractionLost = *_ptrRTCPData++; _packet.ReportBlockItem.CumulativeNumOfPacketsLost = *_ptrRTCPData++ << 16; _packet.ReportBlockItem.CumulativeNumOfPacketsLost += *_ptrRTCPData++ << 8; _packet.ReportBlockItem.CumulativeNumOfPacketsLost += *_ptrRTCPData++; _packet.ReportBlockItem.ExtendedHighestSequenceNumber = *_ptrRTCPData++ << 24; _packet.ReportBlockItem.ExtendedHighestSequenceNumber += *_ptrRTCPData++ << 16; _packet.ReportBlockItem.ExtendedHighestSequenceNumber += *_ptrRTCPData++ << 8; _packet.ReportBlockItem.ExtendedHighestSequenceNumber += *_ptrRTCPData++; _packet.ReportBlockItem.Jitter = *_ptrRTCPData++ << 24; _packet.ReportBlockItem.Jitter += *_ptrRTCPData++ << 16; _packet.ReportBlockItem.Jitter += *_ptrRTCPData++ << 8; _packet.ReportBlockItem.Jitter += *_ptrRTCPData++; _packet.ReportBlockItem.LastSR = *_ptrRTCPData++ << 24; _packet.ReportBlockItem.LastSR += *_ptrRTCPData++ << 16; _packet.ReportBlockItem.LastSR += *_ptrRTCPData++ << 8; _packet.ReportBlockItem.LastSR += *_ptrRTCPData++; _packet.ReportBlockItem.DelayLastSR = *_ptrRTCPData++ << 24; _packet.ReportBlockItem.DelayLastSR += *_ptrRTCPData++ << 16; _packet.ReportBlockItem.DelayLastSR += *_ptrRTCPData++ << 8; _packet.ReportBlockItem.DelayLastSR += *_ptrRTCPData++; _numberOfBlocks--; _packetType = RTCPPacketTypes::kReportBlockItem; return true; } /* From RFC 5450: Transmission Time Offsets in RTP Streams. 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ hdr |V=2|P| RC | PT=IJ=195 | length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | inter-arrival jitter | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ . . . . . . | inter-arrival jitter | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ bool RTCPUtility::RTCPParserV2::ParseIJ() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 4) { return false; } _ptrRTCPData += 4; // Skip header _packetType = RTCPPacketTypes::kExtendedIj; // State transition _state = ParseState::State_ExtendedJitterItem; return true; } bool RTCPUtility::RTCPParserV2::ParseIJItem() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 4 || _numberOfBlocks <= 0) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packet.ExtendedJitterReportItem.Jitter = *_ptrRTCPData++ << 24; _packet.ExtendedJitterReportItem.Jitter += *_ptrRTCPData++ << 16; _packet.ExtendedJitterReportItem.Jitter += *_ptrRTCPData++ << 8; _packet.ExtendedJitterReportItem.Jitter += *_ptrRTCPData++; _numberOfBlocks--; _packetType = RTCPPacketTypes::kExtendedIjItem; return true; } bool RTCPUtility::RTCPParserV2::ParseSDES() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 8) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _ptrRTCPData += 4; // Skip header _state = ParseState::State_SDESChunk; _packetType = RTCPPacketTypes::kSdes; return true; } bool RTCPUtility::RTCPParserV2::ParseSDESChunk() { if(_numberOfBlocks <= 0) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _numberOfBlocks--; // Find CName item in a SDES chunk. while (_ptrRTCPData < _ptrRTCPBlockEnd) { const ptrdiff_t dataLen = _ptrRTCPBlockEnd - _ptrRTCPData; if (dataLen < 4) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } uint32_t SSRC = *_ptrRTCPData++ << 24; SSRC += *_ptrRTCPData++ << 16; SSRC += *_ptrRTCPData++ << 8; SSRC += *_ptrRTCPData++; const bool foundCname = ParseSDESItem(); if (foundCname) { _packet.CName.SenderSSRC = SSRC; // Add SSRC return true; } } _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } bool RTCPUtility::RTCPParserV2::ParseSDESItem() { // Find CName // Only the CNAME item is mandatory. RFC 3550 page 46 bool foundCName = false; size_t itemOctetsRead = 0; while (_ptrRTCPData < _ptrRTCPBlockEnd) { const uint8_t tag = *_ptrRTCPData++; ++itemOctetsRead; if (tag == 0) { // End tag! 4 oct aligned while ((itemOctetsRead++ % 4) != 0) { ++_ptrRTCPData; } return foundCName; } if (_ptrRTCPData < _ptrRTCPBlockEnd) { const uint8_t len = *_ptrRTCPData++; ++itemOctetsRead; if (tag == 1) { // CNAME // Sanity if ((_ptrRTCPData + len) >= _ptrRTCPBlockEnd) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } uint8_t i = 0; for (; i < len; ++i) { const uint8_t c = _ptrRTCPData[i]; if ((c < ' ') || (c > '{') || (c == '%') || (c == '\\')) { // Illegal char _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packet.CName.CName[i] = c; } // Make sure we are null terminated. _packet.CName.CName[i] = 0; _packetType = RTCPPacketTypes::kSdesChunk; foundCName = true; } _ptrRTCPData += len; itemOctetsRead += len; } } // No end tag found! _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } bool RTCPUtility::RTCPParserV2::ParseBYE() { _ptrRTCPData += 4; // Skip header _state = ParseState::State_BYEItem; return ParseBYEItem(); } bool RTCPUtility::RTCPParserV2::ParseBYEItem() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 4 || _numberOfBlocks == 0) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packetType = RTCPPacketTypes::kBye; _packet.BYE.SenderSSRC = *_ptrRTCPData++ << 24; _packet.BYE.SenderSSRC += *_ptrRTCPData++ << 16; _packet.BYE.SenderSSRC += *_ptrRTCPData++ << 8; _packet.BYE.SenderSSRC += *_ptrRTCPData++; // we can have several CSRCs attached // sanity if(length >= 4*_numberOfBlocks) { _ptrRTCPData += (_numberOfBlocks -1)*4; } _numberOfBlocks = 0; return true; } /* 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|reserved | PT=XR=207 | length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SSRC | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ : report blocks : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ bool RTCPUtility::RTCPParserV2::ParseXr() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 8) { EndCurrentBlock(); return false; } _ptrRTCPData += 4; // Skip header _packet.XR.OriginatorSSRC = *_ptrRTCPData++ << 24; _packet.XR.OriginatorSSRC += *_ptrRTCPData++ << 16; _packet.XR.OriginatorSSRC += *_ptrRTCPData++ << 8; _packet.XR.OriginatorSSRC += *_ptrRTCPData++; _packetType = RTCPPacketTypes::kXrHeader; _state = ParseState::State_XRItem; return true; } /* Extended report block format (RFC 3611). BT: block type. block length: length of report block in 32-bits words minus one (including the header). 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BT | type-specific | block length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ : type-specific block contents : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ bool RTCPUtility::RTCPParserV2::ParseXrItem() { const int kBlockHeaderLengthInBytes = 4; const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < kBlockHeaderLengthInBytes) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } uint8_t block_type = *_ptrRTCPData++; _ptrRTCPData++; // Ignore reserved. uint16_t block_length_in_4bytes = *_ptrRTCPData++ << 8; block_length_in_4bytes += *_ptrRTCPData++; switch (block_type) { case kBtReceiverReferenceTime: return ParseXrReceiverReferenceTimeItem(block_length_in_4bytes); case kBtDlrr: return ParseXrDlrr(block_length_in_4bytes); case kBtVoipMetric: return ParseXrVoipMetricItem(block_length_in_4bytes); default: return ParseXrUnsupportedBlockType(block_length_in_4bytes); } } /* Receiver Reference Time Report Block. 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BT=4 | reserved | block length = 2 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | NTP timestamp, most significant word | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | NTP timestamp, least significant word | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ bool RTCPUtility::RTCPParserV2::ParseXrReceiverReferenceTimeItem( int block_length_4bytes) { const int kBlockLengthIn4Bytes = 2; const int kBlockLengthInBytes = kBlockLengthIn4Bytes * 4; const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (block_length_4bytes != kBlockLengthIn4Bytes || length < kBlockLengthInBytes) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packet.XRReceiverReferenceTimeItem.NTPMostSignificant = *_ptrRTCPData++<<24; _packet.XRReceiverReferenceTimeItem.NTPMostSignificant+= *_ptrRTCPData++<<16; _packet.XRReceiverReferenceTimeItem.NTPMostSignificant+= *_ptrRTCPData++<<8; _packet.XRReceiverReferenceTimeItem.NTPMostSignificant+= *_ptrRTCPData++; _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant = *_ptrRTCPData++<<24; _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant+= *_ptrRTCPData++<<16; _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant+= *_ptrRTCPData++<<8; _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant+= *_ptrRTCPData++; _packetType = RTCPPacketTypes::kXrReceiverReferenceTime; _state = ParseState::State_XRItem; return true; } /* DLRR Report Block. 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BT=5 | reserved | block length | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | SSRC_1 (SSRC of first receiver) | sub- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block | last RR (LRR) | 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | delay since last RR (DLRR) | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | SSRC_2 (SSRC of second receiver) | sub- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block : ... : 2 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ */ bool RTCPUtility::RTCPParserV2::ParseXrDlrr(int block_length_4bytes) { const int kSubBlockLengthIn4Bytes = 3; if (block_length_4bytes < 0 || (block_length_4bytes % kSubBlockLengthIn4Bytes) != 0) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packetType = RTCPPacketTypes::kXrDlrrReportBlock; _state = ParseState::State_XR_DLLRItem; _numberOfBlocks = block_length_4bytes / kSubBlockLengthIn4Bytes; return true; } bool RTCPUtility::RTCPParserV2::ParseXrDlrrItem() { if (_numberOfBlocks == 0) { _state = ParseState::State_XRItem; return false; } const int kSubBlockLengthInBytes = 12; const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < kSubBlockLengthInBytes) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packet.XRDLRRReportBlockItem.SSRC = *_ptrRTCPData++ << 24; _packet.XRDLRRReportBlockItem.SSRC += *_ptrRTCPData++ << 16; _packet.XRDLRRReportBlockItem.SSRC += *_ptrRTCPData++ << 8; _packet.XRDLRRReportBlockItem.SSRC += *_ptrRTCPData++; _packet.XRDLRRReportBlockItem.LastRR = *_ptrRTCPData++ << 24; _packet.XRDLRRReportBlockItem.LastRR += *_ptrRTCPData++ << 16; _packet.XRDLRRReportBlockItem.LastRR += *_ptrRTCPData++ << 8; _packet.XRDLRRReportBlockItem.LastRR += *_ptrRTCPData++; _packet.XRDLRRReportBlockItem.DelayLastRR = *_ptrRTCPData++ << 24; _packet.XRDLRRReportBlockItem.DelayLastRR += *_ptrRTCPData++ << 16; _packet.XRDLRRReportBlockItem.DelayLastRR += *_ptrRTCPData++ << 8; _packet.XRDLRRReportBlockItem.DelayLastRR += *_ptrRTCPData++; _packetType = RTCPPacketTypes::kXrDlrrReportBlockItem; --_numberOfBlocks; _state = ParseState::State_XR_DLLRItem; return true; } /* VoIP Metrics Report Block. 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BT=7 | reserved | block length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SSRC of source | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | loss rate | discard rate | burst density | gap density | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | burst duration | gap duration | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | round trip delay | end system delay | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | signal level | noise level | RERL | Gmin | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | R factor | ext. R factor | MOS-LQ | MOS-CQ | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RX config | reserved | JB nominal | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | JB maximum | JB abs max | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ bool RTCPUtility::RTCPParserV2::ParseXrVoipMetricItem(int block_length_4bytes) { const int kBlockLengthIn4Bytes = 8; const int kBlockLengthInBytes = kBlockLengthIn4Bytes * 4; const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (block_length_4bytes != kBlockLengthIn4Bytes || length < kBlockLengthInBytes) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packet.XRVOIPMetricItem.SSRC = *_ptrRTCPData++ << 24; _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++ << 16; _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++ << 8; _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++; _packet.XRVOIPMetricItem.lossRate = *_ptrRTCPData++; _packet.XRVOIPMetricItem.discardRate = *_ptrRTCPData++; _packet.XRVOIPMetricItem.burstDensity = *_ptrRTCPData++; _packet.XRVOIPMetricItem.gapDensity = *_ptrRTCPData++; _packet.XRVOIPMetricItem.burstDuration = *_ptrRTCPData++ << 8; _packet.XRVOIPMetricItem.burstDuration += *_ptrRTCPData++; _packet.XRVOIPMetricItem.gapDuration = *_ptrRTCPData++ << 8; _packet.XRVOIPMetricItem.gapDuration += *_ptrRTCPData++; _packet.XRVOIPMetricItem.roundTripDelay = *_ptrRTCPData++ << 8; _packet.XRVOIPMetricItem.roundTripDelay += *_ptrRTCPData++; _packet.XRVOIPMetricItem.endSystemDelay = *_ptrRTCPData++ << 8; _packet.XRVOIPMetricItem.endSystemDelay += *_ptrRTCPData++; _packet.XRVOIPMetricItem.signalLevel = *_ptrRTCPData++; _packet.XRVOIPMetricItem.noiseLevel = *_ptrRTCPData++; _packet.XRVOIPMetricItem.RERL = *_ptrRTCPData++; _packet.XRVOIPMetricItem.Gmin = *_ptrRTCPData++; _packet.XRVOIPMetricItem.Rfactor = *_ptrRTCPData++; _packet.XRVOIPMetricItem.extRfactor = *_ptrRTCPData++; _packet.XRVOIPMetricItem.MOSLQ = *_ptrRTCPData++; _packet.XRVOIPMetricItem.MOSCQ = *_ptrRTCPData++; _packet.XRVOIPMetricItem.RXconfig = *_ptrRTCPData++; _ptrRTCPData++; // skip reserved _packet.XRVOIPMetricItem.JBnominal = *_ptrRTCPData++ << 8; _packet.XRVOIPMetricItem.JBnominal += *_ptrRTCPData++; _packet.XRVOIPMetricItem.JBmax = *_ptrRTCPData++ << 8; _packet.XRVOIPMetricItem.JBmax += *_ptrRTCPData++; _packet.XRVOIPMetricItem.JBabsMax = *_ptrRTCPData++ << 8; _packet.XRVOIPMetricItem.JBabsMax += *_ptrRTCPData++; _packetType = RTCPPacketTypes::kXrVoipMetric; _state = ParseState::State_XRItem; return true; } bool RTCPUtility::RTCPParserV2::ParseXrUnsupportedBlockType( int block_length_4bytes) { const int32_t kBlockLengthInBytes = block_length_4bytes * 4; const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < kBlockLengthInBytes) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } // Skip block. _ptrRTCPData += kBlockLengthInBytes; _state = ParseState::State_XRItem; return false; } bool RTCPUtility::RTCPParserV2::ParseFBCommon(const RtcpCommonHeader& header) { RTC_CHECK((header.packet_type == PT_RTPFB) || (header.packet_type == PT_PSFB)); // Parser logic check const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; // 4 * 3, RFC4585 section 6.1 if (length < 12) { LOG(LS_WARNING) << "Invalid RTCP packet: Too little data (" << length << " bytes) left in buffer to parse a 12 byte RTPFB/PSFB message."; return false; } _ptrRTCPData += 4; // Skip RTCP header uint32_t senderSSRC = ByteReader::ReadBigEndian(_ptrRTCPData); _ptrRTCPData += 4; uint32_t mediaSSRC = ByteReader::ReadBigEndian(_ptrRTCPData); _ptrRTCPData += 4; if (header.packet_type == PT_RTPFB) { // Transport layer feedback switch (header.count_or_format) { case 1: { // NACK _packetType = RTCPPacketTypes::kRtpfbNack; _packet.NACK.SenderSSRC = senderSSRC; _packet.NACK.MediaSSRC = mediaSSRC; _state = ParseState::State_RTPFB_NACKItem; return true; } case 3: { // TMMBR _packetType = RTCPPacketTypes::kRtpfbTmmbr; _packet.TMMBR.SenderSSRC = senderSSRC; _packet.TMMBR.MediaSSRC = mediaSSRC; _state = ParseState::State_RTPFB_TMMBRItem; return true; } case 4: { // TMMBN _packetType = RTCPPacketTypes::kRtpfbTmmbn; _packet.TMMBN.SenderSSRC = senderSSRC; _packet.TMMBN.MediaSSRC = mediaSSRC; _state = ParseState::State_RTPFB_TMMBNItem; return true; } case 5: { // RTCP-SR-REQ Rapid Synchronisation of RTP Flows // draft-perkins-avt-rapid-rtp-sync-03.txt // trigger a new RTCP SR _packetType = RTCPPacketTypes::kRtpfbSrReq; // Note: No state transition, SR REQ is empty! return true; } case 15: { rtcp_packet_ = rtcp::TransportFeedback::ParseFrom(_ptrRTCPData - 12, length); // Since we parse the whole packet here, keep the TopLevel state and // just end the current block. EndCurrentBlock(); if (rtcp_packet_.get()) { _packetType = RTCPPacketTypes::kTransportFeedback; return true; } break; } default: break; } // Unsupported RTPFB message. Skip and move to next block. ++num_skipped_blocks_; return false; } else if (header.packet_type == PT_PSFB) { // Payload specific feedback switch (header.count_or_format) { case 1: // PLI _packetType = RTCPPacketTypes::kPsfbPli; _packet.PLI.SenderSSRC = senderSSRC; _packet.PLI.MediaSSRC = mediaSSRC; // Note: No state transition, PLI FCI is empty! return true; case 2: // SLI _packetType = RTCPPacketTypes::kPsfbSli; _packet.SLI.SenderSSRC = senderSSRC; _packet.SLI.MediaSSRC = mediaSSRC; _state = ParseState::State_PSFB_SLIItem; return true; case 3: _packetType = RTCPPacketTypes::kPsfbRpsi; _packet.RPSI.SenderSSRC = senderSSRC; _packet.RPSI.MediaSSRC = mediaSSRC; _state = ParseState::State_PSFB_RPSIItem; return true; case 4: // FIR _packetType = RTCPPacketTypes::kPsfbFir; _packet.FIR.SenderSSRC = senderSSRC; _packet.FIR.MediaSSRC = mediaSSRC; _state = ParseState::State_PSFB_FIRItem; return true; case 15: _packetType = RTCPPacketTypes::kPsfbApp; _packet.PSFBAPP.SenderSSRC = senderSSRC; _packet.PSFBAPP.MediaSSRC = mediaSSRC; _state = ParseState::State_PSFB_AppItem; return true; default: break; } return false; } else { RTC_NOTREACHED(); return false; } } bool RTCPUtility::RTCPParserV2::ParseRPSIItem() { // RFC 4585 6.3.3. Reference Picture Selection Indication (RPSI). // // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | PB |0| Payload Type| Native RPSI bit string | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | defined per codec ... | Padding (0) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 4) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } if (length > 2 + RTCP_RPSI_DATA_SIZE) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packetType = RTCPPacketTypes::kPsfbRpsi; uint8_t padding_bits = *_ptrRTCPData++; _packet.RPSI.PayloadType = *_ptrRTCPData++; memcpy(_packet.RPSI.NativeBitString, _ptrRTCPData, length - 2); _ptrRTCPData += length - 2; _packet.RPSI.NumberOfValidBits = static_cast(length - 2) * 8 - padding_bits; return true; } bool RTCPUtility::RTCPParserV2::ParseNACKItem() { // RFC 4585 6.2.1. Generic NACK const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 4) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packetType = RTCPPacketTypes::kRtpfbNackItem; _packet.NACKItem.PacketID = *_ptrRTCPData++ << 8; _packet.NACKItem.PacketID += *_ptrRTCPData++; _packet.NACKItem.BitMask = *_ptrRTCPData++ << 8; _packet.NACKItem.BitMask += *_ptrRTCPData++; return true; } bool RTCPUtility::RTCPParserV2::ParsePsfbAppItem() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 4) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } if(*_ptrRTCPData++ != 'R') { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } if(*_ptrRTCPData++ != 'E') { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } if(*_ptrRTCPData++ != 'M') { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } if(*_ptrRTCPData++ != 'B') { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packetType = RTCPPacketTypes::kPsfbRemb; _state = ParseState::State_PSFB_REMBItem; return true; } bool RTCPUtility::RTCPParserV2::ParsePsfbREMBItem() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 4) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packet.REMBItem.NumberOfSSRCs = *_ptrRTCPData++; const uint8_t brExp = (_ptrRTCPData[0] >> 2) & 0x3F; uint32_t brMantissa = (_ptrRTCPData[0] & 0x03) << 16; brMantissa += (_ptrRTCPData[1] << 8); brMantissa += (_ptrRTCPData[2]); _ptrRTCPData += 3; // Fwd read data _packet.REMBItem.BitRate = (brMantissa << brExp); const ptrdiff_t length_ssrcs = _ptrRTCPBlockEnd - _ptrRTCPData; if (length_ssrcs < 4 * _packet.REMBItem.NumberOfSSRCs) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packetType = RTCPPacketTypes::kPsfbRembItem; for (int i = 0; i < _packet.REMBItem.NumberOfSSRCs; i++) { _packet.REMBItem.SSRCs[i] = *_ptrRTCPData++ << 24; _packet.REMBItem.SSRCs[i] += *_ptrRTCPData++ << 16; _packet.REMBItem.SSRCs[i] += *_ptrRTCPData++ << 8; _packet.REMBItem.SSRCs[i] += *_ptrRTCPData++; } return true; } bool RTCPUtility::RTCPParserV2::ParseTMMBRItem() { // RFC 5104 4.2.1. Temporary Maximum Media Stream Bit Rate Request (TMMBR) const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 8) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packetType = RTCPPacketTypes::kRtpfbTmmbrItem; _packet.TMMBRItem.SSRC = *_ptrRTCPData++ << 24; _packet.TMMBRItem.SSRC += *_ptrRTCPData++ << 16; _packet.TMMBRItem.SSRC += *_ptrRTCPData++ << 8; _packet.TMMBRItem.SSRC += *_ptrRTCPData++; uint8_t mxtbrExp = (_ptrRTCPData[0] >> 2) & 0x3F; uint32_t mxtbrMantissa = (_ptrRTCPData[0] & 0x03) << 15; mxtbrMantissa += (_ptrRTCPData[1] << 7); mxtbrMantissa += (_ptrRTCPData[2] >> 1) & 0x7F; uint32_t measuredOH = (_ptrRTCPData[2] & 0x01) << 8; measuredOH += _ptrRTCPData[3]; _ptrRTCPData += 4; // Fwd read data _packet.TMMBRItem.MaxTotalMediaBitRate = ((mxtbrMantissa << mxtbrExp) / 1000); _packet.TMMBRItem.MeasuredOverhead = measuredOH; return true; } bool RTCPUtility::RTCPParserV2::ParseTMMBNItem() { // RFC 5104 4.2.2. Temporary Maximum Media Stream Bit Rate Notification (TMMBN) const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 8) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packetType = RTCPPacketTypes::kRtpfbTmmbnItem; _packet.TMMBNItem.SSRC = *_ptrRTCPData++ << 24; _packet.TMMBNItem.SSRC += *_ptrRTCPData++ << 16; _packet.TMMBNItem.SSRC += *_ptrRTCPData++ << 8; _packet.TMMBNItem.SSRC += *_ptrRTCPData++; uint8_t mxtbrExp = (_ptrRTCPData[0] >> 2) & 0x3F; uint32_t mxtbrMantissa = (_ptrRTCPData[0] & 0x03) << 15; mxtbrMantissa += (_ptrRTCPData[1] << 7); mxtbrMantissa += (_ptrRTCPData[2] >> 1) & 0x7F; uint32_t measuredOH = (_ptrRTCPData[2] & 0x01) << 8; measuredOH += _ptrRTCPData[3]; _ptrRTCPData += 4; // Fwd read data _packet.TMMBNItem.MaxTotalMediaBitRate = ((mxtbrMantissa << mxtbrExp) / 1000); _packet.TMMBNItem.MeasuredOverhead = measuredOH; return true; } bool RTCPUtility::RTCPParserV2::ParseSLIItem() { // RFC 5104 6.3.2. Slice Loss Indication (SLI) /* 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | First | Number | PictureID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 4) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packetType = RTCPPacketTypes::kPsfbSliItem; uint32_t buffer; buffer = *_ptrRTCPData++ << 24; buffer += *_ptrRTCPData++ << 16; buffer += *_ptrRTCPData++ << 8; buffer += *_ptrRTCPData++; _packet.SLIItem.FirstMB = uint16_t((buffer>>19) & 0x1fff); _packet.SLIItem.NumberOfMB = uint16_t((buffer>>6) & 0x1fff); _packet.SLIItem.PictureId = uint8_t(buffer & 0x3f); return true; } bool RTCPUtility::RTCPParserV2::ParseFIRItem() { // RFC 5104 4.3.1. Full Intra Request (FIR) const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 8) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packetType = RTCPPacketTypes::kPsfbFirItem; _packet.FIRItem.SSRC = *_ptrRTCPData++ << 24; _packet.FIRItem.SSRC += *_ptrRTCPData++ << 16; _packet.FIRItem.SSRC += *_ptrRTCPData++ << 8; _packet.FIRItem.SSRC += *_ptrRTCPData++; _packet.FIRItem.CommandSequenceNumber = *_ptrRTCPData++; _ptrRTCPData += 3; // Skip "Reserved" bytes. return true; } bool RTCPUtility::RTCPParserV2::ParseAPP(const RtcpCommonHeader& header) { ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 12) // 4 * 3, RFC 3550 6.7 APP: Application-Defined RTCP Packet { EndCurrentBlock(); return false; } _ptrRTCPData += 4; // Skip RTCP header uint32_t senderSSRC = *_ptrRTCPData++ << 24; senderSSRC += *_ptrRTCPData++ << 16; senderSSRC += *_ptrRTCPData++ << 8; senderSSRC += *_ptrRTCPData++; uint32_t name = *_ptrRTCPData++ << 24; name += *_ptrRTCPData++ << 16; name += *_ptrRTCPData++ << 8; name += *_ptrRTCPData++; length = _ptrRTCPBlockEnd - _ptrRTCPData; _packetType = RTCPPacketTypes::kApp; _packet.APP.SubType = header.count_or_format; _packet.APP.Name = name; _state = ParseState::State_AppItem; return true; } bool RTCPUtility::RTCPParserV2::ParseAPPItem() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; if (length < 4) { _state = ParseState::State_TopLevel; EndCurrentBlock(); return false; } _packetType = RTCPPacketTypes::kAppItem; if(length > kRtcpAppCode_DATA_SIZE) { memcpy(_packet.APP.Data, _ptrRTCPData, kRtcpAppCode_DATA_SIZE); _packet.APP.Size = kRtcpAppCode_DATA_SIZE; _ptrRTCPData += kRtcpAppCode_DATA_SIZE; }else { memcpy(_packet.APP.Data, _ptrRTCPData, length); _packet.APP.Size = (uint16_t)length; _ptrRTCPData += length; } return true; } size_t RTCPUtility::RTCPParserV2::NumSkippedBlocks() const { return num_skipped_blocks_; } RTCPUtility::RTCPPacketIterator::RTCPPacketIterator(uint8_t* rtcpData, size_t rtcpDataLength) : _ptrBegin(rtcpData), _ptrEnd(rtcpData + rtcpDataLength), _ptrBlock(NULL) { memset(&_header, 0, sizeof(_header)); } RTCPUtility::RTCPPacketIterator::~RTCPPacketIterator() { } const RTCPUtility::RtcpCommonHeader* RTCPUtility::RTCPPacketIterator::Begin() { _ptrBlock = _ptrBegin; return Iterate(); } const RTCPUtility::RtcpCommonHeader* RTCPUtility::RTCPPacketIterator::Iterate() { if ((_ptrEnd <= _ptrBlock) || !RtcpParseCommonHeader(_ptrBlock, _ptrEnd - _ptrBlock, &_header)) { _ptrBlock = nullptr; return nullptr; } _ptrBlock += _header.BlockSize(); if (_ptrBlock > _ptrEnd) { _ptrBlock = nullptr; return nullptr; } return &_header; } const RTCPUtility::RtcpCommonHeader* RTCPUtility::RTCPPacketIterator::Current() { if (!_ptrBlock) { return NULL; } return &_header; } } // namespace webrtc