summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorhubbe@chromium.org <hubbe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-18 20:04:54 +0000
committerhubbe@chromium.org <hubbe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-18 20:07:11 +0000
commit8e464358387df04505304ae7b82875f7b6ba79f5 (patch)
treea4b7c91e8f6a66183b60fb95a29d3efd7fa59c1e /media
parent69c00da6c228c8bf556b952d704068ab9614af6a (diff)
downloadchromium_src-8e464358387df04505304ae7b82875f7b6ba79f5.zip
chromium_src-8e464358387df04505304ae7b82875f7b6ba79f5.tar.gz
chromium_src-8e464358387df04505304ae7b82875f7b6ba79f5.tar.bz2
Rewrite of RTCP parser.
Clears out of lot of cruft and data copying. Makes the parser easier to read. Parser uses BigEndianReader for everything, which makes security easier to verify. Removes ~1000 lines of code. BUG=396207 Review URL: https://codereview.chromium.org/477593003 Cr-Commit-Position: refs/heads/master@{#290348} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@290348 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/cast/BUILD.gn6
-rw-r--r--media/cast/cast.gyp2
-rw-r--r--media/cast/cast_sender_impl.cc1
-rw-r--r--media/cast/cast_testing.gypi4
-rw-r--r--media/cast/net/rtcp/mock_rtcp_receiver_feedback.cc15
-rw-r--r--media/cast/net/rtcp/mock_rtcp_receiver_feedback.h45
-rw-r--r--media/cast/net/rtcp/mock_rtcp_sender_feedback.cc15
-rw-r--r--media/cast/net/rtcp/mock_rtcp_sender_feedback.h28
-rw-r--r--media/cast/net/rtcp/rtcp.cc166
-rw-r--r--media/cast/net/rtcp/rtcp.h18
-rw-r--r--media/cast/net/rtcp/rtcp_receiver.cc414
-rw-r--r--media/cast/net/rtcp/rtcp_receiver.h101
-rw-r--r--media/cast/net/rtcp/rtcp_receiver_unittest.cc493
-rw-r--r--media/cast/net/rtcp/rtcp_unittest.cc1
-rw-r--r--media/cast/net/rtcp/rtcp_utility.cc776
-rw-r--r--media/cast/net/rtcp/rtcp_utility.h243
-rw-r--r--media/cast/net/rtcp/rtcp_utility_unittest.cc401
-rw-r--r--media/cast/net/rtcp/test_rtcp_packet_builder.cc16
-rw-r--r--media/cast/net/rtcp/test_rtcp_packet_builder.h17
-rw-r--r--media/cast/receiver/cast_receiver_impl.cc5
-rw-r--r--media/cast/receiver/frame_receiver.cc3
-rw-r--r--media/cast/sender/audio_sender_unittest.cc3
-rw-r--r--media/cast/sender/video_sender_unittest.cc3
23 files changed, 864 insertions, 1912 deletions
diff --git a/media/cast/BUILD.gn b/media/cast/BUILD.gn
index 8d38089..e1c9e66 100644
--- a/media/cast/BUILD.gn
+++ b/media/cast/BUILD.gn
@@ -72,8 +72,6 @@ source_set("net") {
"net/rtcp/rtcp_defines.h",
"net/rtcp/rtcp.h",
"net/rtcp/rtcp.cc",
- "net/rtcp/rtcp_receiver.cc",
- "net/rtcp/rtcp_receiver.h",
"net/rtcp/rtcp_sender.cc",
"net/rtcp/rtcp_sender.h",
"net/rtcp/rtcp_utility.cc",
@@ -237,11 +235,9 @@ test("cast_unittests") {
"net/pacing/mock_paced_packet_sender.cc",
"net/pacing/mock_paced_packet_sender.h",
"net/pacing/paced_sender_unittest.cc",
- "net/rtcp/mock_rtcp_receiver_feedback.cc",
- "net/rtcp/mock_rtcp_receiver_feedback.h",
- "net/rtcp/rtcp_receiver_unittest.cc",
"net/rtcp/rtcp_sender_unittest.cc",
"net/rtcp/rtcp_unittest.cc",
+ "net/rtcp/rtcp_utility_unittest.cc",
"net/rtcp/receiver_rtcp_event_subscriber_unittest.cc",
# TODO(miu): The following two are test utility modules. Rename/move the files.
"net/rtcp/test_rtcp_packet_builder.cc",
diff --git a/media/cast/cast.gyp b/media/cast/cast.gyp
index 303748a..2f83f75 100644
--- a/media/cast/cast.gyp
+++ b/media/cast/cast.gyp
@@ -192,8 +192,6 @@
'net/rtcp/rtcp_defines.h',
'net/rtcp/rtcp.h',
'net/rtcp/rtcp.cc',
- 'net/rtcp/rtcp_receiver.cc',
- 'net/rtcp/rtcp_receiver.h',
'net/rtcp/rtcp_sender.cc',
'net/rtcp/rtcp_sender.h',
'net/rtcp/rtcp_utility.cc',
diff --git a/media/cast/cast_sender_impl.cc b/media/cast/cast_sender_impl.cc
index c684858..9a4ef31 100644
--- a/media/cast/cast_sender_impl.cc
+++ b/media/cast/cast_sender_impl.cc
@@ -9,7 +9,6 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "media/base/video_frame.h"
-#include "media/cast/net/rtcp/rtcp_receiver.h"
namespace media {
namespace cast {
diff --git a/media/cast/cast_testing.gypi b/media/cast/cast_testing.gypi
index 21585c8..ef12af7 100644
--- a/media/cast/cast_testing.gypi
+++ b/media/cast/cast_testing.gypi
@@ -86,11 +86,9 @@
'net/pacing/mock_paced_packet_sender.cc',
'net/pacing/mock_paced_packet_sender.h',
'net/pacing/paced_sender_unittest.cc',
- 'net/rtcp/mock_rtcp_receiver_feedback.cc',
- 'net/rtcp/mock_rtcp_receiver_feedback.h',
- 'net/rtcp/rtcp_receiver_unittest.cc',
'net/rtcp/rtcp_sender_unittest.cc',
'net/rtcp/rtcp_unittest.cc',
+ 'net/rtcp/rtcp_utility_unittest.cc',
'net/rtcp/receiver_rtcp_event_subscriber_unittest.cc',
# TODO(miu): The following two are test utility modules. Rename/move the files.
'net/rtcp/test_rtcp_packet_builder.cc',
diff --git a/media/cast/net/rtcp/mock_rtcp_receiver_feedback.cc b/media/cast/net/rtcp/mock_rtcp_receiver_feedback.cc
deleted file mode 100644
index d9818ff..0000000
--- a/media/cast/net/rtcp/mock_rtcp_receiver_feedback.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2014 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/net/rtcp/mock_rtcp_receiver_feedback.h"
-
-namespace media {
-namespace cast {
-
-MockRtcpReceiverFeedback::MockRtcpReceiverFeedback() {}
-
-MockRtcpReceiverFeedback::~MockRtcpReceiverFeedback() {}
-
-} // namespace cast
-} // namespace media
diff --git a/media/cast/net/rtcp/mock_rtcp_receiver_feedback.h b/media/cast/net/rtcp/mock_rtcp_receiver_feedback.h
deleted file mode 100644
index ae6b96e..0000000
--- a/media/cast/net/rtcp/mock_rtcp_receiver_feedback.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2014 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.
-
-#ifndef MEDIA_CAST_RTCP_MOCK_RTCP_RECEIVER_FEEDBACK_H_
-#define MEDIA_CAST_RTCP_MOCK_RTCP_RECEIVER_FEEDBACK_H_
-
-#include <vector>
-
-#include "media/cast/net/cast_transport_defines.h"
-#include "media/cast/net/rtcp/rtcp_defines.h"
-#include "media/cast/net/rtcp/rtcp_receiver.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace media {
-namespace cast {
-
-// TODO(hclam): Should be renamed to MockRtcpMessageHandler.
-class MockRtcpReceiverFeedback : public RtcpMessageHandler {
- public:
- MockRtcpReceiverFeedback();
- virtual ~MockRtcpReceiverFeedback();
-
- MOCK_METHOD1(OnReceivedSenderReport,
- void(const RtcpSenderInfo& remote_sender_info));
-
- MOCK_METHOD1(OnReceiverReferenceTimeReport,
- void(const RtcpReceiverReferenceTimeReport& remote_time_report));
-
- MOCK_METHOD0(OnReceivedSendReportRequest, void());
-
- MOCK_METHOD1(OnReceivedReceiverLog,
- void(const RtcpReceiverLogMessage& receiver_log));
-
- MOCK_METHOD2(OnReceivedDelaySinceLastReport,
- void(uint32 last_report, uint32 delay_since_last_report));
-
- MOCK_METHOD1(OnReceivedCastFeedback,
- void(const RtcpCastMessage& cast_message));
-};
-
-} // namespace cast
-} // namespace media
-
-#endif // MEDIA_CAST_RTCP_MOCK_RTCP_RECEIVER_FEEDBACK_H_
diff --git a/media/cast/net/rtcp/mock_rtcp_sender_feedback.cc b/media/cast/net/rtcp/mock_rtcp_sender_feedback.cc
deleted file mode 100644
index 2c51c74..0000000
--- a/media/cast/net/rtcp/mock_rtcp_sender_feedback.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2014 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/net/rtcp/mock_rtcp_sender_feedback.h"
-
-namespace media {
-namespace cast {
-
-MockRtcpSenderFeedback::MockRtcpSenderFeedback() {}
-
-MockRtcpSenderFeedback::~MockRtcpSenderFeedback() {}
-
-} // namespace cast
-} // namespace media
diff --git a/media/cast/net/rtcp/mock_rtcp_sender_feedback.h b/media/cast/net/rtcp/mock_rtcp_sender_feedback.h
deleted file mode 100644
index a6af0aa..0000000
--- a/media/cast/net/rtcp/mock_rtcp_sender_feedback.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 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.
-
-#ifndef MEDIA_CAST_RTCP_MOCK_RTCP_SENDER_FEEDBACK_H_
-#define MEDIA_CAST_RTCP_MOCK_RTCP_SENDER_FEEDBACK_H_
-
-#include <vector>
-
-#include "media/cast/net/rtcp/rtcp_receiver.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace media {
-namespace cast {
-
-class MockRtcpSenderFeedback : public RtcpSenderFeedback {
- public:
- MockRtcpSenderFeedback();
- virtual ~MockRtcpSenderFeedback();
-
- MOCK_METHOD1(OnReceivedCastFeedback,
- void(const RtcpCastMessage& cast_feedback));
-};
-
-} // namespace cast
-} // namespace media
-
-#endif // MEDIA_CAST_RTCP_MOCK_RTCP_SENDER_FEEDBACK_H_
diff --git a/media/cast/net/rtcp/rtcp.cc b/media/cast/net/rtcp/rtcp.cc
index ac413d3..c78e63b 100644
--- a/media/cast/net/rtcp/rtcp.cc
+++ b/media/cast/net/rtcp/rtcp.cc
@@ -9,7 +9,6 @@
#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_defines.h"
#include "media/cast/net/rtcp/rtcp_defines.h"
-#include "media/cast/net/rtcp/rtcp_receiver.h"
#include "media/cast/net/rtcp/rtcp_sender.h"
#include "media/cast/net/rtcp/rtcp_utility.h"
@@ -20,47 +19,35 @@ namespace cast {
static const int32 kMaxRttMs = 10000; // 10 seconds.
-class Rtcp::RtcpMessageHandlerImpl : public RtcpMessageHandler {
- public:
- explicit RtcpMessageHandlerImpl(Rtcp* rtcp)
- : rtcp_(rtcp) {}
-
- virtual void OnReceivedSenderReport(
- const RtcpSenderInfo& remote_sender_info) OVERRIDE {
- rtcp_->OnReceivedNtp(remote_sender_info.ntp_seconds,
- remote_sender_info.ntp_fraction);
- if (remote_sender_info.send_packet_count != 0) {
- rtcp_->OnReceivedLipSyncInfo(remote_sender_info.rtp_timestamp,
- remote_sender_info.ntp_seconds,
- remote_sender_info.ntp_fraction);
- }
- }
-
- virtual void OnReceiverReferenceTimeReport(
- const RtcpReceiverReferenceTimeReport& remote_time_report) OVERRIDE {
- rtcp_->OnReceivedNtp(remote_time_report.ntp_seconds,
- remote_time_report.ntp_fraction);
- }
-
- virtual void OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log)
- OVERRIDE {
- rtcp_->OnReceivedReceiverLog(receiver_log);
- }
-
- virtual void OnReceivedDelaySinceLastReport(
- uint32 last_report,
- uint32 delay_since_last_report) OVERRIDE {
- rtcp_->OnReceivedDelaySinceLastReport(last_report, delay_since_last_report);
- }
+namespace {
+
+// A receiver frame event is identified by frame RTP timestamp, event timestamp
+// and event type.
+// A receiver packet event is identified by all of the above plus packet id.
+// The key format is as follows:
+// First uint64:
+// bits 0-11: zeroes (unused).
+// bits 12-15: event type ID.
+// bits 16-31: packet ID if packet event, 0 otherwise.
+// bits 32-63: RTP timestamp.
+// Second uint64:
+// bits 0-63: event TimeTicks internal value.
+std::pair<uint64, uint64> GetReceiverEventKey(
+ uint32 frame_rtp_timestamp,
+ const base::TimeTicks& event_timestamp,
+ uint8 event_type,
+ uint16 packet_id_or_zero) {
+ uint64 value1 = event_type;
+ value1 <<= 16;
+ value1 |= packet_id_or_zero;
+ value1 <<= 32;
+ value1 |= frame_rtp_timestamp;
+ return std::make_pair(
+ value1, static_cast<uint64>(event_timestamp.ToInternalValue()));
+}
- virtual void OnReceivedCastFeedback(
- const RtcpCastMessage& cast_message) OVERRIDE {
- rtcp_->OnReceivedCastFeedback(cast_message);
- }
+} // namespace
- private:
- Rtcp* rtcp_;
-};
Rtcp::Rtcp(const RtcpCastMessageCallback& cast_callback,
const RtcpRttCallback& rtt_callback,
@@ -76,48 +63,117 @@ Rtcp::Rtcp(const RtcpCastMessageCallback& cast_callback,
rtcp_sender_(new RtcpSender(packet_sender, local_ssrc)),
local_ssrc_(local_ssrc),
remote_ssrc_(remote_ssrc),
- handler_(new RtcpMessageHandlerImpl(this)),
- rtcp_receiver_(new RtcpReceiver(handler_.get(), local_ssrc)),
last_report_truncated_ntp_(0),
local_clock_ahead_by_(ClockDriftSmoother::GetDefaultTimeConstant()),
lip_sync_rtp_timestamp_(0),
lip_sync_ntp_timestamp_(0),
min_rtt_(TimeDelta::FromMilliseconds(kMaxRttMs)),
number_of_rtt_in_avg_(0) {
- rtcp_receiver_->SetRemoteSSRC(remote_ssrc);
-
- // This value is the same in FrameReceiver.
- rtcp_receiver_->SetCastReceiverEventHistorySize(
- kReceiverRtcpEventHistorySize);
}
Rtcp::~Rtcp() {}
+bool Rtcp::IsRtcpPacket(const uint8* packet, size_t length) {
+ if (length < kMinLengthOfRtcp) {
+ LOG(ERROR) << "Invalid RTCP packet received.";
+ return false;
+ }
+
+ uint8 packet_type = packet[1];
+ return packet_type >= kPacketTypeLow && packet_type <= kPacketTypeHigh;
+}
+
+uint32 Rtcp::GetSsrcOfSender(const uint8* rtcp_buffer, size_t length) {
+ if (length < kMinLengthOfRtcp)
+ return 0;
+ uint32 ssrc_of_sender;
+ base::BigEndianReader big_endian_reader(
+ reinterpret_cast<const char*>(rtcp_buffer), length);
+ big_endian_reader.Skip(4); // Skip header.
+ big_endian_reader.ReadU32(&ssrc_of_sender);
+ return ssrc_of_sender;
+}
+
bool Rtcp::IncomingRtcpPacket(const uint8* data, size_t length) {
// Check if this is a valid RTCP packet.
- if (!RtcpReceiver::IsRtcpPacket(data, length)) {
+ if (!IsRtcpPacket(data, length)) {
VLOG(1) << "Rtcp@" << this << "::IncomingRtcpPacket() -- "
<< "Received an invalid (non-RTCP?) packet.";
return false;
}
// Check if this packet is to us.
- uint32 ssrc_of_sender = RtcpReceiver::GetSsrcOfSender(data, length);
+ uint32 ssrc_of_sender = GetSsrcOfSender(data, length);
if (ssrc_of_sender != remote_ssrc_) {
return false;
}
// Parse this packet.
- RtcpParser rtcp_parser(data, length);
- if (!rtcp_parser.IsValid()) {
- // Silently ignore packet.
- VLOG(1) << "Received invalid RTCP packet";
- return false;
+ RtcpParser parser(local_ssrc_, remote_ssrc_);
+ base::BigEndianReader reader(reinterpret_cast<const char*>(data), length);
+ if (parser.Parse(&reader)) {
+ if (parser.has_sender_report()) {
+ OnReceivedNtp(parser.sender_report().ntp_seconds,
+ parser.sender_report().ntp_fraction);
+ OnReceivedLipSyncInfo(parser.sender_report().rtp_timestamp,
+ parser.sender_report().ntp_seconds,
+ parser.sender_report().ntp_fraction);
+ }
+ if (parser.has_receiver_reference_time_report()) {
+ OnReceivedNtp(parser.receiver_reference_time_report().ntp_seconds,
+ parser.receiver_reference_time_report().ntp_fraction);
+ }
+ if (parser.has_receiver_log()) {
+ if (DedupeReceiverLog(parser.mutable_receiver_log())) {
+ OnReceivedReceiverLog(parser.receiver_log());
+ }
+ }
+ if (parser.has_last_report()) {
+ OnReceivedDelaySinceLastReport(parser.last_report(),
+ parser.delay_since_last_report());
+ }
+ if (parser.has_cast_message()) {
+ parser.mutable_cast_message()->ack_frame_id =
+ ack_frame_id_wrap_helper_.MapTo32bitsFrameId(
+ parser.mutable_cast_message()->ack_frame_id);
+ OnReceivedCastFeedback(parser.cast_message());
+ }
}
- rtcp_receiver_->IncomingRtcpPacket(&rtcp_parser);
return true;
}
+bool Rtcp::DedupeReceiverLog(RtcpReceiverLogMessage* receiver_log) {
+ RtcpReceiverLogMessage::iterator i = receiver_log->begin();
+ while (i != receiver_log->end()) {
+ RtcpReceiverEventLogMessages* messages = &i->event_log_messages_;
+ RtcpReceiverEventLogMessages::iterator j = messages->begin();
+ while (j != messages->end()) {
+ ReceiverEventKey key = GetReceiverEventKey(i->rtp_timestamp_,
+ j->event_timestamp,
+ j->type,
+ j->packet_id);
+ RtcpReceiverEventLogMessages::iterator tmp = j;
+ ++j;
+ if (receiver_event_key_set_.insert(key).second) {
+ receiver_event_key_queue_.push(key);
+ if (receiver_event_key_queue_.size() > kReceiverRtcpEventHistorySize) {
+ receiver_event_key_set_.erase(receiver_event_key_queue_.front());
+ receiver_event_key_queue_.pop();
+ }
+ } else {
+ messages->erase(tmp);
+ }
+ }
+
+ RtcpReceiverLogMessage::iterator tmp = i;
+ ++i;
+ if (messages->empty()) {
+ receiver_log->erase(tmp);
+ }
+ }
+ return !receiver_log->empty();
+}
+
void Rtcp::SendRtcpFromRtpReceiver(
const RtcpCastMessage* cast_message,
base::TimeDelta target_delay,
diff --git a/media/cast/net/rtcp/rtcp.h b/media/cast/net/rtcp/rtcp.h
index 4e6fb12..10750c9 100644
--- a/media/cast/net/rtcp/rtcp.h
+++ b/media/cast/net/rtcp/rtcp.h
@@ -107,6 +107,8 @@ class Rtcp {
void OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log);
+ static bool IsRtcpPacket(const uint8* packet, size_t length);
+ static uint32 GetSsrcOfSender(const uint8* rtcp_buffer, size_t length);
const base::TimeDelta& rtt() const { return rtt_; }
protected:
@@ -116,8 +118,6 @@ class Rtcp {
uint32 ntp_fraction);
private:
- class RtcpMessageHandlerImpl;
-
void OnReceivedDelaySinceLastReport(uint32 last_report,
uint32 delay_since_last_report);
@@ -130,6 +130,10 @@ class Rtcp {
uint32 last_ntp_seconds,
uint32 last_ntp_fraction);
+ // Remove duplicate events in |receiver_log|.
+ // Returns true if any events remain.
+ bool DedupeReceiverLog(RtcpReceiverLogMessage* receiver_log);
+
const RtcpCastMessageCallback cast_callback_;
const RtcpRttCallback rtt_callback_;
const RtcpLogMessageCallback log_callback_;
@@ -137,8 +141,6 @@ class Rtcp {
const scoped_ptr<RtcpSender> rtcp_sender_;
const uint32 local_ssrc_;
const uint32 remote_ssrc_;
- const scoped_ptr<RtcpMessageHandlerImpl> handler_;
- const scoped_ptr<RtcpReceiver> rtcp_receiver_;
RtcpSendTimeMap last_reports_sent_map_;
RtcpSendTimeQueue last_reports_sent_queue_;
@@ -169,6 +171,14 @@ class Rtcp {
int number_of_rtt_in_avg_;
base::TimeDelta avg_rtt_;
+ // For extending received ACK frame IDs from 8-bit to 32-bit.
+ FrameIdWrapHelper ack_frame_id_wrap_helper_;
+
+ // Maintains a history of receiver events.
+ typedef std::pair<uint64, uint64> ReceiverEventKey;
+ base::hash_set<ReceiverEventKey> receiver_event_key_set_;
+ std::queue<ReceiverEventKey> receiver_event_key_queue_;
+
DISALLOW_COPY_AND_ASSIGN(Rtcp);
};
diff --git a/media/cast/net/rtcp/rtcp_receiver.cc b/media/cast/net/rtcp/rtcp_receiver.cc
deleted file mode 100644
index 4ba9986..0000000
--- a/media/cast/net/rtcp/rtcp_receiver.cc
+++ /dev/null
@@ -1,414 +0,0 @@
-// Copyright 2014 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/net/rtcp/rtcp_receiver.h"
-
-#include "base/big_endian.h"
-#include "base/logging.h"
-#include "media/cast/net/cast_transport_defines.h"
-#include "media/cast/net/rtcp/rtcp_utility.h"
-
-namespace {
-
-// A receiver frame event is identified by frame RTP timestamp, event timestamp
-// and event type.
-// A receiver packet event is identified by all of the above plus packet id.
-// The key format is as follows:
-// First uint64:
-// bits 0-11: zeroes (unused).
-// bits 12-15: event type ID.
-// bits 16-31: packet ID if packet event, 0 otherwise.
-// bits 32-63: RTP timestamp.
-// Second uint64:
-// bits 0-63: event TimeTicks internal value.
-std::pair<uint64, uint64> GetReceiverEventKey(
- uint32 frame_rtp_timestamp, const base::TimeTicks& event_timestamp,
- uint8 event_type, uint16 packet_id_or_zero) {
- uint64 value1 = event_type;
- value1 <<= 16;
- value1 |= packet_id_or_zero;
- value1 <<= 32;
- value1 |= frame_rtp_timestamp;
- return std::make_pair(
- value1, static_cast<uint64>(event_timestamp.ToInternalValue()));
-}
-
-} // namespace
-
-namespace media {
-namespace cast {
-
-RtcpReceiver::RtcpReceiver(RtcpMessageHandler* handler,
- uint32 local_ssrc)
- : ssrc_(local_ssrc),
- remote_ssrc_(0),
- handler_(handler),
- receiver_event_history_size_(0) {
- DCHECK(handler_);
-}
-
-RtcpReceiver::~RtcpReceiver() {}
-
-// static
-bool RtcpReceiver::IsRtcpPacket(const uint8* packet, size_t length) {
- if (length < kMinLengthOfRtcp) {
- LOG(ERROR) << "Invalid RTCP packet received.";
- return false;
- }
-
- uint8 packet_type = packet[1];
- if (packet_type >= kPacketTypeLow &&
- packet_type <= kPacketTypeHigh) {
- return true;
- }
- return false;
-}
-
-// static
-uint32 RtcpReceiver::GetSsrcOfSender(const uint8* rtcp_buffer, size_t length) {
- if (length < kMinLengthOfRtcp)
- return 0;
- uint32 ssrc_of_sender;
- base::BigEndianReader big_endian_reader(
- reinterpret_cast<const char*>(rtcp_buffer), length);
- big_endian_reader.Skip(4); // Skip header
- big_endian_reader.ReadU32(&ssrc_of_sender);
- return ssrc_of_sender;
-}
-
-void RtcpReceiver::SetRemoteSSRC(uint32 ssrc) { remote_ssrc_ = ssrc; }
-
-void RtcpReceiver::SetCastReceiverEventHistorySize(size_t size) {
- receiver_event_history_size_ = size;
-}
-
-void RtcpReceiver::IncomingRtcpPacket(RtcpParser* rtcp_parser) {
- RtcpFieldTypes field_type = rtcp_parser->Begin();
- while (field_type != kRtcpNotValidCode) {
- // Each "case" is responsible for iterate the parser to the next top
- // level packet.
- switch (field_type) {
- case kRtcpSrCode:
- HandleSenderReport(rtcp_parser);
- break;
- case kRtcpRrCode:
- HandleReceiverReport(rtcp_parser);
- break;
- case kRtcpXrCode:
- HandleXr(rtcp_parser);
- break;
- case kRtcpPayloadSpecificAppCode:
- HandlePayloadSpecificApp(rtcp_parser);
- break;
- case kRtcpApplicationSpecificCastReceiverLogCode:
- HandleApplicationSpecificCastReceiverLog(rtcp_parser);
- break;
- case kRtcpPayloadSpecificCastCode:
- case kRtcpPayloadSpecificCastNackItemCode:
- case kRtcpApplicationSpecificCastReceiverLogFrameCode:
- case kRtcpApplicationSpecificCastReceiverLogEventCode:
- case kRtcpNotValidCode:
- case kRtcpReportBlockItemCode:
- case kRtcpXrRrtrCode:
- case kRtcpXrDlrrCode:
- case kRtcpXrUnknownItemCode:
- rtcp_parser->Iterate();
- NOTREACHED() << "Invalid state";
- break;
- }
- field_type = rtcp_parser->FieldType();
- }
-}
-
-void RtcpReceiver::HandleSenderReport(RtcpParser* rtcp_parser) {
- RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType();
- const RtcpField& rtcp_field = rtcp_parser->Field();
-
- DCHECK(rtcp_field_type == kRtcpSrCode) << "Invalid state";
-
- // Synchronization source identifier for the originator of this SR packet.
- uint32 remote_ssrc = rtcp_field.sender_report.sender_ssrc;
-
- VLOG(2) << "Cast RTCP received SR from SSRC " << remote_ssrc;
-
- if (remote_ssrc_ == remote_ssrc) {
- RtcpSenderInfo remote_sender_info;
- remote_sender_info.ntp_seconds =
- rtcp_field.sender_report.ntp_most_significant;
- remote_sender_info.ntp_fraction =
- rtcp_field.sender_report.ntp_least_significant;
- remote_sender_info.rtp_timestamp = rtcp_field.sender_report.rtp_timestamp;
- remote_sender_info.send_packet_count =
- rtcp_field.sender_report.sender_packet_count;
- remote_sender_info.send_octet_count =
- rtcp_field.sender_report.sender_octet_count;
- handler_->OnReceivedSenderReport(remote_sender_info);
- }
- rtcp_field_type = rtcp_parser->Iterate();
- while (rtcp_field_type == kRtcpReportBlockItemCode) {
- HandleReportBlock(&rtcp_field, remote_ssrc);
- rtcp_field_type = rtcp_parser->Iterate();
- }
-}
-
-void RtcpReceiver::HandleReceiverReport(RtcpParser* rtcp_parser) {
- RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType();
- const RtcpField& rtcp_field = rtcp_parser->Field();
-
- DCHECK(rtcp_field_type == kRtcpRrCode) << "Invalid state";
-
- uint32 remote_ssrc = rtcp_field.receiver_report.sender_ssrc;
-
- VLOG(2) << "Cast RTCP received RR from SSRC " << remote_ssrc;
-
- rtcp_field_type = rtcp_parser->Iterate();
- while (rtcp_field_type == kRtcpReportBlockItemCode) {
- HandleReportBlock(&rtcp_field, remote_ssrc);
- rtcp_field_type = rtcp_parser->Iterate();
- }
-}
-
-void RtcpReceiver::HandleReportBlock(const RtcpField* rtcp_field,
- uint32 remote_ssrc) {
- // This will be called once per report block in the Rtcp packet.
- // We filter out all report blocks that are not for us.
- // Each packet has max 31 RR blocks.
- //
- // We can calculate RTT if we send a send report and get a report block back.
-
- // |rtcp_field.ReportBlockItem.ssrc| is the ssrc identifier of the source to
- // which the information in this reception report block pertains.
-
- const RtcpFieldReportBlockItem& rb = rtcp_field->report_block_item;
-
- // Filter out all report blocks that are not for us.
- if (rb.ssrc != ssrc_) {
- // This block is not for us ignore it.
- return;
- }
- VLOG(2) << "Cast RTCP received RB from SSRC " << remote_ssrc;
-
- RtcpReportBlock report_block;
- report_block.remote_ssrc = remote_ssrc;
- report_block.media_ssrc = rb.ssrc;
- report_block.fraction_lost = rb.fraction_lost;
- report_block.cumulative_lost = rb.cumulative_number_of_packets_lost;
- report_block.extended_high_sequence_number =
- rb.extended_highest_sequence_number;
- report_block.jitter = rb.jitter;
- report_block.last_sr = rb.last_sender_report;
- report_block.delay_since_last_sr = rb.delay_last_sender_report;
- handler_->OnReceivedDelaySinceLastReport(
- rb.last_sender_report, rb.delay_last_sender_report);
-}
-
-void RtcpReceiver::HandleXr(RtcpParser* rtcp_parser) {
- RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType();
- const RtcpField& rtcp_field = rtcp_parser->Field();
-
- DCHECK(rtcp_field_type == kRtcpXrCode) << "Invalid state";
-
- uint32 remote_ssrc = rtcp_field.extended_report.sender_ssrc;
- rtcp_field_type = rtcp_parser->Iterate();
-
- while (rtcp_field_type == kRtcpXrDlrrCode ||
- rtcp_field_type == kRtcpXrRrtrCode ||
- rtcp_field_type == kRtcpXrUnknownItemCode) {
- if (rtcp_field_type == kRtcpXrRrtrCode) {
- HandleRrtr(rtcp_parser, remote_ssrc);
- } else if (rtcp_field_type == kRtcpXrDlrrCode) {
- HandleDlrr(rtcp_parser);
- }
- rtcp_field_type = rtcp_parser->Iterate();
- }
-}
-
-void RtcpReceiver::HandleRrtr(RtcpParser* rtcp_parser, uint32 remote_ssrc) {
- if (remote_ssrc_ != remote_ssrc) {
- // Not to us.
- return;
- }
- const RtcpField& rtcp_field = rtcp_parser->Field();
- RtcpReceiverReferenceTimeReport remote_time_report;
- remote_time_report.remote_ssrc = remote_ssrc;
- remote_time_report.ntp_seconds = rtcp_field.rrtr.ntp_most_significant;
- remote_time_report.ntp_fraction = rtcp_field.rrtr.ntp_least_significant;
- handler_->OnReceiverReferenceTimeReport(remote_time_report);
-}
-
-void RtcpReceiver::HandleDlrr(RtcpParser* rtcp_parser) {
- const RtcpField& rtcp_field = rtcp_parser->Field();
- if (remote_ssrc_ != rtcp_field.dlrr.receivers_ssrc) {
- // Not to us.
- return;
- }
- handler_->OnReceivedDelaySinceLastReport(
- rtcp_field.dlrr.last_receiver_report,
- rtcp_field.dlrr.delay_last_receiver_report);
-}
-
-void RtcpReceiver::HandlePayloadSpecificApp(RtcpParser* rtcp_parser) {
- const RtcpField& rtcp_field = rtcp_parser->Field();
- uint32 remote_ssrc = rtcp_field.application_specific.sender_ssrc;
- if (remote_ssrc_ != remote_ssrc) {
- // Message not to us. Iterate until we have passed this message.
- RtcpFieldTypes field_type;
- do {
- field_type = rtcp_parser->Iterate();
- } while (field_type == kRtcpPayloadSpecificCastCode ||
- field_type == kRtcpPayloadSpecificCastNackItemCode);
- return;
- }
-
- RtcpFieldTypes packet_type = rtcp_parser->Iterate();
- switch (packet_type) {
- case kRtcpPayloadSpecificCastCode:
- packet_type = rtcp_parser->Iterate();
- if (packet_type == kRtcpPayloadSpecificCastCode) {
- HandlePayloadSpecificCastItem(rtcp_parser);
- }
- break;
- default:
- return;
- }
-}
-
-void RtcpReceiver::HandleApplicationSpecificCastReceiverLog(
- RtcpParser* rtcp_parser) {
- const RtcpField& rtcp_field = rtcp_parser->Field();
-
- uint32 remote_ssrc = rtcp_field.cast_receiver_log.sender_ssrc;
- if (remote_ssrc_ != remote_ssrc) {
- // Message not to us. Iterate until we have passed this message.
- RtcpFieldTypes field_type;
- do {
- field_type = rtcp_parser->Iterate();
- } while (field_type == kRtcpApplicationSpecificCastReceiverLogFrameCode ||
- field_type == kRtcpApplicationSpecificCastReceiverLogEventCode);
- return;
- }
- RtcpReceiverLogMessage receiver_log;
- RtcpFieldTypes field_type = rtcp_parser->Iterate();
- while (field_type == kRtcpApplicationSpecificCastReceiverLogFrameCode) {
- RtcpReceiverFrameLogMessage frame_log(
- rtcp_field.cast_receiver_log.rtp_timestamp);
-
- field_type = rtcp_parser->Iterate();
- while (field_type == kRtcpApplicationSpecificCastReceiverLogEventCode) {
- HandleApplicationSpecificCastReceiverEventLog(
- rtcp_field.cast_receiver_log.rtp_timestamp,
- rtcp_parser,
- &frame_log.event_log_messages_);
- field_type = rtcp_parser->Iterate();
- }
-
- if (!frame_log.event_log_messages_.empty())
- receiver_log.push_back(frame_log);
- }
-
- if (!receiver_log.empty())
- handler_->OnReceivedReceiverLog(receiver_log);
-}
-
-void RtcpReceiver::HandleApplicationSpecificCastReceiverEventLog(
- uint32 frame_rtp_timestamp,
- RtcpParser* rtcp_parser,
- RtcpReceiverEventLogMessages* event_log_messages) {
- const RtcpField& rtcp_field = rtcp_parser->Field();
-
- const uint8 event = rtcp_field.cast_receiver_log.event;
- const CastLoggingEvent event_type = TranslateToLogEventFromWireFormat(event);
- uint16 packet_id = event_type == PACKET_RECEIVED ?
- rtcp_field.cast_receiver_log.delay_delta_or_packet_id.packet_id : 0;
- const base::TimeTicks event_timestamp =
- base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(
- rtcp_field.cast_receiver_log.event_timestamp_base +
- rtcp_field.cast_receiver_log.event_timestamp_delta);
-
- // The following code checks to see if we have already seen this event.
- // The algorithm works by maintaining a sliding window of events. We have
- // a queue and a set of events. We enqueue every new event and insert it
- // into the set. When the queue becomes too big we remove the oldest event
- // from both the queue and the set.
- ReceiverEventKey key =
- GetReceiverEventKey(
- frame_rtp_timestamp, event_timestamp, event, packet_id);
- if (receiver_event_key_set_.find(key) != receiver_event_key_set_.end()) {
- return;
- } else {
- receiver_event_key_set_.insert(key);
- receiver_event_key_queue_.push(key);
-
- if (receiver_event_key_queue_.size() > receiver_event_history_size_) {
- const ReceiverEventKey oldest_key = receiver_event_key_queue_.front();
- receiver_event_key_queue_.pop();
- receiver_event_key_set_.erase(oldest_key);
- }
- }
-
- RtcpReceiverEventLogMessage event_log;
- event_log.type = event_type;
- event_log.event_timestamp = event_timestamp;
- event_log.delay_delta = base::TimeDelta::FromMilliseconds(
- rtcp_field.cast_receiver_log.delay_delta_or_packet_id.delay_delta);
- event_log.packet_id =
- rtcp_field.cast_receiver_log.delay_delta_or_packet_id.packet_id;
- event_log_messages->push_back(event_log);
-}
-
-void RtcpReceiver::HandlePayloadSpecificCastItem(RtcpParser* rtcp_parser) {
- const RtcpField& rtcp_field = rtcp_parser->Field();
- RtcpCastMessage cast_message(remote_ssrc_);
- cast_message.ack_frame_id = ack_frame_id_wrap_helper_.MapTo32bitsFrameId(
- rtcp_field.cast_item.last_frame_id);
- cast_message.target_delay_ms = rtcp_field.cast_item.target_delay_ms;
-
- RtcpFieldTypes packet_type = rtcp_parser->Iterate();
- while (packet_type == kRtcpPayloadSpecificCastNackItemCode) {
- const RtcpField& rtcp_field = rtcp_parser->Field();
- HandlePayloadSpecificCastNackItem(
- &rtcp_field, &cast_message.missing_frames_and_packets);
- packet_type = rtcp_parser->Iterate();
- }
- handler_->OnReceivedCastFeedback(cast_message);
-}
-
-void RtcpReceiver::HandlePayloadSpecificCastNackItem(
- const RtcpField* rtcp_field,
- MissingFramesAndPacketsMap* missing_frames_and_packets) {
-
- MissingFramesAndPacketsMap::iterator frame_it =
- missing_frames_and_packets->find(rtcp_field->cast_nack_item.frame_id);
-
- if (frame_it == missing_frames_and_packets->end()) {
- // First missing packet in a frame.
- PacketIdSet empty_set;
- std::pair<MissingFramesAndPacketsMap::iterator, bool> ret =
- missing_frames_and_packets->insert(std::pair<uint8, PacketIdSet>(
- rtcp_field->cast_nack_item.frame_id, empty_set));
- frame_it = ret.first;
- DCHECK(frame_it != missing_frames_and_packets->end()) << "Invalid state";
- }
- uint16 packet_id = rtcp_field->cast_nack_item.packet_id;
- frame_it->second.insert(packet_id);
-
- if (packet_id == kRtcpCastAllPacketsLost) {
- // Special case all packets in a frame is missing.
- return;
- }
- uint8 bitmask = rtcp_field->cast_nack_item.bitmask;
-
- if (bitmask) {
- for (int i = 1; i <= 8; ++i) {
- if (bitmask & 1) {
- frame_it->second.insert(packet_id + i);
- }
- bitmask = bitmask >> 1;
- }
- }
-}
-
-} // namespace cast
-} // namespace media
diff --git a/media/cast/net/rtcp/rtcp_receiver.h b/media/cast/net/rtcp/rtcp_receiver.h
deleted file mode 100644
index e7d432e..0000000
--- a/media/cast/net/rtcp/rtcp_receiver.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2014 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.
-
-#ifndef MEDIA_CAST_RTCP_RTCP_RECEIVER_H_
-#define MEDIA_CAST_RTCP_RTCP_RECEIVER_H_
-
-#include <queue>
-
-#include "base/containers/hash_tables.h"
-#include "media/cast/net/cast_transport_defines.h"
-#include "media/cast/net/rtcp/rtcp.h"
-#include "media/cast/net/rtcp/rtcp_defines.h"
-#include "media/cast/net/rtcp/rtcp_utility.h"
-
-namespace media {
-namespace cast {
-
-// Interface for receiving RTCP messages.
-class RtcpMessageHandler {
- public:
- virtual void OnReceivedSenderReport(
- const RtcpSenderInfo& remote_sender_info) = 0;
-
- virtual void OnReceiverReferenceTimeReport(
- const RtcpReceiverReferenceTimeReport& remote_time_report) = 0;
-
- virtual void OnReceivedReceiverLog(
- const RtcpReceiverLogMessage& receiver_log) = 0;
-
- virtual void OnReceivedDelaySinceLastReport(
- uint32 last_report,
- uint32 delay_since_last_report) = 0;
-
- virtual void OnReceivedCastFeedback(
- const RtcpCastMessage& cast_message) = 0;
-
- virtual ~RtcpMessageHandler() {}
-};
-
-class RtcpReceiver {
- public:
- RtcpReceiver(RtcpMessageHandler* handler, uint32 local_ssrc);
- virtual ~RtcpReceiver();
-
- static bool IsRtcpPacket(const uint8* rtcp_buffer, size_t length);
-
- static uint32 GetSsrcOfSender(const uint8* rtcp_buffer, size_t length);
-
- void SetRemoteSSRC(uint32 ssrc);
-
- // Set the history size to record Cast receiver events. Event history is
- // used to remove duplicates. The history has no more than |size| events.
- void SetCastReceiverEventHistorySize(size_t size);
-
- void IncomingRtcpPacket(RtcpParser* rtcp_parser);
-
- private:
- void HandleSenderReport(RtcpParser* rtcp_parser);
-
- void HandleReceiverReport(RtcpParser* rtcp_parser);
-
- void HandleReportBlock(const RtcpField* rtcp_field, uint32 remote_ssrc);
-
- void HandleXr(RtcpParser* rtcp_parser);
- void HandleRrtr(RtcpParser* rtcp_parser, uint32 remote_ssrc);
- void HandleDlrr(RtcpParser* rtcp_parser);
-
- void HandlePayloadSpecificApp(RtcpParser* rtcp_parser);
- void HandlePayloadSpecificCastItem(RtcpParser* rtcp_parser);
- void HandlePayloadSpecificCastNackItem(
- const RtcpField* rtcp_field,
- MissingFramesAndPacketsMap* missing_frames_and_packets);
-
- void HandleApplicationSpecificCastReceiverLog(RtcpParser* rtcp_parser);
- void HandleApplicationSpecificCastReceiverEventLog(
- uint32 frame_rtp_timestamp,
- RtcpParser* rtcp_parser,
- RtcpReceiverEventLogMessages* event_log_messages);
-
- const uint32 ssrc_;
- uint32 remote_ssrc_;
-
- // Not owned by this class.
- RtcpMessageHandler* const handler_;
-
- FrameIdWrapHelper ack_frame_id_wrap_helper_;
-
- // Maintains a history of receiver events.
- size_t receiver_event_history_size_;
- typedef std::pair<uint64, uint64> ReceiverEventKey;
- base::hash_set<ReceiverEventKey> receiver_event_key_set_;
- std::queue<ReceiverEventKey> receiver_event_key_queue_;
-
- DISALLOW_COPY_AND_ASSIGN(RtcpReceiver);
-};
-
-} // namespace cast
-} // namespace media
-
-#endif // MEDIA_CAST_RTCP_RTCP_RECEIVER_H_
diff --git a/media/cast/net/rtcp/rtcp_receiver_unittest.cc b/media/cast/net/rtcp/rtcp_receiver_unittest.cc
deleted file mode 100644
index a32edbd..0000000
--- a/media/cast/net/rtcp/rtcp_receiver_unittest.cc
+++ /dev/null
@@ -1,493 +0,0 @@
-// Copyright 2014 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 "base/memory/scoped_ptr.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "media/cast/cast_environment.h"
-#include "media/cast/net/cast_transport_defines.h"
-#include "media/cast/net/rtcp/mock_rtcp_receiver_feedback.h"
-#include "media/cast/net/rtcp/rtcp_receiver.h"
-#include "media/cast/net/rtcp/rtcp_utility.h"
-#include "media/cast/net/rtcp/test_rtcp_packet_builder.h"
-#include "media/cast/test/fake_single_thread_task_runner.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace media {
-namespace cast {
-
-using testing::_;
-
-static const uint32 kSenderSsrc = 0x10203;
-static const uint32 kSourceSsrc = 0x40506;
-static const uint32 kUnknownSsrc = 0xDEAD;
-static const base::TimeDelta kTargetDelay =
- base::TimeDelta::FromMilliseconds(100);
-
-namespace {
-
-class RtcpMessageVerification : public MockRtcpReceiverFeedback {
- public:
- RtcpMessageVerification()
- : called_on_received_sender_log_(false),
- called_on_received_receiver_log_(false),
- called_on_received_cast_message_(false) {}
-
- virtual void OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log)
- OVERRIDE {
- EXPECT_EQ(expected_receiver_log_.size(), receiver_log.size());
- RtcpReceiverLogMessage::const_iterator expected_it =
- expected_receiver_log_.begin();
- RtcpReceiverLogMessage::const_iterator incoming_it = receiver_log.begin();
- for (; incoming_it != receiver_log.end(); ++incoming_it) {
- EXPECT_EQ(expected_it->rtp_timestamp_, incoming_it->rtp_timestamp_);
- EXPECT_EQ(expected_it->event_log_messages_.size(),
- incoming_it->event_log_messages_.size());
-
- RtcpReceiverEventLogMessages::const_iterator event_incoming_it =
- incoming_it->event_log_messages_.begin();
- RtcpReceiverEventLogMessages::const_iterator event_expected_it =
- expected_it->event_log_messages_.begin();
- for (; event_incoming_it != incoming_it->event_log_messages_.end();
- ++event_incoming_it, ++event_expected_it) {
- EXPECT_EQ(event_expected_it->type, event_incoming_it->type);
- EXPECT_EQ(event_expected_it->event_timestamp,
- event_incoming_it->event_timestamp);
- if (event_expected_it->type == PACKET_RECEIVED) {
- EXPECT_EQ(event_expected_it->packet_id, event_incoming_it->packet_id);
- } else {
- EXPECT_EQ(event_expected_it->delay_delta,
- event_incoming_it->delay_delta);
- }
- }
- expected_receiver_log_.pop_front();
- expected_it = expected_receiver_log_.begin();
- }
- called_on_received_receiver_log_ = true;
- }
-
- virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_message)
- OVERRIDE {
- EXPECT_EQ(cast_message.media_ssrc, kSenderSsrc);
- EXPECT_EQ(cast_message.ack_frame_id, kAckFrameId);
-
- MissingFramesAndPacketsMap::const_iterator frame_it =
- cast_message.missing_frames_and_packets.begin();
-
- EXPECT_TRUE(frame_it != cast_message.missing_frames_and_packets.end());
- EXPECT_EQ(kLostFrameId, frame_it->first);
- EXPECT_EQ(frame_it->second.size(), 1UL);
- EXPECT_EQ(*frame_it->second.begin(), kRtcpCastAllPacketsLost);
- ++frame_it;
- EXPECT_TRUE(frame_it != cast_message.missing_frames_and_packets.end());
- EXPECT_EQ(kFrameIdWithLostPackets, frame_it->first);
- EXPECT_EQ(3UL, frame_it->second.size());
- PacketIdSet::const_iterator packet_it = frame_it->second.begin();
- EXPECT_EQ(kLostPacketId1, *packet_it);
- ++packet_it;
- EXPECT_EQ(kLostPacketId2, *packet_it);
- ++packet_it;
- EXPECT_EQ(kLostPacketId3, *packet_it);
- ++frame_it;
- EXPECT_TRUE(frame_it == cast_message.missing_frames_and_packets.end());
- called_on_received_cast_message_ = true;
- }
-
- bool OnReceivedReceiverLogCalled() const {
- return called_on_received_receiver_log_ && expected_receiver_log_.empty();
- }
-
- bool OnReceivedCastFeedbackCalled() const {
- return called_on_received_cast_message_;
- }
-
- void SetExpectedReceiverLog(const RtcpReceiverLogMessage& receiver_log) {
- expected_receiver_log_ = receiver_log;
- }
-
- private:
- RtcpReceiverLogMessage expected_receiver_log_;
- bool called_on_received_sender_log_;
- bool called_on_received_receiver_log_;
- bool called_on_received_cast_message_;
-
- DISALLOW_COPY_AND_ASSIGN(RtcpMessageVerification);
-};
-
-} // namespace
-
-class RtcpReceiverTest : public ::testing::Test {
- protected:
- RtcpReceiverTest()
- : testing_clock_(new base::SimpleTestTickClock()),
- task_runner_(new test::FakeSingleThreadTaskRunner(
- testing_clock_.get())),
- rtcp_receiver_(new RtcpReceiver(&mock_receiver_feedback_,
- kSourceSsrc)) {
- EXPECT_CALL(mock_receiver_feedback_, OnReceivedSenderReport(_)).Times(0);
- EXPECT_CALL(mock_receiver_feedback_, OnReceiverReferenceTimeReport(_))
- .Times(0);
- EXPECT_CALL(mock_receiver_feedback_, OnReceivedCastFeedback(_)).Times(0);
- EXPECT_CALL(mock_receiver_feedback_, OnReceivedDelaySinceLastReport(_, _))
- .Times(0);
-
- expected_sender_info_.ntp_seconds = kNtpHigh;
- expected_sender_info_.ntp_fraction = kNtpLow;
- expected_sender_info_.rtp_timestamp = kRtpTimestamp;
- expected_sender_info_.send_packet_count = kSendPacketCount;
- expected_sender_info_.send_octet_count = kSendOctetCount;
-
- expected_report_block_.remote_ssrc = kSenderSsrc;
- expected_report_block_.media_ssrc = kSourceSsrc;
- expected_report_block_.fraction_lost = kLoss >> 24;
- expected_report_block_.cumulative_lost = kLoss & 0xffffff;
- expected_report_block_.extended_high_sequence_number = kExtendedMax;
- expected_report_block_.jitter = kTestJitter;
- expected_report_block_.last_sr = kLastSr;
- expected_report_block_.delay_since_last_sr = kDelayLastSr;
- expected_receiver_reference_report_.remote_ssrc = kSenderSsrc;
- expected_receiver_reference_report_.ntp_seconds = kNtpHigh;
- expected_receiver_reference_report_.ntp_fraction = kNtpLow;
- }
-
- virtual ~RtcpReceiverTest() {}
-
- // Injects an RTCP packet into the receiver.
- void InjectRtcpPacket(const uint8* packet, uint16 length) {
- RtcpParser rtcp_parser(packet, length);
- rtcp_receiver_->IncomingRtcpPacket(&rtcp_parser);
- }
-
- scoped_ptr<base::SimpleTestTickClock> testing_clock_;
- scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
- MockRtcpReceiverFeedback mock_receiver_feedback_;
- scoped_ptr<RtcpReceiver> rtcp_receiver_;
- RtcpSenderInfo expected_sender_info_;
- RtcpReportBlock expected_report_block_;
- RtcpReceiverReferenceTimeReport expected_receiver_reference_report_;
-
- DISALLOW_COPY_AND_ASSIGN(RtcpReceiverTest);
-};
-
-TEST_F(RtcpReceiverTest, BrokenPacketIsIgnored) {
- const uint8 bad_packet[] = {0, 0, 0, 0};
- InjectRtcpPacket(bad_packet, sizeof(bad_packet));
-}
-
-TEST_F(RtcpReceiverTest, InjectSenderReportPacket) {
- TestRtcpPacketBuilder p;
- p.AddSr(kSenderSsrc, 0);
-
- // Expected to be ignored since the sender ssrc does not match our
- // remote ssrc.
- InjectRtcpPacket(p.Data(), p.Length());
-
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceivedSenderReport(expected_sender_info_)).Times(1);
- rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);
-
- // Expected to be pass through since the sender ssrc match our remote ssrc.
- InjectRtcpPacket(p.Data(), p.Length());
-}
-
-TEST_F(RtcpReceiverTest, InjectReceiveReportPacket) {
- TestRtcpPacketBuilder p1;
- p1.AddRr(kSenderSsrc, 1);
- p1.AddRb(kUnknownSsrc);
-
- // Expected to be ignored since the source ssrc does not match our
- // local ssrc.
- InjectRtcpPacket(p1.Data(), p1.Length());
-
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
-
- TestRtcpPacketBuilder p2;
- p2.AddRr(kSenderSsrc, 1);
- p2.AddRb(kSourceSsrc);
-
- // Expected to be pass through since the sender ssrc match our local ssrc.
- InjectRtcpPacket(p2.Data(), p2.Length());
-}
-
-TEST_F(RtcpReceiverTest, InjectSenderReportWithReportBlockPacket) {
- TestRtcpPacketBuilder p1;
- p1.AddSr(kSenderSsrc, 1);
- p1.AddRb(kUnknownSsrc);
-
- // Sender report expected to be ignored since the sender ssrc does not match
- // our remote ssrc.
- // Report block expected to be ignored since the source ssrc does not match
- // our local ssrc.
- InjectRtcpPacket(p1.Data(), p1.Length());
-
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceivedSenderReport(expected_sender_info_)).Times(1);
- rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);
-
- // Sender report expected to be pass through since the sender ssrc match our
- // remote ssrc.
- // Report block expected to be ignored since the source ssrc does not match
- // our local ssrc.
- InjectRtcpPacket(p1.Data(), p1.Length());
-
- EXPECT_CALL(mock_receiver_feedback_, OnReceivedSenderReport(_)).Times(0);
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
-
- rtcp_receiver_->SetRemoteSSRC(0);
-
- TestRtcpPacketBuilder p2;
- p2.AddSr(kSenderSsrc, 1);
- p2.AddRb(kSourceSsrc);
-
- // Sender report expected to be ignored since the sender ssrc does not match
- // our remote ssrc.
- // Receiver report expected to be pass through since the sender ssrc match
- // our local ssrc.
- InjectRtcpPacket(p2.Data(), p2.Length());
-
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceivedSenderReport(expected_sender_info_)).Times(1);
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
-
- rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);
-
- // Sender report expected to be pass through since the sender ssrc match our
- // remote ssrc.
- // Receiver report expected to be pass through since the sender ssrc match
- // our local ssrc.
- InjectRtcpPacket(p2.Data(), p2.Length());
-}
-
-TEST_F(RtcpReceiverTest, InjectSenderReportPacketWithDlrr) {
- TestRtcpPacketBuilder p;
- p.AddSr(kSenderSsrc, 0);
- p.AddXrHeader(kSenderSsrc);
- p.AddXrUnknownBlock();
- p.AddXrExtendedDlrrBlock(kSenderSsrc);
- p.AddXrUnknownBlock();
-
- // Expected to be ignored since the source ssrc does not match our
- // local ssrc.
- InjectRtcpPacket(p.Data(), p.Length());
-
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceivedSenderReport(expected_sender_info_)).Times(1);
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
-
- // Enable receiving sender report.
- rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);
-
- // Expected to be pass through since the sender ssrc match our local ssrc.
- InjectRtcpPacket(p.Data(), p.Length());
-}
-
-TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithRrtr) {
- TestRtcpPacketBuilder p1;
- p1.AddRr(kSenderSsrc, 1);
- p1.AddRb(kUnknownSsrc);
- p1.AddXrHeader(kSenderSsrc);
- p1.AddXrRrtrBlock();
-
- // Expected to be ignored since the source ssrc does not match our
- // local ssrc.
- InjectRtcpPacket(p1.Data(), p1.Length());
-
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceiverReferenceTimeReport(
- expected_receiver_reference_report_)).Times(1);
-
- // Enable receiving reference time report.
- rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);
-
- TestRtcpPacketBuilder p2;
- p2.AddRr(kSenderSsrc, 1);
- p2.AddRb(kSourceSsrc);
- p2.AddXrHeader(kSenderSsrc);
- p2.AddXrRrtrBlock();
-
- // Expected to be pass through since the sender ssrc match our local ssrc.
- InjectRtcpPacket(p2.Data(), p2.Length());
-}
-
-TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithIntraFrameRequest) {
- TestRtcpPacketBuilder p1;
- p1.AddRr(kSenderSsrc, 1);
- p1.AddRb(kUnknownSsrc);
-
- // Expected to be ignored since the source ssrc does not match our
- // local ssrc.
- InjectRtcpPacket(p1.Data(), p1.Length());
-
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
-
- TestRtcpPacketBuilder p2;
- p2.AddRr(kSenderSsrc, 1);
- p2.AddRb(kSourceSsrc);
-
- // Expected to be pass through since the sender ssrc match our local ssrc.
- InjectRtcpPacket(p2.Data(), p2.Length());
-}
-
-TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastFeedback) {
- TestRtcpPacketBuilder p1;
- p1.AddRr(kSenderSsrc, 1);
- p1.AddRb(kUnknownSsrc);
- p1.AddCast(kSenderSsrc, kUnknownSsrc, kTargetDelay);
-
- // Expected to be ignored since the source ssrc does not match our
- // local ssrc.
- InjectRtcpPacket(p1.Data(), p1.Length());
-
- EXPECT_CALL(mock_receiver_feedback_,
- OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
- EXPECT_CALL(mock_receiver_feedback_, OnReceivedCastFeedback(_)).Times(1);
-
- // Enable receiving the cast feedback.
- rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);
-
- TestRtcpPacketBuilder p2;
- p2.AddRr(kSenderSsrc, 1);
- p2.AddRb(kSourceSsrc);
- p2.AddCast(kSenderSsrc, kSourceSsrc, kTargetDelay);
-
- // Expected to be pass through since the sender ssrc match our local ssrc.
- InjectRtcpPacket(p2.Data(), p2.Length());
-}
-
-TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastVerification) {
- RtcpMessageVerification verification;
- RtcpReceiver rtcp_receiver(&verification, kSourceSsrc);
-
- EXPECT_CALL(verification,
- OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
-
- // Enable receiving the cast feedback.
- rtcp_receiver.SetRemoteSSRC(kSenderSsrc);
-
- TestRtcpPacketBuilder p;
- p.AddRr(kSenderSsrc, 1);
- p.AddRb(kSourceSsrc);
- p.AddCast(kSenderSsrc, kSourceSsrc, kTargetDelay);
-
- // Expected to be pass through since the sender ssrc match our local ssrc.
- RtcpParser rtcp_parser(p.Data(), p.Length());
- rtcp_receiver.IncomingRtcpPacket(&rtcp_parser);
-
- EXPECT_TRUE(verification.OnReceivedCastFeedbackCalled());
-}
-
-TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationBase) {
- static const uint32 kTimeBaseMs = 12345678;
- static const uint32 kTimeDelayMs = 10;
- static const uint32 kDelayDeltaMs = 123;
- base::SimpleTestTickClock testing_clock;
- testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
-
- RtcpMessageVerification verification;
- RtcpReceiver rtcp_receiver(&verification,
- kSourceSsrc);
- rtcp_receiver.SetRemoteSSRC(kSenderSsrc);
- rtcp_receiver.SetCastReceiverEventHistorySize(100);
-
- RtcpReceiverLogMessage receiver_log;
- RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp);
- RtcpReceiverEventLogMessage event_log;
-
- event_log.type = FRAME_ACK_SENT;
- event_log.event_timestamp = testing_clock.NowTicks();
- event_log.delay_delta = base::TimeDelta::FromMilliseconds(kDelayDeltaMs);
- frame_log.event_log_messages_.push_back(event_log);
-
- testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
- event_log.type = PACKET_RECEIVED;
- event_log.event_timestamp = testing_clock.NowTicks();
- event_log.packet_id = kLostPacketId1;
- frame_log.event_log_messages_.push_back(event_log);
-
- event_log.type = PACKET_RECEIVED;
- event_log.event_timestamp = testing_clock.NowTicks();
- event_log.packet_id = kLostPacketId2;
- frame_log.event_log_messages_.push_back(event_log);
-
- receiver_log.push_back(frame_log);
-
- verification.SetExpectedReceiverLog(receiver_log);
-
- TestRtcpPacketBuilder p;
- p.AddRr(kSenderSsrc, 1);
- p.AddRb(kSourceSsrc);
- p.AddReceiverLog(kSenderSsrc);
- p.AddReceiverFrameLog(kRtpTimestamp, 3, kTimeBaseMs);
- p.AddReceiverEventLog(kDelayDeltaMs, FRAME_ACK_SENT, 0);
- p.AddReceiverEventLog(kLostPacketId1, PACKET_RECEIVED, kTimeDelayMs);
- p.AddReceiverEventLog(kLostPacketId2, PACKET_RECEIVED, kTimeDelayMs);
-
- // Adds duplicated receiver event.
- p.AddReceiverFrameLog(kRtpTimestamp, 3, kTimeBaseMs);
- p.AddReceiverEventLog(kDelayDeltaMs, FRAME_ACK_SENT, 0);
- p.AddReceiverEventLog(kLostPacketId1, PACKET_RECEIVED, kTimeDelayMs);
- p.AddReceiverEventLog(kLostPacketId2, PACKET_RECEIVED, kTimeDelayMs);
-
- EXPECT_CALL(verification,
- OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
-
- RtcpParser rtcp_parser(p.Data(), p.Length());
- rtcp_receiver.IncomingRtcpPacket(&rtcp_parser);
-
- EXPECT_TRUE(verification.OnReceivedReceiverLogCalled());
-}
-
-TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationMulti) {
- static const uint32 kTimeBaseMs = 12345678;
- static const uint32 kTimeDelayMs = 10;
- static const uint32 kDelayDeltaMs = 123;
- base::SimpleTestTickClock testing_clock;
- testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
-
- RtcpMessageVerification verification;
- RtcpReceiver rtcp_receiver(&verification,
- kSourceSsrc);
- rtcp_receiver.SetRemoteSSRC(kSenderSsrc);
-
- RtcpReceiverLogMessage receiver_log;
-
- for (int j = 0; j < 100; ++j) {
- RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp);
- RtcpReceiverEventLogMessage event_log;
- event_log.type = FRAME_ACK_SENT;
- event_log.event_timestamp = testing_clock.NowTicks();
- event_log.delay_delta = base::TimeDelta::FromMilliseconds(kDelayDeltaMs);
- frame_log.event_log_messages_.push_back(event_log);
- receiver_log.push_back(frame_log);
- testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
- }
-
- verification.SetExpectedReceiverLog(receiver_log);
-
- TestRtcpPacketBuilder p;
- p.AddRr(kSenderSsrc, 1);
- p.AddRb(kSourceSsrc);
- p.AddReceiverLog(kSenderSsrc);
- for (int i = 0; i < 100; ++i) {
- p.AddReceiverFrameLog(kRtpTimestamp, 1, kTimeBaseMs + i * kTimeDelayMs);
- p.AddReceiverEventLog(kDelayDeltaMs, FRAME_ACK_SENT, 0);
- }
-
- EXPECT_CALL(verification,
- OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
-
- RtcpParser rtcp_parser(p.Data(), p.Length());
- rtcp_receiver.IncomingRtcpPacket(&rtcp_parser);
-
- EXPECT_TRUE(verification.OnReceivedReceiverLogCalled());
-}
-
-} // namespace cast
-} // namespace media
diff --git a/media/cast/net/rtcp/rtcp_unittest.cc b/media/cast/net/rtcp/rtcp_unittest.cc
index 5ea9ee1..55c2710 100644
--- a/media/cast/net/rtcp/rtcp_unittest.cc
+++ b/media/cast/net/rtcp/rtcp_unittest.cc
@@ -9,7 +9,6 @@
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/cast_transport_sender_impl.h"
#include "media/cast/net/pacing/paced_sender.h"
-#include "media/cast/net/rtcp/mock_rtcp_receiver_feedback.h"
#include "media/cast/net/rtcp/rtcp.h"
#include "media/cast/net/rtcp/test_rtcp_packet_builder.h"
#include "media/cast/test/fake_single_thread_task_runner.h"
diff --git a/media/cast/net/rtcp/rtcp_utility.cc b/media/cast/net/rtcp/rtcp_utility.cc
index 4f99cd4..f6785f8 100644
--- a/media/cast/net/rtcp/rtcp_utility.cc
+++ b/media/cast/net/rtcp/rtcp_utility.cc
@@ -4,198 +4,66 @@
#include "media/cast/net/rtcp/rtcp_utility.h"
-#include "base/big_endian.h"
#include "base/logging.h"
#include "media/cast/net/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(uint32 local_ssrc, uint32 remote_ssrc) :
+ local_ssrc_(local_ssrc),
+ remote_ssrc_(remote_ssrc),
+ has_sender_report_(false),
+ has_last_report_(false),
+ has_cast_message_(false),
+ has_receiver_reference_time_report_(false) {
}
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 kStateApplicationSpecificCastReceiverFrameLog:
- IterateCastReceiverLogFrame();
- break;
- case kStateApplicationSpecificCastReceiverEventLog:
- IterateCastReceiverLogEvent();
- break;
- case kStateExtendedReportBlock:
- IterateExtendedReportItem();
- break;
- case kStateExtendedReportDelaySinceLastReceiverReport:
- IterateExtendedReportDelaySinceLastReceiverReportItem();
- break;
- case kStatePayloadSpecificApplication:
- IteratePayloadSpecificAppItem();
- break;
- case kStatePayloadSpecificCast:
- IteratePayloadSpecificCastItem();
- break;
- case kStatePayloadSpecificCastNack:
- IteratePayloadSpecificCastNackItem();
- break;
- }
- return field_type_;
-}
-
-void RtcpParser::IterateTopLevel() {
- for (;;) {
+bool RtcpParser::Parse(base::BigEndianReader* reader) {
+ while (reader->remaining()) {
RtcpCommonHeader header;
+ if (!ParseCommonHeader(reader, &header))
+ return false;
- 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!
+ base::StringPiece tmp;
+ if (!reader->ReadPiece(&tmp, header.length_in_octets - 4))
+ return false;
+ base::BigEndianReader chunk(tmp.data(), tmp.size());
switch (header.PT) {
case kPacketTypeSenderReport:
- // number of Report blocks
- number_of_blocks_ = header.IC;
- ParseSR();
- return;
+ if (!ParseSR(&chunk, header))
+ return false;
+ break;
+
case kPacketTypeReceiverReport:
- // number of Report blocks
- number_of_blocks_ = header.IC;
- ParseRR();
- return;
+ if (!ParseRR(&chunk, header))
+ return false;
+ break;
+
case kPacketTypeApplicationDefined:
- if (!ParseApplicationDefined(header.IC)) {
- // Nothing supported found, continue to next block!
- break;
- }
- return;
- case kPacketTypeGenericRtpFeedback: // Fall through!
+ if (!ParseApplicationDefined(&chunk, header))
+ return false;
+ break;
+
case kPacketTypePayloadSpecific:
- if (!ParseFeedBackCommon(header)) {
- // Nothing supported found, continue to next block!
- break;
- }
- return;
+ if (!ParseFeedbackCommon(&chunk, header))
+ return false;
+ break;
+
case kPacketTypeXr:
- if (!ParseExtendedReport()) {
- break; // Nothing supported found, continue to next block!
- }
- return;
- default:
- // Not supported! Skip!
- EndCurrentBlock();
+ if (!ParseExtendedReport(&chunk, header))
+ return false;
break;
}
}
+ return true;
}
-void RtcpParser::IterateReportBlockItem() {
- bool success = ParseReportBlockItem();
- if (!success)
- Iterate();
-}
-
-void RtcpParser::IterateExtendedReportItem() {
- bool success = ParseExtendedReportItem();
- if (!success)
- Iterate();
-}
-
-void RtcpParser::IterateExtendedReportDelaySinceLastReceiverReportItem() {
- bool success = ParseExtendedReportDelaySinceLastReceiverReport();
- if (!success)
- Iterate();
-}
-
-void RtcpParser::IteratePayloadSpecificAppItem() {
- bool success = ParsePayloadSpecificAppItem();
- 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;
-
+bool RtcpParser::ParseCommonHeader(base::BigEndianReader* reader,
+ RtcpCommonHeader* parsed_header) {
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -204,448 +72,291 @@ bool RtcpParser::RtcpParseCommonHeader(const uint8* data_begin,
//
// Common header for all Rtcp packets, 4 octets.
- if ((data_end - data_begin) < 4)
+ uint8 byte;
+ if (!reader->ReadU8(&byte))
return false;
+ parsed_header->V = byte >> 6;
+ parsed_header->P = ((byte & 0x20) == 0) ? false : true;
- 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];
+ // Check if RTP version field == 2.
+ if (parsed_header->V != 2)
+ return false;
- parsed_header->length_in_octets =
- ((data_begin[2] << 8) + data_begin[3] + 1) * 4;
+ parsed_header->IC = byte & 0x1f;
+ if (!reader->ReadU8(&parsed_header->PT))
+ return false;
- if (parsed_header->length_in_octets == 0)
+ uint16 bytes;
+ if (!reader->ReadU16(&bytes))
return false;
- // Check if RTP version field == 2.
- if (parsed_header->V != 2)
+ parsed_header->length_in_octets = (static_cast<size_t>(bytes) + 1) * 4;
+
+ if (parsed_header->length_in_octets == 0)
return false;
return true;
}
-bool RtcpParser::ParseRR() {
- ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
- if (length < 8)
+bool RtcpParser::ParseSR(base::BigEndianReader* reader,
+ const RtcpCommonHeader& header) {
+ uint32 sender_ssrc;
+ if (!reader->ReadU32(&sender_ssrc))
return false;
- field_type_ = kRtcpRrCode;
+ if (sender_ssrc != remote_ssrc_)
+ return true;
+
+ uint32 tmp;
+ if (!reader->ReadU32(&sender_report_.ntp_seconds) ||
+ !reader->ReadU32(&sender_report_.ntp_fraction) ||
+ !reader->ReadU32(&sender_report_.rtp_timestamp) ||
+ !reader->ReadU32(&sender_report_.send_packet_count) ||
+ !reader->ReadU32(&tmp))
+ return false;
+ sender_report_.send_octet_count = tmp;
+ has_sender_report_ = true;
- 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;
+ for (size_t block = 0; block < header.IC; block++)
+ if (!ParseReportBlock(reader))
+ return false;
- // State transition
- state_ = kStateReportBlock;
return true;
}
-bool RtcpParser::ParseSR() {
- ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
- if (length < 28) {
- EndCurrentBlock();
+bool RtcpParser::ParseRR(base::BigEndianReader* reader,
+ const RtcpCommonHeader& header) {
+ uint32 receiver_ssrc;
+ if (!reader->ReadU32(&receiver_ssrc))
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();
- }
+
+ if (receiver_ssrc != remote_ssrc_)
+ return true;
+
+ for (size_t block = 0; block < header.IC; block++)
+ if (!ParseReportBlock(reader))
+ return false;
+
return true;
}
-bool RtcpParser::ParseReportBlockItem() {
- ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
- if (length < 24 || number_of_blocks_ <= 0) {
- state_ = kStateTopLevel;
- EndCurrentBlock();
+bool RtcpParser::ParseReportBlock(base::BigEndianReader* reader) {
+ uint32 ssrc, last_report, delay;
+ if (!reader->ReadU32(&ssrc) ||
+ !reader->Skip(12) ||
+ !reader->ReadU32(&last_report) ||
+ !reader->ReadU32(&delay))
return false;
+
+ if (ssrc == local_ssrc_) {
+ last_report_ = last_report;
+ delay_since_last_report_ = delay;
+ has_last_report_ = true;
}
- 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::ParseApplicationDefined(uint8 subtype) {
- ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
- if (length < 16 || subtype != kReceiverLogSubtype) {
- state_ = kStateTopLevel;
- EndCurrentBlock();
- return false;
- }
-
+bool RtcpParser::ParseApplicationDefined(base::BigEndianReader* reader,
+ const RtcpCommonHeader& header) {
uint32 sender_ssrc;
uint32 name;
+ if (!reader->ReadU32(&sender_ssrc) ||
+ !reader->ReadU32(&name))
+ return false;
- 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 (sender_ssrc != remote_ssrc_)
+ return true;
- if (name != kCast) {
- state_ = kStateTopLevel;
- EndCurrentBlock();
+ if (name != kCast)
return false;
- }
- rtcp_data_ += 12;
- switch (subtype) {
+
+ switch (header.IC /* subtype */ ) {
case kReceiverLogSubtype:
- state_ = kStateApplicationSpecificCastReceiverFrameLog;
- field_type_ = kRtcpApplicationSpecificCastReceiverLogCode;
- field_.cast_receiver_log.sender_ssrc = sender_ssrc;
+ if (!ParseCastReceiverLogFrameItem(reader))
+ return false;
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::ParseCastReceiverLogFrameItem(
+ base::BigEndianReader* reader) {
-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;
-}
+ while (reader->remaining()) {
+ uint32 rtp_timestamp;
+ uint32 data;
+ if (!reader->ReadU32(&rtp_timestamp) ||
+ !reader->ReadU32(&data))
+ return false;
-bool RtcpParser::ParseFeedBackCommon(const RtcpCommonHeader& header) {
- DCHECK((header.PT == kPacketTypeGenericRtpFeedback) ||
- (header.PT == kPacketTypePayloadSpecific))
- << "Invalid state";
+ // We have 24 LSB of the event timestamp base on the wire.
+ base::TimeTicks event_timestamp_base = base::TimeTicks() +
+ base::TimeDelta::FromMilliseconds(data & 0xffffff);
- ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
+ size_t num_events = 1 + static_cast<uint8>(data >> 24);
- if (length < 12) { // 4 * 3, RFC4585 section 6.1
- EndCurrentBlock();
- return false;
- }
+ RtcpReceiverFrameLogMessage frame_log(rtp_timestamp);
+ for (size_t event = 0; event < num_events; event++) {
+ uint16 delay_delta_or_packet_id;
+ uint16 event_type_and_timestamp_delta;
+ if (!reader->ReadU16(&delay_delta_or_packet_id) ||
+ !reader->ReadU16(&event_type_and_timestamp_delta))
+ 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 == kPacketTypePayloadSpecific) {
- // Payload specific feedback
- switch (header.IC) {
- case 1:
- // PLI
- break;
- case 2:
- // SLI.
- break;
- case 3:
- // RPSI.
- break;
- 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;
+ RtcpReceiverEventLogMessage event_log;
+ event_log.type = TranslateToLogEventFromWireFormat(
+ static_cast<uint8>(event_type_and_timestamp_delta >> 12));
+ event_log.event_timestamp =
+ event_timestamp_base +
+ base::TimeDelta::FromMilliseconds(
+ event_type_and_timestamp_delta & 0xfff);
+ if (event_log.type == PACKET_RECEIVED) {
+ event_log.packet_id = delay_delta_or_packet_id;
+ } else {
+ event_log.delay_delta = base::TimeDelta::FromMilliseconds(
+ delay_delta_or_packet_id);
+ }
+ frame_log.event_log_messages_.push_back(event_log);
}
- EndCurrentBlock();
- return false;
- } else {
- DCHECK(false) << "Invalid state";
- EndCurrentBlock();
- return false;
+ receiver_log_.push_back(frame_log);
}
-}
-bool RtcpParser::ParsePayloadSpecificAppItem() {
- ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
+ return true;
+}
- 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 == kCast) {
- field_type_ = kRtcpPayloadSpecificCastCode;
- state_ = kStatePayloadSpecificCast;
+// RFC 4585.
+bool RtcpParser::ParseFeedbackCommon(base::BigEndianReader* reader,
+ const RtcpCommonHeader& header) {
+ // See RTC 4585 Section 6.4 for application specific feedback messages.
+ if (header.IC != 15) {
return true;
}
- state_ = kStateTopLevel;
- EndCurrentBlock();
- return false;
-}
+ uint32 remote_ssrc;
+ uint32 media_ssrc;
+ if (!reader->ReadU32(&remote_ssrc) ||
+ !reader->ReadU32(&media_ssrc))
+ return false;
+
+ if (remote_ssrc != remote_ssrc_)
+ return true;
-bool RtcpParser::ParsePayloadSpecificCastItem() {
- ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
- if (length < 4) {
- state_ = kStateTopLevel;
- EndCurrentBlock();
+ uint32 name;
+ if (!reader->ReadU32(&name))
return false;
+
+ if (name != kCast) {
+ return true;
}
- 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();
+ cast_message_.media_ssrc = remote_ssrc;
+
+ uint8 last_frame_id;
+ uint8 number_of_lost_fields;
+ if (!reader->ReadU8(&last_frame_id) ||
+ !reader->ReadU8(&number_of_lost_fields) ||
+ !reader->ReadU16(&cast_message_.target_delay_ms))
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);
+ // Please note, this frame_id is still only 8-bit!
+ cast_message_.ack_frame_id = last_frame_id;
+
+ for (size_t i = 0; i < number_of_lost_fields; i++) {
+ uint8 frame_id;
+ uint16 packet_id;
+ uint8 bitmask;
+ if (!reader->ReadU8(&frame_id) ||
+ !reader->ReadU16(&packet_id) ||
+ !reader->ReadU8(&bitmask))
+ return false;
+ cast_message_.missing_frames_and_packets[frame_id].insert(packet_id);
+ if (packet_id != kRtcpCastAllPacketsLost) {
+ while (bitmask) {
+ packet_id++;
+ if (bitmask & 1)
+ cast_message_.missing_frames_and_packets[frame_id].insert(packet_id);
+ bitmask >>= 1;
+ }
+ }
+ }
- rtcp_data_ += 4;
+ has_cast_message_ = true;
return true;
}
-bool RtcpParser::ParseExtendedReport() {
- ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
- if (length < 8)
+bool RtcpParser::ParseExtendedReport(base::BigEndianReader* reader,
+ const RtcpCommonHeader& header) {
+ uint32 remote_ssrc;
+ if (!reader->ReadU32(&remote_ssrc))
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);
+ // Is it for us?
+ if (remote_ssrc != remote_ssrc_)
+ return true;
- rtcp_data_ += 8;
+ while (reader->remaining()) {
+ uint8 block_type;
+ uint16 block_length;
+ if (!reader->ReadU8(&block_type) ||
+ !reader->Skip(1) ||
+ !reader->ReadU16(&block_length))
+ return false;
+
+ switch (block_type) {
+ case 4: // RRTR. RFC3611 Section 4.4.
+ if (block_length != 2)
+ return false;
+ if (!ParseExtendedReportReceiverReferenceTimeReport(reader,
+ remote_ssrc))
+ return false;
+ break;
- state_ = kStateExtendedReportBlock;
- return true;
-}
+ case 5: // DLRR. RFC3611 Section 4.5.
+ if (block_length % 3 != 0)
+ return false;
+ for (int block = 0; block < block_length / 3; block++)
+ if (!ParseExtendedReportDelaySinceLastReceiverReport(reader))
+ return false;
+ return true;
-bool RtcpParser::ParseExtendedReportItem() {
- ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
- if (length < 4) {
- state_ = kStateTopLevel;
- EndCurrentBlock();
- return false;
+ default:
+ // Skip unknown item.
+ if (!reader->Skip(block_length * 4))
+ 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: // RRTR. RFC3611 Section 4.4.
- if (block_length != 2) {
- // Invalid block length.
- state_ = kStateTopLevel;
- EndCurrentBlock();
- return false;
- }
- return ParseExtendedReportReceiverReferenceTimeReport();
- case 5: // DLRR. RFC3611 Section 4.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;
- }
+ return true;
}
-bool RtcpParser::ParseExtendedReportReceiverReferenceTimeReport() {
- ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
- if (length < 8) {
- state_ = kStateTopLevel;
- EndCurrentBlock();
+bool RtcpParser::ParseExtendedReportReceiverReferenceTimeReport(
+ base::BigEndianReader* reader,
+ uint32 remote_ssrc) {
+ receiver_reference_time_report_.remote_ssrc = remote_ssrc;
+ if(!reader->ReadU32(&receiver_reference_time_report_.ntp_seconds) ||
+ !reader->ReadU32(&receiver_reference_time_report_.ntp_fraction))
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;
+ has_receiver_reference_time_report_ = true;
return true;
}
-bool RtcpParser::ParseExtendedReportDelaySinceLastReceiverReport() {
- ptrdiff_t length = rtcp_block_end_ - rtcp_data_;
- if (length < 12) {
- state_ = kStateTopLevel;
- EndCurrentBlock();
+bool RtcpParser::ParseExtendedReportDelaySinceLastReceiverReport(
+ base::BigEndianReader* reader) {
+ uint32 ssrc, last_report, delay;
+ if (!reader->ReadU32(&ssrc) ||
+ !reader->ReadU32(&last_report) ||
+ !reader->ReadU32(&delay))
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;
+ if (ssrc == remote_ssrc_) {
+ last_report_ = last_report;
+ delay_since_last_report_ = delay;
+ has_last_report_ = true;
+ }
- number_of_blocks_--;
- field_type_ = kRtcpXrDlrrCode;
+ has_last_report_ = true;
return true;
}
@@ -692,7 +403,6 @@ CastLoggingEvent TranslateToLogEventFromWireFormat(uint8 event) {
// 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;
}
}
diff --git a/media/cast/net/rtcp/rtcp_utility.h b/media/cast/net/rtcp/rtcp_utility.h
index a20fd80..8fd8edc 100644
--- a/media/cast/net/rtcp/rtcp_utility.h
+++ b/media/cast/net/rtcp/rtcp_utility.h
@@ -5,6 +5,7 @@
#ifndef MEDIA_CAST_RTCP_RTCP_UTILITY_H_
#define MEDIA_CAST_RTCP_RTCP_UTILITY_H_
+#include "base/big_endian.h"
#include "media/cast/cast_config.h"
#include "media/cast/cast_defines.h"
#include "media/cast/logging/logging_defines.h"
@@ -23,203 +24,85 @@ static const uint8 kReceiverLogSubtype = 2;
static const size_t kRtcpMaxReceiverLogMessages = 256;
static const size_t kRtcpMaxCastLossFields = 100;
-struct RtcpFieldReceiverReport {
- // RFC 3550.
- uint32 sender_ssrc;
- uint8 number_of_report_blocks;
-};
-
-struct RtcpFieldSenderReport {
- // RFC 3550.
- uint32 sender_ssrc;
- uint8 number_of_report_blocks;
- uint32 ntp_most_significant;
- uint32 ntp_least_significant;
- uint32 rtp_timestamp;
- uint32 sender_packet_count;
- uint32 sender_octet_count;
-};
-
-struct RtcpFieldReportBlockItem {
- // RFC 3550.
- uint32 ssrc;
- uint8 fraction_lost;
- uint32 cumulative_number_of_packets_lost;
- uint32 extended_highest_sequence_number;
- uint32 jitter;
- uint32 last_sender_report;
- uint32 delay_last_sender_report;
-};
-
-struct RtcpFieldXr {
- // RFC 3611.
- uint32 sender_ssrc;
-};
-
-struct RtcpFieldXrRrtr {
- // RFC 3611.
- uint32 ntp_most_significant;
- uint32 ntp_least_significant;
-};
-
-struct RtcpFieldXrDlrr {
- // RFC 3611.
- uint32 receivers_ssrc;
- uint32 last_receiver_report;
- uint32 delay_last_receiver_report;
-};
-
-struct RtcpFieldPayloadSpecificApplication {
- uint32 sender_ssrc;
- uint32 media_ssrc;
-};
-
-struct RtcpFieldPayloadSpecificCastItem {
- uint8 last_frame_id;
- uint8 number_of_lost_fields;
- uint16 target_delay_ms;
-};
-
-struct RtcpFieldPayloadSpecificCastNackItem {
- uint8 frame_id;
- uint16 packet_id;
- uint8 bitmask;
-};
-
-struct RtcpFieldApplicationSpecificCastReceiverLogItem {
- uint32 sender_ssrc;
- uint32 rtp_timestamp;
- uint32 event_timestamp_base;
- uint8 event;
- union {
- uint16 packet_id;
- int16 delay_delta;
- } delay_delta_or_packet_id;
- uint16 event_timestamp_delta;
-};
-
-union RtcpField {
- RtcpFieldReceiverReport receiver_report;
- RtcpFieldSenderReport sender_report;
- RtcpFieldReportBlockItem report_block_item;
-
- RtcpFieldXr extended_report;
- RtcpFieldXrRrtr rrtr;
- RtcpFieldXrDlrr dlrr;
-
- RtcpFieldPayloadSpecificApplication application_specific;
- RtcpFieldPayloadSpecificCastItem cast_item;
- RtcpFieldPayloadSpecificCastNackItem cast_nack_item;
-
- RtcpFieldApplicationSpecificCastReceiverLogItem cast_receiver_log;
-};
-
-enum RtcpFieldTypes {
- kRtcpNotValidCode,
-
- // RFC 3550.
- kRtcpRrCode,
- kRtcpSrCode,
- kRtcpReportBlockItemCode,
-
- // RFC 3611.
- kRtcpXrCode,
- kRtcpXrRrtrCode,
- kRtcpXrDlrrCode,
- kRtcpXrUnknownItemCode,
-
- // RFC 4585.
- kRtcpPayloadSpecificAppCode,
-
- // Application specific.
- kRtcpPayloadSpecificCastCode,
- kRtcpPayloadSpecificCastNackItemCode,
- kRtcpApplicationSpecificCastReceiverLogCode,
- kRtcpApplicationSpecificCastReceiverLogFrameCode,
- kRtcpApplicationSpecificCastReceiverLogEventCode,
-};
-
struct RtcpCommonHeader {
uint8 V; // Version.
bool P; // Padding.
uint8 IC; // Item count / subtype.
uint8 PT; // Packet Type.
- uint16 length_in_octets;
+ size_t length_in_octets;
};
class RtcpParser {
public:
- RtcpParser(const uint8* rtcp_data, size_t rtcp_length);
+ RtcpParser(uint32 local_ssrc, uint32 remote_ssrc);
~RtcpParser();
- RtcpFieldTypes FieldType() const;
- const RtcpField& Field() const;
+ bool Parse(base::BigEndianReader* reader);
- bool IsValid() const;
+ bool has_sender_report() const { return has_sender_report_; }
+ const RtcpSenderInfo& sender_report() const {
+ return sender_report_;
+ }
- RtcpFieldTypes Begin();
- RtcpFieldTypes Iterate();
+ bool has_last_report() const { return has_last_report_; }
+ uint32 last_report() const { return last_report_; }
+ uint32 delay_since_last_report() const { return delay_since_last_report_; }
- private:
- enum ParseState {
- kStateTopLevel, // Top level packet
- kStateReportBlock, // Sender/Receiver report report blocks.
- kStateApplicationSpecificCastReceiverFrameLog,
- kStateApplicationSpecificCastReceiverEventLog,
- kStateExtendedReportBlock,
- kStateExtendedReportDelaySinceLastReceiverReport,
- kStatePayloadSpecificApplication,
- kStatePayloadSpecificCast, // Application specific Cast.
- kStatePayloadSpecificCastNack, // Application specific Nack for Cast.
- };
-
- bool RtcpParseCommonHeader(const uint8* begin,
- const uint8* end,
- RtcpCommonHeader* parsed_header) const;
-
- void IterateTopLevel();
- void IterateReportBlockItem();
- void IterateCastReceiverLogFrame();
- void IterateCastReceiverLogEvent();
- void IterateExtendedReportItem();
- void IterateExtendedReportDelaySinceLastReceiverReportItem();
- void IteratePayloadSpecificAppItem();
- void IteratePayloadSpecificCastItem();
- void IteratePayloadSpecificCastNackItem();
-
- void Validate();
- void EndCurrentBlock();
-
- bool ParseRR();
- bool ParseSR();
- bool ParseReportBlockItem();
-
- bool ParseApplicationDefined(uint8 subtype);
- bool ParseCastReceiverLogFrameItem();
- bool ParseCastReceiverLogEventItem();
-
- bool ParseExtendedReport();
- bool ParseExtendedReportItem();
- bool ParseExtendedReportReceiverReferenceTimeReport();
- bool ParseExtendedReportDelaySinceLastReceiverReport();
-
- bool ParseFeedBackCommon(const RtcpCommonHeader& header);
- bool ParsePayloadSpecificAppItem();
- bool ParsePayloadSpecificCastItem();
- bool ParsePayloadSpecificCastNackItem();
+ bool has_receiver_log() const { return !receiver_log_.empty(); }
+ const RtcpReceiverLogMessage& receiver_log() const { return receiver_log_; }
+ RtcpReceiverLogMessage* mutable_receiver_log() { return & receiver_log_; }
- private:
- const uint8* const rtcp_data_begin_;
- const uint8* const rtcp_data_end_;
+ bool has_cast_message() const { return has_cast_message_; }
+ const RtcpCastMessage& cast_message() const { return cast_message_; }
+ RtcpCastMessage* mutable_cast_message() { return &cast_message_; }
- bool valid_packet_;
- const uint8* rtcp_data_;
- const uint8* rtcp_block_end_;
+ bool has_receiver_reference_time_report() const {
+ return has_receiver_reference_time_report_;
+ }
+ const RtcpReceiverReferenceTimeReport&
+ receiver_reference_time_report() const {
+ return receiver_reference_time_report_;
+ }
- ParseState state_;
- uint8 number_of_blocks_;
- RtcpFieldTypes field_type_;
- RtcpField field_;
+ private:
+ bool ParseCommonHeader(base::BigEndianReader* reader,
+ RtcpCommonHeader* parsed_header);
+ bool ParseSR(base::BigEndianReader* reader,
+ const RtcpCommonHeader& header);
+ bool ParseRR(base::BigEndianReader* reader,
+ const RtcpCommonHeader& header);
+ bool ParseReportBlock(base::BigEndianReader* reader);
+ bool ParseApplicationDefined(base::BigEndianReader* reader,
+ const RtcpCommonHeader& header);
+ bool ParseCastReceiverLogFrameItem(base::BigEndianReader* reader);
+ bool ParseFeedbackCommon(base::BigEndianReader* reader,
+ const RtcpCommonHeader& header);
+ bool ParseExtendedReport(base::BigEndianReader* reader,
+ const RtcpCommonHeader& header);
+ bool ParseExtendedReportReceiverReferenceTimeReport(
+ base::BigEndianReader* reader,
+ uint32 remote_ssrc);
+ bool ParseExtendedReportDelaySinceLastReceiverReport(
+ base::BigEndianReader* reader);
+
+ uint32 local_ssrc_;
+ uint32 remote_ssrc_;
+
+ bool has_sender_report_;
+ RtcpSenderInfo sender_report_;
+
+ uint32 last_report_;
+ uint32 delay_since_last_report_;
+ bool has_last_report_;
+
+ // |receiver_log_| is a vector vector, no need for has_*.
+ RtcpReceiverLogMessage receiver_log_;
+
+ bool has_cast_message_;
+ RtcpCastMessage cast_message_;
+
+ bool has_receiver_reference_time_report_;
+ RtcpReceiverReferenceTimeReport receiver_reference_time_report_;
DISALLOW_COPY_AND_ASSIGN(RtcpParser);
};
diff --git a/media/cast/net/rtcp/rtcp_utility_unittest.cc b/media/cast/net/rtcp/rtcp_utility_unittest.cc
new file mode 100644
index 0000000..8f8f740
--- /dev/null
+++ b/media/cast/net/rtcp/rtcp_utility_unittest.cc
@@ -0,0 +1,401 @@
+// Copyright 2014 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 "base/memory/scoped_ptr.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "media/cast/cast_environment.h"
+#include "media/cast/net/cast_transport_defines.h"
+#include "media/cast/net/rtcp/rtcp_utility.h"
+#include "media/cast/net/rtcp/test_rtcp_packet_builder.h"
+#include "media/cast/test/fake_single_thread_task_runner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+namespace cast {
+
+static const uint32 kSenderSsrc = 0x10203;
+static const uint32 kSourceSsrc = 0x40506;
+static const uint32 kUnknownSsrc = 0xDEAD;
+static const base::TimeDelta kTargetDelay =
+ base::TimeDelta::FromMilliseconds(100);
+
+class RtcpParserTest : public ::testing::Test {
+ protected:
+ RtcpParserTest()
+ : testing_clock_(new base::SimpleTestTickClock()),
+ task_runner_(new test::FakeSingleThreadTaskRunner(
+ testing_clock_.get())) {
+ }
+
+ bool HasAnything(const RtcpParser& parser) {
+ return parser.has_sender_report() ||
+ parser.has_last_report() ||
+ parser.has_receiver_log() ||
+ parser.has_cast_message() ||
+ parser.has_receiver_reference_time_report();
+ }
+
+ void ExpectSenderInfo(const RtcpParser& parser) {
+ EXPECT_TRUE(parser.has_sender_report());
+ EXPECT_EQ(kNtpHigh, parser.sender_report().ntp_seconds);
+ EXPECT_EQ(kNtpLow, parser.sender_report().ntp_fraction);
+ EXPECT_EQ(kRtpTimestamp, parser.sender_report().rtp_timestamp);
+ EXPECT_EQ(kSendPacketCount, parser.sender_report().send_packet_count);
+ EXPECT_EQ(kSendOctetCount, parser.sender_report().send_octet_count);
+ }
+
+ void ExpectLastReport(const RtcpParser& parser) {
+ EXPECT_TRUE(parser.has_last_report());
+ EXPECT_EQ(kLastSr, parser.last_report());
+ EXPECT_EQ(kDelayLastSr, parser.delay_since_last_report());
+ }
+
+ void ExpectReceiverReference(const RtcpParser& parser) {
+ EXPECT_TRUE(parser.has_receiver_reference_time_report());
+ EXPECT_EQ(kSenderSsrc, parser.receiver_reference_time_report().remote_ssrc);
+ EXPECT_EQ(kNtpHigh, parser.receiver_reference_time_report().ntp_seconds);
+ EXPECT_EQ(kNtpLow, parser.receiver_reference_time_report().ntp_fraction);
+ }
+
+ void ExpectCastFeedback(const RtcpParser& parser) {
+ EXPECT_TRUE(parser.has_cast_message());
+ EXPECT_EQ(kSenderSsrc, parser.cast_message().media_ssrc);
+ EXPECT_EQ(kAckFrameId, parser.cast_message().ack_frame_id);
+
+ MissingFramesAndPacketsMap::const_iterator frame_it =
+ parser.cast_message().missing_frames_and_packets.begin();
+
+ EXPECT_TRUE(
+ frame_it != parser.cast_message().missing_frames_and_packets.end());
+ EXPECT_EQ(kLostFrameId, frame_it->first);
+ EXPECT_EQ(frame_it->second.size(), 1UL);
+ EXPECT_EQ(*frame_it->second.begin(), kRtcpCastAllPacketsLost);
+ ++frame_it;
+ EXPECT_TRUE(
+ frame_it != parser.cast_message().missing_frames_and_packets.end());
+ EXPECT_EQ(kFrameIdWithLostPackets, frame_it->first);
+ EXPECT_EQ(3UL, frame_it->second.size());
+ PacketIdSet::const_iterator packet_it = frame_it->second.begin();
+ EXPECT_EQ(kLostPacketId1, *packet_it);
+ ++packet_it;
+ EXPECT_EQ(kLostPacketId2, *packet_it);
+ ++packet_it;
+ EXPECT_EQ(kLostPacketId3, *packet_it);
+ ++frame_it;
+ EXPECT_TRUE(
+ frame_it == parser.cast_message().missing_frames_and_packets.end());
+ }
+
+ void ExpectReceiverLog(const RtcpParser& parser,
+ const RtcpReceiverLogMessage& expected_receiver_log) {
+ EXPECT_TRUE(parser.has_receiver_log());
+ EXPECT_EQ(expected_receiver_log.size(), parser.receiver_log().size());
+ RtcpReceiverLogMessage::const_iterator expected_it =
+ expected_receiver_log.begin();
+ RtcpReceiverLogMessage::const_iterator incoming_it =
+ parser.receiver_log().begin();
+ for (; incoming_it != parser.receiver_log().end();
+ ++incoming_it, ++expected_it) {
+ EXPECT_EQ(expected_it->rtp_timestamp_, incoming_it->rtp_timestamp_);
+ EXPECT_EQ(expected_it->event_log_messages_.size(),
+ incoming_it->event_log_messages_.size());
+
+ RtcpReceiverEventLogMessages::const_iterator event_incoming_it =
+ incoming_it->event_log_messages_.begin();
+ RtcpReceiverEventLogMessages::const_iterator event_expected_it =
+ expected_it->event_log_messages_.begin();
+ for (; event_incoming_it != incoming_it->event_log_messages_.end();
+ ++event_incoming_it, ++event_expected_it) {
+ EXPECT_EQ(event_expected_it->type, event_incoming_it->type);
+ EXPECT_EQ(event_expected_it->event_timestamp,
+ event_incoming_it->event_timestamp);
+ if (event_expected_it->type == PACKET_RECEIVED) {
+ EXPECT_EQ(event_expected_it->packet_id, event_incoming_it->packet_id);
+ } else {
+ EXPECT_EQ(event_expected_it->delay_delta,
+ event_incoming_it->delay_delta);
+ }
+ }
+ }
+ }
+
+ scoped_ptr<base::SimpleTestTickClock> testing_clock_;
+ scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(RtcpParserTest);
+};
+
+TEST_F(RtcpParserTest, BrokenPacketIsIgnored) {
+ const char bad_packet[] = {0, 0, 0, 0};
+ RtcpParser parser(kSourceSsrc, kSenderSsrc);
+ base::BigEndianReader reader(bad_packet, sizeof(bad_packet));
+ EXPECT_FALSE(parser.Parse(&reader));
+}
+
+TEST_F(RtcpParserTest, UnknownBlockIgnored) {
+ // Only unknown data, nothing happens.
+ TestRtcpPacketBuilder p;
+ p.AddUnknownBlock();
+ RtcpParser parser1(kSourceSsrc, 0);
+ EXPECT_TRUE(parser1.Parse(p.Reader()));
+ EXPECT_FALSE(HasAnything(parser1));
+
+ // Add valid sender report *after* unknown data - should work fine.
+ p.AddSr(kSenderSsrc, 0);
+ RtcpParser parser2(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser2.Parse(p.Reader()));
+ ExpectSenderInfo(parser2);
+}
+
+TEST_F(RtcpParserTest, InjectSenderReportPacket) {
+ TestRtcpPacketBuilder p;
+ p.AddSr(kSenderSsrc, 0);
+
+ // Expected to be ignored since the sender ssrc does not match our
+ // remote ssrc.
+ RtcpParser parser1(kSourceSsrc, 0);
+ EXPECT_TRUE(parser1.Parse(p.Reader()));
+ EXPECT_FALSE(HasAnything(parser1));
+
+ // Expected to be pass through since the sender ssrc match our remote ssrc.
+ RtcpParser parser2(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser2.Parse(p.Reader()));
+ ExpectSenderInfo(parser2);
+}
+
+TEST_F(RtcpParserTest, InjectReceiveReportPacket) {
+ TestRtcpPacketBuilder p1;
+ p1.AddRr(kSenderSsrc, 1);
+ p1.AddRb(kUnknownSsrc);
+
+ // Expected to be ignored since the source ssrc does not match our
+ // local ssrc.
+ RtcpParser parser1(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser1.Parse(p1.Reader()));
+ EXPECT_FALSE(HasAnything(parser1));
+
+ TestRtcpPacketBuilder p2;
+ p2.AddRr(kSenderSsrc, 1);
+ p2.AddRb(kSourceSsrc);
+
+ // Expected to be pass through since the sender ssrc match our local ssrc.
+ RtcpParser parser2(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser2.Parse(p2.Reader()));
+ ExpectLastReport(parser2);
+}
+
+TEST_F(RtcpParserTest, InjectSenderReportWithReportBlockPacket) {
+ TestRtcpPacketBuilder p1;
+ p1.AddSr(kSenderSsrc, 1);
+ p1.AddRb(kUnknownSsrc);
+
+ // Sender report expected to be ignored since the sender ssrc does not match
+ // our remote ssrc.
+ // Report block expected to be ignored since the source ssrc does not match
+ // our local ssrc.
+ RtcpParser parser1(kSourceSsrc, 0);
+ EXPECT_TRUE(parser1.Parse(p1.Reader()));
+ EXPECT_FALSE(HasAnything(parser1));
+
+ // Sender report expected to be pass through since the sender ssrc match our
+ // remote ssrc.
+ // Report block expected to be ignored since the source ssrc does not match
+ // our local ssrc.
+ RtcpParser parser2(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser2.Parse(p1.Reader()));
+ ExpectSenderInfo(parser2);
+ EXPECT_FALSE(parser2.has_last_report());
+
+ // Sender report expected to be ignored since the sender ssrc does not match
+ // our remote ssrc.
+ // Report block expected to be ignored too since it's a part of the
+ // sender report.
+ TestRtcpPacketBuilder p2;
+ p2.AddSr(kSenderSsrc, 1);
+ p2.AddRb(kSourceSsrc);
+
+ RtcpParser parser3(kSourceSsrc, 0);
+ EXPECT_TRUE(parser3.Parse(p2.Reader()));
+ EXPECT_FALSE(parser3.has_last_report());
+
+ // Sender report expected to be pass through since the sender ssrc match our
+ // remote ssrc.
+ // Report block expected to be pass through since the sender ssrc match
+ // our local ssrc.
+ RtcpParser parser4(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser4.Parse(p2.Reader()));
+ ExpectSenderInfo(parser4);
+ ExpectLastReport(parser4);
+}
+
+TEST_F(RtcpParserTest, InjectSenderReportPacketWithDlrr) {
+ TestRtcpPacketBuilder p;
+ p.AddSr(kSenderSsrc, 0);
+ p.AddXrHeader(kSenderSsrc);
+ p.AddXrUnknownBlock();
+ p.AddXrExtendedDlrrBlock(kSenderSsrc);
+ p.AddXrUnknownBlock();
+
+ // Expected to be ignored since the source ssrc does not match our
+ // local ssrc.
+ RtcpParser parser1(kSourceSsrc, 0);
+ EXPECT_TRUE(parser1.Parse(p.Reader()));
+ EXPECT_FALSE(HasAnything(parser1));
+
+ // Expected to be pass through since the sender ssrc match our local ssrc.
+ RtcpParser parser2(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser2.Parse(p.Reader()));
+ ExpectSenderInfo(parser2);
+ ExpectLastReport(parser2);
+}
+
+TEST_F(RtcpParserTest, InjectReceiverReportPacketWithRrtr) {
+ TestRtcpPacketBuilder p1;
+ p1.AddRr(kSenderSsrc, 1);
+ p1.AddRb(kUnknownSsrc);
+ p1.AddXrHeader(kSenderSsrc);
+ p1.AddXrRrtrBlock();
+
+ // Expected to be ignored since the source ssrc does not match our
+ // local ssrc.
+ RtcpParser parser1(kSourceSsrc, 0);
+ EXPECT_TRUE(parser1.Parse(p1.Reader()));
+ EXPECT_FALSE(HasAnything(parser1));
+
+ TestRtcpPacketBuilder p2;
+ p2.AddRr(kSenderSsrc, 1);
+ p2.AddRb(kSourceSsrc);
+ p2.AddXrHeader(kSenderSsrc);
+ p2.AddXrRrtrBlock();
+
+ // Expected to be pass through since the sender ssrc match our local ssrc.
+ RtcpParser parser2(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser2.Parse(p2.Reader()));
+ ExpectLastReport(parser2);
+ ExpectReceiverReference(parser2);
+}
+
+TEST_F(RtcpParserTest, InjectReceiverReportPacketWithIntraFrameRequest) {
+ TestRtcpPacketBuilder p1;
+ p1.AddRr(kSenderSsrc, 1);
+ p1.AddRb(kUnknownSsrc);
+
+ // Expected to be ignored since the source ssrc does not match our
+ // local ssrc.
+ RtcpParser parser1(kSourceSsrc, 0);
+ EXPECT_TRUE(parser1.Parse(p1.Reader()));
+ EXPECT_FALSE(HasAnything(parser1));
+
+ TestRtcpPacketBuilder p2;
+ p2.AddRr(kSenderSsrc, 1);
+ p2.AddRb(kSourceSsrc);
+
+ RtcpParser parser2(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser2.Parse(p2.Reader()));
+ ExpectLastReport(parser2);
+}
+
+TEST_F(RtcpParserTest, InjectReceiverReportPacketWithCastFeedback) {
+ TestRtcpPacketBuilder p1;
+ p1.AddRr(kSenderSsrc, 1);
+ p1.AddRb(kUnknownSsrc);
+ p1.AddCast(kSenderSsrc, kUnknownSsrc, kTargetDelay);
+
+ // Expected to be ignored since the source ssrc does not match our
+ // local ssrc.
+ RtcpParser parser1(kSourceSsrc, 0);
+ EXPECT_TRUE(parser1.Parse(p1.Reader()));
+ EXPECT_FALSE(HasAnything(parser1));
+
+ TestRtcpPacketBuilder p2;
+ p2.AddRr(kSenderSsrc, 1);
+ p2.AddRb(kSourceSsrc);
+ p2.AddCast(kSenderSsrc, kSourceSsrc, kTargetDelay);
+
+ // Expected to be pass through since the sender ssrc match our local ssrc.
+ RtcpParser parser2(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser2.Parse(p2.Reader()));
+ ExpectLastReport(parser2);
+ ExpectCastFeedback(parser2);
+}
+
+TEST_F(RtcpParserTest, InjectReceiverReportWithReceiverLogVerificationBase) {
+ static const uint32 kTimeBaseMs = 12345678;
+ static const uint32 kTimeDelayMs = 10;
+ static const uint32 kDelayDeltaMs = 123;
+ base::SimpleTestTickClock testing_clock;
+ testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
+
+ RtcpReceiverLogMessage receiver_log;
+ RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp);
+ RtcpReceiverEventLogMessage event_log;
+
+ event_log.type = FRAME_ACK_SENT;
+ event_log.event_timestamp = testing_clock.NowTicks();
+ event_log.delay_delta = base::TimeDelta::FromMilliseconds(kDelayDeltaMs);
+ frame_log.event_log_messages_.push_back(event_log);
+
+ testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
+ event_log.type = PACKET_RECEIVED;
+ event_log.event_timestamp = testing_clock.NowTicks();
+ event_log.packet_id = kLostPacketId1;
+ frame_log.event_log_messages_.push_back(event_log);
+
+ event_log.type = PACKET_RECEIVED;
+ event_log.event_timestamp = testing_clock.NowTicks();
+ event_log.packet_id = kLostPacketId2;
+ frame_log.event_log_messages_.push_back(event_log);
+
+ receiver_log.push_back(frame_log);
+
+ TestRtcpPacketBuilder p;
+ p.AddRr(kSenderSsrc, 1);
+ p.AddRb(kSourceSsrc);
+ p.AddReceiverLog(kSenderSsrc);
+ p.AddReceiverFrameLog(kRtpTimestamp, 3, kTimeBaseMs);
+ p.AddReceiverEventLog(kDelayDeltaMs, FRAME_ACK_SENT, 0);
+ p.AddReceiverEventLog(kLostPacketId1, PACKET_RECEIVED, kTimeDelayMs);
+ p.AddReceiverEventLog(kLostPacketId2, PACKET_RECEIVED, kTimeDelayMs);
+
+ RtcpParser parser(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser.Parse(p.Reader()));
+ ExpectReceiverLog(parser, receiver_log);
+}
+
+TEST_F(RtcpParserTest, InjectReceiverReportWithReceiverLogVerificationMulti) {
+ static const uint32 kTimeBaseMs = 12345678;
+ static const uint32 kTimeDelayMs = 10;
+ static const uint32 kDelayDeltaMs = 123;
+ base::SimpleTestTickClock testing_clock;
+ testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
+
+ RtcpReceiverLogMessage receiver_log;
+
+ for (int j = 0; j < 100; ++j) {
+ RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp);
+ RtcpReceiverEventLogMessage event_log;
+ event_log.type = FRAME_ACK_SENT;
+ event_log.event_timestamp = testing_clock.NowTicks();
+ event_log.delay_delta = base::TimeDelta::FromMilliseconds(kDelayDeltaMs);
+ frame_log.event_log_messages_.push_back(event_log);
+ receiver_log.push_back(frame_log);
+ testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
+ }
+
+ TestRtcpPacketBuilder p;
+ p.AddRr(kSenderSsrc, 1);
+ p.AddRb(kSourceSsrc);
+ p.AddReceiverLog(kSenderSsrc);
+ for (int i = 0; i < 100; ++i) {
+ p.AddReceiverFrameLog(kRtpTimestamp, 1, kTimeBaseMs + i * kTimeDelayMs);
+ p.AddReceiverEventLog(kDelayDeltaMs, FRAME_ACK_SENT, 0);
+ }
+
+ RtcpParser parser(kSourceSsrc, kSenderSsrc);
+ EXPECT_TRUE(parser.Parse(p.Reader()));
+ ExpectReceiverLog(parser, receiver_log);
+}
+
+} // namespace cast
+} // namespace media
diff --git a/media/cast/net/rtcp/test_rtcp_packet_builder.cc b/media/cast/net/rtcp/test_rtcp_packet_builder.cc
index 046cc04..32e1883 100644
--- a/media/cast/net/rtcp/test_rtcp_packet_builder.cc
+++ b/media/cast/net/rtcp/test_rtcp_packet_builder.cc
@@ -12,7 +12,8 @@ namespace cast {
TestRtcpPacketBuilder::TestRtcpPacketBuilder()
: ptr_of_length_(NULL),
- big_endian_writer_(reinterpret_cast<char*>(buffer_), kMaxIpPacketSize) {}
+ big_endian_writer_(reinterpret_cast<char*>(buffer_), kMaxIpPacketSize),
+ big_endian_reader_(NULL, 0) {}
void TestRtcpPacketBuilder::AddSr(uint32 sender_ssrc,
int number_of_report_blocks) {
@@ -69,6 +70,13 @@ void TestRtcpPacketBuilder::AddXrUnknownBlock() {
big_endian_writer_.WriteU32(0);
}
+void TestRtcpPacketBuilder::AddUnknownBlock() {
+ AddRtcpHeader(99, 0);
+ big_endian_writer_.WriteU32(42);
+ big_endian_writer_.WriteU32(42);
+ big_endian_writer_.WriteU32(42);
+}
+
void TestRtcpPacketBuilder::AddXrDlrrBlock(uint32 sender_ssrc) {
big_endian_writer_.WriteU8(5); // Block type.
big_endian_writer_.WriteU8(0); // Reserved.
@@ -184,6 +192,12 @@ const uint8* TestRtcpPacketBuilder::Data() {
return buffer_;
}
+base::BigEndianReader* TestRtcpPacketBuilder::Reader() {
+ big_endian_reader_ = base::BigEndianReader(
+ reinterpret_cast<const char *>(Data()), Length());
+ return &big_endian_reader_;
+}
+
void TestRtcpPacketBuilder::PatchLengthField() {
if (ptr_of_length_) {
// Back-patch the packet length. The client must have taken
diff --git a/media/cast/net/rtcp/test_rtcp_packet_builder.h b/media/cast/net/rtcp/test_rtcp_packet_builder.h
index afbf4c6..3fab3b5 100644
--- a/media/cast/net/rtcp/test_rtcp_packet_builder.h
+++ b/media/cast/net/rtcp/test_rtcp_packet_builder.h
@@ -19,18 +19,18 @@ namespace cast {
namespace {
// Sender report.
-static const int kNtpHigh = 0x01020304;
-static const int kNtpLow = 0x05060708;
-static const int kRtpTimestamp = 0x10203040;
-static const int kSendPacketCount = 987;
-static const int kSendOctetCount = 87654;
+static const uint32 kNtpHigh = 0x01020304;
+static const uint32 kNtpLow = 0x05060708;
+static const uint32 kRtpTimestamp = 0x10203040;
+static const uint32 kSendPacketCount = 987;
+static const uint32 kSendOctetCount = 87654;
// Report block.
static const int kLoss = 0x01000123;
static const int kExtendedMax = 0x15678;
static const int kTestJitter = 0x10203;
-static const int kLastSr = 0x34561234;
-static const int kDelayLastSr = 1000;
+static const uint32 kLastSr = 0x34561234;
+static const uint32 kDelayLastSr = 1000;
// DLRR block.
static const int kLastRr = 0x34561234;
@@ -65,6 +65,7 @@ class TestRtcpPacketBuilder {
void AddXrExtendedDlrrBlock(uint32 sender_ssrc);
void AddXrRrtrBlock();
void AddXrUnknownBlock();
+ void AddUnknownBlock();
void AddNack(uint32 sender_ssrc, uint32 media_ssrc);
void AddSendReportRequest(uint32 sender_ssrc, uint32 media_ssrc);
@@ -83,6 +84,7 @@ class TestRtcpPacketBuilder {
scoped_ptr<Packet> GetPacket();
const uint8* Data();
int Length() { return kMaxIpPacketSize - big_endian_writer_.remaining(); }
+ base::BigEndianReader* Reader();
private:
void AddRtcpHeader(int payload, int format_or_count);
@@ -93,6 +95,7 @@ class TestRtcpPacketBuilder {
uint8 buffer_[kMaxIpPacketSize];
char* ptr_of_length_;
base::BigEndianWriter big_endian_writer_;
+ base::BigEndianReader big_endian_reader_;
DISALLOW_COPY_AND_ASSIGN(TestRtcpPacketBuilder);
};
diff --git a/media/cast/receiver/cast_receiver_impl.cc b/media/cast/receiver/cast_receiver_impl.cc
index 91821bb..36669b9 100644
--- a/media/cast/receiver/cast_receiver_impl.cc
+++ b/media/cast/receiver/cast_receiver_impl.cc
@@ -10,7 +10,6 @@
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
-#include "media/cast/net/rtcp/rtcp_receiver.h"
#include "media/cast/receiver/audio_decoder.h"
#include "media/cast/receiver/video_decoder.h"
@@ -52,8 +51,8 @@ void CastReceiverImpl::DispatchReceivedPacket(scoped_ptr<Packet> packet) {
const size_t length = packet->size();
uint32 ssrc_of_sender;
- if (RtcpReceiver::IsRtcpPacket(data, length)) {
- ssrc_of_sender = RtcpReceiver::GetSsrcOfSender(data, length);
+ if (Rtcp::IsRtcpPacket(data, length)) {
+ ssrc_of_sender = Rtcp::GetSsrcOfSender(data, length);
} else if (!FrameReceiver::ParseSenderSsrc(data, length, &ssrc_of_sender)) {
VLOG(1) << "Invalid RTP packet.";
return;
diff --git a/media/cast/receiver/frame_receiver.cc b/media/cast/receiver/frame_receiver.cc
index 2670372..1f6d75e 100644
--- a/media/cast/receiver/frame_receiver.cc
+++ b/media/cast/receiver/frame_receiver.cc
@@ -11,7 +11,6 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "media/cast/cast_environment.h"
-#include "media/cast/net/rtcp/rtcp_receiver.h"
namespace {
const int kMinSchedulingDelayMs = 1;
@@ -74,7 +73,7 @@ void FrameReceiver::RequestEncodedFrame(
bool FrameReceiver::ProcessPacket(scoped_ptr<Packet> packet) {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- if (RtcpReceiver::IsRtcpPacket(&packet->front(), packet->size())) {
+ if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) {
rtcp_.IncomingRtcpPacket(&packet->front(), packet->size());
} else {
RtpCastHeader rtp_header;
diff --git a/media/cast/sender/audio_sender_unittest.cc b/media/cast/sender/audio_sender_unittest.cc
index 287630d..b6a074d 100644
--- a/media/cast/sender/audio_sender_unittest.cc
+++ b/media/cast/sender/audio_sender_unittest.cc
@@ -13,7 +13,6 @@
#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/cast_transport_sender_impl.h"
-#include "media/cast/net/rtcp/rtcp_receiver.h"
#include "media/cast/sender/audio_sender.h"
#include "media/cast/test/fake_single_thread_task_runner.h"
#include "media/cast/test/utility/audio_utility.h"
@@ -28,7 +27,7 @@ class TestPacketSender : public PacketSender {
virtual bool SendPacket(PacketRef packet,
const base::Closure& cb) OVERRIDE {
- if (RtcpReceiver::IsRtcpPacket(&packet->data[0], packet->data.size())) {
+ if (Rtcp::IsRtcpPacket(&packet->data[0], packet->data.size())) {
++number_of_rtcp_packets_;
} else {
// Check that at least one RTCP packet was sent before the first RTP
diff --git a/media/cast/sender/video_sender_unittest.cc b/media/cast/sender/video_sender_unittest.cc
index 5522c26..a95f3e5 100644
--- a/media/cast/sender/video_sender_unittest.cc
+++ b/media/cast/sender/video_sender_unittest.cc
@@ -15,7 +15,6 @@
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/cast_transport_sender_impl.h"
#include "media/cast/net/pacing/paced_sender.h"
-#include "media/cast/net/rtcp/rtcp_receiver.h"
#include "media/cast/sender/video_sender.h"
#include "media/cast/test/fake_single_thread_task_runner.h"
#include "media/cast/test/fake_video_encode_accelerator.h"
@@ -67,7 +66,7 @@ class TestPacketSender : public PacketSender {
callback_ = cb;
return false;
}
- if (RtcpReceiver::IsRtcpPacket(&packet->data[0], packet->data.size())) {
+ if (Rtcp::IsRtcpPacket(&packet->data[0], packet->data.size())) {
++number_of_rtcp_packets_;
} else {
// Check that at least one RTCP packet was sent before the first RTP