普通文本  |  1010行  |  27.47 KB

// 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/logging.h"
#include "net/base/big_endian.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) {
  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 kStateApplicationSpecificCastSenderLog:
      IterateCastSenderLog();
      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 kPacketTypeSenderReport:
        // number of Report blocks
        number_of_blocks_ = header.IC;
        ParseSR();
        return;
      case kPacketTypeReceiverReport:
        // number of Report blocks
        number_of_blocks_ = header.IC;
        ParseRR();
        return;
      case kPacketTypeSdes:
        // number of Sdes blocks
        number_of_blocks_ = header.IC;
        if (!ParseSdes()) {
          break;  // Nothing supported found, continue to next block!
        }
        return;
      case kPacketTypeBye:
        number_of_blocks_ = header.IC;
        if (!ParseBye()) {
          // Nothing supported found, continue to next block!
          break;
        }
        return;
      case kPacketTypeApplicationDefined:
        if (!ParseApplicationDefined(header.IC)) {
          // Nothing supported found, continue to next block!
          break;
        }
        return;
      case kPacketTypeGenericRtpFeedback:  // Fall through!
      case kPacketTypePayloadSpecific:
        if (!ParseFeedBackCommon(header)) {
          // Nothing supported found, continue to next block!
          break;
        }
        return;
      case 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::IterateCastSenderLog() {
  bool success = ParseCastSenderLogItem();
  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;

  net::BigEndianReader big_endian_reader(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;

  net::BigEndianReader big_endian_reader(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;
  }

  net::BigEndianReader big_endian_reader(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;
    net::BigEndianReader big_endian_reader(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_;
  net::BigEndianReader big_endian_reader(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;

  net::BigEndianReader big_endian_reader(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 == kSenderLogSubtype || subtype == kReceiverLogSubtype)) {
    state_ = kStateTopLevel;
    EndCurrentBlock();
    return false;
  }

  uint32 sender_ssrc;
  uint32 name;

  net::BigEndianReader big_endian_reader(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 kSenderLogSubtype:
      state_ = kStateApplicationSpecificCastSenderLog;
      field_type_ = kRtcpApplicationSpecificCastSenderLogCode;
      field_.cast_sender_log.sender_ssrc = sender_ssrc;
      break;
    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;
  net::BigEndianReader big_endian_reader(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;
  net::BigEndianReader big_endian_reader(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);
  field_.cast_receiver_log.delay_delta_or_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::ParseCastSenderLogItem() {
  ptrdiff_t length = rtcp_block_end_ - rtcp_data_;

  if (length < 4) {
    state_ = kStateTopLevel;
    EndCurrentBlock();
    return false;
  }
  uint32 data;
  net::BigEndianReader big_endian_reader(rtcp_data_, length);
  big_endian_reader.ReadU32(&data);

  rtcp_data_ += 4;

  field_.cast_sender_log.status = static_cast<uint8>(data >> 24);
  // We have 24 LSB of the RTP timestamp on the wire.
  field_.cast_sender_log.rtp_timestamp = data & 0xffffff;
  field_type_ = kRtcpApplicationSpecificCastSenderLogCode;
  return true;
}

bool RtcpParser::ParseFeedBackCommon(const RtcpCommonHeader& header) {
  DCHECK((header.PT == kPacketTypeGenericRtpFeedback) ||
         (header.PT == 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;
  net::BigEndianReader big_endian_reader(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 == 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 == 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;
  net::BigEndianReader big_endian_reader(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;

  net::BigEndianReader big_endian_reader(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;
  net::BigEndianReader big_endian_reader(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;
  }

  net::BigEndianReader big_endian_reader(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;

  net::BigEndianReader big_endian_reader(rtcp_data_, length);
  big_endian_reader.ReadU8(&field_.cast_item.last_frame_id);
  big_endian_reader.ReadU8(&field_.cast_item.number_of_lost_fields);

  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;

  net::BigEndianReader big_endian_reader(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;

  net::BigEndianReader big_endian_reader(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;

  net::BigEndianReader big_endian_reader(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;
  net::BigEndianReader big_endian_reader(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;
  }

  net::BigEndianReader big_endian_reader(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;
  }

  net::BigEndianReader big_endian_reader(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;
}

}  // namespace cast
}  // namespace media