| /* |
| * 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/base/checks.h" |
| #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" |
| #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" |
| |
| #include <assert.h> |
| #include <math.h> // ceil |
| #include <string.h> // memcpy |
| |
| #include "webrtc/base/checks.h" |
| #include "webrtc/base/logging.h" |
| #include "webrtc/modules/rtp_rtcp/source/byte_io.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); |
| } // end 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<int>(kRtcpVersion) << " but was " |
| << static_cast<int>(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<uint16_t>::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<uint32_t>::ReadBigEndian(_ptrRTCPData); |
| _ptrRTCPData += 4; |
| |
| uint32_t mediaSSRC = ByteReader<uint32_t>::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<uint16_t>(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 |