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 |