root/media/cast/rtcp/rtcp_utility.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. field_type_
  2. Begin
  3. Iterate
  4. IterateTopLevel
  5. IterateReportBlockItem
  6. IterateSdesItem
  7. IterateByeItem
  8. IterateExtendedReportItem
  9. IterateExtendedReportDelaySinceLastReceiverReportItem
  10. IterateNackItem
  11. IterateRpsiItem
  12. IterateFirItem
  13. IteratePayloadSpecificAppItem
  14. IteratePayloadSpecificRembItem
  15. IteratePayloadSpecificCastItem
  16. IteratePayloadSpecificCastNackItem
  17. IterateCastReceiverLogFrame
  18. IterateCastReceiverLogEvent
  19. IterateCastSenderLog
  20. Validate
  21. IsValid
  22. EndCurrentBlock
  23. RtcpParseCommonHeader
  24. ParseRR
  25. ParseSR
  26. ParseReportBlockItem
  27. ParseSdes
  28. ParseSdesItem
  29. ParseSdesTypes
  30. ParseBye
  31. ParseByeItem
  32. ParseApplicationDefined
  33. ParseCastReceiverLogFrameItem
  34. ParseCastReceiverLogEventItem
  35. ParseCastSenderLogItem
  36. ParseFeedBackCommon
  37. ParseRpsiItem
  38. ParseNackItem
  39. ParsePayloadSpecificAppItem
  40. ParsePayloadSpecificRembItem
  41. ParsePayloadSpecificCastItem
  42. ParsePayloadSpecificCastNackItem
  43. ParseFirItem
  44. ParseExtendedReport
  45. ParseExtendedReportItem
  46. ParseExtendedReportReceiverReferenceTimeReport
  47. ParseExtendedReportDelaySinceLastReceiverReport

// 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 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 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::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;

  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 == kSenderLogSubtype || 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 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;
  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);
  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;
  base::BigEndianReader big_endian_reader(
      reinterpret_cast<const char*>(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 == 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;
}

}  // namespace cast
}  // namespace media

/* [<][>][^][v][top][bottom][index][help] */