| Index: media/cast/rtcp/rtcp_utility.cc
|
| diff --git a/media/cast/rtcp/rtcp_utility.cc b/media/cast/rtcp/rtcp_utility.cc
|
| deleted file mode 100644
|
| index e29f82e9cf93d0a8f41fc28c3b5239848cef51a4..0000000000000000000000000000000000000000
|
| --- a/media/cast/rtcp/rtcp_utility.cc
|
| +++ /dev/null
|
| @@ -1,1066 +0,0 @@
|
| -// Copyright 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "media/cast/rtcp/rtcp_utility.h"
|
| -
|
| -#include "base/big_endian.h"
|
| -#include "base/logging.h"
|
| -#include "media/cast/transport/cast_transport_defines.h"
|
| -
|
| -namespace media {
|
| -namespace cast {
|
| -
|
| -RtcpParser::RtcpParser(const uint8* rtcpData, size_t rtcpDataLength)
|
| - : rtcp_data_begin_(rtcpData),
|
| - rtcp_data_end_(rtcpData + rtcpDataLength),
|
| - valid_packet_(false),
|
| - rtcp_data_(rtcpData),
|
| - rtcp_block_end_(NULL),
|
| - state_(kStateTopLevel),
|
| - number_of_blocks_(0),
|
| - field_type_(kRtcpNotValidCode) {
|
| - memset(&field_, 0, sizeof(field_));
|
| - Validate();
|
| -}
|
| -
|
| -RtcpParser::~RtcpParser() {}
|
| -
|
| -RtcpFieldTypes RtcpParser::FieldType() const { return field_type_; }
|
| -
|
| -const RtcpField& RtcpParser::Field() const { return field_; }
|
| -
|
| -RtcpFieldTypes RtcpParser::Begin() {
|
| - rtcp_data_ = rtcp_data_begin_;
|
| - return Iterate();
|
| -}
|
| -
|
| -RtcpFieldTypes RtcpParser::Iterate() {
|
| - // Reset packet type
|
| - field_type_ = kRtcpNotValidCode;
|
| -
|
| - if (!IsValid())
|
| - return kRtcpNotValidCode;
|
| -
|
| - switch (state_) {
|
| - case kStateTopLevel:
|
| - IterateTopLevel();
|
| - break;
|
| - case kStateReportBlock:
|
| - IterateReportBlockItem();
|
| - break;
|
| - case kStateSdes:
|
| - IterateSdesItem();
|
| - break;
|
| - case kStateBye:
|
| - IterateByeItem();
|
| - break;
|
| - case kStateApplicationSpecificCastReceiverFrameLog:
|
| - IterateCastReceiverLogFrame();
|
| - break;
|
| - case kStateApplicationSpecificCastReceiverEventLog:
|
| - IterateCastReceiverLogEvent();
|
| - break;
|
| - case kStateExtendedReportBlock:
|
| - IterateExtendedReportItem();
|
| - break;
|
| - case kStateExtendedReportDelaySinceLastReceiverReport:
|
| - IterateExtendedReportDelaySinceLastReceiverReportItem();
|
| - break;
|
| - case kStateGenericRtpFeedbackNack:
|
| - IterateNackItem();
|
| - break;
|
| - case kStatePayloadSpecificRpsi:
|
| - IterateRpsiItem();
|
| - break;
|
| - case kStatePayloadSpecificFir:
|
| - IterateFirItem();
|
| - break;
|
| - case kStatePayloadSpecificApplication:
|
| - IteratePayloadSpecificAppItem();
|
| - break;
|
| - case kStatePayloadSpecificRemb:
|
| - IteratePayloadSpecificRembItem();
|
| - break;
|
| - case kStatePayloadSpecificCast:
|
| - IteratePayloadSpecificCastItem();
|
| - break;
|
| - case kStatePayloadSpecificCastNack:
|
| - IteratePayloadSpecificCastNackItem();
|
| - break;
|
| - }
|
| - return field_type_;
|
| -}
|
| -
|
| -void RtcpParser::IterateTopLevel() {
|
| - for (;;) {
|
| - RtcpCommonHeader header;
|
| -
|
| - bool success = RtcpParseCommonHeader(rtcp_data_, rtcp_data_end_, &header);
|
| - if (!success)
|
| - return;
|
| -
|
| - rtcp_block_end_ = rtcp_data_ + header.length_in_octets;
|
| -
|
| - if (rtcp_block_end_ > rtcp_data_end_)
|
| - return; // Bad block!
|
| -
|
| - switch (header.PT) {
|
| - case transport::kPacketTypeSenderReport:
|
| - // number of Report blocks
|
| - number_of_blocks_ = header.IC;
|
| - ParseSR();
|
| - return;
|
| - case transport::kPacketTypeReceiverReport:
|
| - // number of Report blocks
|
| - number_of_blocks_ = header.IC;
|
| - ParseRR();
|
| - return;
|
| - case transport::kPacketTypeSdes:
|
| - // number of Sdes blocks
|
| - number_of_blocks_ = header.IC;
|
| - if (!ParseSdes()) {
|
| - break; // Nothing supported found, continue to next block!
|
| - }
|
| - return;
|
| - case transport::kPacketTypeBye:
|
| - number_of_blocks_ = header.IC;
|
| - if (!ParseBye()) {
|
| - // Nothing supported found, continue to next block!
|
| - break;
|
| - }
|
| - return;
|
| - case transport::kPacketTypeApplicationDefined:
|
| - if (!ParseApplicationDefined(header.IC)) {
|
| - // Nothing supported found, continue to next block!
|
| - break;
|
| - }
|
| - return;
|
| - case transport::kPacketTypeGenericRtpFeedback: // Fall through!
|
| - case transport::kPacketTypePayloadSpecific:
|
| - if (!ParseFeedBackCommon(header)) {
|
| - // Nothing supported found, continue to next block!
|
| - break;
|
| - }
|
| - return;
|
| - case transport::kPacketTypeXr:
|
| - if (!ParseExtendedReport()) {
|
| - break; // Nothing supported found, continue to next block!
|
| - }
|
| - return;
|
| - default:
|
| - // Not supported! Skip!
|
| - EndCurrentBlock();
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void RtcpParser::IterateReportBlockItem() {
|
| - bool success = ParseReportBlockItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IterateSdesItem() {
|
| - bool success = ParseSdesItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IterateByeItem() {
|
| - bool success = ParseByeItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IterateExtendedReportItem() {
|
| - bool success = ParseExtendedReportItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IterateExtendedReportDelaySinceLastReceiverReportItem() {
|
| - bool success = ParseExtendedReportDelaySinceLastReceiverReport();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IterateNackItem() {
|
| - bool success = ParseNackItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IterateRpsiItem() {
|
| - bool success = ParseRpsiItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IterateFirItem() {
|
| - bool success = ParseFirItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IteratePayloadSpecificAppItem() {
|
| - bool success = ParsePayloadSpecificAppItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IteratePayloadSpecificRembItem() {
|
| - bool success = ParsePayloadSpecificRembItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IteratePayloadSpecificCastItem() {
|
| - bool success = ParsePayloadSpecificCastItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IteratePayloadSpecificCastNackItem() {
|
| - bool success = ParsePayloadSpecificCastNackItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IterateCastReceiverLogFrame() {
|
| - bool success = ParseCastReceiverLogFrameItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::IterateCastReceiverLogEvent() {
|
| - bool success = ParseCastReceiverLogEventItem();
|
| - if (!success)
|
| - Iterate();
|
| -}
|
| -
|
| -void RtcpParser::Validate() {
|
| - if (rtcp_data_ == NULL)
|
| - return; // NOT VALID
|
| -
|
| - RtcpCommonHeader header;
|
| - bool success =
|
| - RtcpParseCommonHeader(rtcp_data_begin_, rtcp_data_end_, &header);
|
| -
|
| - if (!success)
|
| - return; // NOT VALID!
|
| -
|
| - valid_packet_ = true;
|
| -}
|
| -
|
| -bool RtcpParser::IsValid() const { return valid_packet_; }
|
| -
|
| -void RtcpParser::EndCurrentBlock() { rtcp_data_ = rtcp_block_end_; }
|
| -
|
| -bool RtcpParser::RtcpParseCommonHeader(const uint8* data_begin,
|
| - const uint8* data_end,
|
| - RtcpCommonHeader* parsed_header) const {
|
| - if (!data_begin || !data_end)
|
| - return false;
|
| -
|
| - // 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.
|
| -
|
| - if ((data_end - data_begin) < 4)
|
| - return false;
|
| -
|
| - parsed_header->V = data_begin[0] >> 6;
|
| - parsed_header->P = ((data_begin[0] & 0x20) == 0) ? false : true;
|
| - parsed_header->IC = data_begin[0] & 0x1f;
|
| - parsed_header->PT = data_begin[1];
|
| -
|
| - parsed_header->length_in_octets =
|
| - ((data_begin[2] << 8) + data_begin[3] + 1) * 4;
|
| -
|
| - if (parsed_header->length_in_octets == 0)
|
| - return false;
|
| -
|
| - // Check if RTP version field == 2.
|
| - if (parsed_header->V != 2)
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseRR() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 8)
|
| - return false;
|
| -
|
| - field_type_ = kRtcpRrCode;
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.Skip(4); // Skip header
|
| - big_endian_reader.ReadU32(&field_.receiver_report.sender_ssrc);
|
| - field_.receiver_report.number_of_report_blocks = number_of_blocks_;
|
| - rtcp_data_ += 8;
|
| -
|
| - // State transition
|
| - state_ = kStateReportBlock;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseSR() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 28) {
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - field_type_ = kRtcpSrCode;
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.Skip(4); // Skip header
|
| - big_endian_reader.ReadU32(&field_.sender_report.sender_ssrc);
|
| - big_endian_reader.ReadU32(&field_.sender_report.ntp_most_significant);
|
| - big_endian_reader.ReadU32(&field_.sender_report.ntp_least_significant);
|
| - big_endian_reader.ReadU32(&field_.sender_report.rtp_timestamp);
|
| - big_endian_reader.ReadU32(&field_.sender_report.sender_packet_count);
|
| - big_endian_reader.ReadU32(&field_.sender_report.sender_octet_count);
|
| - field_.sender_report.number_of_report_blocks = number_of_blocks_;
|
| - rtcp_data_ += 28;
|
| -
|
| - if (number_of_blocks_ != 0) {
|
| - // State transition.
|
| - state_ = kStateReportBlock;
|
| - } else {
|
| - // Don't go to state report block item if 0 report blocks.
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseReportBlockItem() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 24 || number_of_blocks_ <= 0) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU32(&field_.report_block_item.ssrc);
|
| - big_endian_reader.ReadU8(&field_.report_block_item.fraction_lost);
|
| -
|
| - uint8 temp_number_of_packets_lost;
|
| - big_endian_reader.ReadU8(&temp_number_of_packets_lost);
|
| - field_.report_block_item.cumulative_number_of_packets_lost =
|
| - temp_number_of_packets_lost << 16;
|
| - big_endian_reader.ReadU8(&temp_number_of_packets_lost);
|
| - field_.report_block_item.cumulative_number_of_packets_lost +=
|
| - temp_number_of_packets_lost << 8;
|
| - big_endian_reader.ReadU8(&temp_number_of_packets_lost);
|
| - field_.report_block_item.cumulative_number_of_packets_lost +=
|
| - temp_number_of_packets_lost;
|
| -
|
| - big_endian_reader.ReadU32(
|
| - &field_.report_block_item.extended_highest_sequence_number);
|
| - big_endian_reader.ReadU32(&field_.report_block_item.jitter);
|
| - big_endian_reader.ReadU32(&field_.report_block_item.last_sender_report);
|
| - big_endian_reader.ReadU32(&field_.report_block_item.delay_last_sender_report);
|
| - rtcp_data_ += 24;
|
| -
|
| - number_of_blocks_--;
|
| - field_type_ = kRtcpReportBlockItemCode;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseSdes() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| -
|
| - if (length < 8) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - rtcp_data_ += 4; // Skip header
|
| -
|
| - state_ = kStateSdes;
|
| - field_type_ = kRtcpSdesCode;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseSdesItem() {
|
| - if (number_of_blocks_ <= 0) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - number_of_blocks_--;
|
| -
|
| - // Find c_name item in a Sdes chunk.
|
| - while (rtcp_data_ < rtcp_block_end_) {
|
| - ptrdiff_t data_length = rtcp_block_end_ - rtcp_data_;
|
| - if (data_length < 4) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -
|
| - uint32 ssrc;
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), data_length);
|
| - big_endian_reader.ReadU32(&ssrc);
|
| - rtcp_data_ += 4;
|
| -
|
| - bool found_c_name = ParseSdesTypes();
|
| - if (found_c_name) {
|
| - field_.c_name.sender_ssrc = ssrc;
|
| - return true;
|
| - }
|
| - }
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| -}
|
| -
|
| -bool RtcpParser::ParseSdesTypes() {
|
| - // Only the c_name item is mandatory. RFC 3550 page 46.
|
| - bool found_c_name = false;
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| -
|
| - while (big_endian_reader.remaining() > 0) {
|
| - uint8 tag;
|
| - big_endian_reader.ReadU8(&tag);
|
| -
|
| - if (tag == 0) {
|
| - // End tag! 4 octet aligned.
|
| - rtcp_data_ = rtcp_block_end_;
|
| - return found_c_name;
|
| - }
|
| -
|
| - if (big_endian_reader.remaining() > 0) {
|
| - uint8 len;
|
| - big_endian_reader.ReadU8(&len);
|
| -
|
| - if (tag == 1) { // c_name.
|
| - // Sanity check.
|
| - if (big_endian_reader.remaining() < len) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - int i = 0;
|
| - for (; i < len; ++i) {
|
| - uint8 c;
|
| - big_endian_reader.ReadU8(&c);
|
| - if ((c < ' ') || (c > '{') || (c == '%') || (c == '\\')) {
|
| - // Illegal char.
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - field_.c_name.name[i] = c;
|
| - }
|
| - // Make sure we are null terminated.
|
| - field_.c_name.name[i] = 0;
|
| - field_type_ = kRtcpSdesChunkCode;
|
| - found_c_name = true;
|
| - } else {
|
| - big_endian_reader.Skip(len);
|
| - }
|
| - }
|
| - }
|
| - // No end tag found!
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| -}
|
| -
|
| -bool RtcpParser::ParseBye() {
|
| - rtcp_data_ += 4; // Skip header.
|
| - state_ = kStateBye;
|
| - return ParseByeItem();
|
| -}
|
| -
|
| -bool RtcpParser::ParseByeItem() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 4 || number_of_blocks_ == 0) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -
|
| - field_type_ = kRtcpByeCode;
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU32(&field_.bye.sender_ssrc);
|
| - rtcp_data_ += 4;
|
| -
|
| - // We can have several CSRCs attached.
|
| - if (length >= 4 * number_of_blocks_) {
|
| - rtcp_data_ += (number_of_blocks_ - 1) * 4;
|
| - }
|
| - number_of_blocks_ = 0;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseApplicationDefined(uint8 subtype) {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 16 || subtype != kReceiverLogSubtype) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -
|
| - uint32 sender_ssrc;
|
| - uint32 name;
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.Skip(4); // Skip header.
|
| - big_endian_reader.ReadU32(&sender_ssrc);
|
| - big_endian_reader.ReadU32(&name);
|
| -
|
| - if (name != kCast) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - rtcp_data_ += 12;
|
| - switch (subtype) {
|
| - case kReceiverLogSubtype:
|
| - state_ = kStateApplicationSpecificCastReceiverFrameLog;
|
| - field_type_ = kRtcpApplicationSpecificCastReceiverLogCode;
|
| - field_.cast_receiver_log.sender_ssrc = sender_ssrc;
|
| - break;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseCastReceiverLogFrameItem() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 12) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - uint32 rtp_timestamp;
|
| - uint32 data;
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU32(&rtp_timestamp);
|
| - big_endian_reader.ReadU32(&data);
|
| -
|
| - rtcp_data_ += 8;
|
| -
|
| - field_.cast_receiver_log.rtp_timestamp = rtp_timestamp;
|
| - // We have 24 LSB of the event timestamp base on the wire.
|
| - field_.cast_receiver_log.event_timestamp_base = data & 0xffffff;
|
| -
|
| - number_of_blocks_ = 1 + static_cast<uint8>(data >> 24);
|
| - state_ = kStateApplicationSpecificCastReceiverEventLog;
|
| - field_type_ = kRtcpApplicationSpecificCastReceiverLogFrameCode;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseCastReceiverLogEventItem() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 4) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - if (number_of_blocks_ == 0) {
|
| - // Continue parsing the next receiver frame event.
|
| - state_ = kStateApplicationSpecificCastReceiverFrameLog;
|
| - return false;
|
| - }
|
| - number_of_blocks_--;
|
| -
|
| - uint16 delay_delta_or_packet_id;
|
| - uint16 event_type_and_timestamp_delta;
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU16(&delay_delta_or_packet_id);
|
| - big_endian_reader.ReadU16(&event_type_and_timestamp_delta);
|
| -
|
| - rtcp_data_ += 4;
|
| -
|
| - field_.cast_receiver_log.event =
|
| - static_cast<uint8>(event_type_and_timestamp_delta >> 12);
|
| - // delay_delta is in union'ed with packet_id.
|
| - field_.cast_receiver_log.delay_delta_or_packet_id.packet_id =
|
| - delay_delta_or_packet_id;
|
| - field_.cast_receiver_log.event_timestamp_delta =
|
| - event_type_and_timestamp_delta & 0xfff;
|
| -
|
| - field_type_ = kRtcpApplicationSpecificCastReceiverLogEventCode;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseFeedBackCommon(const RtcpCommonHeader& header) {
|
| - DCHECK((header.PT == transport::kPacketTypeGenericRtpFeedback) ||
|
| - (header.PT == transport::kPacketTypePayloadSpecific))
|
| - << "Invalid state";
|
| -
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| -
|
| - if (length < 12) { // 4 * 3, RFC4585 section 6.1
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -
|
| - uint32 sender_ssrc;
|
| - uint32 media_ssrc;
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.Skip(4); // Skip header.
|
| - big_endian_reader.ReadU32(&sender_ssrc);
|
| - big_endian_reader.ReadU32(&media_ssrc);
|
| -
|
| - rtcp_data_ += 12;
|
| -
|
| - if (header.PT == transport::kPacketTypeGenericRtpFeedback) {
|
| - // Transport layer feedback
|
| - switch (header.IC) {
|
| - case 1:
|
| - // Nack
|
| - field_type_ = kRtcpGenericRtpFeedbackNackCode;
|
| - field_.nack.sender_ssrc = sender_ssrc;
|
| - field_.nack.media_ssrc = media_ssrc;
|
| - state_ = kStateGenericRtpFeedbackNack;
|
| - return true;
|
| - case 2:
|
| - // Used to be ACK is this code point, which is removed conficts with
|
| - // http://tools.ietf.org/html/draft-levin-avt-rtcp-burst-00
|
| - break;
|
| - case 3:
|
| - // Tmmbr
|
| - break;
|
| - case 4:
|
| - // Tmmbn
|
| - break;
|
| - case 5:
|
| - // RFC 6051 RTCP-sender_report-REQ Rapid Synchronisation of RTP Flows
|
| - // Trigger a new Rtcp sender_report
|
| - field_type_ = kRtcpGenericRtpFeedbackSrReqCode;
|
| -
|
| - // Note: No state transition, sender report REQ is empty!
|
| - return true;
|
| - default:
|
| - break;
|
| - }
|
| - EndCurrentBlock();
|
| - return false;
|
| -
|
| - } else if (header.PT == transport::kPacketTypePayloadSpecific) {
|
| - // Payload specific feedback
|
| - switch (header.IC) {
|
| - case 1:
|
| - // PLI
|
| - field_type_ = kRtcpPayloadSpecificPliCode;
|
| - field_.pli.sender_ssrc = sender_ssrc;
|
| - field_.pli.media_ssrc = media_ssrc;
|
| -
|
| - // Note: No state transition, PLI FCI is empty!
|
| - return true;
|
| - case 2:
|
| - // Sli
|
| - break;
|
| - case 3:
|
| - field_type_ = kRtcpPayloadSpecificRpsiCode;
|
| - field_.rpsi.sender_ssrc = sender_ssrc;
|
| - field_.rpsi.media_ssrc = media_ssrc;
|
| - state_ = kStatePayloadSpecificRpsi;
|
| - return true;
|
| - case 4:
|
| - // fir
|
| - break;
|
| - case 15:
|
| - field_type_ = kRtcpPayloadSpecificAppCode;
|
| - field_.application_specific.sender_ssrc = sender_ssrc;
|
| - field_.application_specific.media_ssrc = media_ssrc;
|
| - state_ = kStatePayloadSpecificApplication;
|
| - return true;
|
| - default:
|
| - break;
|
| - }
|
| -
|
| - EndCurrentBlock();
|
| - return false;
|
| - } else {
|
| - DCHECK(false) << "Invalid state";
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -bool RtcpParser::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) |
|
| - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
| - */
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| -
|
| - if (length < 4) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - if (length > 2 + kRtcpRpsiDataSize) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -
|
| - field_type_ = kRtcpPayloadSpecificRpsiCode;
|
| -
|
| - uint8 padding_bits;
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU8(&padding_bits);
|
| - big_endian_reader.ReadU8(&field_.rpsi.payload_type);
|
| - big_endian_reader.ReadBytes(&field_.rpsi.native_bit_string, length - 2);
|
| - field_.rpsi.number_of_valid_bits =
|
| - static_cast<uint16>(length - 2) * 8 - padding_bits;
|
| -
|
| - rtcp_data_ += length;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseNackItem() {
|
| - // RFC 4585 6.2.1. Generic Nack
|
| -
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 4) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -
|
| - field_type_ = kRtcpGenericRtpFeedbackNackItemCode;
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU16(&field_.nack_item.packet_id);
|
| - big_endian_reader.ReadU16(&field_.nack_item.bitmask);
|
| - rtcp_data_ += 4;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParsePayloadSpecificAppItem() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| -
|
| - if (length < 4) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - uint32 name;
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU32(&name);
|
| - rtcp_data_ += 4;
|
| -
|
| - if (name == kRemb) {
|
| - field_type_ = kRtcpPayloadSpecificRembCode;
|
| - state_ = kStatePayloadSpecificRemb;
|
| - return true;
|
| - } else if (name == kCast) {
|
| - field_type_ = kRtcpPayloadSpecificCastCode;
|
| - state_ = kStatePayloadSpecificCast;
|
| - return true;
|
| - }
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| -}
|
| -
|
| -bool RtcpParser::ParsePayloadSpecificRembItem() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| -
|
| - if (length < 4) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU8(&field_.remb_item.number_of_ssrcs);
|
| -
|
| - uint8 byte_1;
|
| - uint8 byte_2;
|
| - uint8 byte_3;
|
| - big_endian_reader.ReadU8(&byte_1);
|
| - big_endian_reader.ReadU8(&byte_2);
|
| - big_endian_reader.ReadU8(&byte_3);
|
| - rtcp_data_ += 4;
|
| -
|
| - uint8 br_exp = (byte_1 >> 2) & 0x3F;
|
| - uint32 br_mantissa = ((byte_1 & 0x03) << 16) + (byte_2 << 8) + byte_3;
|
| - field_.remb_item.bitrate = (br_mantissa << br_exp);
|
| -
|
| - ptrdiff_t length_ssrcs = rtcp_block_end_ - rtcp_data_;
|
| - if (length_ssrcs < 4 * field_.remb_item.number_of_ssrcs) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -
|
| - field_type_ = kRtcpPayloadSpecificRembItemCode;
|
| -
|
| - for (int i = 0; i < field_.remb_item.number_of_ssrcs; i++) {
|
| - big_endian_reader.ReadU32(&field_.remb_item.ssrcs[i]);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParsePayloadSpecificCastItem() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 4) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - field_type_ = kRtcpPayloadSpecificCastCode;
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU8(&field_.cast_item.last_frame_id);
|
| - big_endian_reader.ReadU8(&field_.cast_item.number_of_lost_fields);
|
| - big_endian_reader.ReadU16(&field_.cast_item.target_delay_ms);
|
| -
|
| - rtcp_data_ += 4;
|
| -
|
| - if (field_.cast_item.number_of_lost_fields != 0) {
|
| - // State transition
|
| - state_ = kStatePayloadSpecificCastNack;
|
| - } else {
|
| - // Don't go to state cast nack item if got 0 fields.
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParsePayloadSpecificCastNackItem() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 4) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - field_type_ = kRtcpPayloadSpecificCastNackItemCode;
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU8(&field_.cast_nack_item.frame_id);
|
| - big_endian_reader.ReadU16(&field_.cast_nack_item.packet_id);
|
| - big_endian_reader.ReadU8(&field_.cast_nack_item.bitmask);
|
| -
|
| - rtcp_data_ += 4;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseFirItem() {
|
| - // RFC 5104 4.3.1. Full Intra Request (fir)
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| -
|
| - if (length < 8) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - field_type_ = kRtcpPayloadSpecificFirItemCode;
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU32(&field_.fir_item.ssrc);
|
| - big_endian_reader.ReadU8(&field_.fir_item.command_sequence_number);
|
| -
|
| - rtcp_data_ += 8;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseExtendedReport() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 8)
|
| - return false;
|
| -
|
| - field_type_ = kRtcpXrCode;
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.Skip(4); // Skip header.
|
| - big_endian_reader.ReadU32(&field_.extended_report.sender_ssrc);
|
| -
|
| - rtcp_data_ += 8;
|
| -
|
| - state_ = kStateExtendedReportBlock;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseExtendedReportItem() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 4) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -
|
| - uint8 block_type;
|
| - uint16 block_length;
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU8(&block_type);
|
| - big_endian_reader.Skip(1); // Ignore reserved.
|
| - big_endian_reader.ReadU16(&block_length);
|
| -
|
| - rtcp_data_ += 4;
|
| -
|
| - switch (block_type) {
|
| - case 4:
|
| - if (block_length != 2) {
|
| - // Invalid block length.
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - return ParseExtendedReportReceiverReferenceTimeReport();
|
| - case 5:
|
| - if (block_length % 3 != 0) {
|
| - // Invalid block length.
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - if (block_length >= 3) {
|
| - number_of_blocks_ = block_length / 3;
|
| - state_ = kStateExtendedReportDelaySinceLastReceiverReport;
|
| - return ParseExtendedReportDelaySinceLastReceiverReport();
|
| - }
|
| - return true;
|
| - default:
|
| - if (length < block_length * 4) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - field_type_ = kRtcpXrUnknownItemCode;
|
| - rtcp_data_ += block_length * 4;
|
| - return true;
|
| - }
|
| -}
|
| -
|
| -bool RtcpParser::ParseExtendedReportReceiverReferenceTimeReport() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 8) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU32(&field_.rrtr.ntp_most_significant);
|
| - big_endian_reader.ReadU32(&field_.rrtr.ntp_least_significant);
|
| -
|
| - rtcp_data_ += 8;
|
| -
|
| - field_type_ = kRtcpXrRrtrCode;
|
| - return true;
|
| -}
|
| -
|
| -bool RtcpParser::ParseExtendedReportDelaySinceLastReceiverReport() {
|
| - ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
|
| - if (length < 12) {
|
| - state_ = kStateTopLevel;
|
| - EndCurrentBlock();
|
| - return false;
|
| - }
|
| - if (number_of_blocks_ == 0) {
|
| - // Continue parsing the extended report block.
|
| - state_ = kStateExtendedReportBlock;
|
| - return false;
|
| - }
|
| -
|
| - base::BigEndianReader big_endian_reader(
|
| - reinterpret_cast<const char*>(rtcp_data_), length);
|
| - big_endian_reader.ReadU32(&field_.dlrr.receivers_ssrc);
|
| - big_endian_reader.ReadU32(&field_.dlrr.last_receiver_report);
|
| - big_endian_reader.ReadU32(&field_.dlrr.delay_last_receiver_report);
|
| -
|
| - rtcp_data_ += 12;
|
| -
|
| - number_of_blocks_--;
|
| - field_type_ = kRtcpXrDlrrCode;
|
| - return true;
|
| -}
|
| -
|
| -// Converts a log event type to an integer value.
|
| -// NOTE: We have only allocated 4 bits to represent the type of event over the
|
| -// wire. Therefore, this function can only return values from 0 to 15.
|
| -uint8 ConvertEventTypeToWireFormat(CastLoggingEvent event) {
|
| - switch (event) {
|
| - case FRAME_ACK_SENT:
|
| - return 11;
|
| - case FRAME_PLAYOUT:
|
| - return 12;
|
| - case FRAME_DECODED:
|
| - return 13;
|
| - case PACKET_RECEIVED:
|
| - return 14;
|
| - default:
|
| - return 0; // Not an interesting event.
|
| - }
|
| -}
|
| -
|
| -CastLoggingEvent TranslateToLogEventFromWireFormat(uint8 event) {
|
| - // TODO(imcheng): Remove the old mappings once they are no longer used.
|
| - switch (event) {
|
| - case 1: // AudioAckSent
|
| - case 5: // VideoAckSent
|
| - case 11: // Unified
|
| - return FRAME_ACK_SENT;
|
| - case 2: // AudioPlayoutDelay
|
| - case 7: // VideoRenderDelay
|
| - case 12: // Unified
|
| - return FRAME_PLAYOUT;
|
| - case 3: // AudioFrameDecoded
|
| - case 6: // VideoFrameDecoded
|
| - case 13: // Unified
|
| - return FRAME_DECODED;
|
| - case 4: // AudioPacketReceived
|
| - case 8: // VideoPacketReceived
|
| - case 14: // Unified
|
| - return PACKET_RECEIVED;
|
| - case 9: // DuplicateAudioPacketReceived
|
| - case 10: // DuplicateVideoPacketReceived
|
| - default:
|
| - // If the sender adds new log messages we will end up here until we add
|
| - // the new messages in the receiver.
|
| - VLOG(1) << "Unexpected log message received: " << static_cast<int>(event);
|
| - NOTREACHED();
|
| - return UNKNOWN;
|
| - }
|
| -}
|
| -
|
| -} // namespace cast
|
| -} // namespace media
|
|
|