diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/media/cast/rtcp | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/media/cast/rtcp')
22 files changed, 2172 insertions, 1935 deletions
diff --git a/chromium/media/cast/rtcp/mock_rtcp_receiver_feedback.cc b/chromium/media/cast/rtcp/mock_rtcp_receiver_feedback.cc index daaa1ad0883..9ff2d48f03c 100644 --- a/chromium/media/cast/rtcp/mock_rtcp_receiver_feedback.cc +++ b/chromium/media/cast/rtcp/mock_rtcp_receiver_feedback.cc @@ -7,17 +7,13 @@ namespace media { namespace cast { -MockRtcpReceiverFeedback::MockRtcpReceiverFeedback() { -} +MockRtcpReceiverFeedback::MockRtcpReceiverFeedback() {} -MockRtcpReceiverFeedback::~MockRtcpReceiverFeedback() { -} +MockRtcpReceiverFeedback::~MockRtcpReceiverFeedback() {} -MockRtcpRttFeedback::MockRtcpRttFeedback() { -} +MockRtcpRttFeedback::MockRtcpRttFeedback() {} -MockRtcpRttFeedback::~MockRtcpRttFeedback() { -} +MockRtcpRttFeedback::~MockRtcpRttFeedback() {} } // namespace cast } // namespace media diff --git a/chromium/media/cast/rtcp/mock_rtcp_receiver_feedback.h b/chromium/media/cast/rtcp/mock_rtcp_receiver_feedback.h index 0316d9819f2..56fe1ca6995 100644 --- a/chromium/media/cast/rtcp/mock_rtcp_receiver_feedback.h +++ b/chromium/media/cast/rtcp/mock_rtcp_receiver_feedback.h @@ -7,7 +7,9 @@ #include <vector> +#include "media/cast/rtcp/rtcp_defines.h" #include "media/cast/rtcp/rtcp_receiver.h" +#include "media/cast/transport/cast_transport_defines.h" #include "testing/gmock/include/gmock/gmock.h" namespace media { @@ -19,7 +21,7 @@ class MockRtcpReceiverFeedback : public RtcpReceiverFeedback { virtual ~MockRtcpReceiverFeedback(); MOCK_METHOD1(OnReceivedSenderReport, - void(const RtcpSenderInfo& remote_sender_info)); + void(const transport::RtcpSenderInfo& remote_sender_info)); MOCK_METHOD1(OnReceiverReferenceTimeReport, void(const RtcpReceiverReferenceTimeReport& remote_time_report)); @@ -28,8 +30,6 @@ class MockRtcpReceiverFeedback : public RtcpReceiverFeedback { MOCK_METHOD1(OnReceivedReceiverLog, void(const RtcpReceiverLogMessage& receiver_log)); - MOCK_METHOD1(OnReceivedSenderLog, - void(const RtcpSenderLogMessage& sender_log)); }; class MockRtcpRttFeedback : public RtcpRttFeedback { diff --git a/chromium/media/cast/rtcp/mock_rtcp_sender_feedback.cc b/chromium/media/cast/rtcp/mock_rtcp_sender_feedback.cc index 65c630148c2..e44e0bfdef4 100644 --- a/chromium/media/cast/rtcp/mock_rtcp_sender_feedback.cc +++ b/chromium/media/cast/rtcp/mock_rtcp_sender_feedback.cc @@ -7,11 +7,9 @@ namespace media { namespace cast { -MockRtcpSenderFeedback::MockRtcpSenderFeedback() { -} +MockRtcpSenderFeedback::MockRtcpSenderFeedback() {} -MockRtcpSenderFeedback::~MockRtcpSenderFeedback() { -} +MockRtcpSenderFeedback::~MockRtcpSenderFeedback() {} } // namespace cast } // namespace media diff --git a/chromium/media/cast/rtcp/receiver_rtcp_event_subscriber.cc b/chromium/media/cast/rtcp/receiver_rtcp_event_subscriber.cc new file mode 100644 index 00000000000..9a9c0aeeb74 --- /dev/null +++ b/chromium/media/cast/rtcp/receiver_rtcp_event_subscriber.cc @@ -0,0 +1,96 @@ +// 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/rtcp/receiver_rtcp_event_subscriber.h" + +#include <utility> + +namespace media { +namespace cast { + +ReceiverRtcpEventSubscriber::ReceiverRtcpEventSubscriber( + const size_t max_size_to_retain, EventMediaType type) + : max_size_to_retain_(max_size_to_retain), type_(type) { + DCHECK(max_size_to_retain_ > 0u); + DCHECK(type_ == AUDIO_EVENT || type_ == VIDEO_EVENT); +} + +ReceiverRtcpEventSubscriber::~ReceiverRtcpEventSubscriber() { + DCHECK(thread_checker_.CalledOnValidThread()); +} + +void ReceiverRtcpEventSubscriber::OnReceiveFrameEvent( + const FrameEvent& frame_event) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (ShouldProcessEvent(frame_event.type, frame_event.media_type)) { + RtcpEvent rtcp_event; + switch (frame_event.type) { + case FRAME_PLAYOUT: + rtcp_event.delay_delta = frame_event.delay_delta; + case FRAME_ACK_SENT: + case FRAME_DECODED: + rtcp_event.type = frame_event.type; + rtcp_event.timestamp = frame_event.timestamp; + rtcp_events_.insert( + std::make_pair(frame_event.rtp_timestamp, rtcp_event)); + break; + default: + break; + } + } + + TruncateMapIfNeeded(); + + DCHECK(rtcp_events_.size() <= max_size_to_retain_); +} + +void ReceiverRtcpEventSubscriber::OnReceivePacketEvent( + const PacketEvent& packet_event) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (ShouldProcessEvent(packet_event.type, packet_event.media_type)) { + RtcpEvent rtcp_event; + if (packet_event.type == PACKET_RECEIVED) { + rtcp_event.type = packet_event.type; + rtcp_event.timestamp = packet_event.timestamp; + rtcp_event.packet_id = packet_event.packet_id; + rtcp_events_.insert( + std::make_pair(packet_event.rtp_timestamp, rtcp_event)); + } + } + + TruncateMapIfNeeded(); + + DCHECK(rtcp_events_.size() <= max_size_to_retain_); +} + +void ReceiverRtcpEventSubscriber::GetRtcpEventsAndReset( + RtcpEventMultiMap* rtcp_events) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(rtcp_events); + rtcp_events->swap(rtcp_events_); + rtcp_events_.clear(); +} + +void ReceiverRtcpEventSubscriber::TruncateMapIfNeeded() { + // If map size has exceeded |max_size_to_retain_|, remove entry with + // the smallest RTP timestamp. + if (rtcp_events_.size() > max_size_to_retain_) { + DVLOG(3) << "RTCP event map exceeded size limit; " + << "removing oldest entry"; + // This is fine since we only insert elements one at a time. + rtcp_events_.erase(rtcp_events_.begin()); + } +} + +bool ReceiverRtcpEventSubscriber::ShouldProcessEvent( + CastLoggingEvent event_type, EventMediaType event_media_type) { + return type_ == event_media_type && + (event_type == FRAME_ACK_SENT || event_type == FRAME_DECODED || + event_type == FRAME_PLAYOUT || event_type == PACKET_RECEIVED); +} + +} // namespace cast +} // namespace media diff --git a/chromium/media/cast/rtcp/receiver_rtcp_event_subscriber.h b/chromium/media/cast/rtcp/receiver_rtcp_event_subscriber.h new file mode 100644 index 00000000000..84af7cbaf3f --- /dev/null +++ b/chromium/media/cast/rtcp/receiver_rtcp_event_subscriber.h @@ -0,0 +1,79 @@ +// 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_RECEIVER_RTCP_EVENT_SUBSCRIBER_H_ +#define MEDIA_CAST_RTCP_RECEIVER_RTCP_EVENT_SUBSCRIBER_H_ + +#include <map> + +#include "base/threading/thread_checker.h" +#include "media/cast/logging/logging_defines.h" +#include "media/cast/logging/raw_event_subscriber.h" +#include "media/cast/rtcp/rtcp_defines.h" + +namespace media { +namespace cast { + +// A RawEventSubscriber implementation with the following properties: +// - Only processes raw event types that are relevant for sending from cast +// receiver to cast sender via RTCP. +// - Captures information to be sent over to RTCP from raw event logs into the +// more compact RtcpEvent struct. +// - Orders events by RTP timestamp with a multimap. +// - Internally, the map is capped at a maximum size configurable by the caller. +// The subscriber only keeps the most recent events (determined by RTP +// timestamp) up to the size limit. +class ReceiverRtcpEventSubscriber : public RawEventSubscriber { + public: + typedef std::multimap<RtpTimestamp, RtcpEvent> RtcpEventMultiMap; + + // |max_size_to_retain|: The object will keep up to |max_size_to_retain| + // events + // in the map. Once threshold has been reached, an event with the smallest + // RTP timestamp will be removed. + // |type|: Determines whether the subscriber will process only audio or video + // events. + ReceiverRtcpEventSubscriber(const size_t max_size_to_retain, + EventMediaType type); + + virtual ~ReceiverRtcpEventSubscriber(); + + // RawEventSubscriber implementation. + virtual void OnReceiveFrameEvent(const FrameEvent& frame_event) OVERRIDE; + virtual void OnReceivePacketEvent(const PacketEvent& packet_event) OVERRIDE; + + // Assigns events collected to |rtcp_events| and clears them from this + // object. + void GetRtcpEventsAndReset(RtcpEventMultiMap* rtcp_events); + + private: + // If |rtcp_events_.size()| exceeds |max_size_to_retain_|, remove an oldest + // entry (determined by RTP timestamp) so its size no greater than + // |max_size_to_retain_|. + void TruncateMapIfNeeded(); + + // Returns |true| if events of |event_type| and |media_type| + // should be processed. + bool ShouldProcessEvent(CastLoggingEvent event_type, + EventMediaType media_type); + + const size_t max_size_to_retain_; + EventMediaType type_; + + // The key should really be something more than just a RTP timestamp in order + // to differentiate between video and audio frames, but since the + // implementation doesn't mix audio and video frame events, RTP timestamp + // only as key is fine. + RtcpEventMultiMap rtcp_events_; + + // Ensures methods are only called on the main thread. + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(ReceiverRtcpEventSubscriber); +}; + +} // namespace cast +} // namespace media + +#endif // MEDIA_CAST_RTCP_RECEIVER_RTCP_EVENT_SUBSCRIBER_H_ diff --git a/chromium/media/cast/rtcp/receiver_rtcp_event_subscriber_unittest.cc b/chromium/media/cast/rtcp/receiver_rtcp_event_subscriber_unittest.cc new file mode 100644 index 00000000000..e0d0f172160 --- /dev/null +++ b/chromium/media/cast/rtcp/receiver_rtcp_event_subscriber_unittest.cc @@ -0,0 +1,131 @@ +// 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/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/test/simple_test_tick_clock.h" +#include "base/time/tick_clock.h" +#include "media/cast/cast_environment.h" +#include "media/cast/logging/logging_defines.h" +#include "media/cast/rtcp/receiver_rtcp_event_subscriber.h" +#include "media/cast/test/fake_single_thread_task_runner.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { +namespace cast { + +namespace { + +const size_t kMaxEventEntries = 10u; +const int64 kDelayMs = 20L; + +} // namespace + +class ReceiverRtcpEventSubscriberTest : public ::testing::Test { + protected: + ReceiverRtcpEventSubscriberTest() + : testing_clock_(new base::SimpleTestTickClock()), + task_runner_(new test::FakeSingleThreadTaskRunner(testing_clock_)), + cast_environment_(new CastEnvironment( + scoped_ptr<base::TickClock>(testing_clock_).Pass(), + task_runner_, + task_runner_, + task_runner_)) {} + + virtual ~ReceiverRtcpEventSubscriberTest() {} + + virtual void TearDown() OVERRIDE { + if (event_subscriber_) { + cast_environment_->Logging()->RemoveRawEventSubscriber( + event_subscriber_.get()); + } + } + + void Init(EventMediaType type) { + event_subscriber_.reset( + new ReceiverRtcpEventSubscriber(kMaxEventEntries, type)); + cast_environment_->Logging()->AddRawEventSubscriber( + event_subscriber_.get()); + } + + void InsertEvents() { + // Video events + cast_environment_->Logging()->InsertFrameEventWithDelay( + testing_clock_->NowTicks(), FRAME_PLAYOUT, VIDEO_EVENT, + /*rtp_timestamp*/ 100u, /*frame_id*/ 2u, + base::TimeDelta::FromMilliseconds(kDelayMs)); + cast_environment_->Logging()->InsertFrameEvent( + testing_clock_->NowTicks(), FRAME_DECODED, VIDEO_EVENT, + /*rtp_timestamp*/ 200u, /*frame_id*/ 1u); + cast_environment_->Logging()->InsertPacketEvent( + testing_clock_->NowTicks(), PACKET_RECEIVED, VIDEO_EVENT, + /*rtp_timestamp */ 200u, /*frame_id*/ 2u, /*packet_id*/ 1u, + /*max_packet_id*/ 10u, /*size*/ 1024u); + + // Audio events + cast_environment_->Logging()->InsertFrameEventWithDelay( + testing_clock_->NowTicks(), FRAME_PLAYOUT, AUDIO_EVENT, + /*rtp_timestamp*/ 300u, /*frame_id*/ 4u, + base::TimeDelta::FromMilliseconds(kDelayMs)); + cast_environment_->Logging()->InsertFrameEvent( + testing_clock_->NowTicks(), FRAME_DECODED, AUDIO_EVENT, + /*rtp_timestamp*/ 400u, /*frame_id*/ 3u); + cast_environment_->Logging()->InsertPacketEvent( + testing_clock_->NowTicks(), PACKET_RECEIVED, AUDIO_EVENT, + /*rtp_timestamp */ 400u, /*frame_id*/ 5u, /*packet_id*/ 1u, + /*max_packet_id*/ 10u, /*size*/ 128u); + + // Unrelated events + cast_environment_->Logging()->InsertFrameEvent(testing_clock_->NowTicks(), + FRAME_CAPTURE_END, + VIDEO_EVENT, + /*rtp_timestamp*/ 100u, + /*frame_id*/ 1u); + cast_environment_->Logging()->InsertFrameEvent(testing_clock_->NowTicks(), + FRAME_CAPTURE_END, + AUDIO_EVENT, + /*rtp_timestamp*/ 100u, + /*frame_id*/ 1u); + } + + base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment. + scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_; + scoped_refptr<CastEnvironment> cast_environment_; + scoped_ptr<ReceiverRtcpEventSubscriber> event_subscriber_; +}; + +TEST_F(ReceiverRtcpEventSubscriberTest, LogVideoEvents) { + Init(VIDEO_EVENT); + + InsertEvents(); + ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; + event_subscriber_->GetRtcpEventsAndReset(&rtcp_events); + EXPECT_EQ(3u, rtcp_events.size()); +} + +TEST_F(ReceiverRtcpEventSubscriberTest, LogAudioEvents) { + Init(AUDIO_EVENT); + + InsertEvents(); + ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; + event_subscriber_->GetRtcpEventsAndReset(&rtcp_events); + EXPECT_EQ(3u, rtcp_events.size()); +} + +TEST_F(ReceiverRtcpEventSubscriberTest, DropEventsWhenSizeExceeded) { + Init(VIDEO_EVENT); + + for (uint32 i = 1u; i <= 10u; ++i) { + cast_environment_->Logging()->InsertFrameEvent( + testing_clock_->NowTicks(), FRAME_DECODED, VIDEO_EVENT, + /*rtp_timestamp*/ i * 10, /*frame_id*/ i); + } + + ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; + event_subscriber_->GetRtcpEventsAndReset(&rtcp_events); + EXPECT_EQ(10u, rtcp_events.size()); +} + +} // namespace cast +} // namespace media diff --git a/chromium/media/cast/rtcp/rtcp.cc b/chromium/media/cast/rtcp/rtcp.cc index 4ea4bc99ba9..480b2ac3990 100644 --- a/chromium/media/cast/rtcp/rtcp.cc +++ b/chromium/media/cast/rtcp/rtcp.cc @@ -4,6 +4,7 @@ #include "media/cast/rtcp/rtcp.h" +#include "base/big_endian.h" #include "base/rand_util.h" #include "media/cast/cast_config.h" #include "media/cast/cast_defines.h" @@ -12,28 +13,22 @@ #include "media/cast/rtcp/rtcp_receiver.h" #include "media/cast/rtcp/rtcp_sender.h" #include "media/cast/rtcp/rtcp_utility.h" -#include "net/base/big_endian.h" +#include "media/cast/transport/cast_transport_defines.h" namespace media { namespace cast { static const int kMaxRttMs = 10000; // 10 seconds. - -// Time limit for received RTCP messages when we stop using it for lip-sync. -static const int64 kMaxDiffSinceReceivedRtcpMs = 100000; // 100 seconds. +static const int kMaxDelay = 2000; class LocalRtcpRttFeedback : public RtcpRttFeedback { public: - explicit LocalRtcpRttFeedback(Rtcp* rtcp) - : rtcp_(rtcp) { - } + explicit LocalRtcpRttFeedback(Rtcp* rtcp) : rtcp_(rtcp) {} virtual void OnReceivedDelaySinceLastReport( - uint32 receivers_ssrc, - uint32 last_report, + uint32 receivers_ssrc, uint32 last_report, uint32 delay_since_last_report) OVERRIDE { - rtcp_->OnReceivedDelaySinceLastReport(receivers_ssrc, - last_report, + rtcp_->OnReceivedDelaySinceLastReport(receivers_ssrc, last_report, delay_since_last_report); } @@ -41,31 +36,14 @@ class LocalRtcpRttFeedback : public RtcpRttFeedback { Rtcp* rtcp_; }; -RtcpCastMessage::RtcpCastMessage(uint32 media_ssrc) - : media_ssrc_(media_ssrc) {} - -RtcpCastMessage::~RtcpCastMessage() {} - -RtcpNackMessage::RtcpNackMessage() {} -RtcpNackMessage::~RtcpNackMessage() {} - -RtcpRembMessage::RtcpRembMessage() {} -RtcpRembMessage::~RtcpRembMessage() {} - -RtcpReceiverFrameLogMessage::RtcpReceiverFrameLogMessage(uint32 timestamp) - : rtp_timestamp_(timestamp) {} - -RtcpReceiverFrameLogMessage::~RtcpReceiverFrameLogMessage() {} - class LocalRtcpReceiverFeedback : public RtcpReceiverFeedback { public: LocalRtcpReceiverFeedback(Rtcp* rtcp, - scoped_refptr<CastEnvironment> cast_environment) - : rtcp_(rtcp), cast_environment_(cast_environment) { - } + scoped_refptr<CastEnvironment> cast_environment) + : rtcp_(rtcp), cast_environment_(cast_environment) {} virtual void OnReceivedSenderReport( - const RtcpSenderInfo& remote_sender_info) OVERRIDE { + const transport::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) { @@ -85,80 +63,9 @@ class LocalRtcpReceiverFeedback : public RtcpReceiverFeedback { rtcp_->OnReceivedSendReportRequest(); } - virtual void OnReceivedReceiverLog( - const RtcpReceiverLogMessage& receiver_log) OVERRIDE { - // Add received log messages into our log system. - RtcpReceiverLogMessage::const_iterator it = receiver_log.begin(); - - for (; it != receiver_log.end(); ++it) { - uint32 rtp_timestamp = it->rtp_timestamp_; - - RtcpReceiverEventLogMessages::const_iterator event_it = - it->event_log_messages_.begin(); - for (; event_it != it->event_log_messages_.end(); ++event_it) { - // TODO(pwestin): we need to send in the event_it->event_timestamp to - // the log system too. - switch (event_it->type) { - case kPacketReceived: - cast_environment_->Logging()->InsertPacketEvent(kPacketReceived, - rtp_timestamp, kFrameIdUnknown, event_it->packet_id, 0, 0); - break; - case kAckSent: - case kAudioFrameDecoded: - case kVideoFrameDecoded: - cast_environment_->Logging()->InsertFrameEvent(event_it->type, - rtp_timestamp, kFrameIdUnknown); - break; - case kAudioPlayoutDelay: - case kVideoRenderDelay: - cast_environment_->Logging()->InsertFrameEventWithDelay( - event_it->type, rtp_timestamp, kFrameIdUnknown, - event_it->delay_delta); - break; - default: - VLOG(2) << "Received log message via RTCP that we did not expect: " - << static_cast<int>(event_it->type); - break; - } - } - } - } - - virtual void OnReceivedSenderLog( - const RtcpSenderLogMessage& sender_log) OVERRIDE { - RtcpSenderLogMessage::const_iterator it = sender_log.begin(); - - for (; it != sender_log.end(); ++it) { - uint32 rtp_timestamp = it->rtp_timestamp; - CastLoggingEvent log_event = kUnknown; - - // These events are provided to know the status of frames that never - // reached the receiver. The timing information for these events are not - // relevant and is not sent over the wire. - switch (it->frame_status) { - case kRtcpSenderFrameStatusDroppedByFlowControl: - // A frame that have been dropped by the flow control would have - // kVideoFrameCaptured as its last event in the log. - log_event = kVideoFrameCaptured; - break; - case kRtcpSenderFrameStatusDroppedByEncoder: - // A frame that have been dropped by the encoder would have - // kVideoFrameSentToEncoder as its last event in the log. - log_event = kVideoFrameSentToEncoder; - break; - case kRtcpSenderFrameStatusSentToNetwork: - // A frame that have be encoded is always sent to the network. We - // do not add a new log entry for this. - log_event = kVideoFrameEncoded; - break; - default: - continue; - } - // TODO(pwestin): how do we handle the truncated rtp_timestamp? - // Add received log messages into our log system. - cast_environment_->Logging()->InsertFrameEvent(log_event, rtp_timestamp, - kFrameIdUnknown); - } + virtual void OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log) + OVERRIDE { + rtcp_->OnReceivedReceiverLog(receiver_log); } private: @@ -168,36 +75,34 @@ class LocalRtcpReceiverFeedback : public RtcpReceiverFeedback { Rtcp::Rtcp(scoped_refptr<CastEnvironment> cast_environment, RtcpSenderFeedback* sender_feedback, - PacedPacketSender* paced_packet_sender, - RtpSenderStatistics* rtp_sender_statistics, - RtpReceiverStatistics* rtp_receiver_statistics, - RtcpMode rtcp_mode, - const base::TimeDelta& rtcp_interval, - uint32 local_ssrc, - uint32 remote_ssrc, - const std::string& c_name) - : rtcp_interval_(rtcp_interval), + transport::CastTransportSender* const transport_sender, + transport::PacedPacketSender* paced_packet_sender, + RtpReceiverStatistics* rtp_receiver_statistics, RtcpMode rtcp_mode, + const base::TimeDelta& rtcp_interval, uint32 local_ssrc, + uint32 remote_ssrc, const std::string& c_name, + EventMediaType event_media_type) + : cast_environment_(cast_environment), + transport_sender_(transport_sender), + rtcp_interval_(rtcp_interval), rtcp_mode_(rtcp_mode), local_ssrc_(local_ssrc), remote_ssrc_(remote_ssrc), - rtp_sender_statistics_(rtp_sender_statistics), + c_name_(c_name), + event_media_type_(event_media_type), rtp_receiver_statistics_(rtp_receiver_statistics), - receiver_feedback_(new LocalRtcpReceiverFeedback(this, cast_environment)), rtt_feedback_(new LocalRtcpRttFeedback(this)), + receiver_feedback_(new LocalRtcpReceiverFeedback(this, cast_environment)), rtcp_sender_(new RtcpSender(cast_environment, paced_packet_sender, local_ssrc, c_name)), - last_report_received_(0), - last_received_rtp_timestamp_(0), - last_received_ntp_seconds_(0), - last_received_ntp_fraction_(0), + last_report_truncated_ntp_(0), + local_clock_ahead_by_(ClockDriftSmoother::GetDefaultTimeConstant()), + lip_sync_rtp_timestamp_(0), + lip_sync_ntp_timestamp_(0), min_rtt_(base::TimeDelta::FromMilliseconds(kMaxRttMs)), - number_of_rtt_in_avg_(0), - cast_environment_(cast_environment) { - rtcp_receiver_.reset(new RtcpReceiver(cast_environment, - sender_feedback, + number_of_rtt_in_avg_(0) { + rtcp_receiver_.reset(new RtcpReceiver(cast_environment, sender_feedback, receiver_feedback_.get(), - rtt_feedback_.get(), - local_ssrc)); + rtt_feedback_.get(), local_ssrc)); rtcp_receiver_->SetRemoteSSRC(remote_ssrc); } @@ -209,7 +114,8 @@ bool Rtcp::IsRtcpPacket(const uint8* packet, size_t length) { if (length < kMinLengthOfRtcp) return false; uint8 packet_type = packet[1]; - if (packet_type >= kPacketTypeLow && packet_type <= kPacketTypeHigh) { + if (packet_type >= transport::kPacketTypeLow && + packet_type <= transport::kPacketTypeHigh) { return true; } return false; @@ -219,7 +125,8 @@ bool Rtcp::IsRtcpPacket(const uint8* packet, size_t length) { uint32 Rtcp::GetSsrcOfSender(const uint8* rtcp_buffer, size_t length) { DCHECK_GE(length, kMinLengthOfRtcp) << "Invalid RTCP packet"; uint32 ssrc_of_sender; - net::BigEndianReader big_endian_reader(rtcp_buffer, length); + 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; @@ -242,117 +149,145 @@ void Rtcp::IncomingRtcpPacket(const uint8* rtcp_buffer, size_t length) { rtcp_receiver_->IncomingRtcpPacket(&rtcp_parser); } -void Rtcp::SendRtcpFromRtpReceiver(const RtcpCastMessage* cast_message, - RtcpReceiverLogMessage* receiver_log) { +void Rtcp::SendRtcpFromRtpReceiver( + const RtcpCastMessage* cast_message, + const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events) { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); uint32 packet_type_flags = 0; base::TimeTicks now = cast_environment_->Clock()->NowTicks(); - RtcpReportBlock report_block; + transport::RtcpReportBlock report_block; RtcpReceiverReferenceTimeReport rrtr; + // Attach our NTP to all RTCP packets; with this information a "smart" sender + // can make decisions based on how old the RTCP message is. + packet_type_flags |= transport::kRtcpRrtr; + ConvertTimeTicksToNtp(now, &rrtr.ntp_seconds, &rrtr.ntp_fraction); + SaveLastSentNtpTime(now, rrtr.ntp_seconds, rrtr.ntp_fraction); + if (cast_message) { - packet_type_flags |= RtcpSender::kRtcpCast; - cast_environment_->Logging()->InsertGenericEvent(kAckSent, - cast_message->ack_frame_id_); + packet_type_flags |= transport::kRtcpCast; } - if (receiver_log) { - packet_type_flags |= RtcpSender::kRtcpReceiverLog; + if (rtcp_events) { + packet_type_flags |= transport::kRtcpReceiverLog; } if (rtcp_mode_ == kRtcpCompound || now >= next_time_to_send_rtcp_) { - packet_type_flags |= RtcpSender::kRtcpRr; + packet_type_flags |= transport::kRtcpRr; - report_block.remote_ssrc = 0; // Not needed to set send side. + report_block.remote_ssrc = 0; // Not needed to set send side. report_block.media_ssrc = remote_ssrc_; // SSRC of the RTP packet sender. if (rtp_receiver_statistics_) { rtp_receiver_statistics_->GetStatistics( - &report_block.fraction_lost, - &report_block.cumulative_lost, - &report_block.extended_high_sequence_number, - &report_block.jitter); - cast_environment_->Logging()->InsertGenericEvent(kJitterMs, - report_block.jitter); - cast_environment_->Logging()->InsertGenericEvent(kPacketLoss, - report_block.fraction_lost); - + &report_block.fraction_lost, &report_block.cumulative_lost, + &report_block.extended_high_sequence_number, &report_block.jitter); } - report_block.last_sr = last_report_received_; + report_block.last_sr = last_report_truncated_ntp_; if (!time_last_report_received_.is_null()) { uint32 delay_seconds = 0; uint32 delay_fraction = 0; base::TimeDelta delta = now - time_last_report_received_; - ConvertTimeToFractions(delta.InMicroseconds(), - &delay_seconds, + ConvertTimeToFractions(delta.InMicroseconds(), &delay_seconds, &delay_fraction); report_block.delay_since_last_sr = ConvertToNtpDiff(delay_seconds, delay_fraction); } else { report_block.delay_since_last_sr = 0; } - - packet_type_flags |= RtcpSender::kRtcpRrtr; - ConvertTimeTicksToNtp(now, &rrtr.ntp_seconds, &rrtr.ntp_fraction); - SaveLastSentNtpTime(now, rrtr.ntp_seconds, rrtr.ntp_fraction); UpdateNextTimeToSendRtcp(); } rtcp_sender_->SendRtcpFromRtpReceiver(packet_type_flags, &report_block, &rrtr, cast_message, - receiver_log); + rtcp_events, + target_delay_ms_); } -void Rtcp::SendRtcpFromRtpSender( - RtcpSenderLogMessage* sender_log_message) { - uint32 packet_type_flags = RtcpSender::kRtcpSr; - base::TimeTicks now = cast_environment_->Clock()->NowTicks(); - - if (sender_log_message) { - packet_type_flags |= RtcpSender::kRtcpSenderLog; - } - - RtcpSenderInfo sender_info; - if (rtp_sender_statistics_) { - rtp_sender_statistics_->GetStatistics(now, &sender_info); - } else { - memset(&sender_info, 0, sizeof(sender_info)); - } - SaveLastSentNtpTime(now, sender_info.ntp_seconds, sender_info.ntp_fraction); - - RtcpDlrrReportBlock dlrr; +void Rtcp::SendRtcpFromRtpSender(base::TimeTicks current_time, + uint32 current_time_as_rtp_timestamp) { + DCHECK(transport_sender_); + uint32 packet_type_flags = transport::kRtcpSr; + uint32 current_ntp_seconds = 0; + uint32 current_ntp_fractions = 0; + ConvertTimeTicksToNtp(current_time, ¤t_ntp_seconds, + ¤t_ntp_fractions); + SaveLastSentNtpTime(current_time, current_ntp_seconds, + current_ntp_fractions); + + transport::RtcpDlrrReportBlock dlrr; if (!time_last_report_received_.is_null()) { - packet_type_flags |= RtcpSender::kRtcpDlrr; - dlrr.last_rr = last_report_received_; + packet_type_flags |= transport::kRtcpDlrr; + dlrr.last_rr = last_report_truncated_ntp_; uint32 delay_seconds = 0; uint32 delay_fraction = 0; - base::TimeDelta delta = now - time_last_report_received_; - ConvertTimeToFractions(delta.InMicroseconds(), - &delay_seconds, + base::TimeDelta delta = current_time - time_last_report_received_; + ConvertTimeToFractions(delta.InMicroseconds(), &delay_seconds, &delay_fraction); dlrr.delay_since_last_rr = ConvertToNtpDiff(delay_seconds, delay_fraction); } - rtcp_sender_->SendRtcpFromRtpSender(packet_type_flags, - &sender_info, - &dlrr, - sender_log_message); + transport_sender_->SendRtcpFromRtpSender( + packet_type_flags, current_ntp_seconds, current_ntp_fractions, + current_time_as_rtp_timestamp, dlrr, local_ssrc_, c_name_); UpdateNextTimeToSendRtcp(); } void Rtcp::OnReceivedNtp(uint32 ntp_seconds, uint32 ntp_fraction) { - last_report_received_ = (ntp_seconds << 16) + (ntp_fraction >> 16); + last_report_truncated_ntp_ = ConvertToNtpDiff(ntp_seconds, ntp_fraction); - base::TimeTicks now = cast_environment_->Clock()->NowTicks(); + const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); time_last_report_received_ = now; + + // TODO(miu): This clock offset calculation does not account for packet + // transit time over the network. End2EndTest.EvilNetwork confirms that this + // contributes a very significant source of error here. Fix this along with + // the RTT clean-up. + const base::TimeDelta measured_offset = + now - ConvertNtpToTimeTicks(ntp_seconds, ntp_fraction); + local_clock_ahead_by_.Update(now, measured_offset); + if (measured_offset < local_clock_ahead_by_.Current()) { + // Logically, the minimum offset between the clocks has to be the correct + // one. For example, the time it took to transmit the current report may + // have been lower than usual, and so some of the error introduced by the + // transmission time can be eliminated. + local_clock_ahead_by_.Reset(now, measured_offset); + } + VLOG(1) << "Local clock is ahead of the remote clock by: " + << "measured=" << measured_offset.InMicroseconds() << " usec, " + << "filtered=" << local_clock_ahead_by_.Current().InMicroseconds() + << " usec."; } -void Rtcp::OnReceivedLipSyncInfo(uint32 rtp_timestamp, - uint32 ntp_seconds, +void Rtcp::OnReceivedLipSyncInfo(uint32 rtp_timestamp, uint32 ntp_seconds, uint32 ntp_fraction) { - last_received_rtp_timestamp_ = rtp_timestamp; - last_received_ntp_seconds_ = ntp_seconds; - last_received_ntp_fraction_ = ntp_fraction; + if (ntp_seconds == 0) { + NOTREACHED(); + return; + } + lip_sync_rtp_timestamp_ = rtp_timestamp; + lip_sync_ntp_timestamp_ = + (static_cast<uint64>(ntp_seconds) << 32) | ntp_fraction; +} + +bool Rtcp::GetLatestLipSyncTimes(uint32* rtp_timestamp, + base::TimeTicks* reference_time) const { + if (!lip_sync_ntp_timestamp_) + return false; + + const base::TimeTicks local_reference_time = + ConvertNtpToTimeTicks(static_cast<uint32>(lip_sync_ntp_timestamp_ >> 32), + static_cast<uint32>(lip_sync_ntp_timestamp_)) + + local_clock_ahead_by_.Current(); + + // Sanity-check: Getting regular lip sync updates? + DCHECK((cast_environment_->Clock()->NowTicks() - local_reference_time) < + base::TimeDelta::FromMinutes(1)); + + *rtp_timestamp = lip_sync_rtp_timestamp_; + *reference_time = local_reference_time; + return true; } void Rtcp::OnReceivedSendReportRequest() { @@ -362,35 +297,13 @@ void Rtcp::OnReceivedSendReportRequest() { next_time_to_send_rtcp_ = now; } -bool Rtcp::RtpTimestampInSenderTime(int frequency, uint32 rtp_timestamp, - base::TimeTicks* rtp_timestamp_in_ticks) const { - if (last_received_ntp_seconds_ == 0) return false; - - int wrap = CheckForWrapAround(rtp_timestamp, last_received_rtp_timestamp_); - int64 rtp_timestamp_int64 = rtp_timestamp; - int64 last_received_rtp_timestamp_int64 = last_received_rtp_timestamp_; - - if (wrap == 1) { - rtp_timestamp_int64 += (1LL << 32); - } else if (wrap == -1) { - last_received_rtp_timestamp_int64 += (1LL << 32); - } - // Time since the last RTCP message. - // Note that this can be negative since we can compare a rtp timestamp from - // a frame older than the last received RTCP message. - int64 rtp_timestamp_diff = - rtp_timestamp_int64 - last_received_rtp_timestamp_int64; - - int frequency_khz = frequency / 1000; - int64 rtp_time_diff_ms = rtp_timestamp_diff / frequency_khz; - - // Sanity check. - if (abs(rtp_time_diff_ms) > kMaxDiffSinceReceivedRtcpMs) return false; +void Rtcp::SetCastReceiverEventHistorySize(size_t size) { + rtcp_receiver_->SetCastReceiverEventHistorySize(size); +} - *rtp_timestamp_in_ticks = ConvertNtpToTimeTicks(last_received_ntp_seconds_, - last_received_ntp_fraction_) + - base::TimeDelta::FromMilliseconds(rtp_time_diff_ms); - return true; +void Rtcp::SetTargetDelay(base::TimeDelta target_delay) { + DCHECK(target_delay.InMilliseconds() < kMaxDelay); + target_delay_ms_ = static_cast<uint16>(target_delay.InMilliseconds()); } void Rtcp::OnReceivedDelaySinceLastReport(uint32 receivers_ssrc, @@ -401,8 +314,8 @@ void Rtcp::OnReceivedDelaySinceLastReport(uint32 receivers_ssrc, return; // Feedback on another report. } - base::TimeDelta sender_delay = cast_environment_->Clock()->NowTicks() - - it->second; + base::TimeDelta sender_delay = + cast_environment_->Clock()->NowTicks() - it->second; UpdateRtt(sender_delay, ConvertFromNtpDiff(delay_since_last_report)); } @@ -411,9 +324,8 @@ void Rtcp::SaveLastSentNtpTime(const base::TimeTicks& now, uint32 last_ntp_fraction) { // Make sure |now| is always greater than the last element in // |last_reports_sent_queue_|. - if (!last_reports_sent_queue_.empty()) { + if (!last_reports_sent_queue_.empty()) DCHECK(now >= last_reports_sent_queue_.back().second); - } uint32 last_report = ConvertToNtpDiff(last_ntp_seconds, last_ntp_fraction); last_reports_sent_map_[last_report] = now; @@ -436,66 +348,85 @@ void Rtcp::SaveLastSentNtpTime(const base::TimeTicks& now, void Rtcp::UpdateRtt(const base::TimeDelta& sender_delay, const base::TimeDelta& receiver_delay) { base::TimeDelta rtt = sender_delay - receiver_delay; + // TODO(miu): Find out why this must be >= 1 ms, and remove the fudge if it's + // bogus. rtt = std::max(rtt, base::TimeDelta::FromMilliseconds(1)); rtt_ = rtt; min_rtt_ = std::min(min_rtt_, rtt); max_rtt_ = std::max(max_rtt_, rtt); + // TODO(miu): Replace "average for all time" with an EWMA, or suitable + // "average over recent past" mechanism. if (number_of_rtt_in_avg_ != 0) { - float ac = static_cast<float>(number_of_rtt_in_avg_); - avg_rtt_ms_= ((ac / (ac + 1.0)) * avg_rtt_ms_) + - ((1.0 / (ac + 1.0)) * rtt.InMilliseconds()); + const double ac = static_cast<double>(number_of_rtt_in_avg_); + avg_rtt_ms_ = ((ac / (ac + 1.0)) * avg_rtt_ms_) + + ((1.0 / (ac + 1.0)) * rtt.InMillisecondsF()); } else { - avg_rtt_ms_ = rtt.InMilliseconds(); + avg_rtt_ms_ = rtt.InMillisecondsF(); } number_of_rtt_in_avg_++; } -bool Rtcp::Rtt(base::TimeDelta* rtt, - base::TimeDelta* avg_rtt, - base::TimeDelta* min_rtt, - base::TimeDelta* max_rtt) const { +bool Rtcp::Rtt(base::TimeDelta* rtt, base::TimeDelta* avg_rtt, + base::TimeDelta* min_rtt, base::TimeDelta* max_rtt) const { DCHECK(rtt) << "Invalid argument"; DCHECK(avg_rtt) << "Invalid argument"; DCHECK(min_rtt) << "Invalid argument"; DCHECK(max_rtt) << "Invalid argument"; if (number_of_rtt_in_avg_ == 0) return false; - cast_environment_->Logging()->InsertGenericEvent(kRttMs, - rtt->InMilliseconds()); *rtt = rtt_; - *avg_rtt = base::TimeDelta::FromMilliseconds(avg_rtt_ms_); + *avg_rtt = base::TimeDelta::FromMillisecondsD(avg_rtt_ms_); *min_rtt = min_rtt_; *max_rtt = max_rtt_; return true; } -int Rtcp::CheckForWrapAround(uint32 new_timestamp, - uint32 old_timestamp) const { - if (new_timestamp < old_timestamp) { - // This difference should be less than -2^31 if we have had a wrap around - // (e.g. |new_timestamp| = 1, |rtcp_rtp_timestamp| = 2^32 - 1). Since it is - // cast to a int32_t, it should be positive. - if (static_cast<int32>(new_timestamp - old_timestamp) > 0) { - return 1; // Forward wrap around. - } - } else if (static_cast<int32>(old_timestamp - new_timestamp) > 0) { - // This difference should be less than -2^31 if we have had a backward wrap - // around. Since it is cast to a int32, it should be positive. - return -1; - } - return 0; -} - void Rtcp::UpdateNextTimeToSendRtcp() { int random = base::RandInt(0, 999); - base::TimeDelta time_to_next = (rtcp_interval_ / 2) + - (rtcp_interval_ * random / 1000); + base::TimeDelta time_to_next = + (rtcp_interval_ / 2) + (rtcp_interval_ * random / 1000); base::TimeTicks now = cast_environment_->Clock()->NowTicks(); next_time_to_send_rtcp_ = now + time_to_next; } +void Rtcp::OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log) { + // Add received log messages into our log system. + RtcpReceiverLogMessage::const_iterator it = receiver_log.begin(); + for (; it != receiver_log.end(); ++it) { + uint32 rtp_timestamp = it->rtp_timestamp_; + + RtcpReceiverEventLogMessages::const_iterator event_it = + it->event_log_messages_.begin(); + for (; event_it != it->event_log_messages_.end(); ++event_it) { + switch (event_it->type) { + case PACKET_RECEIVED: + cast_environment_->Logging()->InsertPacketEvent( + event_it->event_timestamp, event_it->type, + event_media_type_, rtp_timestamp, + kFrameIdUnknown, event_it->packet_id, 0, 0); + break; + case FRAME_ACK_SENT: + case FRAME_DECODED: + cast_environment_->Logging()->InsertFrameEvent( + event_it->event_timestamp, event_it->type, event_media_type_, + rtp_timestamp, kFrameIdUnknown); + break; + case FRAME_PLAYOUT: + cast_environment_->Logging()->InsertFrameEventWithDelay( + event_it->event_timestamp, event_it->type, event_media_type_, + rtp_timestamp, kFrameIdUnknown, event_it->delay_delta); + break; + default: + VLOG(2) << "Received log message via RTCP that we did not expect: " + << static_cast<int>(event_it->type); + break; + } + } + } +} + } // namespace cast } // namespace media diff --git a/chromium/media/cast/rtcp/rtcp.gyp b/chromium/media/cast/rtcp/rtcp.gyp deleted file mode 100644 index 14119988c8e..00000000000 --- a/chromium/media/cast/rtcp/rtcp.gyp +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'targets': [ - { - 'target_name': 'cast_rtcp', - 'type': 'static_library', - 'include_dirs': [ - '<(DEPTH)/', - ], - 'sources': [ - 'rtcp_defines.h', - 'rtcp.h', - 'rtcp.cc', - 'rtcp_receiver.cc', - 'rtcp_receiver.h', - 'rtcp_sender.cc', - 'rtcp_sender.h', - 'rtcp_utility.cc', - 'rtcp_utility.h', - ], # source - 'dependencies': [ - '<(DEPTH)/base/base.gyp:base', - '<(DEPTH)/net/net.gyp:net', - ], - }, - { - 'target_name': 'cast_rtcp_test', - 'type': 'static_library', - 'include_dirs': [ - '<(DEPTH)/', - ], - 'sources': [ - 'test_rtcp_packet_builder.cc', - 'test_rtcp_packet_builder.h', - ], # source - 'dependencies': [ - 'cast_rtcp', - '<(DEPTH)/testing/gtest.gyp:gtest', - ], - }, - ], -} - diff --git a/chromium/media/cast/rtcp/rtcp.h b/chromium/media/cast/rtcp/rtcp.h index aa083a5a4dd..9d0184f9033 100644 --- a/chromium/media/cast/rtcp/rtcp.h +++ b/chromium/media/cast/rtcp/rtcp.h @@ -5,20 +5,23 @@ #ifndef MEDIA_CAST_RTCP_RTCP_H_ #define MEDIA_CAST_RTCP_RTCP_H_ -#include <list> #include <map> #include <queue> -#include <set> #include <string> #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "base/time/tick_clock.h" #include "base/time/time.h" +#include "media/cast/base/clock_drift_smoother.h" #include "media/cast/cast_config.h" #include "media/cast/cast_defines.h" #include "media/cast/cast_environment.h" +#include "media/cast/rtcp/receiver_rtcp_event_subscriber.h" #include "media/cast/rtcp/rtcp_defines.h" +#include "media/cast/transport/cast_transport_defines.h" +#include "media/cast/transport/cast_transport_sender.h" +#include "media/cast/transport/pacing/paced_sender.h" namespace media { namespace cast { @@ -40,14 +43,6 @@ class RtcpSenderFeedback { virtual ~RtcpSenderFeedback() {} }; -class RtpSenderStatistics { - public: - virtual void GetStatistics(const base::TimeTicks& now, - RtcpSenderInfo* sender_info) = 0; - - virtual ~RtpSenderStatistics() {} -}; - class RtpReceiverStatistics { public: virtual void GetStatistics(uint8* fraction_lost, @@ -60,16 +55,20 @@ class RtpReceiverStatistics { class Rtcp { public: + // Rtcp accepts two transports, one to be used by Cast senders + // (CastTransportSender) only, and the other (PacedPacketSender) should only + // be used by the Cast receivers and test applications. Rtcp(scoped_refptr<CastEnvironment> cast_environment, RtcpSenderFeedback* sender_feedback, - PacedPacketSender* paced_packet_sender, - RtpSenderStatistics* rtp_sender_statistics, + transport::CastTransportSender* const transport_sender, // Send-side. + transport::PacedPacketSender* paced_packet_sender, // Receive side. RtpReceiverStatistics* rtp_receiver_statistics, RtcpMode rtcp_mode, const base::TimeDelta& rtcp_interval, uint32 local_ssrc, uint32 remote_ssrc, - const std::string& c_name); + const std::string& c_name, + EventMediaType event_media_type); virtual ~Rtcp(); @@ -78,35 +77,55 @@ class Rtcp { static uint32 GetSsrcOfSender(const uint8* rtcp_buffer, size_t length); base::TimeTicks TimeToSendNextRtcpReport(); - // |sender_log_message| is optional; without it no log messages will be - // attached to the RTCP report; instead a normal RTCP send report will be - // sent. - // Additionally if all messages in |sender_log_message| does - // not fit in the packet the |sender_log_message| will contain the remaining - // unsent messages. - void SendRtcpFromRtpSender(RtcpSenderLogMessage* sender_log_message); - - // |cast_message| and |receiver_log| is optional; if |cast_message| is + + // Send a RTCP sender report. + // |current_time| is the current time reported by a tick clock. + // |current_time_as_rtp_timestamp| is the corresponding RTP timestamp. + void SendRtcpFromRtpSender(base::TimeTicks current_time, + uint32 current_time_as_rtp_timestamp); + + // |cast_message| and |rtcp_events| is optional; if |cast_message| is // provided the RTCP receiver report will append a Cast message containing - // Acks and Nacks; if |receiver_log| is provided the RTCP receiver report will - // append the log messages. If no argument is set a normal RTCP receiver - // report will be sent. Additionally if all messages in |receiver_log| does - // not fit in the packet the |receiver_log| will contain the remaining unsent - // messages. - void SendRtcpFromRtpReceiver(const RtcpCastMessage* cast_message, - RtcpReceiverLogMessage* receiver_log); + // Acks and Nacks; if |rtcp_events| is provided the RTCP receiver report + // will append the log messages. + void SendRtcpFromRtpReceiver( + const RtcpCastMessage* cast_message, + const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events); void IncomingRtcpPacket(const uint8* rtcp_buffer, size_t length); - bool Rtt(base::TimeDelta* rtt, base::TimeDelta* avg_rtt, - base::TimeDelta* min_rtt, base::TimeDelta* max_rtt) const; - bool RtpTimestampInSenderTime(int frequency, - uint32 rtp_timestamp, - base::TimeTicks* rtp_timestamp_in_ticks) const; - protected: - int CheckForWrapAround(uint32 new_timestamp, - uint32 old_timestamp) const; + // TODO(miu): Clean up this method and downstream code: Only VideoSender uses + // this (for congestion control), and only the |rtt| and |avg_rtt| values, and + // it's not clear that any of the downstream code is doing the right thing + // with this data. + bool Rtt(base::TimeDelta* rtt, + base::TimeDelta* avg_rtt, + base::TimeDelta* min_rtt, + base::TimeDelta* max_rtt) const; + + bool is_rtt_available() const { return number_of_rtt_in_avg_ > 0; } + + // If available, returns true and sets the output arguments to the latest + // lip-sync timestamps gleaned from the sender reports. While the sender + // provides reference NTP times relative to its own wall clock, the + // |reference_time| returned here has been translated to the local + // CastEnvironment clock. + bool GetLatestLipSyncTimes(uint32* rtp_timestamp, + base::TimeTicks* reference_time) const; + + // Set the history size to record Cast receiver events. The event history is + // used to remove duplicates. The history will store at most |size| events. + void SetCastReceiverEventHistorySize(size_t size); + // Update the target delay. Will be added to every report sent back to the + // sender. + // TODO(miu): Remove this deprecated functionality. The sender ignores this. + void SetTargetDelay(base::TimeDelta target_delay); + + void OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log); + + protected: + void OnReceivedNtp(uint32 ntp_seconds, uint32 ntp_fraction); void OnReceivedLipSyncInfo(uint32 rtp_timestamp, uint32 ntp_seconds, uint32 ntp_fraction); @@ -115,13 +134,6 @@ class Rtcp { friend class LocalRtcpRttFeedback; friend class LocalRtcpReceiverFeedback; - void SendRtcp(const base::TimeTicks& now, - uint32 packet_type_flags, - uint32 media_ssrc, - const RtcpCastMessage* cast_message); - - void OnReceivedNtp(uint32 ntp_seconds, uint32 ntp_fraction); - void OnReceivedDelaySinceLastReport(uint32 receivers_ssrc, uint32 last_report, uint32 delay_since_last_report); @@ -133,17 +145,20 @@ class Rtcp { void UpdateNextTimeToSendRtcp(); - void SaveLastSentNtpTime(const base::TimeTicks& now, uint32 last_ntp_seconds, + void SaveLastSentNtpTime(const base::TimeTicks& now, + uint32 last_ntp_seconds, uint32 last_ntp_fraction); scoped_refptr<CastEnvironment> cast_environment_; + transport::CastTransportSender* const transport_sender_; const base::TimeDelta rtcp_interval_; const RtcpMode rtcp_mode_; const uint32 local_ssrc_; const uint32 remote_ssrc_; + const std::string c_name_; + const EventMediaType event_media_type_; // Not owned by this class. - RtpSenderStatistics* const rtp_sender_statistics_; RtpReceiverStatistics* const rtp_receiver_statistics_; scoped_ptr<LocalRtcpRttFeedback> rtt_feedback_; @@ -154,18 +169,33 @@ class Rtcp { base::TimeTicks next_time_to_send_rtcp_; RtcpSendTimeMap last_reports_sent_map_; RtcpSendTimeQueue last_reports_sent_queue_; + + // The truncated (i.e., 64-->32-bit) NTP timestamp provided in the last report + // from the remote peer, along with the local time at which the report was + // received. These values are used for ping-pong'ing NTP timestamps between + // the peers so that they can estimate the network's round-trip time. + uint32 last_report_truncated_ntp_; base::TimeTicks time_last_report_received_; - uint32 last_report_received_; - uint32 last_received_rtp_timestamp_; - uint32 last_received_ntp_seconds_; - uint32 last_received_ntp_fraction_; + // Maintains a smoothed offset between the local clock and the remote clock. + // Calling this member's Current() method is only valid if + // |time_last_report_received_| is not "null." + ClockDriftSmoother local_clock_ahead_by_; + + // Latest "lip sync" info from the sender. The sender provides the RTP + // timestamp of some frame of its choosing and also a corresponding reference + // NTP timestamp sampled from a clock common to all media streams. It is + // expected that the sender will update this data regularly and in a timely + // manner (e.g., about once per second). + uint32 lip_sync_rtp_timestamp_; + uint64 lip_sync_ntp_timestamp_; base::TimeDelta rtt_; base::TimeDelta min_rtt_; base::TimeDelta max_rtt_; int number_of_rtt_in_avg_; - float avg_rtt_ms_; + double avg_rtt_ms_; + uint16 target_delay_ms_; DISALLOW_COPY_AND_ASSIGN(Rtcp); }; diff --git a/chromium/media/cast/rtcp/rtcp_defines.cc b/chromium/media/cast/rtcp/rtcp_defines.cc new file mode 100644 index 00000000000..214100d4d9e --- /dev/null +++ b/chromium/media/cast/rtcp/rtcp_defines.cc @@ -0,0 +1,49 @@ +// 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/rtcp/rtcp_defines.h" + +#include "media/cast/logging/logging_defines.h" + +namespace media { +namespace cast { + +RtcpCastMessage::RtcpCastMessage(uint32 media_ssrc) + : media_ssrc_(media_ssrc), ack_frame_id_(0u), target_delay_ms_(0) {} +RtcpCastMessage::~RtcpCastMessage() {} + +void RtcpCastMessage::Copy(const RtcpCastMessage& cast_message) { + media_ssrc_ = cast_message.media_ssrc_; + ack_frame_id_ = cast_message.ack_frame_id_; + target_delay_ms_ = cast_message.target_delay_ms_; + missing_frames_and_packets_ = cast_message.missing_frames_and_packets_; +} + +RtcpReceiverEventLogMessage::RtcpReceiverEventLogMessage() + : type(UNKNOWN), packet_id(0u) {} +RtcpReceiverEventLogMessage::~RtcpReceiverEventLogMessage() {} + +RtcpReceiverFrameLogMessage::RtcpReceiverFrameLogMessage(uint32 timestamp) + : rtp_timestamp_(timestamp) {} +RtcpReceiverFrameLogMessage::~RtcpReceiverFrameLogMessage() {} + +RtcpRpsiMessage::RtcpRpsiMessage() + : remote_ssrc(0u), payload_type(0u), picture_id(0u) {} +RtcpRpsiMessage::~RtcpRpsiMessage() {} + +RtcpNackMessage::RtcpNackMessage() : remote_ssrc(0u) {} +RtcpNackMessage::~RtcpNackMessage() {} + +RtcpRembMessage::RtcpRembMessage() : remb_bitrate(0u) {} +RtcpRembMessage::~RtcpRembMessage() {} + +RtcpReceiverReferenceTimeReport::RtcpReceiverReferenceTimeReport() + : remote_ssrc(0u), ntp_seconds(0u), ntp_fraction(0u) {} +RtcpReceiverReferenceTimeReport::~RtcpReceiverReferenceTimeReport() {} + +RtcpEvent::RtcpEvent() : type(UNKNOWN), packet_id(0u) {} +RtcpEvent::~RtcpEvent() {} + +} // namespace cast +} // namespace media diff --git a/chromium/media/cast/rtcp/rtcp_defines.h b/chromium/media/cast/rtcp/rtcp_defines.h index 0277bd1feaf..31795648c64 100644 --- a/chromium/media/cast/rtcp/rtcp_defines.h +++ b/chromium/media/cast/rtcp/rtcp_defines.h @@ -5,45 +5,42 @@ #ifndef MEDIA_CAST_RTCP_RTCP_DEFINES_H_ #define MEDIA_CAST_RTCP_RTCP_DEFINES_H_ -#include <list> #include <map> #include <set> #include "media/cast/cast_config.h" #include "media/cast/cast_defines.h" #include "media/cast/logging/logging_defines.h" +#include "media/cast/transport/cast_transport_defines.h" namespace media { namespace cast { +static const size_t kRtcpCastLogHeaderSize = 12; +static const size_t kRtcpReceiverFrameLogSize = 8; +static const size_t kRtcpReceiverEventLogSize = 4; + // Handle the per frame ACK and NACK messages. class RtcpCastMessage { public: explicit RtcpCastMessage(uint32 media_ssrc); ~RtcpCastMessage(); + void Copy(const RtcpCastMessage& cast_message); + uint32 media_ssrc_; uint32 ack_frame_id_; + uint16 target_delay_ms_; MissingFramesAndPacketsMap missing_frames_and_packets_; -}; - -// Log messages form sender to receiver. -enum RtcpSenderFrameStatus { - kRtcpSenderFrameStatusUnknown = 0, - kRtcpSenderFrameStatusDroppedByEncoder = 1, - kRtcpSenderFrameStatusDroppedByFlowControl = 2, - kRtcpSenderFrameStatusSentToNetwork = 3, -}; -struct RtcpSenderFrameLogMessage { - RtcpSenderFrameStatus frame_status; - uint32 rtp_timestamp; + DISALLOW_COPY_AND_ASSIGN(RtcpCastMessage); }; -typedef std::list<RtcpSenderFrameLogMessage> RtcpSenderLogMessage; - // Log messages from receiver to sender. struct RtcpReceiverEventLogMessage { + RtcpReceiverEventLogMessage(); + ~RtcpReceiverEventLogMessage(); + CastLoggingEvent type; base::TimeTicks event_timestamp; base::TimeDelta delay_delta; @@ -52,99 +49,84 @@ struct RtcpReceiverEventLogMessage { typedef std::list<RtcpReceiverEventLogMessage> RtcpReceiverEventLogMessages; -class RtcpReceiverFrameLogMessage { - public: +struct RtcpReceiverFrameLogMessage { explicit RtcpReceiverFrameLogMessage(uint32 rtp_timestamp); ~RtcpReceiverFrameLogMessage(); uint32 rtp_timestamp_; RtcpReceiverEventLogMessages event_log_messages_; -}; -typedef std::list<RtcpReceiverFrameLogMessage> RtcpReceiverLogMessage; - -struct RtcpSenderInfo { - // First three members are used for lipsync. - // First two members are used for rtt. - uint32 ntp_seconds; - uint32 ntp_fraction; - uint32 rtp_timestamp; - uint32 send_packet_count; - size_t send_octet_count; + // TODO(mikhal): Investigate what's the best way to allow adding + // DISALLOW_COPY_AND_ASSIGN, as currently it contradicts the implementation + // and possible changes have a big impact on design. }; -struct RtcpReportBlock { - uint32 remote_ssrc; // SSRC of sender of this report. - uint32 media_ssrc; // SSRC of the RTP packet sender. - uint8 fraction_lost; - uint32 cumulative_lost; // 24 bits valid. - uint32 extended_high_sequence_number; - uint32 jitter; - uint32 last_sr; - uint32 delay_since_last_sr; -}; +typedef std::list<RtcpReceiverFrameLogMessage> RtcpReceiverLogMessage; struct RtcpRpsiMessage { + RtcpRpsiMessage(); + ~RtcpRpsiMessage(); + uint32 remote_ssrc; uint8 payload_type; uint64 picture_id; }; -class RtcpNackMessage { - public: +struct RtcpNackMessage { RtcpNackMessage(); ~RtcpNackMessage(); uint32 remote_ssrc; std::list<uint16> nack_list; + + DISALLOW_COPY_AND_ASSIGN(RtcpNackMessage); }; -class RtcpRembMessage { - public: +struct RtcpRembMessage { RtcpRembMessage(); ~RtcpRembMessage(); uint32 remb_bitrate; std::list<uint32> remb_ssrcs; + + DISALLOW_COPY_AND_ASSIGN(RtcpRembMessage); }; struct RtcpReceiverReferenceTimeReport { + RtcpReceiverReferenceTimeReport(); + ~RtcpReceiverReferenceTimeReport(); + uint32 remote_ssrc; uint32 ntp_seconds; uint32 ntp_fraction; }; -struct RtcpDlrrReportBlock { - uint32 last_rr; - uint32 delay_since_last_rr; -}; - -inline bool operator==(RtcpReportBlock lhs, RtcpReportBlock rhs) { - return lhs.remote_ssrc == rhs.remote_ssrc && - lhs.media_ssrc == rhs.media_ssrc && - lhs.fraction_lost == rhs.fraction_lost && - lhs.cumulative_lost == rhs.cumulative_lost && - lhs.extended_high_sequence_number == rhs.extended_high_sequence_number && - lhs.jitter == rhs.jitter && - lhs.last_sr == rhs.last_sr && - lhs.delay_since_last_sr == rhs.delay_since_last_sr; -} - -inline bool operator==(RtcpSenderInfo lhs, RtcpSenderInfo rhs) { - return lhs.ntp_seconds == rhs.ntp_seconds && - lhs.ntp_fraction == rhs.ntp_fraction && - lhs.rtp_timestamp == rhs.rtp_timestamp && - lhs.send_packet_count == rhs.send_packet_count && - lhs.send_octet_count == rhs.send_octet_count; -} - inline bool operator==(RtcpReceiverReferenceTimeReport lhs, RtcpReceiverReferenceTimeReport rhs) { return lhs.remote_ssrc == rhs.remote_ssrc && - lhs.ntp_seconds == rhs.ntp_seconds && - lhs.ntp_fraction == rhs.ntp_fraction; + lhs.ntp_seconds == rhs.ntp_seconds && + lhs.ntp_fraction == rhs.ntp_fraction; } +// Struct used by raw event subscribers as an intermediate format before +// sending off to the other side via RTCP. +// (i.e., {Sender,Receiver}RtcpEventSubscriber) +struct RtcpEvent { + RtcpEvent(); + ~RtcpEvent(); + + CastLoggingEvent type; + + // Time of event logged. + base::TimeTicks timestamp; + + // Render/playout delay. Only set for FRAME_PLAYOUT events. + base::TimeDelta delay_delta; + + // Only set for packet events. + uint16 packet_id; +}; + } // namespace cast } // namespace media diff --git a/chromium/media/cast/rtcp/rtcp_receiver.cc b/chromium/media/cast/rtcp/rtcp_receiver.cc index 152ebc00d7b..3be8e921c46 100644 --- a/chromium/media/cast/rtcp/rtcp_receiver.cc +++ b/chromium/media/cast/rtcp/rtcp_receiver.cc @@ -6,50 +6,31 @@ #include "base/logging.h" #include "media/cast/rtcp/rtcp_utility.h" +#include "media/cast/transport/cast_transport_defines.h" namespace { -media::cast::CastLoggingEvent TranslateToLogEventFromWireFormat(uint8 event) { - switch (event) { - case 1: - return media::cast::kAckSent; - case 2: - return media::cast::kAudioPlayoutDelay; - case 3: - return media::cast::kAudioFrameDecoded; - case 4: - return media::cast::kVideoFrameDecoded; - case 5: - return media::cast::kVideoRenderDelay; - case 6: - return media::cast::kPacketReceived; - default: - // If the sender adds new log messages we will end up here until we add - // the new messages in the receiver. - VLOG(1) << "Unexpected log message received: " << static_cast<int>(event); - NOTREACHED(); - return media::cast::kUnknown; - } -} - -media::cast::RtcpSenderFrameStatus TranslateToFrameStatusFromWireFormat( - uint8 status) { - switch (status) { - case 0: - return media::cast::kRtcpSenderFrameStatusUnknown; - case 1: - return media::cast::kRtcpSenderFrameStatusDroppedByEncoder; - case 2: - return media::cast::kRtcpSenderFrameStatusDroppedByFlowControl; - case 3: - return media::cast::kRtcpSenderFrameStatusSentToNetwork; - default: - // If the sender adds new log messages we will end up here until we add - // the new messages in the receiver. - NOTREACHED(); - VLOG(1) << "Unexpected status received: " << static_cast<int>(status); - return media::cast::kRtcpSenderFrameStatusUnknown; - } +// 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 @@ -67,12 +48,15 @@ RtcpReceiver::RtcpReceiver(scoped_refptr<CastEnvironment> cast_environment, sender_feedback_(sender_feedback), receiver_feedback_(receiver_feedback), rtt_feedback_(rtt_feedback), - cast_environment_(cast_environment) {} + cast_environment_(cast_environment), + receiver_event_history_size_(0) {} RtcpReceiver::~RtcpReceiver() {} -void RtcpReceiver::SetRemoteSSRC(uint32 ssrc) { - remote_ssrc_ = ssrc; +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) { @@ -117,9 +101,6 @@ void RtcpReceiver::IncomingRtcpPacket(RtcpParser* rtcp_parser) { case kRtcpApplicationSpecificCastReceiverLogCode: HandleApplicationSpecificCastReceiverLog(rtcp_parser); break; - case kRtcpApplicationSpecificCastSenderLogCode: - HandleApplicationSpecificCastSenderLog(rtcp_parser); - break; case kRtcpPayloadSpecificRembCode: case kRtcpPayloadSpecificRembItemCode: case kRtcpPayloadSpecificCastCode: @@ -151,16 +132,15 @@ void RtcpReceiver::HandleSenderReport(RtcpParser* rtcp_parser) { // Synchronization source identifier for the originator of this SR packet. uint32 remote_ssrc = rtcp_field.sender_report.sender_ssrc; - VLOG(1) << "Cast RTCP received SR from SSRC " << remote_ssrc; + VLOG(2) << "Cast RTCP received SR from SSRC " << remote_ssrc; if (remote_ssrc_ == remote_ssrc) { - RtcpSenderInfo remote_sender_info; + transport::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.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 = @@ -184,7 +164,7 @@ void RtcpReceiver::HandleReceiverReport(RtcpParser* rtcp_parser) { uint32 remote_ssrc = rtcp_field.receiver_report.sender_ssrc; - VLOG(1) << "Cast RTCP received RR from SSRC " << remote_ssrc; + VLOG(2) << "Cast RTCP received RR from SSRC " << remote_ssrc; rtcp_field_type = rtcp_parser->Iterate(); while (rtcp_field_type == kRtcpReportBlockItemCode) { @@ -211,13 +191,9 @@ void RtcpReceiver::HandleReportBlock(const RtcpField* rtcp_field, // This block is not for us ignore it. return; } - VLOG(1) << "Cast RTCP received RB from SSRC " << remote_ssrc; - cast_environment_->Logging()->InsertGenericEvent(kPacketLoss, - rb.fraction_lost); - cast_environment_->Logging()->InsertGenericEvent(kJitterMs, - rb.jitter); + VLOG(2) << "Cast RTCP received RB from SSRC " << remote_ssrc; - RtcpReportBlock report_block; + transport::RtcpReportBlock report_block; report_block.remote_ssrc = remote_ssrc; report_block.media_ssrc = rb.ssrc; report_block.fraction_lost = rb.fraction_lost; @@ -229,9 +205,8 @@ void RtcpReceiver::HandleReportBlock(const RtcpField* rtcp_field, report_block.delay_since_last_sr = rb.delay_last_sender_report; if (rtt_feedback_) { - rtt_feedback_->OnReceivedDelaySinceLastReport(rb.ssrc, - rb.last_sender_report, - rb.delay_last_sender_report); + rtt_feedback_->OnReceivedDelaySinceLastReport( + rb.ssrc, rb.last_sender_report, rb.delay_last_sender_report); } } @@ -245,7 +220,7 @@ void RtcpReceiver::HandleSDES(RtcpParser* rtcp_parser) { void RtcpReceiver::HandleSDESChunk(RtcpParser* rtcp_parser) { const RtcpField& rtcp_field = rtcp_parser->Field(); - VLOG(1) << "Cast RTCP received SDES with cname " << rtcp_field.c_name.name; + VLOG(2) << "Cast RTCP received SDES with cname " << rtcp_field.c_name.name; } void RtcpReceiver::HandleXr(RtcpParser* rtcp_parser) { @@ -337,7 +312,7 @@ void RtcpReceiver::HandleBYE(RtcpParser* rtcp_parser) { const RtcpField& rtcp_field = rtcp_parser->Field(); uint32 remote_ssrc = rtcp_field.bye.sender_ssrc; if (remote_ssrc_ == remote_ssrc) { - VLOG(1) << "Cast RTCP received BYE from SSRC " << remote_ssrc; + VLOG(2) << "Cast RTCP received BYE from SSRC " << remote_ssrc; } rtcp_parser->Iterate(); } @@ -346,7 +321,7 @@ void RtcpReceiver::HandlePLI(RtcpParser* rtcp_parser) { const RtcpField& rtcp_field = rtcp_parser->Field(); if (ssrc_ == rtcp_field.pli.media_ssrc) { // Received a signal that we need to send a new key frame. - VLOG(1) << "Cast RTCP received PLI on our SSRC " << ssrc_; + VLOG(2) << "Cast RTCP received PLI on our SSRC " << ssrc_; } rtcp_parser->Iterate(); } @@ -377,7 +352,7 @@ void RtcpReceiver::HandleRpsi(RtcpParser* rtcp_parser) { } rpsi_picture_id += (rtcp_field.rpsi.native_bit_string[bytes - 1] & 0x7f); - VLOG(1) << "Cast RTCP received RPSI with picture_id " << rpsi_picture_id; + VLOG(2) << "Cast RTCP received RPSI with picture_id " << rpsi_picture_id; } void RtcpReceiver::HandlePayloadSpecificApp(RtcpParser* rtcp_parser) { @@ -421,7 +396,7 @@ void RtcpReceiver::HandlePayloadSpecificRembItem(RtcpParser* rtcp_parser) { for (int i = 0; i < rtcp_field.remb_item.number_of_ssrcs; ++i) { if (rtcp_field.remb_item.ssrcs[i] == ssrc_) { // Found matching ssrc. - VLOG(1) << "Cast RTCP received REMB with received_bitrate " + VLOG(2) << "Cast RTCP received REMB with received_bitrate " << rtcp_field.remb_item.bitrate; return; } @@ -450,11 +425,15 @@ void RtcpReceiver::HandleApplicationSpecificCastReceiverLog( field_type = rtcp_parser->Iterate(); while (field_type == kRtcpApplicationSpecificCastReceiverLogEventCode) { - HandleApplicationSpecificCastReceiverEventLog(rtcp_parser, + HandleApplicationSpecificCastReceiverEventLog( + rtcp_field.cast_receiver_log.rtp_timestamp, + rtcp_parser, &frame_log.event_log_messages_); field_type = rtcp_parser->Iterate(); } - receiver_log.push_back(frame_log); + + if (!frame_log.event_log_messages_.empty()) + receiver_log.push_back(frame_log); } if (receiver_feedback_ && !receiver_log.empty()) { @@ -463,52 +442,50 @@ void RtcpReceiver::HandleApplicationSpecificCastReceiverLog( } void RtcpReceiver::HandleApplicationSpecificCastReceiverEventLog( + uint32 frame_rtp_timestamp, RtcpParser* rtcp_parser, RtcpReceiverEventLogMessages* event_log_messages) { const RtcpField& rtcp_field = rtcp_parser->Field(); - RtcpReceiverEventLogMessage event_log; - event_log.type = TranslateToLogEventFromWireFormat( - rtcp_field.cast_receiver_log.event); - event_log.event_timestamp = base::TimeTicks() + + 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); - event_log.delay_delta = base::TimeDelta::FromMilliseconds( - rtcp_field.cast_receiver_log.delay_delta_or_packet_id); - event_log.packet_id = - rtcp_field.cast_receiver_log.delay_delta_or_packet_id; - event_log_messages->push_back(event_log); -} - -void RtcpReceiver::HandleApplicationSpecificCastSenderLog( - RtcpParser* rtcp_parser) { - const RtcpField& rtcp_field = rtcp_parser->Field(); - uint32 remote_ssrc = rtcp_field.cast_sender_log.sender_ssrc; - if (remote_ssrc_ != remote_ssrc) { - RtcpFieldTypes field_type; - // Message not to us. Iterate until we have passed this message. - do { - field_type = rtcp_parser->Iterate(); - } while (field_type == kRtcpApplicationSpecificCastSenderLogCode); + // 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); + } } - RtcpSenderLogMessage sender_log; - RtcpFieldTypes field_type = rtcp_parser->Iterate(); - while (field_type == kRtcpApplicationSpecificCastSenderLogCode) { - const RtcpField& rtcp_field = rtcp_parser->Field(); - RtcpSenderFrameLogMessage frame_log; - frame_log.frame_status = - TranslateToFrameStatusFromWireFormat(rtcp_field.cast_sender_log.status); - frame_log.rtp_timestamp = rtcp_field.cast_sender_log.rtp_timestamp; - sender_log.push_back(frame_log); - field_type = rtcp_parser->Iterate(); - } - if (receiver_feedback_) { - receiver_feedback_->OnReceivedSenderLog(sender_log); - } + 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) { @@ -516,6 +493,7 @@ void RtcpReceiver::HandlePayloadSpecificCastItem(RtcpParser* rtcp_parser) { 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) { @@ -545,15 +523,15 @@ void RtcpReceiver::HandlePayloadSpecificCastNackItem( frame_it = ret.first; DCHECK(frame_it != missing_frames_and_packets->end()) << "Invalid state"; } - if (rtcp_field->cast_nack_item.packet_id == kRtcpCastAllPacketsLost) { + 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; } - uint16 packet_id = rtcp_field->cast_nack_item.packet_id; uint8 bitmask = rtcp_field->cast_nack_item.bitmask; - frame_it->second.insert(packet_id); - if (bitmask) { for (int i = 1; i <= 8; ++i) { if (bitmask & 1) { @@ -576,9 +554,10 @@ void RtcpReceiver::HandleFIR(RtcpParser* rtcp_parser) { void RtcpReceiver::HandleFIRItem(const RtcpField* rtcp_field) { // Is it our sender that is requested to generate a new keyframe. - if (ssrc_ != rtcp_field->fir_item.ssrc) return; + if (ssrc_ != rtcp_field->fir_item.ssrc) + return; - VLOG(1) << "Cast RTCP received FIR on our SSRC " << ssrc_; + VLOG(2) << "Cast RTCP received FIR on our SSRC " << ssrc_; } } // namespace cast diff --git a/chromium/media/cast/rtcp/rtcp_receiver.h b/chromium/media/cast/rtcp/rtcp_receiver.h index 81383c4ec10..d3cef9e57b4 100644 --- a/chromium/media/cast/rtcp/rtcp_receiver.h +++ b/chromium/media/cast/rtcp/rtcp_receiver.h @@ -5,10 +5,13 @@ #ifndef MEDIA_CAST_RTCP_RTCP_RECEIVER_H_ #define MEDIA_CAST_RTCP_RTCP_RECEIVER_H_ -#include "media/cast/net/cast_net_defines.h" +#include <queue> + +#include "base/containers/hash_tables.h" #include "media/cast/rtcp/rtcp.h" #include "media/cast/rtcp/rtcp_defines.h" #include "media/cast/rtcp/rtcp_utility.h" +#include "media/cast/transport/cast_transport_defines.h" namespace media { namespace cast { @@ -16,7 +19,7 @@ namespace cast { class RtcpReceiverFeedback { public: virtual void OnReceivedSenderReport( - const RtcpSenderInfo& remote_sender_info) = 0; + const transport::RtcpSenderInfo& remote_sender_info) = 0; virtual void OnReceiverReferenceTimeReport( const RtcpReceiverReferenceTimeReport& remote_time_report) = 0; @@ -26,9 +29,6 @@ class RtcpReceiverFeedback { virtual void OnReceivedReceiverLog( const RtcpReceiverLogMessage& receiver_log) = 0; - virtual void OnReceivedSenderLog( - const RtcpSenderLogMessage& sender_log) = 0; - virtual ~RtcpReceiverFeedback() {} }; @@ -53,6 +53,10 @@ class RtcpReceiver { 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: @@ -60,8 +64,7 @@ class RtcpReceiver { void HandleReceiverReport(RtcpParser* rtcp_parser); - void HandleReportBlock(const RtcpField* rtcp_field, - uint32 remote_ssrc); + void HandleReportBlock(const RtcpField* rtcp_field, uint32 remote_ssrc); void HandleSDES(RtcpParser* rtcp_parser); void HandleSDESChunk(RtcpParser* rtcp_parser); @@ -100,6 +103,7 @@ class RtcpReceiver { void HandleApplicationSpecificCastReceiverLog(RtcpParser* rtcp_parser); void HandleApplicationSpecificCastSenderLog(RtcpParser* rtcp_parser); void HandleApplicationSpecificCastReceiverEventLog( + uint32 frame_rtp_timestamp, RtcpParser* rtcp_parser, RtcpReceiverEventLogMessages* event_log_messages); @@ -112,7 +116,13 @@ class RtcpReceiver { RtcpRttFeedback* const rtt_feedback_; scoped_refptr<CastEnvironment> cast_environment_; - FrameIdWrapHelper ack_frame_id_wrap_helper_; + transport::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); }; diff --git a/chromium/media/cast/rtcp/rtcp_receiver_unittest.cc b/chromium/media/cast/rtcp/rtcp_receiver_unittest.cc index b5c5d2d3889..51026d1554b 100644 --- a/chromium/media/cast/rtcp/rtcp_receiver_unittest.cc +++ b/chromium/media/cast/rtcp/rtcp_receiver_unittest.cc @@ -10,7 +10,8 @@ #include "media/cast/rtcp/rtcp_receiver.h" #include "media/cast/rtcp/rtcp_utility.h" #include "media/cast/rtcp/test_rtcp_packet_builder.h" -#include "media/cast/test/fake_task_runner.h" +#include "media/cast/test/fake_single_thread_task_runner.h" +#include "media/cast/transport/cast_transport_defines.h" #include "testing/gmock/include/gmock/gmock.h" namespace media { @@ -21,6 +22,7 @@ using testing::_; static const uint32 kSenderSsrc = 0x10203; static const uint32 kSourceSsrc = 0x40506; static const uint32 kUnknownSsrc = 0xDEAD; +static const uint16 kTargetDelayMs = 100; static const std::string kCName("test@10.1.1.1"); namespace { @@ -28,8 +30,8 @@ class SenderFeedbackCastVerification : public RtcpSenderFeedback { public: SenderFeedbackCastVerification() : called_(false) {} - virtual void OnReceivedCastFeedback( - const RtcpCastMessage& cast_feedback) OVERRIDE { + virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) + OVERRIDE { EXPECT_EQ(cast_feedback.media_ssrc_, kSenderSsrc); EXPECT_EQ(cast_feedback.ack_frame_id_, kAckFrameId); @@ -38,7 +40,8 @@ class SenderFeedbackCastVerification : public RtcpSenderFeedback { EXPECT_TRUE(frame_it != cast_feedback.missing_frames_and_packets_.end()); EXPECT_EQ(kLostFrameId, frame_it->first); - EXPECT_TRUE(frame_it->second.empty()); + EXPECT_EQ(frame_it->second.size(), 1UL); + EXPECT_EQ(*frame_it->second.begin(), kRtcpCastAllPacketsLost); ++frame_it; EXPECT_TRUE(frame_it != cast_feedback.missing_frames_and_packets_.end()); EXPECT_EQ(kFrameIdWithLostPackets, frame_it->first); @@ -58,6 +61,8 @@ class SenderFeedbackCastVerification : public RtcpSenderFeedback { private: bool called_; + + DISALLOW_COPY_AND_ASSIGN(SenderFeedbackCastVerification); }; class RtcpReceiverCastLogVerification : public RtcpReceiverFeedback { @@ -67,18 +72,18 @@ class RtcpReceiverCastLogVerification : public RtcpReceiverFeedback { called_on_received_receiver_log_(false) {} virtual void OnReceivedSenderReport( - const RtcpSenderInfo& remote_sender_info) OVERRIDE {}; + const transport::RtcpSenderInfo& remote_sender_info) OVERRIDE{}; virtual void OnReceiverReferenceTimeReport( - const RtcpReceiverReferenceTimeReport& remote_time_report) OVERRIDE {}; + const RtcpReceiverReferenceTimeReport& remote_time_report) OVERRIDE{}; - virtual void OnReceivedSendReportRequest() OVERRIDE {}; + virtual void OnReceivedSendReportRequest() OVERRIDE{}; - virtual void OnReceivedReceiverLog( - const RtcpReceiverLogMessage& receiver_log) OVERRIDE { + 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(); + 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_); @@ -94,7 +99,7 @@ class RtcpReceiverCastLogVerification : public RtcpReceiverFeedback { 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 == kPacketReceived) { + 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, @@ -107,26 +112,6 @@ class RtcpReceiverCastLogVerification : public RtcpReceiverFeedback { called_on_received_receiver_log_ = true; } - virtual void OnReceivedSenderLog( - const RtcpSenderLogMessage& sender_log) OVERRIDE { - EXPECT_EQ(expected_sender_log_.size(), sender_log.size()); - - RtcpSenderLogMessage::const_iterator expected_it = - expected_sender_log_.begin(); - RtcpSenderLogMessage::const_iterator incoming_it = sender_log.begin(); - for (; expected_it != expected_sender_log_.end(); - ++expected_it, ++incoming_it) { - EXPECT_EQ(expected_it->frame_status, incoming_it->frame_status); - EXPECT_EQ(0xffffff & expected_it->rtp_timestamp, - incoming_it->rtp_timestamp); - } - called_on_received_sender_log_ = true; - } - - bool OnReceivedSenderLogCalled() { - return called_on_received_sender_log_; - } - bool OnReceivedReceiverLogCalled() { return called_on_received_receiver_log_ && expected_receiver_log_.empty(); } @@ -135,15 +120,12 @@ class RtcpReceiverCastLogVerification : public RtcpReceiverFeedback { expected_receiver_log_ = receiver_log; } - void SetExpectedSenderLog(const RtcpSenderLogMessage& sender_log) { - expected_sender_log_ = sender_log; - } - private: RtcpReceiverLogMessage expected_receiver_log_; - RtcpSenderLogMessage expected_sender_log_; bool called_on_received_sender_log_; bool called_on_received_receiver_log_; + + DISALLOW_COPY_AND_ASSIGN(RtcpReceiverCastLogVerification); }; } // namespace @@ -151,28 +133,26 @@ class RtcpReceiverCastLogVerification : public RtcpReceiverFeedback { class RtcpReceiverTest : public ::testing::Test { protected: RtcpReceiverTest() - : task_runner_(new test::FakeTaskRunner(&testing_clock_)), - cast_environment_(new CastEnvironment(&testing_clock_, task_runner_, - task_runner_, task_runner_, task_runner_, task_runner_, - GetDefaultCastLoggingConfig())), + : testing_clock_(new base::SimpleTestTickClock()), + task_runner_(new test::FakeSingleThreadTaskRunner(testing_clock_)), + cast_environment_(new CastEnvironment( + scoped_ptr<base::TickClock>(testing_clock_).Pass(), + task_runner_, + task_runner_, + task_runner_)), rtcp_receiver_(new RtcpReceiver(cast_environment_, &mock_sender_feedback_, &mock_receiver_feedback_, &mock_rtt_feedback_, kSourceSsrc)) { - } - - virtual ~RtcpReceiverTest() {} - - virtual void SetUp() OVERRIDE { EXPECT_CALL(mock_receiver_feedback_, OnReceivedSenderReport(_)).Times(0); - EXPECT_CALL(mock_receiver_feedback_, - OnReceiverReferenceTimeReport(_)).Times(0); - EXPECT_CALL(mock_receiver_feedback_, - OnReceivedSendReportRequest()).Times(0); + EXPECT_CALL(mock_receiver_feedback_, OnReceiverReferenceTimeReport(_)) + .Times(0); + EXPECT_CALL(mock_receiver_feedback_, OnReceivedSendReportRequest()) + .Times(0); EXPECT_CALL(mock_sender_feedback_, OnReceivedCastFeedback(_)).Times(0); - EXPECT_CALL(mock_rtt_feedback_, - OnReceivedDelaySinceLastReport(_, _, _)).Times(0); + EXPECT_CALL(mock_rtt_feedback_, OnReceivedDelaySinceLastReport(_, _, _)) + .Times(0); expected_sender_info_.ntp_seconds = kNtpHigh; expected_sender_info_.ntp_fraction = kNtpLow; @@ -193,22 +173,26 @@ class RtcpReceiverTest : public ::testing::Test { 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); } - base::SimpleTestTickClock testing_clock_; - scoped_refptr<test::FakeTaskRunner> task_runner_; + base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment. + scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_; scoped_refptr<CastEnvironment> cast_environment_; MockRtcpReceiverFeedback mock_receiver_feedback_; MockRtcpRttFeedback mock_rtt_feedback_; MockRtcpSenderFeedback mock_sender_feedback_; scoped_ptr<RtcpReceiver> rtcp_receiver_; - RtcpSenderInfo expected_sender_info_; - RtcpReportBlock expected_report_block_; + transport::RtcpSenderInfo expected_sender_info_; + transport::RtcpReportBlock expected_report_block_; RtcpReceiverReferenceTimeReport expected_receiver_reference_report_; + + DISALLOW_COPY_AND_ASSIGN(RtcpReceiverTest); }; TEST_F(RtcpReceiverTest, BrokenPacketIsIgnored) { @@ -222,14 +206,14 @@ TEST_F(RtcpReceiverTest, InjectSenderReportPacket) { // Expected to be ignored since the sender ssrc does not match our // remote ssrc. - InjectRtcpPacket(p.Packet(), p.Length()); + 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.Packet(), p.Length()); + InjectRtcpPacket(p.Data(), p.Length()); } TEST_F(RtcpReceiverTest, InjectReceiveReportPacket) { @@ -239,19 +223,18 @@ TEST_F(RtcpReceiverTest, InjectReceiveReportPacket) { // Expected to be ignored since the source ssrc does not match our // local ssrc. - InjectRtcpPacket(p1.Packet(), p1.Length()); + InjectRtcpPacket(p1.Data(), p1.Length()); EXPECT_CALL(mock_rtt_feedback_, - OnReceivedDelaySinceLastReport(kSourceSsrc, - kLastSr, - kDelayLastSr)).Times(1); + OnReceivedDelaySinceLastReport( + kSourceSsrc, 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.Packet(), p2.Length()); + InjectRtcpPacket(p2.Data(), p2.Length()); } TEST_F(RtcpReceiverTest, InjectSenderReportWithReportBlockPacket) { @@ -263,7 +246,7 @@ TEST_F(RtcpReceiverTest, InjectSenderReportWithReportBlockPacket) { // our remote ssrc. // Report block expected to be ignored since the source ssrc does not match // our local ssrc. - InjectRtcpPacket(p1.Packet(), p1.Length()); + InjectRtcpPacket(p1.Data(), p1.Length()); EXPECT_CALL(mock_receiver_feedback_, OnReceivedSenderReport(expected_sender_info_)).Times(1); @@ -273,13 +256,12 @@ TEST_F(RtcpReceiverTest, InjectSenderReportWithReportBlockPacket) { // remote ssrc. // Report block expected to be ignored since the source ssrc does not match // our local ssrc. - InjectRtcpPacket(p1.Packet(), p1.Length()); + InjectRtcpPacket(p1.Data(), p1.Length()); EXPECT_CALL(mock_receiver_feedback_, OnReceivedSenderReport(_)).Times(0); EXPECT_CALL(mock_rtt_feedback_, - OnReceivedDelaySinceLastReport(kSourceSsrc, - kLastSr, - kDelayLastSr)).Times(1); + OnReceivedDelaySinceLastReport( + kSourceSsrc, kLastSr, kDelayLastSr)).Times(1); rtcp_receiver_->SetRemoteSSRC(0); @@ -291,14 +273,13 @@ TEST_F(RtcpReceiverTest, InjectSenderReportWithReportBlockPacket) { // our remote ssrc. // Receiver report expected to be pass through since the sender ssrc match // our local ssrc. - InjectRtcpPacket(p2.Packet(), p2.Length()); + InjectRtcpPacket(p2.Data(), p2.Length()); EXPECT_CALL(mock_receiver_feedback_, OnReceivedSenderReport(expected_sender_info_)).Times(1); EXPECT_CALL(mock_rtt_feedback_, - OnReceivedDelaySinceLastReport(kSourceSsrc, - kLastSr, - kDelayLastSr)).Times(1); + OnReceivedDelaySinceLastReport( + kSourceSsrc, kLastSr, kDelayLastSr)).Times(1); rtcp_receiver_->SetRemoteSSRC(kSenderSsrc); @@ -306,7 +287,7 @@ TEST_F(RtcpReceiverTest, InjectSenderReportWithReportBlockPacket) { // remote ssrc. // Receiver report expected to be pass through since the sender ssrc match // our local ssrc. - InjectRtcpPacket(p2.Packet(), p2.Length()); + InjectRtcpPacket(p2.Data(), p2.Length()); } TEST_F(RtcpReceiverTest, InjectSenderReportPacketWithDlrr) { @@ -320,20 +301,19 @@ TEST_F(RtcpReceiverTest, InjectSenderReportPacketWithDlrr) { // Expected to be ignored since the source ssrc does not match our // local ssrc. - InjectRtcpPacket(p.Packet(), p.Length()); + InjectRtcpPacket(p.Data(), p.Length()); EXPECT_CALL(mock_receiver_feedback_, OnReceivedSenderReport(expected_sender_info_)).Times(1); EXPECT_CALL(mock_rtt_feedback_, - OnReceivedDelaySinceLastReport(kSenderSsrc, - kLastSr, - kDelayLastSr)).Times(1); + OnReceivedDelaySinceLastReport( + kSenderSsrc, 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.Packet(), p.Length()); + InjectRtcpPacket(p.Data(), p.Length()); } TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithRrtr) { @@ -345,14 +325,14 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithRrtr) { // Expected to be ignored since the source ssrc does not match our // local ssrc. - InjectRtcpPacket(p1.Packet(), p1.Length()); + InjectRtcpPacket(p1.Data(), p1.Length()); EXPECT_CALL(mock_rtt_feedback_, - OnReceivedDelaySinceLastReport(kSourceSsrc, - kLastSr, - kDelayLastSr)).Times(1); - EXPECT_CALL(mock_receiver_feedback_, OnReceiverReferenceTimeReport( - expected_receiver_reference_report_)).Times(1); + OnReceivedDelaySinceLastReport( + kSourceSsrc, 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); @@ -364,7 +344,7 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithRrtr) { p2.AddXrRrtrBlock(); // Expected to be pass through since the sender ssrc match our local ssrc. - InjectRtcpPacket(p2.Packet(), p2.Length()); + InjectRtcpPacket(p2.Data(), p2.Length()); } TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithIntraFrameRequest) { @@ -375,12 +355,11 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithIntraFrameRequest) { // Expected to be ignored since the source ssrc does not match our // local ssrc. - InjectRtcpPacket(p1.Packet(), p1.Length()); + InjectRtcpPacket(p1.Data(), p1.Length()); EXPECT_CALL(mock_rtt_feedback_, - OnReceivedDelaySinceLastReport(kSourceSsrc, - kLastSr, - kDelayLastSr)).Times(1); + OnReceivedDelaySinceLastReport( + kSourceSsrc, kLastSr, kDelayLastSr)).Times(1); TestRtcpPacketBuilder p2; p2.AddRr(kSenderSsrc, 1); @@ -388,23 +367,22 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithIntraFrameRequest) { p2.AddPli(kSenderSsrc, kSourceSsrc); // Expected to be pass through since the sender ssrc match our local ssrc. - InjectRtcpPacket(p2.Packet(), p2.Length()); + InjectRtcpPacket(p2.Data(), p2.Length()); } TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastFeedback) { TestRtcpPacketBuilder p1; p1.AddRr(kSenderSsrc, 1); p1.AddRb(kUnknownSsrc); - p1.AddCast(kSenderSsrc, kUnknownSsrc); + p1.AddCast(kSenderSsrc, kUnknownSsrc, kTargetDelayMs); // Expected to be ignored since the source ssrc does not match our // local ssrc. - InjectRtcpPacket(p1.Packet(), p1.Length()); + InjectRtcpPacket(p1.Data(), p1.Length()); EXPECT_CALL(mock_rtt_feedback_, - OnReceivedDelaySinceLastReport(kSourceSsrc, - kLastSr, - kDelayLastSr)).Times(1); + OnReceivedDelaySinceLastReport( + kSourceSsrc, kLastSr, kDelayLastSr)).Times(1); EXPECT_CALL(mock_sender_feedback_, OnReceivedCastFeedback(_)).Times(1); // Enable receiving the cast feedback. @@ -413,10 +391,10 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastFeedback) { TestRtcpPacketBuilder p2; p2.AddRr(kSenderSsrc, 1); p2.AddRb(kSourceSsrc); - p2.AddCast(kSenderSsrc, kSourceSsrc); + p2.AddCast(kSenderSsrc, kSourceSsrc, kTargetDelayMs); // Expected to be pass through since the sender ssrc match our local ssrc. - InjectRtcpPacket(p2.Packet(), p2.Length()); + InjectRtcpPacket(p2.Data(), p2.Length()); } TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastVerification) { @@ -428,9 +406,8 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastVerification) { kSourceSsrc); EXPECT_CALL(mock_rtt_feedback_, - OnReceivedDelaySinceLastReport(kSourceSsrc, - kLastSr, - kDelayLastSr)).Times(1); + OnReceivedDelaySinceLastReport( + kSourceSsrc, kLastSr, kDelayLastSr)).Times(1); // Enable receiving the cast feedback. rtcp_receiver.SetRemoteSSRC(kSenderSsrc); @@ -438,48 +415,15 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastVerification) { TestRtcpPacketBuilder p; p.AddRr(kSenderSsrc, 1); p.AddRb(kSourceSsrc); - p.AddCast(kSenderSsrc, kSourceSsrc); + p.AddCast(kSenderSsrc, kSourceSsrc, kTargetDelayMs); // Expected to be pass through since the sender ssrc match our local ssrc. - RtcpParser rtcp_parser(p.Packet(), p.Length()); + RtcpParser rtcp_parser(p.Data(), p.Length()); rtcp_receiver.IncomingRtcpPacket(&rtcp_parser); EXPECT_TRUE(sender_feedback_cast_verification.called()); } -TEST_F(RtcpReceiverTest, InjectSenderReportWithCastSenderLogVerification) { - RtcpReceiverCastLogVerification cast_log_verification; - RtcpReceiver rtcp_receiver(cast_environment_, - &mock_sender_feedback_, - &cast_log_verification, - &mock_rtt_feedback_, - kSourceSsrc); - rtcp_receiver.SetRemoteSSRC(kSenderSsrc); - - RtcpSenderLogMessage sender_log; - for (int j = 0; j < 359; ++j) { - RtcpSenderFrameLogMessage sender_frame_log; - sender_frame_log.frame_status = kRtcpSenderFrameStatusSentToNetwork; - sender_frame_log.rtp_timestamp = kRtpTimestamp + j * 90; - sender_log.push_back(sender_frame_log); - } - cast_log_verification.SetExpectedSenderLog(sender_log); - - TestRtcpPacketBuilder p; - p.AddSr(kSenderSsrc, 0); - p.AddSdesCname(kSenderSsrc, kCName); - p.AddSenderLog(kSenderSsrc); - - for (int i = 0; i < 359; ++i) { - p.AddSenderFrameLog(kRtcpSenderFrameStatusSentToNetwork, - kRtpTimestamp + i * 90); - } - RtcpParser rtcp_parser(p.Packet(), p.Length()); - rtcp_receiver.IncomingRtcpPacket(&rtcp_parser); - - EXPECT_TRUE(cast_log_verification.OnReceivedSenderLogCalled()); -} - TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationBase) { static const uint32 kTimeBaseMs = 12345678; static const uint32 kTimeDelayMs = 10; @@ -494,21 +438,28 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationBase) { &mock_rtt_feedback_, kSourceSsrc); rtcp_receiver.SetRemoteSSRC(kSenderSsrc); + rtcp_receiver.SetCastReceiverEventHistorySize(100); RtcpReceiverLogMessage receiver_log; RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp); RtcpReceiverEventLogMessage event_log; - event_log.type = kAckSent; + 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 = kPacketReceived; + 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); cast_log_verification.SetExpectedReceiverLog(receiver_log); @@ -517,15 +468,22 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationBase) { p.AddRr(kSenderSsrc, 1); p.AddRb(kSourceSsrc); p.AddReceiverLog(kSenderSsrc); - p.AddReceiverFrameLog(kRtpTimestamp, 2, kTimeBaseMs); - p.AddReceiverEventLog(kDelayDeltaMs, 1, 0); - p.AddReceiverEventLog(kLostPacketId1, 6, kTimeDelayMs); + 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(mock_rtt_feedback_, - OnReceivedDelaySinceLastReport(kSourceSsrc, kLastSr, kDelayLastSr)). - Times(1); + OnReceivedDelaySinceLastReport( + kSourceSsrc, kLastSr, kDelayLastSr)).Times(1); - RtcpParser rtcp_parser(p.Packet(), p.Length()); + RtcpParser rtcp_parser(p.Data(), p.Length()); rtcp_receiver.IncomingRtcpPacket(&rtcp_parser); EXPECT_TRUE(cast_log_verification.OnReceivedReceiverLogCalled()); @@ -551,7 +509,7 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationMulti) { for (int j = 0; j < 100; ++j) { RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp); RtcpReceiverEventLogMessage event_log; - event_log.type = kAckSent; + 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); @@ -566,21 +524,19 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationMulti) { p.AddRb(kSourceSsrc); p.AddReceiverLog(kSenderSsrc); for (int i = 0; i < 100; ++i) { - p.AddReceiverFrameLog(kRtpTimestamp, 1, kTimeBaseMs + i * kTimeDelayMs); - p.AddReceiverEventLog(kDelayDeltaMs, 1, 0); + p.AddReceiverFrameLog(kRtpTimestamp, 1, kTimeBaseMs + i * kTimeDelayMs); + p.AddReceiverEventLog(kDelayDeltaMs, FRAME_ACK_SENT, 0); } EXPECT_CALL(mock_rtt_feedback_, - OnReceivedDelaySinceLastReport(kSourceSsrc, kLastSr, kDelayLastSr)). - Times(1); + OnReceivedDelaySinceLastReport( + kSourceSsrc, kLastSr, kDelayLastSr)).Times(1); - RtcpParser rtcp_parser(p.Packet(), p.Length()); + RtcpParser rtcp_parser(p.Data(), p.Length()); rtcp_receiver.IncomingRtcpPacket(&rtcp_parser); EXPECT_TRUE(cast_log_verification.OnReceivedReceiverLogCalled()); } - - } // namespace cast } // namespace media diff --git a/chromium/media/cast/rtcp/rtcp_sender.cc b/chromium/media/cast/rtcp/rtcp_sender.cc index b5cf4ce4ced..bf7d30c84c8 100644 --- a/chromium/media/cast/rtcp/rtcp_sender.cc +++ b/chromium/media/cast/rtcp/rtcp_sender.cc @@ -4,263 +4,226 @@ #include "media/cast/rtcp/rtcp_sender.h" +#include <stdint.h> + #include <algorithm> #include <vector> +#include "base/big_endian.h" #include "base/logging.h" #include "media/cast/cast_environment.h" -#include "media/cast/net/pacing/paced_sender.h" +#include "media/cast/rtcp/rtcp_defines.h" #include "media/cast/rtcp/rtcp_utility.h" -#include "net/base/big_endian.h" - -static const size_t kRtcpCastLogHeaderSize = 12; -static const size_t kRtcpSenderFrameLogSize = 4; -static const size_t kRtcpReceiverFrameLogSize = 8; -static const size_t kRtcpReceiverEventLogSize = 4; +#include "media/cast/transport/cast_transport_defines.h" +#include "media/cast/transport/pacing/paced_sender.h" +namespace media { +namespace cast { namespace { + +// Max delta is 4095 milliseconds because we need to be able to encode it in +// 12 bits. +const int64 kMaxWireFormatTimeDeltaMs = INT64_C(0xfff); + uint16 MergeEventTypeAndTimestampForWireFormat( - const media::cast::CastLoggingEvent& event, + const CastLoggingEvent& event, const base::TimeDelta& time_delta) { int64 time_delta_ms = time_delta.InMilliseconds(); - // Max delta is 4096 milliseconds. - DCHECK_GE(GG_INT64_C(0xfff), time_delta_ms); - - uint16 event_type_and_timestamp_delta = - static_cast<uint16>(time_delta_ms & 0xfff); - - uint16 event_type = 0; - switch (event) { - case media::cast::kAckSent: - event_type = 1; - break; - case media::cast::kAudioPlayoutDelay: - event_type = 2; - break; - case media::cast::kAudioFrameDecoded: - event_type = 3; - break; - case media::cast::kVideoFrameDecoded: - event_type = 4; - break; - case media::cast::kVideoRenderDelay: - event_type = 5; - break; - case media::cast::kPacketReceived: - event_type = 6; - break; - default: - NOTREACHED(); - } - DCHECK(!(event_type & 0xfff0)); - return (event_type << 12) + event_type_and_timestamp_delta; -} -bool ScanRtcpReceiverLogMessage( - const media::cast::RtcpReceiverLogMessage& receiver_log_message, - size_t start_size, - size_t* number_of_frames, - size_t* total_number_of_messages_to_send, - size_t* rtcp_log_size) { - if (receiver_log_message.empty()) return false; + DCHECK_GE(time_delta_ms, 0); + DCHECK_LE(time_delta_ms, kMaxWireFormatTimeDeltaMs); - size_t remaining_space = media::cast::kIpPacketSize - start_size; + uint16 time_delta_12_bits = + static_cast<uint16>(time_delta_ms & kMaxWireFormatTimeDeltaMs); - // We must have space for at least one message - DCHECK_GE(remaining_space, kRtcpCastLogHeaderSize + - kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) - << "Not enough buffer space"; + uint16 event_type_4_bits = ConvertEventTypeToWireFormat(event); + DCHECK(event_type_4_bits); + DCHECK(~(event_type_4_bits & 0xfff0)); + return (event_type_4_bits << 12) | time_delta_12_bits; +} - if (remaining_space < kRtcpCastLogHeaderSize + kRtcpReceiverFrameLogSize + - kRtcpReceiverEventLogSize) { - return false; - } - // Account for the RTCP header for an application-defined packet. - remaining_space -= kRtcpCastLogHeaderSize; +bool EventTimestampLessThan(const RtcpReceiverEventLogMessage& lhs, + const RtcpReceiverEventLogMessage& rhs) { + return lhs.event_timestamp < rhs.event_timestamp; +} - media::cast::RtcpReceiverLogMessage::const_iterator frame_it = - receiver_log_message.begin(); - for (; frame_it != receiver_log_message.end(); ++frame_it) { - (*number_of_frames)++; +void AddReceiverLog( + const RtcpReceiverLogMessage& redundancy_receiver_log_message, + RtcpReceiverLogMessage* receiver_log_message, + size_t* remaining_space, + size_t* number_of_frames, + size_t* total_number_of_messages_to_send) { + RtcpReceiverLogMessage::const_iterator it = + redundancy_receiver_log_message.begin(); + while (it != redundancy_receiver_log_message.end() && + *remaining_space >= + kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) { + receiver_log_message->push_front(*it); + size_t num_event_logs = (*remaining_space - kRtcpReceiverFrameLogSize) / + kRtcpReceiverEventLogSize; + RtcpReceiverEventLogMessages& event_log_messages = + receiver_log_message->front().event_log_messages_; + if (num_event_logs < event_log_messages.size()) + event_log_messages.resize(num_event_logs); + + *remaining_space -= kRtcpReceiverFrameLogSize + + event_log_messages.size() * kRtcpReceiverEventLogSize; + ++*number_of_frames; + *total_number_of_messages_to_send += event_log_messages.size(); + ++it; + } +} - remaining_space -= kRtcpReceiverFrameLogSize; +// A class to build a string representing the NACK list in Cast message. +// +// The string will look like "23:3-6 25:1,5-6", meaning packets 3 to 6 in frame +// 23 are being NACK'ed (i.e. they are missing from the receiver's point of +// view) and packets 1, 5 and 6 are missing in frame 25. A frame that is +// completely missing will show as "26:65535". +class NackStringBuilder { + public: + NackStringBuilder() + : frame_count_(0), + packet_count_(0), + last_frame_id_(-1), + last_packet_id_(-1), + contiguous_sequence_(false) {} + ~NackStringBuilder() {} + + bool Empty() const { return frame_count_ == 0; } + + void PushFrame(int frame_id) { + DCHECK_GE(frame_id, 0); + if (frame_count_ > 0) { + if (frame_id == last_frame_id_) { + return; + } + if (contiguous_sequence_) { + stream_ << "-" << last_packet_id_; + } + stream_ << ", "; + } + stream_ << frame_id; + last_frame_id_ = frame_id; + packet_count_ = 0; + contiguous_sequence_ = false; + ++frame_count_; + } - size_t messages_in_frame = frame_it->event_log_messages_.size(); - size_t remaining_space_in_messages = - remaining_space / kRtcpReceiverEventLogSize; - size_t messages_to_send = std::min(messages_in_frame, - remaining_space_in_messages); - if (messages_to_send > media::cast::kRtcpMaxReceiverLogMessages) { - // We can't send more than 256 messages. - remaining_space -= media::cast::kRtcpMaxReceiverLogMessages * - kRtcpReceiverEventLogSize; - *total_number_of_messages_to_send += - media::cast::kRtcpMaxReceiverLogMessages; - break; + void PushPacket(int packet_id) { + DCHECK_GE(last_frame_id_, 0); + DCHECK_GE(packet_id, 0); + if (packet_count_ == 0) { + stream_ << ":" << packet_id; + } else if (packet_id == last_packet_id_ + 1) { + contiguous_sequence_ = true; + } else { + if (contiguous_sequence_) { + stream_ << "-" << last_packet_id_; + contiguous_sequence_ = false; + } + stream_ << "," << packet_id; } - remaining_space -= messages_to_send * kRtcpReceiverEventLogSize; - *total_number_of_messages_to_send += messages_to_send; + ++packet_count_; + last_packet_id_ = packet_id; + } - if (remaining_space < - kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) { - // Make sure that we have room for at least one more message. - break; + std::string GetString() { + if (contiguous_sequence_) { + stream_ << "-" << last_packet_id_; + contiguous_sequence_ = false; } + return stream_.str(); } - *rtcp_log_size = kRtcpCastLogHeaderSize + - *number_of_frames * kRtcpReceiverFrameLogSize + - *total_number_of_messages_to_send * kRtcpReceiverEventLogSize; - DCHECK_GE(media::cast::kIpPacketSize, - start_size + *rtcp_log_size) << "Not enough buffer space"; - VLOG(1) << "number of frames " << *number_of_frames; - VLOG(1) << "total messages to send " << *total_number_of_messages_to_send; - VLOG(1) << "rtcp log size " << *rtcp_log_size; - return true; -} + private: + std::ostringstream stream_; + int frame_count_; + int packet_count_; + int last_frame_id_; + int last_packet_id_; + bool contiguous_sequence_; +}; } // namespace -namespace media { -namespace cast { - +// TODO(mikhal): This is only used by the receiver. Consider renaming. RtcpSender::RtcpSender(scoped_refptr<CastEnvironment> cast_environment, - PacedPacketSender* outgoing_transport, + transport::PacedPacketSender* outgoing_transport, uint32 sending_ssrc, const std::string& c_name) - : ssrc_(sending_ssrc), - c_name_(c_name), - transport_(outgoing_transport), - cast_environment_(cast_environment) { + : ssrc_(sending_ssrc), + c_name_(c_name), + transport_(outgoing_transport), + cast_environment_(cast_environment) { DCHECK_LT(c_name_.length(), kRtcpCnameSize) << "Invalid config"; } RtcpSender::~RtcpSender() {} -void RtcpSender::SendRtcpFromRtpSender(uint32 packet_type_flags, - const RtcpSenderInfo* sender_info, - const RtcpDlrrReportBlock* dlrr, - RtcpSenderLogMessage* sender_log) { - if (packet_type_flags & kRtcpRr || - packet_type_flags & kRtcpPli || - packet_type_flags & kRtcpRrtr || - packet_type_flags & kRtcpCast || - packet_type_flags & kRtcpReceiverLog || - packet_type_flags & kRtcpRpsi || - packet_type_flags & kRtcpRemb || - packet_type_flags & kRtcpNack) { - NOTREACHED() << "Invalid argument"; - } - - std::vector<uint8> packet; - packet.reserve(kIpPacketSize); - if (packet_type_flags & kRtcpSr) { - DCHECK(sender_info) << "Invalid argument"; - BuildSR(*sender_info, NULL, &packet); - BuildSdec(&packet); - } - if (packet_type_flags & kRtcpBye) { - BuildBye(&packet); - } - if (packet_type_flags & kRtcpDlrr) { - DCHECK(dlrr) << "Invalid argument"; - BuildDlrrRb(dlrr, &packet); - } - if (packet_type_flags & kRtcpSenderLog) { - DCHECK(sender_log) << "Invalid argument"; - BuildSenderLog(sender_log, &packet); - } - if (packet.empty()) - return; // Sanity don't send empty packets. - - transport_->SendRtcpPacket(packet); -} - void RtcpSender::SendRtcpFromRtpReceiver( uint32 packet_type_flags, - const RtcpReportBlock* report_block, + const transport::RtcpReportBlock* report_block, const RtcpReceiverReferenceTimeReport* rrtr, const RtcpCastMessage* cast_message, - RtcpReceiverLogMessage* receiver_log) { - if (packet_type_flags & kRtcpSr || - packet_type_flags & kRtcpDlrr || - packet_type_flags & kRtcpSenderLog) { + const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events, + uint16 target_delay_ms) { + if (packet_type_flags & transport::kRtcpSr || + packet_type_flags & transport::kRtcpDlrr || + packet_type_flags & transport::kRtcpSenderLog) { NOTREACHED() << "Invalid argument"; } - if (packet_type_flags & kRtcpPli || - packet_type_flags & kRtcpRpsi || - packet_type_flags & kRtcpRemb || - packet_type_flags & kRtcpNack) { + if (packet_type_flags & transport::kRtcpPli || + packet_type_flags & transport::kRtcpRpsi || + packet_type_flags & transport::kRtcpRemb || + packet_type_flags & transport::kRtcpNack) { // Implement these for webrtc interop. NOTIMPLEMENTED(); } - std::vector<uint8> packet; - packet.reserve(kIpPacketSize); + transport::PacketRef packet(new base::RefCountedData<Packet>); + packet->data.reserve(kMaxIpPacketSize); - if (packet_type_flags & kRtcpRr) { - BuildRR(report_block, &packet); + if (packet_type_flags & transport::kRtcpRr) { + BuildRR(report_block, &packet->data); if (!c_name_.empty()) { - BuildSdec(&packet); + BuildSdec(&packet->data); } } - if (packet_type_flags & kRtcpBye) { - BuildBye(&packet); + if (packet_type_flags & transport::kRtcpBye) { + BuildBye(&packet->data); } - if (packet_type_flags & kRtcpRrtr) { + if (packet_type_flags & transport::kRtcpRrtr) { DCHECK(rrtr) << "Invalid argument"; - BuildRrtr(rrtr, &packet); + BuildRrtr(rrtr, &packet->data); } - if (packet_type_flags & kRtcpCast) { + if (packet_type_flags & transport::kRtcpCast) { DCHECK(cast_message) << "Invalid argument"; - BuildCast(cast_message, &packet); + BuildCast(cast_message, target_delay_ms, &packet->data); } - if (packet_type_flags & kRtcpReceiverLog) { - DCHECK(receiver_log) << "Invalid argument"; - BuildReceiverLog(receiver_log, &packet); + if (packet_type_flags & transport::kRtcpReceiverLog) { + DCHECK(rtcp_events) << "Invalid argument"; + BuildReceiverLog(*rtcp_events, &packet->data); } - if (packet.empty()) return; // Sanity don't send empty packets. - transport_->SendRtcpPacket(packet); -} - -void RtcpSender::BuildSR(const RtcpSenderInfo& sender_info, - const RtcpReportBlock* report_block, - std::vector<uint8>* packet) const { - // Sender report. - size_t start_size = packet->size(); - DCHECK_LT(start_size + 52, kIpPacketSize) << "Not enough buffer space"; - if (start_size + 52 > kIpPacketSize) return; - - uint16 number_of_rows = (report_block) ? 12 : 6; - packet->resize(start_size + 28); - - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 28); - big_endian_writer.WriteU8(0x80 + (report_block ? 1 : 0)); - big_endian_writer.WriteU8(kPacketTypeSenderReport); - big_endian_writer.WriteU16(number_of_rows); - big_endian_writer.WriteU32(ssrc_); - big_endian_writer.WriteU32(sender_info.ntp_seconds); - big_endian_writer.WriteU32(sender_info.ntp_fraction); - big_endian_writer.WriteU32(sender_info.rtp_timestamp); - big_endian_writer.WriteU32(sender_info.send_packet_count); - big_endian_writer.WriteU32(static_cast<uint32>(sender_info.send_octet_count)); + if (packet->data.empty()) + return; // Sanity don't send empty packets. - if (report_block) { - AddReportBlocks(*report_block, packet); // Adds 24 bytes. - } + transport_->SendRtcpPacket(ssrc_, packet); } -void RtcpSender::BuildRR(const RtcpReportBlock* report_block, - std::vector<uint8>* packet) const { +void RtcpSender::BuildRR(const transport::RtcpReportBlock* report_block, + Packet* packet) const { size_t start_size = packet->size(); - DCHECK_LT(start_size + 32, kIpPacketSize) << "Not enough buffer space"; - if (start_size + 32 > kIpPacketSize) return; + DCHECK_LT(start_size + 32, kMaxIpPacketSize) << "Not enough buffer space"; + if (start_size + 32 > kMaxIpPacketSize) + return; uint16 number_of_rows = (report_block) ? 7 : 1; packet->resize(start_size + 8); - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 8); + base::BigEndianWriter big_endian_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 8); big_endian_writer.WriteU8(0x80 + (report_block ? 1 : 0)); - big_endian_writer.WriteU8(kPacketTypeReceiverReport); + big_endian_writer.WriteU8(transport::kPacketTypeReceiverReport); big_endian_writer.WriteU16(number_of_rows); big_endian_writer.WriteU32(ssrc_); @@ -269,15 +232,17 @@ void RtcpSender::BuildRR(const RtcpReportBlock* report_block, } } -void RtcpSender::AddReportBlocks(const RtcpReportBlock& report_block, - std::vector<uint8>* packet) const { +void RtcpSender::AddReportBlocks(const transport::RtcpReportBlock& report_block, + Packet* packet) const { size_t start_size = packet->size(); - DCHECK_LT(start_size + 24, kIpPacketSize) << "Not enough buffer space"; - if (start_size + 24 > kIpPacketSize) return; + DCHECK_LT(start_size + 24, kMaxIpPacketSize) << "Not enough buffer space"; + if (start_size + 24 > kMaxIpPacketSize) + return; packet->resize(start_size + 24); - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 24); + base::BigEndianWriter big_endian_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 24); big_endian_writer.WriteU32(report_block.media_ssrc); big_endian_writer.WriteU8(report_block.fraction_lost); big_endian_writer.WriteU8(report_block.cumulative_lost >> 16); @@ -297,30 +262,32 @@ void RtcpSender::AddReportBlocks(const RtcpReportBlock& report_block, big_endian_writer.WriteU32(report_block.delay_since_last_sr); } -void RtcpSender::BuildSdec(std::vector<uint8>* packet) const { +void RtcpSender::BuildSdec(Packet* packet) const { size_t start_size = packet->size(); - DCHECK_LT(start_size + 12 + c_name_.length(), kIpPacketSize) + DCHECK_LT(start_size + 12 + c_name_.length(), kMaxIpPacketSize) << "Not enough buffer space"; - if (start_size + 12 > kIpPacketSize) return; + if (start_size + 12 > kMaxIpPacketSize) + return; // SDES Source Description. packet->resize(start_size + 10); - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 10); + base::BigEndianWriter big_endian_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 10); // We always need to add one SDES CNAME. big_endian_writer.WriteU8(0x80 + 1); - big_endian_writer.WriteU8(kPacketTypeSdes); + big_endian_writer.WriteU8(transport::kPacketTypeSdes); // Handle SDES length later on. uint32 sdes_length_position = static_cast<uint32>(start_size) + 3; big_endian_writer.WriteU16(0); big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. - big_endian_writer.WriteU8(1); // CNAME = 1 + big_endian_writer.WriteU8(1); // CNAME = 1 big_endian_writer.WriteU8(static_cast<uint8>(c_name_.length())); size_t sdes_length = 10 + c_name_.length(); - packet->insert(packet->end(), c_name_.c_str(), - c_name_.c_str() + c_name_.length()); + packet->insert( + packet->end(), c_name_.c_str(), c_name_.c_str() + c_name_.length()); size_t padding = 0; @@ -340,20 +307,21 @@ void RtcpSender::BuildSdec(std::vector<uint8>* packet) const { (*packet)[sdes_length_position] = buffer_length; } -void RtcpSender::BuildPli(uint32 remote_ssrc, - std::vector<uint8>* packet) const { +void RtcpSender::BuildPli(uint32 remote_ssrc, Packet* packet) const { size_t start_size = packet->size(); - DCHECK_LT(start_size + 12, kIpPacketSize) << "Not enough buffer space"; - if (start_size + 12 > kIpPacketSize) return; + DCHECK_LT(start_size + 12, kMaxIpPacketSize) << "Not enough buffer space"; + if (start_size + 12 > kMaxIpPacketSize) + return; packet->resize(start_size + 12); - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 12); + base::BigEndianWriter big_endian_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 12); uint8 FMT = 1; // Picture loss indicator. big_endian_writer.WriteU8(0x80 + FMT); - big_endian_writer.WriteU8(kPacketTypePayloadSpecific); - big_endian_writer.WriteU16(2); // Used fixed length of 2. - big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. + big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific); + big_endian_writer.WriteU16(2); // Used fixed length of 2. + big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. big_endian_writer.WriteU32(remote_ssrc); // Add the remote SSRC. } @@ -366,18 +334,19 @@ void RtcpSender::BuildPli(uint32 remote_ssrc, | defined per codec ... | Padding (0) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi, - std::vector<uint8>* packet) const { +void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi, Packet* packet) const { size_t start_size = packet->size(); - DCHECK_LT(start_size + 24, kIpPacketSize) << "Not enough buffer space"; - if (start_size + 24 > kIpPacketSize) return; + DCHECK_LT(start_size + 24, kMaxIpPacketSize) << "Not enough buffer space"; + if (start_size + 24 > kMaxIpPacketSize) + return; packet->resize(start_size + 24); - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 24); + base::BigEndianWriter big_endian_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 24); uint8 FMT = 3; // Reference Picture Selection Indication. big_endian_writer.WriteU8(0x80 + FMT); - big_endian_writer.WriteU8(kPacketTypePayloadSpecific); + big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific); // Calculate length. uint32 bits_required = 7; @@ -407,8 +376,8 @@ void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi, // Add picture ID. for (int i = bytes_required - 1; i > 0; i--) { - big_endian_writer.WriteU8( - 0x80 | static_cast<uint8>(rpsi->picture_id >> (i * 7))); + big_endian_writer.WriteU8(0x80 | + static_cast<uint8>(rpsi->picture_id >> (i * 7))); } // Add last byte of picture ID. big_endian_writer.WriteU8(static_cast<uint8>(rpsi->picture_id & 0x7f)); @@ -419,38 +388,38 @@ void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi, } } -void RtcpSender::BuildRemb(const RtcpRembMessage* remb, - std::vector<uint8>* packet) const { +void RtcpSender::BuildRemb(const RtcpRembMessage* remb, Packet* packet) const { size_t start_size = packet->size(); size_t remb_size = 20 + 4 * remb->remb_ssrcs.size(); - DCHECK_LT(start_size + remb_size, kIpPacketSize) + DCHECK_LT(start_size + remb_size, kMaxIpPacketSize) << "Not enough buffer space"; - if (start_size + remb_size > kIpPacketSize) return; + if (start_size + remb_size > kMaxIpPacketSize) + return; packet->resize(start_size + remb_size); - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), remb_size); + base::BigEndianWriter big_endian_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), remb_size); // Add application layer feedback. uint8 FMT = 15; big_endian_writer.WriteU8(0x80 + FMT); - big_endian_writer.WriteU8(kPacketTypePayloadSpecific); + big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific); big_endian_writer.WriteU8(0); big_endian_writer.WriteU8(static_cast<uint8>(remb->remb_ssrcs.size() + 4)); big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. - big_endian_writer.WriteU32(0); // Remote SSRC must be 0. + big_endian_writer.WriteU32(0); // Remote SSRC must be 0. big_endian_writer.WriteU32(kRemb); big_endian_writer.WriteU8(static_cast<uint8>(remb->remb_ssrcs.size())); // 6 bit exponent and a 18 bit mantissa. uint8 bitrate_exponent; uint32 bitrate_mantissa; - BitrateToRembExponentBitrate(remb->remb_bitrate, - &bitrate_exponent, - &bitrate_mantissa); + BitrateToRembExponentBitrate( + remb->remb_bitrate, &bitrate_exponent, &bitrate_mantissa); - big_endian_writer.WriteU8(static_cast<uint8>((bitrate_exponent << 2) + - ((bitrate_mantissa >> 16) & 0x03))); + big_endian_writer.WriteU8(static_cast<uint8>( + (bitrate_exponent << 2) + ((bitrate_mantissa >> 16) & 0x03))); big_endian_writer.WriteU8(static_cast<uint8>(bitrate_mantissa >> 8)); big_endian_writer.WriteU8(static_cast<uint8>(bitrate_mantissa)); @@ -458,34 +427,33 @@ void RtcpSender::BuildRemb(const RtcpRembMessage* remb, for (; it != remb->remb_ssrcs.end(); ++it) { big_endian_writer.WriteU32(*it); } - cast_environment_->Logging()->InsertGenericEvent(kRembBitrate, - remb->remb_bitrate); } -void RtcpSender::BuildNack(const RtcpNackMessage* nack, - std::vector<uint8>* packet) const { +void RtcpSender::BuildNack(const RtcpNackMessage* nack, Packet* packet) const { size_t start_size = packet->size(); - DCHECK_LT(start_size + 16, kIpPacketSize) << "Not enough buffer space"; - if (start_size + 16 > kIpPacketSize) return; + DCHECK_LT(start_size + 16, kMaxIpPacketSize) << "Not enough buffer space"; + if (start_size + 16 > kMaxIpPacketSize) + return; packet->resize(start_size + 16); - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 16); + base::BigEndianWriter big_endian_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 16); uint8 FMT = 1; big_endian_writer.WriteU8(0x80 + FMT); - big_endian_writer.WriteU8(kPacketTypeGenericRtpFeedback); + big_endian_writer.WriteU8(transport::kPacketTypeGenericRtpFeedback); big_endian_writer.WriteU8(0); size_t nack_size_pos = start_size + 3; big_endian_writer.WriteU8(3); - big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. + big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. big_endian_writer.WriteU32(nack->remote_ssrc); // Add the remote SSRC. // Build NACK bitmasks and write them to the Rtcp message. // The nack list should be sorted and not contain duplicates. size_t number_of_nack_fields = 0; - size_t max_number_of_nack_fields = std::min<size_t>(kRtcpMaxNackFields, - (kIpPacketSize - packet->size()) / 4); + size_t max_number_of_nack_fields = std::min<size_t>( + kRtcpMaxNackFields, (kMaxIpPacketSize - packet->size()) / 4); std::list<uint16>::const_iterator it = nack->nack_list.begin(); while (it != nack->nack_list.end() && @@ -504,11 +472,13 @@ void RtcpSender::BuildNack(const RtcpNackMessage* nack, } // Write the sequence number and the bitmask to the packet. start_size = packet->size(); - DCHECK_LT(start_size + 4, kIpPacketSize) << "Not enough buffer space"; - if (start_size + 4 > kIpPacketSize) return; + DCHECK_LT(start_size + 4, kMaxIpPacketSize) << "Not enough buffer space"; + if (start_size + 4 > kMaxIpPacketSize) + return; packet->resize(start_size + 4); - net::BigEndianWriter big_endian_nack_writer(&((*packet)[start_size]), 4); + base::BigEndianWriter big_endian_nack_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 4); big_endian_nack_writer.WriteU16(nack_sequence_number); big_endian_nack_writer.WriteU16(bitmask); number_of_nack_fields++; @@ -517,75 +487,41 @@ void RtcpSender::BuildNack(const RtcpNackMessage* nack, (*packet)[nack_size_pos] = static_cast<uint8>(2 + number_of_nack_fields); } -void RtcpSender::BuildBye(std::vector<uint8>* packet) const { +void RtcpSender::BuildBye(Packet* packet) const { size_t start_size = packet->size(); - DCHECK_LT(start_size + 8, kIpPacketSize) << "Not enough buffer space"; - if (start_size + 8 > kIpPacketSize) return; + DCHECK_LT(start_size + 8, kMaxIpPacketSize) << "Not enough buffer space"; + if (start_size + 8 > kMaxIpPacketSize) + return; packet->resize(start_size + 8); - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 8); + base::BigEndianWriter big_endian_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 8); big_endian_writer.WriteU8(0x80 + 1); - big_endian_writer.WriteU8(kPacketTypeBye); - big_endian_writer.WriteU16(1); // Length. - big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. -} - -/* - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |V=2|P|reserved | PT=XR=207 | length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | SSRC | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | BT=5 | reserved | block length | - +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ - | SSRC_1 (SSRC of first receiver) | sub- - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block - | last RR (LRR) | 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | delay since last RR (DLRR) | - +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -*/ -void RtcpSender::BuildDlrrRb(const RtcpDlrrReportBlock* dlrr, - std::vector<uint8>* packet) const { - size_t start_size = packet->size(); - DCHECK_LT(start_size + 24, kIpPacketSize) << "Not enough buffer space"; - if (start_size + 24 > kIpPacketSize) return; - - packet->resize(start_size + 24); - - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 24); - big_endian_writer.WriteU8(0x80); - big_endian_writer.WriteU8(kPacketTypeXr); - big_endian_writer.WriteU16(5); // Length. + big_endian_writer.WriteU8(transport::kPacketTypeBye); + big_endian_writer.WriteU16(1); // Length. big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. - big_endian_writer.WriteU8(5); // Add block type. - big_endian_writer.WriteU8(0); // Add reserved. - big_endian_writer.WriteU16(3); // Block length. - big_endian_writer.WriteU32(ssrc_); // Add the media (received RTP) SSRC. - big_endian_writer.WriteU32(dlrr->last_rr); - big_endian_writer.WriteU32(dlrr->delay_since_last_rr); } void RtcpSender::BuildRrtr(const RtcpReceiverReferenceTimeReport* rrtr, - std::vector<uint8>* packet) const { + Packet* packet) const { size_t start_size = packet->size(); - DCHECK_LT(start_size + 20, kIpPacketSize) << "Not enough buffer space"; - if (start_size + 20 > kIpPacketSize) return; + DCHECK_LT(start_size + 20, kMaxIpPacketSize) << "Not enough buffer space"; + if (start_size + 20 > kMaxIpPacketSize) + return; packet->resize(start_size + 20); - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 20); + base::BigEndianWriter big_endian_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 20); big_endian_writer.WriteU8(0x80); - big_endian_writer.WriteU8(kPacketTypeXr); - big_endian_writer.WriteU16(4); // Length. + big_endian_writer.WriteU8(transport::kPacketTypeXr); + big_endian_writer.WriteU16(4); // Length. big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. - big_endian_writer.WriteU8(4); // Add block type. - big_endian_writer.WriteU8(0); // Add reserved. - big_endian_writer.WriteU16(2); // Block length. + big_endian_writer.WriteU8(4); // Add block type. + big_endian_writer.WriteU8(0); // Add reserved. + big_endian_writer.WriteU16(2); // Block length. // Add the media (received RTP) SSRC. big_endian_writer.WriteU32(rrtr->ntp_seconds); @@ -593,47 +529,54 @@ void RtcpSender::BuildRrtr(const RtcpReceiverReferenceTimeReport* rrtr, } void RtcpSender::BuildCast(const RtcpCastMessage* cast, - std::vector<uint8>* packet) const { + uint16 target_delay_ms, + Packet* packet) const { size_t start_size = packet->size(); - DCHECK_LT(start_size + 20, kIpPacketSize) << "Not enough buffer space"; - if (start_size + 20 > kIpPacketSize) return; + DCHECK_LT(start_size + 20, kMaxIpPacketSize) << "Not enough buffer space"; + if (start_size + 20 > kMaxIpPacketSize) + return; packet->resize(start_size + 20); - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 20); + base::BigEndianWriter big_endian_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 20); uint8 FMT = 15; // Application layer feedback. big_endian_writer.WriteU8(0x80 + FMT); - big_endian_writer.WriteU8(kPacketTypePayloadSpecific); + big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific); big_endian_writer.WriteU8(0); - size_t cast_size_pos = start_size + 3; // Save length position. + size_t cast_size_pos = start_size + 3; // Save length position. big_endian_writer.WriteU8(4); - big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. + big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. big_endian_writer.WriteU32(cast->media_ssrc_); // Remote SSRC. big_endian_writer.WriteU32(kCast); big_endian_writer.WriteU8(static_cast<uint8>(cast->ack_frame_id_)); size_t cast_loss_field_pos = start_size + 17; // Save loss field position. big_endian_writer.WriteU8(0); // Overwritten with number_of_loss_fields. - big_endian_writer.WriteU8(0); // Reserved. - big_endian_writer.WriteU8(0); // Reserved. + big_endian_writer.WriteU16(target_delay_ms); size_t number_of_loss_fields = 0; - size_t max_number_of_loss_fields = std::min<size_t>(kRtcpMaxCastLossFields, - (kIpPacketSize - packet->size()) / 4); + size_t max_number_of_loss_fields = std::min<size_t>( + kRtcpMaxCastLossFields, (kMaxIpPacketSize - packet->size()) / 4); MissingFramesAndPacketsMap::const_iterator frame_it = cast->missing_frames_and_packets_.begin(); + NackStringBuilder nack_string_builder; for (; frame_it != cast->missing_frames_and_packets_.end() && - number_of_loss_fields < max_number_of_loss_fields; ++frame_it) { + number_of_loss_fields < max_number_of_loss_fields; + ++frame_it) { + nack_string_builder.PushFrame(frame_it->first); // Iterate through all frames with missing packets. if (frame_it->second.empty()) { // Special case all packets in a frame is missing. start_size = packet->size(); packet->resize(start_size + 4); - net::BigEndianWriter big_endian_nack_writer(&((*packet)[start_size]), 4); + base::BigEndianWriter big_endian_nack_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 4); big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first)); big_endian_nack_writer.WriteU16(kRtcpCastAllPacketsLost); big_endian_nack_writer.WriteU8(0); + nack_string_builder.PushPacket(kRtcpCastAllPacketsLost); ++number_of_loss_fields; } else { PacketIdSet::const_iterator packet_it = frame_it->second.begin(); @@ -642,18 +585,20 @@ void RtcpSender::BuildCast(const RtcpCastMessage* cast, start_size = packet->size(); packet->resize(start_size + 4); - net::BigEndianWriter big_endian_nack_writer( - &((*packet)[start_size]), 4); + base::BigEndianWriter big_endian_nack_writer( + reinterpret_cast<char*>(&((*packet)[start_size])), 4); // Write frame and packet id to buffer before calculating bitmask. big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first)); big_endian_nack_writer.WriteU16(packet_id); + nack_string_builder.PushPacket(packet_id); uint8 bitmask = 0; ++packet_it; while (packet_it != frame_it->second.end()) { int shift = static_cast<uint8>(*packet_it - packet_id) - 1; if (shift >= 0 && shift <= 7) { + nack_string_builder.PushPacket(*packet_it); bitmask |= (1 << shift); ++packet_it; } else { @@ -665,80 +610,48 @@ void RtcpSender::BuildCast(const RtcpCastMessage* cast, } } } + VLOG_IF(1, !nack_string_builder.Empty()) + << "SSRC: " << cast->media_ssrc_ + << ", ACK: " << cast->ack_frame_id_ + << ", NACK: " << nack_string_builder.GetString(); DCHECK_LE(number_of_loss_fields, kRtcpMaxCastLossFields); (*packet)[cast_size_pos] = static_cast<uint8>(4 + number_of_loss_fields); (*packet)[cast_loss_field_pos] = static_cast<uint8>(number_of_loss_fields); } -void RtcpSender::BuildSenderLog(RtcpSenderLogMessage* sender_log_message, - std::vector<uint8>* packet) const { - DCHECK(sender_log_message); - DCHECK(packet); - size_t start_size = packet->size(); - size_t remaining_space = kIpPacketSize - start_size; - DCHECK_GE(remaining_space, kRtcpCastLogHeaderSize + kRtcpSenderFrameLogSize) - << "Not enough buffer space"; - if (remaining_space < kRtcpCastLogHeaderSize + kRtcpSenderFrameLogSize) - return; - - size_t space_for_x_messages = - (remaining_space - kRtcpCastLogHeaderSize) / kRtcpSenderFrameLogSize; - size_t number_of_messages = std::min(space_for_x_messages, - sender_log_message->size()); - - size_t log_size = kRtcpCastLogHeaderSize + - number_of_messages * kRtcpSenderFrameLogSize; - packet->resize(start_size + log_size); - - net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), log_size); - big_endian_writer.WriteU8(0x80 + kSenderLogSubtype); - big_endian_writer.WriteU8(kPacketTypeApplicationDefined); - big_endian_writer.WriteU16(static_cast<uint16>(2 + number_of_messages)); - big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. - big_endian_writer.WriteU32(kCast); - - for (; number_of_messages > 0; --number_of_messages) { - DCHECK(!sender_log_message->empty()); - const RtcpSenderFrameLogMessage& message = sender_log_message->front(); - big_endian_writer.WriteU8(static_cast<uint8>(message.frame_status)); - // We send the 24 east significant bits of the RTP timestamp. - big_endian_writer.WriteU8(static_cast<uint8>(message.rtp_timestamp >> 16)); - big_endian_writer.WriteU8(static_cast<uint8>(message.rtp_timestamp >> 8)); - big_endian_writer.WriteU8(static_cast<uint8>(message.rtp_timestamp)); - sender_log_message->pop_front(); - } -} - -void RtcpSender::BuildReceiverLog(RtcpReceiverLogMessage* receiver_log_message, - std::vector<uint8>* packet) const { - DCHECK(receiver_log_message); +void RtcpSender::BuildReceiverLog( + const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events, + Packet* packet) { const size_t packet_start_size = packet->size(); size_t number_of_frames = 0; size_t total_number_of_messages_to_send = 0; size_t rtcp_log_size = 0; - - if (!ScanRtcpReceiverLogMessage(*receiver_log_message, - packet_start_size, - &number_of_frames, - &total_number_of_messages_to_send, - &rtcp_log_size)) { + RtcpReceiverLogMessage receiver_log_message; + + if (!BuildRtcpReceiverLogMessage(rtcp_events, + packet_start_size, + &receiver_log_message, + &number_of_frames, + &total_number_of_messages_to_send, + &rtcp_log_size)) { return; } packet->resize(packet_start_size + rtcp_log_size); - net::BigEndianWriter big_endian_writer(&((*packet)[packet_start_size]), - rtcp_log_size); + base::BigEndianWriter big_endian_writer( + reinterpret_cast<char*>(&((*packet)[packet_start_size])), rtcp_log_size); big_endian_writer.WriteU8(0x80 + kReceiverLogSubtype); - big_endian_writer.WriteU8(kPacketTypeApplicationDefined); - big_endian_writer.WriteU16(static_cast<uint16>(2 + 2 * number_of_frames + - total_number_of_messages_to_send)); + big_endian_writer.WriteU8(transport::kPacketTypeApplicationDefined); + big_endian_writer.WriteU16(static_cast<uint16>( + 2 + 2 * number_of_frames + total_number_of_messages_to_send)); big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. big_endian_writer.WriteU32(kCast); - while (!receiver_log_message->empty() && + while (!receiver_log_message.empty() && total_number_of_messages_to_send > 0) { - RtcpReceiverFrameLogMessage& frame_log_messages = - receiver_log_message->front(); + RtcpReceiverFrameLogMessage& frame_log_messages( + receiver_log_message.front()); + // Add our frame header. big_endian_writer.WriteU32(frame_log_messages.rtp_timestamp_); size_t messages_in_frame = frame_log_messages.event_log_messages_.size(); @@ -765,19 +678,18 @@ void RtcpSender::BuildReceiverLog(RtcpReceiverLogMessage* receiver_log_message, const RtcpReceiverEventLogMessage& event_message = frame_log_messages.event_log_messages_.front(); uint16 event_type_and_timestamp_delta = - MergeEventTypeAndTimestampForWireFormat(event_message.type, - event_message.event_timestamp - event_timestamp_base); + MergeEventTypeAndTimestampForWireFormat( + event_message.type, + event_message.event_timestamp - event_timestamp_base); switch (event_message.type) { - case kAckSent: - case kAudioPlayoutDelay: - case kAudioFrameDecoded: - case kVideoFrameDecoded: - case kVideoRenderDelay: - big_endian_writer.WriteU16(static_cast<uint16>( - event_message.delay_delta.InMilliseconds())); + case FRAME_ACK_SENT: + case FRAME_PLAYOUT: + case FRAME_DECODED: + big_endian_writer.WriteU16( + static_cast<uint16>(event_message.delay_delta.InMilliseconds())); big_endian_writer.WriteU16(event_type_and_timestamp_delta); break; - case kPacketReceived: + case PACKET_RECEIVED: big_endian_writer.WriteU16(event_message.packet_id); big_endian_writer.WriteU16(event_type_and_timestamp_delta); break; @@ -789,10 +701,124 @@ void RtcpSender::BuildReceiverLog(RtcpReceiverLogMessage* receiver_log_message, } if (frame_log_messages.event_log_messages_.empty()) { // We sent all messages on this frame; pop the frame header. - receiver_log_message->pop_front(); + receiver_log_message.pop_front(); } } - DCHECK_EQ(total_number_of_messages_to_send, 0); + DCHECK_EQ(total_number_of_messages_to_send, 0u); +} + +bool RtcpSender::BuildRtcpReceiverLogMessage( + const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events, + size_t start_size, + RtcpReceiverLogMessage* receiver_log_message, + size_t* number_of_frames, + size_t* total_number_of_messages_to_send, + size_t* rtcp_log_size) { + size_t remaining_space = + std::min(kMaxReceiverLogBytes, kMaxIpPacketSize - start_size); + if (remaining_space < kRtcpCastLogHeaderSize + kRtcpReceiverFrameLogSize + + kRtcpReceiverEventLogSize) { + return false; + } + + // We use this to do event timestamp sorting and truncating for events of + // a single frame. + std::vector<RtcpReceiverEventLogMessage> sorted_log_messages; + + // Account for the RTCP header for an application-defined packet. + remaining_space -= kRtcpCastLogHeaderSize; + + ReceiverRtcpEventSubscriber::RtcpEventMultiMap::const_reverse_iterator rit = + rtcp_events.rbegin(); + + while (rit != rtcp_events.rend() && + remaining_space >= + kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) { + const RtpTimestamp rtp_timestamp = rit->first; + RtcpReceiverFrameLogMessage frame_log(rtp_timestamp); + remaining_space -= kRtcpReceiverFrameLogSize; + ++*number_of_frames; + + // Get all events of a single frame. + sorted_log_messages.clear(); + do { + RtcpReceiverEventLogMessage event_log_message; + event_log_message.type = rit->second.type; + event_log_message.event_timestamp = rit->second.timestamp; + event_log_message.delay_delta = rit->second.delay_delta; + event_log_message.packet_id = rit->second.packet_id; + sorted_log_messages.push_back(event_log_message); + ++rit; + } while (rit != rtcp_events.rend() && rit->first == rtp_timestamp); + + std::sort(sorted_log_messages.begin(), + sorted_log_messages.end(), + &EventTimestampLessThan); + + // From |sorted_log_messages|, only take events that are no greater than + // |kMaxWireFormatTimeDeltaMs| seconds away from the latest event. Events + // older than that cannot be encoded over the wire. + std::vector<RtcpReceiverEventLogMessage>::reverse_iterator sorted_rit = + sorted_log_messages.rbegin(); + base::TimeTicks first_event_timestamp = sorted_rit->event_timestamp; + size_t events_in_frame = 0; + while (sorted_rit != sorted_log_messages.rend() && + events_in_frame < kRtcpMaxReceiverLogMessages && + remaining_space >= kRtcpReceiverEventLogSize) { + base::TimeDelta delta(first_event_timestamp - + sorted_rit->event_timestamp); + if (delta.InMilliseconds() > kMaxWireFormatTimeDeltaMs) + break; + frame_log.event_log_messages_.push_front(*sorted_rit); + ++events_in_frame; + ++*total_number_of_messages_to_send; + remaining_space -= kRtcpReceiverEventLogSize; + ++sorted_rit; + } + + receiver_log_message->push_front(frame_log); + } + + rtcp_events_history_.push_front(*receiver_log_message); + + // We don't try to match RTP timestamps of redundancy frame logs with those + // from the newest set (which would save the space of an extra RTP timestamp + // over the wire). Unless the redundancy frame logs are very recent, it's + // unlikely there will be a match anyway. + if (rtcp_events_history_.size() > kFirstRedundancyOffset) { + // Add first redundnacy messages, if enough space remaining + AddReceiverLog(rtcp_events_history_[kFirstRedundancyOffset], + receiver_log_message, + &remaining_space, + number_of_frames, + total_number_of_messages_to_send); + } + + if (rtcp_events_history_.size() > kSecondRedundancyOffset) { + // Add second redundancy messages, if enough space remaining + AddReceiverLog(rtcp_events_history_[kSecondRedundancyOffset], + receiver_log_message, + &remaining_space, + number_of_frames, + total_number_of_messages_to_send); + } + + if (rtcp_events_history_.size() > kReceiveLogMessageHistorySize) { + rtcp_events_history_.pop_back(); + } + + DCHECK_LE(rtcp_events_history_.size(), kReceiveLogMessageHistorySize); + + *rtcp_log_size = + kRtcpCastLogHeaderSize + *number_of_frames * kRtcpReceiverFrameLogSize + + *total_number_of_messages_to_send * kRtcpReceiverEventLogSize; + DCHECK_GE(kMaxIpPacketSize, start_size + *rtcp_log_size) + << "Not enough buffer space."; + + VLOG(3) << "number of frames: " << *number_of_frames; + VLOG(3) << "total messages to send: " << *total_number_of_messages_to_send; + VLOG(3) << "rtcp log size: " << *rtcp_log_size; + return *number_of_frames > 0; } } // namespace cast diff --git a/chromium/media/cast/rtcp/rtcp_sender.h b/chromium/media/cast/rtcp/rtcp_sender.h index e931c693c0f..f09a4fb0e53 100644 --- a/chromium/media/cast/rtcp/rtcp_sender.h +++ b/chromium/media/cast/rtcp/rtcp_sender.h @@ -5,95 +5,96 @@ #ifndef MEDIA_CAST_RTCP_RTCP_SENDER_H_ #define MEDIA_CAST_RTCP_RTCP_SENDER_H_ +#include <deque> #include <list> #include <string> #include "media/cast/cast_config.h" #include "media/cast/cast_defines.h" +#include "media/cast/rtcp/receiver_rtcp_event_subscriber.h" #include "media/cast/rtcp/rtcp.h" #include "media/cast/rtcp/rtcp_defines.h" +#include "media/cast/transport/cast_transport_defines.h" +#include "media/cast/transport/rtcp/rtcp_builder.h" namespace media { namespace cast { +// We limit the size of receiver logs to avoid queuing up packets. +const size_t kMaxReceiverLogBytes = 200; + +// The determines how long to hold receiver log events, based on how +// many "receiver log message reports" ago the events were sent. +const size_t kReceiveLogMessageHistorySize = 20; + +// This determines when to send events the second time. +const size_t kFirstRedundancyOffset = 10; +COMPILE_ASSERT(kFirstRedundancyOffset > 0 && + kFirstRedundancyOffset <= kReceiveLogMessageHistorySize, + redundancy_offset_out_of_range); + +// When to send events the third time. +const size_t kSecondRedundancyOffset = 20; +COMPILE_ASSERT(kSecondRedundancyOffset > + kFirstRedundancyOffset && kSecondRedundancyOffset <= + kReceiveLogMessageHistorySize, + redundancy_offset_out_of_range); + +// TODO(mikhal): Resolve duplication between this and RtcpBuilder. class RtcpSender { public: RtcpSender(scoped_refptr<CastEnvironment> cast_environment, - PacedPacketSender* const paced_packet_sender, + transport::PacedPacketSender* outgoing_transport, uint32 sending_ssrc, const std::string& c_name); virtual ~RtcpSender(); - void SendRtcpFromRtpSender(uint32 packet_type_flags, - const RtcpSenderInfo* sender_info, - const RtcpDlrrReportBlock* dlrr, - RtcpSenderLogMessage* sender_log); - - void SendRtcpFromRtpReceiver(uint32 packet_type_flags, - const RtcpReportBlock* report_block, - const RtcpReceiverReferenceTimeReport* rrtr, - const RtcpCastMessage* cast_message, - RtcpReceiverLogMessage* receiver_log); - - enum RtcpPacketType { - kRtcpSr = 0x0002, - kRtcpRr = 0x0004, - kRtcpBye = 0x0008, - kRtcpPli = 0x0010, - kRtcpNack = 0x0020, - kRtcpFir = 0x0040, - kRtcpSrReq = 0x0200, - kRtcpDlrr = 0x0400, - kRtcpRrtr = 0x0800, - kRtcpRpsi = 0x8000, - kRtcpRemb = 0x10000, - kRtcpCast = 0x20000, - kRtcpSenderLog = 0x40000, - kRtcpReceiverLog = 0x80000, - }; + void SendRtcpFromRtpReceiver( + uint32 packet_type_flags, + const transport::RtcpReportBlock* report_block, + const RtcpReceiverReferenceTimeReport* rrtr, + const RtcpCastMessage* cast_message, + const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events, + uint16 target_delay_ms); private: - void BuildSR(const RtcpSenderInfo& sender_info, - const RtcpReportBlock* report_block, - std::vector<uint8>* packet) const; + void BuildRR(const transport::RtcpReportBlock* report_block, + Packet* packet) const; - void BuildRR(const RtcpReportBlock* report_block, - std::vector<uint8>* packet) const; + void AddReportBlocks(const transport::RtcpReportBlock& report_block, + Packet* packet) const; - void AddReportBlocks(const RtcpReportBlock& report_block, - std::vector<uint8>* packet) const; + void BuildSdec(Packet* packet) const; - void BuildSdec(std::vector<uint8>* packet) const; + void BuildPli(uint32 remote_ssrc, Packet* packet) const; - void BuildPli(uint32 remote_ssrc, - std::vector<uint8>* packet) const; + void BuildRemb(const RtcpRembMessage* remb, Packet* packet) const; - void BuildRemb(const RtcpRembMessage* remb, - std::vector<uint8>* packet) const; + void BuildRpsi(const RtcpRpsiMessage* rpsi, Packet* packet) const; - void BuildRpsi(const RtcpRpsiMessage* rpsi, - std::vector<uint8>* packet) const; + void BuildNack(const RtcpNackMessage* nack, Packet* packet) const; - void BuildNack(const RtcpNackMessage* nack, - std::vector<uint8>* packet) const; - - void BuildBye(std::vector<uint8>* packet) const; - - void BuildDlrrRb(const RtcpDlrrReportBlock* dlrr, - std::vector<uint8>* packet) const; + void BuildBye(Packet* packet) const; void BuildRrtr(const RtcpReceiverReferenceTimeReport* rrtr, - std::vector<uint8>* packet) const; + Packet* packet) const; void BuildCast(const RtcpCastMessage* cast_message, - std::vector<uint8>* packet) const; + uint16 target_delay_ms, + Packet* packet) const; - void BuildSenderLog(RtcpSenderLogMessage* sender_log_message, - std::vector<uint8>* packet) const; + void BuildReceiverLog( + const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events, + Packet* packet); - void BuildReceiverLog(RtcpReceiverLogMessage* receiver_log_message, - std::vector<uint8>* packet) const; + bool BuildRtcpReceiverLogMessage( + const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events, + size_t start_size, + RtcpReceiverLogMessage* receiver_log_message, + size_t* number_of_frames, + size_t* total_number_of_messages_to_send, + size_t* rtcp_log_size); inline void BitrateToRembExponentBitrate(uint32 bitrate, uint8* exponent, @@ -113,9 +114,11 @@ class RtcpSender { const std::string c_name_; // Not owned by this class. - PacedPacketSender* transport_; + transport::PacedPacketSender* const transport_; scoped_refptr<CastEnvironment> cast_environment_; + std::deque<RtcpReceiverLogMessage> rtcp_events_history_; + DISALLOW_COPY_AND_ASSIGN(RtcpSender); }; diff --git a/chromium/media/cast/rtcp/rtcp_sender_unittest.cc b/chromium/media/cast/rtcp/rtcp_sender_unittest.cc index 16e9ee18ffb..0b0c7d3ab89 100644 --- a/chromium/media/cast/rtcp/rtcp_sender_unittest.cc +++ b/chromium/media/cast/rtcp/rtcp_sender_unittest.cc @@ -6,11 +6,13 @@ #include "base/test/simple_test_tick_clock.h" #include "media/cast/cast_defines.h" #include "media/cast/cast_environment.h" -#include "media/cast/net/pacing/paced_sender.h" +#include "media/cast/rtcp/receiver_rtcp_event_subscriber.h" #include "media/cast/rtcp/rtcp_sender.h" #include "media/cast/rtcp/rtcp_utility.h" #include "media/cast/rtcp/test_rtcp_packet_builder.h" -#include "media/cast/test/fake_task_runner.h" +#include "media/cast/test/fake_single_thread_task_runner.h" +#include "media/cast/transport/cast_transport_defines.h" +#include "media/cast/transport/pacing/paced_sender.h" #include "testing/gmock/include/gmock/gmock.h" namespace media { @@ -19,95 +21,99 @@ namespace cast { namespace { static const uint32 kSendingSsrc = 0x12345678; static const uint32 kMediaSsrc = 0x87654321; +static const int16 kDefaultDelay = 100; static const std::string kCName("test@10.1.1.1"); + +transport::RtcpReportBlock GetReportBlock() { + transport::RtcpReportBlock report_block; + // Initialize remote_ssrc to a "clearly illegal" value. + report_block.remote_ssrc = 0xDEAD; + report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender. + report_block.fraction_lost = kLoss >> 24; + report_block.cumulative_lost = kLoss; // 24 bits valid. + report_block.extended_high_sequence_number = kExtendedMax; + report_block.jitter = kTestJitter; + report_block.last_sr = kLastSr; + report_block.delay_since_last_sr = kDelayLastSr; + return report_block; +} + } // namespace -class TestRtcpTransport : public PacedPacketSender { +class TestRtcpTransport : public transport::PacedPacketSender { public: - TestRtcpTransport() - : expected_packet_length_(0), - packet_count_(0) { - } - - virtual bool SendRtcpPacket(const Packet& packet) OVERRIDE { - EXPECT_EQ(expected_packet_length_, packet.size()); - EXPECT_EQ(0, memcmp(expected_packet_, &(packet[0]), packet.size())); + TestRtcpTransport() : packet_count_(0) {} + + virtual bool SendRtcpPacket(uint32 ssrc, + transport::PacketRef packet) OVERRIDE { + EXPECT_EQ(expected_packet_.size(), packet->data.size()); + EXPECT_EQ(0, memcmp(expected_packet_.data(), + packet->data.data(), + packet->data.size())); packet_count_++; return true; } - virtual bool SendPackets(const PacketList& packets) OVERRIDE { + virtual bool SendPackets( + const transport::SendPacketVector& packets) OVERRIDE { return false; } - - virtual bool ResendPackets(const PacketList& packets) OVERRIDE { + virtual bool ResendPackets( + const transport::SendPacketVector& packets, + base::TimeDelta dedupe_window) OVERRIDE { return false; } - void SetExpectedRtcpPacket(const uint8* rtcp_buffer, size_t length) { - expected_packet_length_ = length; - memcpy(expected_packet_, rtcp_buffer, length); + virtual void CancelSendingPacket( + const transport::PacketKey& packet_key) OVERRIDE { + } + + void SetExpectedRtcpPacket(scoped_ptr<Packet> packet) { + expected_packet_.swap(*packet); } int packet_count() const { return packet_count_; } private: - uint8 expected_packet_[kIpPacketSize]; - size_t expected_packet_length_; + Packet expected_packet_; int packet_count_; + + DISALLOW_COPY_AND_ASSIGN(TestRtcpTransport); }; class RtcpSenderTest : public ::testing::Test { protected: RtcpSenderTest() - : task_runner_(new test::FakeTaskRunner(&testing_clock_)), - cast_environment_(new CastEnvironment(&testing_clock_, task_runner_, - task_runner_, task_runner_, task_runner_, task_runner_, - GetDefaultCastLoggingConfig())), + : testing_clock_(new base::SimpleTestTickClock()), + task_runner_(new test::FakeSingleThreadTaskRunner(testing_clock_)), + cast_environment_(new CastEnvironment( + scoped_ptr<base::TickClock>(testing_clock_).Pass(), + task_runner_, + task_runner_, + task_runner_)), rtcp_sender_(new RtcpSender(cast_environment_, &test_transport_, kSendingSsrc, - kCName)) { - } + kCName)) {} - base::SimpleTestTickClock testing_clock_; + base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment. TestRtcpTransport test_transport_; - scoped_refptr<test::FakeTaskRunner> task_runner_; + scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_; scoped_refptr<CastEnvironment> cast_environment_; scoped_ptr<RtcpSender> rtcp_sender_; -}; - -TEST_F(RtcpSenderTest, RtcpSenderReport) { - RtcpSenderInfo sender_info; - sender_info.ntp_seconds = kNtpHigh; - sender_info.ntp_fraction = kNtpLow; - sender_info.rtp_timestamp = kRtpTimestamp; - sender_info.send_packet_count = kSendPacketCount; - sender_info.send_octet_count = kSendOctetCount; - // Sender report + c_name. - TestRtcpPacketBuilder p; - p.AddSr(kSendingSsrc, 0); - p.AddSdesCname(kSendingSsrc, kCName); - test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length()); - - rtcp_sender_->SendRtcpFromRtpSender(RtcpSender::kRtcpSr, - &sender_info, - NULL, - NULL); - - EXPECT_EQ(1, test_transport_.packet_count()); -} + DISALLOW_COPY_AND_ASSIGN(RtcpSenderTest); +}; TEST_F(RtcpSenderTest, RtcpReceiverReport) { // Empty receiver report + c_name. TestRtcpPacketBuilder p1; p1.AddRr(kSendingSsrc, 0); p1.AddSdesCname(kSendingSsrc, kCName); - test_transport_.SetExpectedRtcpPacket(p1.Packet(), p1.Length()); + test_transport_.SetExpectedRtcpPacket(p1.GetPacket()); - rtcp_sender_->SendRtcpFromRtpReceiver(RtcpSender::kRtcpRr, - NULL, NULL, NULL, NULL); + rtcp_sender_->SendRtcpFromRtpReceiver( + transport::kRtcpRr, NULL, NULL, NULL, NULL, kDefaultDelay); EXPECT_EQ(1, test_transport_.packet_count()); @@ -116,133 +122,16 @@ TEST_F(RtcpSenderTest, RtcpReceiverReport) { p2.AddRr(kSendingSsrc, 1); p2.AddRb(kMediaSsrc); p2.AddSdesCname(kSendingSsrc, kCName); - test_transport_.SetExpectedRtcpPacket(p2.Packet(), p2.Length()); + test_transport_.SetExpectedRtcpPacket(p2.GetPacket().Pass()); - RtcpReportBlock report_block; - // Initialize remote_ssrc to a "clearly illegal" value. - report_block.remote_ssrc = 0xDEAD; - report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender. - report_block.fraction_lost = kLoss >> 24; - report_block.cumulative_lost = kLoss; // 24 bits valid. - report_block.extended_high_sequence_number = kExtendedMax; - report_block.jitter = kTestJitter; - report_block.last_sr = kLastSr; - report_block.delay_since_last_sr = kDelayLastSr; + transport::RtcpReportBlock report_block = GetReportBlock(); - rtcp_sender_->SendRtcpFromRtpReceiver(RtcpSender::kRtcpRr, &report_block, - NULL, NULL, NULL); + rtcp_sender_->SendRtcpFromRtpReceiver( + transport::kRtcpRr, &report_block, NULL, NULL, NULL, kDefaultDelay); EXPECT_EQ(2, test_transport_.packet_count()); } -TEST_F(RtcpSenderTest, RtcpSenderReportWithDlrr) { - RtcpSenderInfo sender_info; - sender_info.ntp_seconds = kNtpHigh; - sender_info.ntp_fraction = kNtpLow; - sender_info.rtp_timestamp = kRtpTimestamp; - sender_info.send_packet_count = kSendPacketCount; - sender_info.send_octet_count = kSendOctetCount; - - // Sender report + c_name + dlrr. - TestRtcpPacketBuilder p1; - p1.AddSr(kSendingSsrc, 0); - p1.AddSdesCname(kSendingSsrc, kCName); - p1.AddXrHeader(kSendingSsrc); - p1.AddXrDlrrBlock(kSendingSsrc); - test_transport_.SetExpectedRtcpPacket(p1.Packet(), p1.Length()); - - RtcpDlrrReportBlock dlrr_rb; - dlrr_rb.last_rr = kLastRr; - dlrr_rb.delay_since_last_rr = kDelayLastRr; - - rtcp_sender_->SendRtcpFromRtpSender( - RtcpSender::kRtcpSr | RtcpSender::kRtcpDlrr, - &sender_info, - &dlrr_rb, - NULL); - - EXPECT_EQ(1, test_transport_.packet_count()); -} - -TEST_F(RtcpSenderTest, RtcpSenderReportWithDlrrAndLog) { - RtcpSenderInfo sender_info; - sender_info.ntp_seconds = kNtpHigh; - sender_info.ntp_fraction = kNtpLow; - sender_info.rtp_timestamp = kRtpTimestamp; - sender_info.send_packet_count = kSendPacketCount; - sender_info.send_octet_count = kSendOctetCount; - - // Sender report + c_name + dlrr + sender log. - TestRtcpPacketBuilder p; - p.AddSr(kSendingSsrc, 0); - p.AddSdesCname(kSendingSsrc, kCName); - p.AddXrHeader(kSendingSsrc); - p.AddXrDlrrBlock(kSendingSsrc); - p.AddSenderLog(kSendingSsrc); - p.AddSenderFrameLog(kRtcpSenderFrameStatusSentToNetwork, kRtpTimestamp); - - test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length()); - - RtcpDlrrReportBlock dlrr_rb; - dlrr_rb.last_rr = kLastRr; - dlrr_rb.delay_since_last_rr = kDelayLastRr; - - RtcpSenderFrameLogMessage sender_frame_log; - sender_frame_log.frame_status = kRtcpSenderFrameStatusSentToNetwork; - sender_frame_log.rtp_timestamp = kRtpTimestamp; - - RtcpSenderLogMessage sender_log; - sender_log.push_back(sender_frame_log); - - rtcp_sender_->SendRtcpFromRtpSender( - RtcpSender::kRtcpSr | RtcpSender::kRtcpDlrr | RtcpSender::kRtcpSenderLog, - &sender_info, - &dlrr_rb, - &sender_log); - - EXPECT_EQ(1, test_transport_.packet_count()); - EXPECT_TRUE(sender_log.empty()); -} - -TEST_F(RtcpSenderTest, RtcpSenderReporWithTooManyLogFrames) { - RtcpSenderInfo sender_info; - sender_info.ntp_seconds = kNtpHigh; - sender_info.ntp_fraction = kNtpLow; - sender_info.rtp_timestamp = kRtpTimestamp; - sender_info.send_packet_count = kSendPacketCount; - sender_info.send_octet_count = kSendOctetCount; - - // Sender report + c_name + sender log. - TestRtcpPacketBuilder p; - p.AddSr(kSendingSsrc, 0); - p.AddSdesCname(kSendingSsrc, kCName); - p.AddSenderLog(kSendingSsrc); - - for (int i = 0; i < 359; ++i) { - p.AddSenderFrameLog(kRtcpSenderFrameStatusSentToNetwork, - kRtpTimestamp + i * 90); - } - test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length()); - - - RtcpSenderLogMessage sender_log; - for (int j = 0; j < 400; ++j) { - RtcpSenderFrameLogMessage sender_frame_log; - sender_frame_log.frame_status = kRtcpSenderFrameStatusSentToNetwork; - sender_frame_log.rtp_timestamp = kRtpTimestamp + j * 90; - sender_log.push_back(sender_frame_log); - } - - rtcp_sender_->SendRtcpFromRtpSender( - RtcpSender::kRtcpSr | RtcpSender::kRtcpSenderLog, - &sender_info, - NULL, - &sender_log); - - EXPECT_EQ(1, test_transport_.packet_count()); - EXPECT_EQ(41u, sender_log.size()); -} - TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtr) { // Receiver report with report block + c_name. TestRtcpPacketBuilder p; @@ -251,29 +140,21 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtr) { p.AddSdesCname(kSendingSsrc, kCName); p.AddXrHeader(kSendingSsrc); p.AddXrRrtrBlock(); - test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length()); + test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass()); - RtcpReportBlock report_block; - // Initialize remote_ssrc to a "clearly illegal" value. - report_block.remote_ssrc = 0xDEAD; - report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender. - report_block.fraction_lost = kLoss >> 24; - report_block.cumulative_lost = kLoss; // 24 bits valid. - report_block.extended_high_sequence_number = kExtendedMax; - report_block.jitter = kTestJitter; - report_block.last_sr = kLastSr; - report_block.delay_since_last_sr = kDelayLastSr; + transport::RtcpReportBlock report_block = GetReportBlock(); RtcpReceiverReferenceTimeReport rrtr; rrtr.ntp_seconds = kNtpHigh; rrtr.ntp_fraction = kNtpLow; rtcp_sender_->SendRtcpFromRtpReceiver( - RtcpSender::kRtcpRr | RtcpSender::kRtcpRrtr, + transport::kRtcpRr | transport::kRtcpRrtr, &report_block, &rrtr, NULL, - NULL); + NULL, + kDefaultDelay); EXPECT_EQ(1, test_transport_.packet_count()); } @@ -284,19 +165,10 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithCast) { p.AddRr(kSendingSsrc, 1); p.AddRb(kMediaSsrc); p.AddSdesCname(kSendingSsrc, kCName); - p.AddCast(kSendingSsrc, kMediaSsrc); - test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length()); + p.AddCast(kSendingSsrc, kMediaSsrc, kDefaultDelay); + test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass()); - RtcpReportBlock report_block; - // Initialize remote_ssrc to a "clearly illegal" value. - report_block.remote_ssrc = 0xDEAD; - report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender. - report_block.fraction_lost = kLoss >> 24; - report_block.cumulative_lost = kLoss; // 24 bits valid. - report_block.extended_high_sequence_number = kExtendedMax; - report_block.jitter = kTestJitter; - report_block.last_sr = kLastSr; - report_block.delay_since_last_sr = kDelayLastSr; + transport::RtcpReportBlock report_block = GetReportBlock(); RtcpCastMessage cast_message(kMediaSsrc); cast_message.ack_frame_id_ = kAckFrameId; @@ -310,11 +182,12 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithCast) { missing_packets; rtcp_sender_->SendRtcpFromRtpReceiver( - RtcpSender::kRtcpRr | RtcpSender::kRtcpCast, + transport::kRtcpRr | transport::kRtcpCast, &report_block, NULL, &cast_message, - NULL); + NULL, + kDefaultDelay); EXPECT_EQ(1, test_transport_.packet_count()); } @@ -326,19 +199,10 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtraAndCastMessage) { p.AddSdesCname(kSendingSsrc, kCName); p.AddXrHeader(kSendingSsrc); p.AddXrRrtrBlock(); - p.AddCast(kSendingSsrc, kMediaSsrc); - test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length()); + p.AddCast(kSendingSsrc, kMediaSsrc, kDefaultDelay); + test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass()); - RtcpReportBlock report_block; - // Initialize remote_ssrc to a "clearly illegal" value. - report_block.remote_ssrc = 0xDEAD; - report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender. - report_block.fraction_lost = kLoss >> 24; - report_block.cumulative_lost = kLoss; // 24 bits valid. - report_block.extended_high_sequence_number = kExtendedMax; - report_block.jitter = kTestJitter; - report_block.last_sr = kLastSr; - report_block.delay_since_last_sr = kDelayLastSr; + transport::RtcpReportBlock report_block = GetReportBlock(); RtcpReceiverReferenceTimeReport rrtr; rrtr.ntp_seconds = kNtpHigh; @@ -356,11 +220,12 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtraAndCastMessage) { missing_packets; rtcp_sender_->SendRtcpFromRtpReceiver( - RtcpSender::kRtcpRr | RtcpSender::kRtcpRrtr | RtcpSender::kRtcpCast, + transport::kRtcpRr | transport::kRtcpRrtr | transport::kRtcpCast, &report_block, &rrtr, &cast_message, - NULL); + NULL, + kDefaultDelay); EXPECT_EQ(1, test_transport_.packet_count()); } @@ -368,7 +233,6 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtraAndCastMessage) { TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtrCastMessageAndLog) { static const uint32 kTimeBaseMs = 12345678; static const uint32 kTimeDelayMs = 10; - static const uint32 kDelayDeltaMs = 123; TestRtcpPacketBuilder p; p.AddRr(kSendingSsrc, 1); @@ -376,19 +240,10 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtrCastMessageAndLog) { p.AddSdesCname(kSendingSsrc, kCName); p.AddXrHeader(kSendingSsrc); p.AddXrRrtrBlock(); - p.AddCast(kSendingSsrc, kMediaSsrc); - test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length()); + p.AddCast(kSendingSsrc, kMediaSsrc, kDefaultDelay); + test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass()); - RtcpReportBlock report_block; - // Initialize remote_ssrc to a "clearly illegal" value. - report_block.remote_ssrc = 0xDEAD; - report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender. - report_block.fraction_lost = kLoss >> 24; - report_block.cumulative_lost = kLoss; // 24 bits valid. - report_block.extended_high_sequence_number = kExtendedMax; - report_block.jitter = kTestJitter; - report_block.last_sr = kLastSr; - report_block.delay_since_last_sr = kDelayLastSr; + transport::RtcpReportBlock report_block = GetReportBlock(); RtcpReceiverReferenceTimeReport rrtr; rrtr.ntp_seconds = kNtpHigh; @@ -405,185 +260,296 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtrCastMessageAndLog) { cast_message.missing_frames_and_packets_[kFrameIdWithLostPackets] = missing_packets; - // Test empty Log message. - RtcpReceiverLogMessage receiver_log; + ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT); + ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; - VLOG(0) << " Test empty Log " ; rtcp_sender_->SendRtcpFromRtpReceiver( - RtcpSender::kRtcpRr | RtcpSender::kRtcpRrtr | RtcpSender::kRtcpCast | - RtcpSender::kRtcpReceiverLog, + transport::kRtcpRr | transport::kRtcpRrtr | transport::kRtcpCast | + transport::kRtcpReceiverLog, &report_block, &rrtr, &cast_message, - &receiver_log); - + &rtcp_events, + kDefaultDelay); base::SimpleTestTickClock testing_clock; testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs)); p.AddReceiverLog(kSendingSsrc); p.AddReceiverFrameLog(kRtpTimestamp, 2, kTimeBaseMs); - p.AddReceiverEventLog(kDelayDeltaMs, 1, 0); - p.AddReceiverEventLog(kLostPacketId1, 6, kTimeDelayMs); - - test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length()); + p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0); + p.AddReceiverEventLog(kLostPacketId1, PACKET_RECEIVED, kTimeDelayMs); - RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp); - RtcpReceiverEventLogMessage event_log; - - event_log.type = kAckSent; - event_log.event_timestamp = testing_clock.NowTicks(); - event_log.delay_delta = base::TimeDelta::FromMilliseconds(kDelayDeltaMs); - frame_log.event_log_messages_.push_back(event_log); + test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass()); + FrameEvent frame_event; + frame_event.rtp_timestamp = kRtpTimestamp; + frame_event.type = FRAME_ACK_SENT; + frame_event.media_type = VIDEO_EVENT; + frame_event.timestamp = testing_clock.NowTicks(); + event_subscriber.OnReceiveFrameEvent(frame_event); testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs)); - event_log.type = kPacketReceived; - event_log.event_timestamp = testing_clock.NowTicks(); - event_log.packet_id = kLostPacketId1; - frame_log.event_log_messages_.push_back(event_log); - receiver_log.push_back(frame_log); + PacketEvent packet_event; + packet_event.rtp_timestamp = kRtpTimestamp; + packet_event.type = PACKET_RECEIVED; + packet_event.media_type = VIDEO_EVENT; + packet_event.timestamp = testing_clock.NowTicks(); + packet_event.packet_id = kLostPacketId1; + event_subscriber.OnReceivePacketEvent(packet_event); + event_subscriber.GetRtcpEventsAndReset(&rtcp_events); + EXPECT_EQ(2u, rtcp_events.size()); - VLOG(0) << " Test Log " ; rtcp_sender_->SendRtcpFromRtpReceiver( - RtcpSender::kRtcpRr | RtcpSender::kRtcpRrtr | RtcpSender::kRtcpCast | - RtcpSender::kRtcpReceiverLog, + transport::kRtcpRr | transport::kRtcpRrtr | transport::kRtcpCast | + transport::kRtcpReceiverLog, &report_block, &rrtr, &cast_message, - &receiver_log); + &rtcp_events, + kDefaultDelay); - EXPECT_TRUE(receiver_log.empty()); EXPECT_EQ(2, test_transport_.packet_count()); } TEST_F(RtcpSenderTest, RtcpReceiverReportWithOversizedFrameLog) { static const uint32 kTimeBaseMs = 12345678; static const uint32 kTimeDelayMs = 10; - static const uint32 kDelayDeltaMs = 123; TestRtcpPacketBuilder p; p.AddRr(kSendingSsrc, 1); p.AddRb(kMediaSsrc); p.AddSdesCname(kSendingSsrc, kCName); - RtcpReportBlock report_block; - // Initialize remote_ssrc to a "clearly illegal" value. - report_block.remote_ssrc = 0xDEAD; - report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender. - report_block.fraction_lost = kLoss >> 24; - report_block.cumulative_lost = kLoss; // 24 bits valid. - report_block.extended_high_sequence_number = kExtendedMax; - report_block.jitter = kTestJitter; - report_block.last_sr = kLastSr; - report_block.delay_since_last_sr = kDelayLastSr; + transport::RtcpReportBlock report_block = GetReportBlock(); base::SimpleTestTickClock testing_clock; testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs)); p.AddReceiverLog(kSendingSsrc); - p.AddReceiverFrameLog(kRtpTimestamp, 1, kTimeBaseMs); - p.AddReceiverEventLog(kDelayDeltaMs, 1, 0); - p.AddReceiverFrameLog(kRtpTimestamp + 2345, - kRtcpMaxReceiverLogMessages, kTimeBaseMs); - - for (size_t i = 0; i < kRtcpMaxReceiverLogMessages; ++i) { + int remaining_bytes = kMaxReceiverLogBytes; + remaining_bytes -= kRtcpCastLogHeaderSize; + + remaining_bytes -= kRtcpReceiverFrameLogSize; + int num_events = remaining_bytes / kRtcpReceiverEventLogSize; + EXPECT_LE(num_events, static_cast<int>(kRtcpMaxReceiverLogMessages)); + // Only the last |num_events| events are sent due to receiver log size cap. + p.AddReceiverFrameLog( + kRtpTimestamp + 2345, + num_events, + kTimeBaseMs + (kRtcpMaxReceiverLogMessages - num_events) * kTimeDelayMs); + for (int i = 0; i < num_events; i++) { p.AddReceiverEventLog( - kLostPacketId1, 6, static_cast<uint16>(kTimeDelayMs * i)); + kLostPacketId1, PACKET_RECEIVED, + static_cast<uint16>(kTimeDelayMs * i)); } - test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length()); - - RtcpReceiverFrameLogMessage frame_1_log(kRtpTimestamp); - RtcpReceiverEventLogMessage event_log; - - event_log.type = kAckSent; - event_log.event_timestamp = testing_clock.NowTicks(); - event_log.delay_delta = base::TimeDelta::FromMilliseconds(kDelayDeltaMs); - frame_1_log.event_log_messages_.push_back(event_log); + test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass()); - RtcpReceiverLogMessage receiver_log; - receiver_log.push_back(frame_1_log); + ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT); + FrameEvent frame_event; + frame_event.rtp_timestamp = kRtpTimestamp; + frame_event.type = FRAME_ACK_SENT; + frame_event.media_type = VIDEO_EVENT; + frame_event.timestamp = testing_clock.NowTicks(); + event_subscriber.OnReceiveFrameEvent(frame_event); - RtcpReceiverFrameLogMessage frame_2_log(kRtpTimestamp + 2345); - - for (int j = 0; j < 300; ++j) { - event_log.type = kPacketReceived; - event_log.event_timestamp = testing_clock.NowTicks(); - event_log.packet_id = kLostPacketId1; - frame_2_log.event_log_messages_.push_back(event_log); + for (size_t i = 0; i < kRtcpMaxReceiverLogMessages; ++i) { + PacketEvent packet_event; + packet_event.rtp_timestamp = kRtpTimestamp + 2345; + packet_event.type = PACKET_RECEIVED; + packet_event.media_type = VIDEO_EVENT; + packet_event.timestamp = testing_clock.NowTicks(); + packet_event.packet_id = kLostPacketId1; + event_subscriber.OnReceivePacketEvent(packet_event); testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs)); } - receiver_log.push_back(frame_2_log); + + ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; + event_subscriber.GetRtcpEventsAndReset(&rtcp_events); rtcp_sender_->SendRtcpFromRtpReceiver( - RtcpSender::kRtcpRr | RtcpSender::kRtcpReceiverLog, + transport::kRtcpRr | transport::kRtcpReceiverLog, &report_block, NULL, NULL, - &receiver_log); + &rtcp_events, + kDefaultDelay); EXPECT_EQ(1, test_transport_.packet_count()); - EXPECT_EQ(1u, receiver_log.size()); - EXPECT_EQ(300u - kRtcpMaxReceiverLogMessages, - receiver_log.front().event_log_messages_.size()); } TEST_F(RtcpSenderTest, RtcpReceiverReportWithTooManyLogFrames) { static const uint32 kTimeBaseMs = 12345678; static const uint32 kTimeDelayMs = 10; - static const uint32 kDelayDeltaMs = 123; TestRtcpPacketBuilder p; p.AddRr(kSendingSsrc, 1); p.AddRb(kMediaSsrc); p.AddSdesCname(kSendingSsrc, kCName); - RtcpReportBlock report_block; - // Initialize remote_ssrc to a "clearly illegal" value. - report_block.remote_ssrc = 0xDEAD; - report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender. - report_block.fraction_lost = kLoss >> 24; - report_block.cumulative_lost = kLoss; // 24 bits valid. - report_block.extended_high_sequence_number = kExtendedMax; - report_block.jitter = kTestJitter; - report_block.last_sr = kLastSr; - report_block.delay_since_last_sr = kDelayLastSr; + transport::RtcpReportBlock report_block = GetReportBlock(); base::SimpleTestTickClock testing_clock; testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs)); p.AddReceiverLog(kSendingSsrc); - for (int i = 0; i < 119; ++i) { - p.AddReceiverFrameLog(kRtpTimestamp, 1, kTimeBaseMs + i * kTimeDelayMs); - p.AddReceiverEventLog(kDelayDeltaMs, 1, 0); - } - test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length()); + int remaining_bytes = kMaxReceiverLogBytes; + remaining_bytes -= kRtcpCastLogHeaderSize; + + int num_events = + remaining_bytes / (kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize); - RtcpReceiverLogMessage receiver_log; + // The last |num_events| events are sent due to receiver log size cap. + for (size_t i = kRtcpMaxReceiverLogMessages - num_events; + i < kRtcpMaxReceiverLogMessages; + ++i) { + p.AddReceiverFrameLog(kRtpTimestamp + i, 1, kTimeBaseMs + i * kTimeDelayMs); + p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0); + } + test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass()); - for (int j = 0; j < 200; ++j) { - RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp); - RtcpReceiverEventLogMessage event_log; + ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT); - event_log.type = kAckSent; - 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); + for (size_t i = 0; i < kRtcpMaxReceiverLogMessages; ++i) { + FrameEvent frame_event; + frame_event.rtp_timestamp = kRtpTimestamp + static_cast<int>(i); + frame_event.type = FRAME_ACK_SENT; + frame_event.media_type = VIDEO_EVENT; + frame_event.timestamp = testing_clock.NowTicks(); + event_subscriber.OnReceiveFrameEvent(frame_event); testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs)); } + + ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; + event_subscriber.GetRtcpEventsAndReset(&rtcp_events); + rtcp_sender_->SendRtcpFromRtpReceiver( - RtcpSender::kRtcpRr | RtcpSender::kRtcpReceiverLog, + transport::kRtcpRr | transport::kRtcpReceiverLog, &report_block, NULL, NULL, - &receiver_log); + &rtcp_events, + kDefaultDelay); EXPECT_EQ(1, test_transport_.packet_count()); - EXPECT_EQ(81u, receiver_log.size()); +} + +TEST_F(RtcpSenderTest, RtcpReceiverReportWithOldLogFrames) { + static const uint32 kTimeBaseMs = 12345678; + + TestRtcpPacketBuilder p; + p.AddRr(kSendingSsrc, 1); + p.AddRb(kMediaSsrc); + p.AddSdesCname(kSendingSsrc, kCName); + + transport::RtcpReportBlock report_block = GetReportBlock(); + + base::SimpleTestTickClock testing_clock; + testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs)); + + p.AddReceiverLog(kSendingSsrc); + + // Log 11 events for a single frame, each |kTimeBetweenEventsMs| apart. + // Only last 10 events will be sent because the first event is more than + // 4095 milliseconds away from latest event. + const int kTimeBetweenEventsMs = 410; + p.AddReceiverFrameLog(kRtpTimestamp, 10, kTimeBaseMs + kTimeBetweenEventsMs); + for (int i = 0; i < 10; ++i) { + p.AddReceiverEventLog(0, FRAME_ACK_SENT, i * kTimeBetweenEventsMs); + } + test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass()); + + ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT); + for (int i = 0; i < 11; ++i) { + FrameEvent frame_event; + frame_event.rtp_timestamp = kRtpTimestamp; + frame_event.type = FRAME_ACK_SENT; + frame_event.media_type = VIDEO_EVENT; + frame_event.timestamp = testing_clock.NowTicks(); + event_subscriber.OnReceiveFrameEvent(frame_event); + testing_clock.Advance( + base::TimeDelta::FromMilliseconds(kTimeBetweenEventsMs)); + } + + ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; + event_subscriber.GetRtcpEventsAndReset(&rtcp_events); + + rtcp_sender_->SendRtcpFromRtpReceiver( + transport::kRtcpRr | transport::kRtcpReceiverLog, + &report_block, + NULL, + NULL, + &rtcp_events, + kDefaultDelay); + + EXPECT_EQ(1, test_transport_.packet_count()); +} + +TEST_F(RtcpSenderTest, RtcpReceiverReportRedundancy) { + uint32 time_base_ms = 12345678; + int kTimeBetweenEventsMs = 10; + + transport::RtcpReportBlock report_block = GetReportBlock(); + + base::SimpleTestTickClock testing_clock; + testing_clock.Advance(base::TimeDelta::FromMilliseconds(time_base_ms)); + + ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT); + size_t packet_count = kReceiveLogMessageHistorySize + 10; + for (size_t i = 0; i < packet_count; i++) { + TestRtcpPacketBuilder p; + p.AddRr(kSendingSsrc, 1); + p.AddRb(kMediaSsrc); + p.AddSdesCname(kSendingSsrc, kCName); + + p.AddReceiverLog(kSendingSsrc); + + if (i >= kSecondRedundancyOffset) { + p.AddReceiverFrameLog( + kRtpTimestamp, + 1, + time_base_ms - kSecondRedundancyOffset * kTimeBetweenEventsMs); + p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0); + } + if (i >= kFirstRedundancyOffset) { + p.AddReceiverFrameLog( + kRtpTimestamp, + 1, + time_base_ms - kFirstRedundancyOffset * kTimeBetweenEventsMs); + p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0); + } + p.AddReceiverFrameLog(kRtpTimestamp, 1, time_base_ms); + p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0); + + test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass()); + + FrameEvent frame_event; + frame_event.rtp_timestamp = kRtpTimestamp; + frame_event.type = FRAME_ACK_SENT; + frame_event.media_type = VIDEO_EVENT; + frame_event.timestamp = testing_clock.NowTicks(); + event_subscriber.OnReceiveFrameEvent(frame_event); + + ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; + event_subscriber.GetRtcpEventsAndReset(&rtcp_events); + + rtcp_sender_->SendRtcpFromRtpReceiver( + transport::kRtcpRr | transport::kRtcpReceiverLog, + &report_block, + NULL, + NULL, + &rtcp_events, + kDefaultDelay); + + testing_clock.Advance( + base::TimeDelta::FromMilliseconds(kTimeBetweenEventsMs)); + time_base_ms += kTimeBetweenEventsMs; + } + + EXPECT_EQ(static_cast<int>(packet_count), test_transport_.packet_count()); } } // namespace cast diff --git a/chromium/media/cast/rtcp/rtcp_unittest.cc b/chromium/media/cast/rtcp/rtcp_unittest.cc index 535f3c34f83..095e6d24df9 100644 --- a/chromium/media/cast/rtcp/rtcp_unittest.cc +++ b/chromium/media/cast/rtcp/rtcp_unittest.cc @@ -2,15 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <stdint.h> + #include "base/test/simple_test_tick_clock.h" #include "media/cast/cast_defines.h" #include "media/cast/cast_environment.h" -#include "media/cast/net/pacing/paced_sender.h" #include "media/cast/rtcp/mock_rtcp_receiver_feedback.h" #include "media/cast/rtcp/mock_rtcp_sender_feedback.h" #include "media/cast/rtcp/rtcp.h" #include "media/cast/rtcp/test_rtcp_packet_builder.h" -#include "media/cast/test/fake_task_runner.h" +#include "media/cast/test/fake_single_thread_task_runner.h" +#include "media/cast/transport/cast_transport_config.h" +#include "media/cast/transport/cast_transport_sender_impl.h" +#include "media/cast/transport/pacing/paced_sender.h" #include "testing/gmock/include/gmock/gmock.h" namespace media { @@ -22,60 +26,109 @@ static const uint32 kSenderSsrc = 0x10203; static const uint32 kReceiverSsrc = 0x40506; static const std::string kCName("test@10.1.1.1"); static const uint32 kRtcpIntervalMs = 500; -static const int64 kStartMillisecond = GG_INT64_C(12345678900000); static const int64 kAddedDelay = 123; -static const int64 kAddedShortDelay= 100; +static const int64 kAddedShortDelay = 100; -class LocalRtcpTransport : public PacedPacketSender { +class RtcpTestPacketSender : public transport::PacketSender { public: - explicit LocalRtcpTransport(scoped_refptr<CastEnvironment> cast_environment, - base::SimpleTestTickClock* testing_clock) + explicit RtcpTestPacketSender(base::SimpleTestTickClock* testing_clock) : drop_packets_(false), short_delay_(false), + rtcp_receiver_(NULL), testing_clock_(testing_clock) {} + virtual ~RtcpTestPacketSender() {} + // Packet lists imply a RTP packet. + void set_rtcp_receiver(Rtcp* rtcp) { rtcp_receiver_ = rtcp; } + + void set_short_delay() { short_delay_ = true; } + + void set_drop_packets(bool drop_packets) { drop_packets_ = drop_packets; } + + // A singular packet implies a RTCP packet. + virtual bool SendPacket(transport::PacketRef packet, + const base::Closure& cb) OVERRIDE { + if (short_delay_) { + testing_clock_->Advance( + base::TimeDelta::FromMilliseconds(kAddedShortDelay)); + } else { + testing_clock_->Advance(base::TimeDelta::FromMilliseconds(kAddedDelay)); + } + if (drop_packets_) + return true; + + rtcp_receiver_->IncomingRtcpPacket(&packet->data[0], packet->data.size()); + return true; + } - void SetRtcpReceiver(Rtcp* rtcp) { rtcp_ = rtcp; } + private: + bool drop_packets_; + bool short_delay_; + Rtcp* rtcp_receiver_; + base::SimpleTestTickClock* testing_clock_; - void SetShortDelay() { short_delay_ = true; } + DISALLOW_COPY_AND_ASSIGN(RtcpTestPacketSender); +}; - void SetDropPackets(bool drop_packets) { drop_packets_ = drop_packets; } +class LocalRtcpTransport : public transport::PacedPacketSender { + public: + LocalRtcpTransport(scoped_refptr<CastEnvironment> cast_environment, + base::SimpleTestTickClock* testing_clock) + : drop_packets_(false), + short_delay_(false), + testing_clock_(testing_clock) {} + void set_rtcp_receiver(Rtcp* rtcp) { rtcp_ = rtcp; } - virtual bool SendRtcpPacket(const std::vector<uint8>& packet) OVERRIDE { + void set_short_delay() { short_delay_ = true; } + + void set_drop_packets(bool drop_packets) { drop_packets_ = drop_packets; } + + virtual bool SendRtcpPacket(uint32 ssrc, + transport::PacketRef packet) OVERRIDE { if (short_delay_) { testing_clock_->Advance( base::TimeDelta::FromMilliseconds(kAddedShortDelay)); } else { testing_clock_->Advance(base::TimeDelta::FromMilliseconds(kAddedDelay)); } - if (drop_packets_) return true; + if (drop_packets_) + return true; - rtcp_->IncomingRtcpPacket(&(packet[0]), packet.size()); + rtcp_->IncomingRtcpPacket(&packet->data[0], packet->data.size()); return true; } - virtual bool SendPackets(const PacketList& packets) OVERRIDE { + virtual bool SendPackets( + const transport::SendPacketVector& packets) OVERRIDE { return false; } - virtual bool ResendPackets(const PacketList& packets) OVERRIDE { + virtual bool ResendPackets( + const transport::SendPacketVector& packets, + base::TimeDelta dedupe_window) OVERRIDE { return false; } + virtual void CancelSendingPacket( + const transport::PacketKey& packet_key) OVERRIDE { + } + private: bool drop_packets_; bool short_delay_; Rtcp* rtcp_; base::SimpleTestTickClock* testing_clock_; scoped_refptr<CastEnvironment> cast_environment_; + + DISALLOW_COPY_AND_ASSIGN(LocalRtcpTransport); }; class RtcpPeer : public Rtcp { public: RtcpPeer(scoped_refptr<CastEnvironment> cast_environment, RtcpSenderFeedback* sender_feedback, - PacedPacketSender* const paced_packet_sender, - RtpSenderStatistics* rtp_sender_statistics, + transport::CastTransportSender* const transport_sender, + transport::PacedPacketSender* paced_packet_sender, RtpReceiverStatistics* rtp_receiver_statistics, RtcpMode rtcp_mode, const base::TimeDelta& rtcp_interval, @@ -84,95 +137,129 @@ class RtcpPeer : public Rtcp { const std::string& c_name) : Rtcp(cast_environment, sender_feedback, + transport_sender, paced_packet_sender, - rtp_sender_statistics, rtp_receiver_statistics, rtcp_mode, rtcp_interval, local_ssrc, remote_ssrc, - c_name) { - } + c_name, + AUDIO_EVENT) {} - using Rtcp::CheckForWrapAround; + using Rtcp::OnReceivedNtp; using Rtcp::OnReceivedLipSyncInfo; }; class RtcpTest : public ::testing::Test { protected: RtcpTest() - : task_runner_(new test::FakeTaskRunner(&testing_clock_)), - cast_environment_(new CastEnvironment(&testing_clock_, task_runner_, - task_runner_, task_runner_, task_runner_, task_runner_, - GetDefaultCastLoggingConfig())), - transport_(cast_environment_, &testing_clock_) { - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kStartMillisecond)); + : testing_clock_(new base::SimpleTestTickClock()), + task_runner_(new test::FakeSingleThreadTaskRunner(testing_clock_)), + cast_environment_(new CastEnvironment( + scoped_ptr<base::TickClock>(testing_clock_).Pass(), + task_runner_, + task_runner_, + task_runner_)), + sender_to_receiver_(testing_clock_), + receiver_to_sender_(cast_environment_, testing_clock_) { + testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks()); + net::IPEndPoint dummy_endpoint; + transport_sender_.reset(new transport::CastTransportSenderImpl( + NULL, + testing_clock_, + dummy_endpoint, + base::Bind(&UpdateCastTransportStatus), + transport::BulkRawEventsCallback(), + base::TimeDelta(), + task_runner_, + &sender_to_receiver_)); + transport::CastTransportAudioConfig config; + config.rtp.config.ssrc = kSenderSsrc; + config.rtp.max_outstanding_frames = 1; + transport_sender_->InitializeAudio(config); + EXPECT_CALL(mock_sender_feedback_, OnReceivedCastFeedback(_)).Times(0); } virtual ~RtcpTest() {} - virtual void SetUp() { - EXPECT_CALL(mock_sender_feedback_, OnReceivedCastFeedback(_)).Times(0); + static void UpdateCastTransportStatus(transport::CastTransportStatus status) { + bool result = (status == transport::TRANSPORT_AUDIO_INITIALIZED || + status == transport::TRANSPORT_VIDEO_INITIALIZED); + EXPECT_TRUE(result); + } + + void RunTasks(int during_ms) { + for (int i = 0; i < during_ms; ++i) { + // Call process the timers every 1 ms. + testing_clock_->Advance(base::TimeDelta::FromMilliseconds(1)); + task_runner_->RunTasks(); + } } - base::SimpleTestTickClock testing_clock_; - scoped_refptr<test::FakeTaskRunner> task_runner_; + base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment. + scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_; scoped_refptr<CastEnvironment> cast_environment_; - LocalRtcpTransport transport_; + RtcpTestPacketSender sender_to_receiver_; + scoped_ptr<transport::CastTransportSenderImpl> transport_sender_; + LocalRtcpTransport receiver_to_sender_; MockRtcpSenderFeedback mock_sender_feedback_; + + DISALLOW_COPY_AND_ASSIGN(RtcpTest); }; TEST_F(RtcpTest, TimeToSend) { - base::TimeTicks start_time; - start_time += base::TimeDelta::FromMilliseconds(kStartMillisecond); + const base::TimeTicks start_time = testing_clock_->NowTicks(); Rtcp rtcp(cast_environment_, &mock_sender_feedback_, - &transport_, - NULL, + transport_sender_.get(), + &receiver_to_sender_, NULL, kRtcpCompound, base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), kSenderSsrc, kReceiverSsrc, - kCName); - transport_.SetRtcpReceiver(&rtcp); + kCName, + AUDIO_EVENT); + receiver_to_sender_.set_rtcp_receiver(&rtcp); EXPECT_LE(start_time, rtcp.TimeToSendNextRtcpReport()); - EXPECT_GE(start_time + base::TimeDelta::FromMilliseconds( - kRtcpIntervalMs * 3 / 2), - rtcp.TimeToSendNextRtcpReport()); + EXPECT_GE( + start_time + base::TimeDelta::FromMilliseconds(kRtcpIntervalMs * 3 / 2), + rtcp.TimeToSendNextRtcpReport()); base::TimeDelta delta = rtcp.TimeToSendNextRtcpReport() - start_time; - testing_clock_.Advance(delta); - EXPECT_EQ(testing_clock_.NowTicks(), rtcp.TimeToSendNextRtcpReport()); + testing_clock_->Advance(delta); + EXPECT_EQ(testing_clock_->NowTicks(), rtcp.TimeToSendNextRtcpReport()); } TEST_F(RtcpTest, BasicSenderReport) { Rtcp rtcp(cast_environment_, &mock_sender_feedback_, - &transport_, + transport_sender_.get(), NULL, NULL, kRtcpCompound, base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), kSenderSsrc, kReceiverSsrc, - kCName); - transport_.SetRtcpReceiver(&rtcp); - rtcp.SendRtcpFromRtpSender(NULL); + kCName, + AUDIO_EVENT); + sender_to_receiver_.set_rtcp_receiver(&rtcp); + rtcp.SendRtcpFromRtpSender(base::TimeTicks(), 0); } TEST_F(RtcpTest, BasicReceiverReport) { Rtcp rtcp(cast_environment_, &mock_sender_feedback_, - &transport_, NULL, + &receiver_to_sender_, NULL, kRtcpCompound, base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), kSenderSsrc, kReceiverSsrc, - kCName); - transport_.SetRtcpReceiver(&rtcp); + kCName, + AUDIO_EVENT); + receiver_to_sender_.set_rtcp_receiver(&rtcp); rtcp.SendRtcpFromRtpReceiver(NULL, NULL); } @@ -182,20 +269,20 @@ TEST_F(RtcpTest, BasicCast) { // Media receiver. Rtcp rtcp(cast_environment_, &mock_sender_feedback_, - &transport_, NULL, + &receiver_to_sender_, NULL, kRtcpReducedSize, base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), kSenderSsrc, kSenderSsrc, - kCName); - transport_.SetRtcpReceiver(&rtcp); + kCName, + AUDIO_EVENT); + receiver_to_sender_.set_rtcp_receiver(&rtcp); RtcpCastMessage cast_message(kSenderSsrc); cast_message.ack_frame_id_ = kAckFrameId; PacketIdSet missing_packets; - cast_message.missing_frames_and_packets_[ - kLostFrameId] = missing_packets; + cast_message.missing_frames_and_packets_[kLostFrameId] = missing_packets; missing_packets.insert(kLostPacketId1); missing_packets.insert(kLostPacketId2); @@ -207,334 +294,254 @@ TEST_F(RtcpTest, BasicCast) { TEST_F(RtcpTest, RttReducedSizeRtcp) { // Media receiver. - LocalRtcpTransport receiver_transport(cast_environment_, &testing_clock_); Rtcp rtcp_receiver(cast_environment_, &mock_sender_feedback_, - &receiver_transport, NULL, + &receiver_to_sender_, NULL, kRtcpReducedSize, base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), kReceiverSsrc, kSenderSsrc, - kCName); + kCName, + AUDIO_EVENT); // Media sender. - LocalRtcpTransport sender_transport(cast_environment_, &testing_clock_); Rtcp rtcp_sender(cast_environment_, &mock_sender_feedback_, - &sender_transport, + transport_sender_.get(), NULL, NULL, kRtcpReducedSize, base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), kSenderSsrc, kReceiverSsrc, - kCName); + kCName, + AUDIO_EVENT); - receiver_transport.SetRtcpReceiver(&rtcp_sender); - sender_transport.SetRtcpReceiver(&rtcp_receiver); + sender_to_receiver_.set_rtcp_receiver(&rtcp_receiver); + receiver_to_sender_.set_rtcp_receiver(&rtcp_sender); base::TimeDelta rtt; base::TimeDelta avg_rtt; base::TimeDelta min_rtt; base::TimeDelta max_rtt; - EXPECT_FALSE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_FALSE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_FALSE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_FALSE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - rtcp_sender.SendRtcpFromRtpSender(NULL); + rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 1); + RunTasks(33); rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL); - EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_FALSE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_NEAR(2 * kAddedDelay, rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, avg_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, min_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 1); - rtcp_sender.SendRtcpFromRtpSender(NULL); - EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - - EXPECT_NEAR(2 * kAddedDelay, rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, avg_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, min_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 1); + EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_FALSE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_NEAR(2 * kAddedDelay, rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, avg_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, min_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2); + rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 2); + RunTasks(33); + EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + + EXPECT_NEAR(2 * kAddedDelay, rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, avg_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, min_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2); } TEST_F(RtcpTest, Rtt) { // Media receiver. - LocalRtcpTransport receiver_transport(cast_environment_, &testing_clock_); Rtcp rtcp_receiver(cast_environment_, &mock_sender_feedback_, - &receiver_transport, NULL, + &receiver_to_sender_, NULL, kRtcpCompound, base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), kReceiverSsrc, kSenderSsrc, - kCName); + kCName, + AUDIO_EVENT); // Media sender. - LocalRtcpTransport sender_transport(cast_environment_, &testing_clock_); Rtcp rtcp_sender(cast_environment_, &mock_sender_feedback_, - &sender_transport, + transport_sender_.get(), NULL, NULL, kRtcpCompound, base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), kSenderSsrc, kReceiverSsrc, - kCName); + kCName, + AUDIO_EVENT); - receiver_transport.SetRtcpReceiver(&rtcp_sender); - sender_transport.SetRtcpReceiver(&rtcp_receiver); + receiver_to_sender_.set_rtcp_receiver(&rtcp_sender); + sender_to_receiver_.set_rtcp_receiver(&rtcp_receiver); base::TimeDelta rtt; base::TimeDelta avg_rtt; base::TimeDelta min_rtt; base::TimeDelta max_rtt; - EXPECT_FALSE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_FALSE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_FALSE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_FALSE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - rtcp_sender.SendRtcpFromRtpSender(NULL); + rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 1); + RunTasks(33); rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL); - EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_FALSE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_NEAR(2 * kAddedDelay, rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, avg_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, min_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 1); - rtcp_sender.SendRtcpFromRtpSender(NULL); - EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_NEAR(2 * kAddedDelay, rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, avg_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, min_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 1); + EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + RunTasks(33); - receiver_transport.SetShortDelay(); - sender_transport.SetShortDelay(); - rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL); - EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_NEAR(kAddedDelay + kAddedShortDelay, rtt.InMilliseconds(), 1); - EXPECT_NEAR((kAddedShortDelay + 3 * kAddedDelay) / 2, - avg_rtt.InMilliseconds(), - 1); - EXPECT_NEAR(kAddedDelay + kAddedShortDelay, min_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 1); + EXPECT_FALSE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + RunTasks(33); - rtcp_sender.SendRtcpFromRtpSender(NULL); - EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_NEAR(2 * kAddedDelay, rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, avg_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, min_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2); + + rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 2); + RunTasks(33); + EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_NEAR(2 * kAddedDelay, rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, avg_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, min_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2); + + receiver_to_sender_.set_short_delay(); + sender_to_receiver_.set_short_delay(); + rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL); + EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_NEAR(kAddedDelay + kAddedShortDelay, rtt.InMilliseconds(), 2); + EXPECT_NEAR( + (kAddedShortDelay + 3 * kAddedDelay) / 2, avg_rtt.InMilliseconds(), 2); + EXPECT_NEAR(kAddedDelay + kAddedShortDelay, min_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2); + + rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 3); + RunTasks(33); + EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); EXPECT_NEAR(2 * kAddedShortDelay, rtt.InMilliseconds(), 1); EXPECT_NEAR((2 * kAddedShortDelay + 2 * kAddedDelay) / 2, - avg_rtt.InMilliseconds(), - 1); - EXPECT_NEAR(2 * kAddedShortDelay, min_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 1); + avg_rtt.InMilliseconds(), + 1); + EXPECT_NEAR(2 * kAddedShortDelay, min_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2); rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL); - EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_NEAR(2 * kAddedShortDelay, rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedShortDelay, min_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 1); + EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_NEAR(2 * kAddedShortDelay, rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedShortDelay, min_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2); rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL); - EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_NEAR(2 * kAddedShortDelay, rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedShortDelay, min_rtt.InMilliseconds(), 1); - EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 1); + EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_NEAR(2 * kAddedShortDelay, rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedShortDelay, min_rtt.InMilliseconds(), 2); + EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2); } TEST_F(RtcpTest, RttWithPacketLoss) { // Media receiver. - LocalRtcpTransport receiver_transport(cast_environment_, &testing_clock_); Rtcp rtcp_receiver(cast_environment_, &mock_sender_feedback_, - &receiver_transport, NULL, + &receiver_to_sender_, NULL, kRtcpReducedSize, base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), - kSenderSsrc, kReceiverSsrc, - kCName); + kSenderSsrc, + kCName, + AUDIO_EVENT); // Media sender. - LocalRtcpTransport sender_transport(cast_environment_, &testing_clock_); Rtcp rtcp_sender(cast_environment_, &mock_sender_feedback_, - &sender_transport, + transport_sender_.get(), NULL, NULL, kRtcpReducedSize, base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), - kReceiverSsrc, kSenderSsrc, - kCName); + kReceiverSsrc, + kCName, + AUDIO_EVENT); - receiver_transport.SetRtcpReceiver(&rtcp_sender); - sender_transport.SetRtcpReceiver(&rtcp_receiver); + receiver_to_sender_.set_rtcp_receiver(&rtcp_sender); + sender_to_receiver_.set_rtcp_receiver(&rtcp_receiver); rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL); - rtcp_sender.SendRtcpFromRtpSender(NULL); + rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 0); + RunTasks(33); base::TimeDelta rtt; base::TimeDelta avg_rtt; base::TimeDelta min_rtt; base::TimeDelta max_rtt; - EXPECT_FALSE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_FALSE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); EXPECT_NEAR(2 * kAddedDelay, rtt.InMilliseconds(), 1); EXPECT_NEAR(2 * kAddedDelay, avg_rtt.InMilliseconds(), 1); EXPECT_NEAR(2 * kAddedDelay, min_rtt.InMilliseconds(), 1); EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 1); - receiver_transport.SetShortDelay(); - sender_transport.SetShortDelay(); - receiver_transport.SetDropPackets(true); + receiver_to_sender_.set_short_delay(); + sender_to_receiver_.set_short_delay(); + receiver_to_sender_.set_drop_packets(true); rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL); - rtcp_sender.SendRtcpFromRtpSender(NULL); + rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 1); + RunTasks(33); - EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); - EXPECT_NEAR(kAddedDelay + kAddedShortDelay, rtt.InMilliseconds(), 1); + EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_NEAR(kAddedDelay + kAddedShortDelay, rtt.InMilliseconds(), 2); } TEST_F(RtcpTest, NtpAndTime) { - const int64 kSecondsbetweenYear1900and2010 = GG_INT64_C(40176 * 24 * 60 * 60); - const int64 kSecondsbetweenYear1900and2030 = GG_INT64_C(47481 * 24 * 60 * 60); + const int64 kSecondsbetweenYear1900and2010 = INT64_C(40176 * 24 * 60 * 60); + const int64 kSecondsbetweenYear1900and2030 = INT64_C(47481 * 24 * 60 * 60); uint32 ntp_seconds_1 = 0; - uint32 ntp_fractions_1 = 0; + uint32 ntp_fraction_1 = 0; base::TimeTicks input_time = base::TimeTicks::Now(); - ConvertTimeTicksToNtp(input_time, &ntp_seconds_1, &ntp_fractions_1); + ConvertTimeTicksToNtp(input_time, &ntp_seconds_1, &ntp_fraction_1); // Verify absolute value. EXPECT_GT(ntp_seconds_1, kSecondsbetweenYear1900and2010); EXPECT_LT(ntp_seconds_1, kSecondsbetweenYear1900and2030); - base::TimeTicks out_1 = ConvertNtpToTimeTicks(ntp_seconds_1, ntp_fractions_1); + base::TimeTicks out_1 = ConvertNtpToTimeTicks(ntp_seconds_1, ntp_fraction_1); EXPECT_EQ(input_time, out_1); // Verify inverse. base::TimeDelta time_delta = base::TimeDelta::FromMilliseconds(1000); input_time += time_delta; uint32 ntp_seconds_2 = 0; - uint32 ntp_fractions_2 = 0; + uint32 ntp_fraction_2 = 0; - ConvertTimeTicksToNtp(input_time, &ntp_seconds_2, &ntp_fractions_2); - base::TimeTicks out_2 = ConvertNtpToTimeTicks(ntp_seconds_2, ntp_fractions_2); + ConvertTimeTicksToNtp(input_time, &ntp_seconds_2, &ntp_fraction_2); + base::TimeTicks out_2 = ConvertNtpToTimeTicks(ntp_seconds_2, ntp_fraction_2); EXPECT_EQ(input_time, out_2); // Verify inverse. // Verify delta. EXPECT_EQ((out_2 - out_1), time_delta); - EXPECT_EQ((ntp_seconds_2 - ntp_seconds_1), GG_UINT32_C(1)); - EXPECT_NEAR(ntp_fractions_2, ntp_fractions_1, 1); + EXPECT_EQ((ntp_seconds_2 - ntp_seconds_1), UINT32_C(1)); + EXPECT_NEAR(ntp_fraction_2, ntp_fraction_1, 1); time_delta = base::TimeDelta::FromMilliseconds(500); input_time += time_delta; uint32 ntp_seconds_3 = 0; - uint32 ntp_fractions_3 = 0; + uint32 ntp_fraction_3 = 0; - ConvertTimeTicksToNtp(input_time, &ntp_seconds_3, &ntp_fractions_3); - base::TimeTicks out_3 = ConvertNtpToTimeTicks(ntp_seconds_3, ntp_fractions_3); + ConvertTimeTicksToNtp(input_time, &ntp_seconds_3, &ntp_fraction_3); + base::TimeTicks out_3 = ConvertNtpToTimeTicks(ntp_seconds_3, ntp_fraction_3); EXPECT_EQ(input_time, out_3); // Verify inverse. // Verify delta. EXPECT_EQ((out_3 - out_2), time_delta); - EXPECT_NEAR((ntp_fractions_3 - ntp_fractions_2), 0xffffffff / 2, 1); -} - -TEST_F(RtcpTest, WrapAround) { - RtcpPeer rtcp_peer(cast_environment_, - &mock_sender_feedback_, - NULL, - NULL, - NULL, - kRtcpReducedSize, - base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), - kReceiverSsrc, - kSenderSsrc, - kCName); - uint32 new_timestamp = 0; - uint32 old_timestamp = 0; - EXPECT_EQ(0, rtcp_peer.CheckForWrapAround(new_timestamp, old_timestamp)); - new_timestamp = 1234567890; - old_timestamp = 1234567000; - EXPECT_EQ(0, rtcp_peer.CheckForWrapAround(new_timestamp, old_timestamp)); - new_timestamp = 1234567000; - old_timestamp = 1234567890; - EXPECT_EQ(0, rtcp_peer.CheckForWrapAround(new_timestamp, old_timestamp)); - new_timestamp = 123; - old_timestamp = 4234567890u; - EXPECT_EQ(1, rtcp_peer.CheckForWrapAround(new_timestamp, old_timestamp)); - new_timestamp = 4234567890u; - old_timestamp = 123; - EXPECT_EQ(-1, rtcp_peer.CheckForWrapAround(new_timestamp, old_timestamp)); -} - -TEST_F(RtcpTest, RtpTimestampInSenderTime) { - RtcpPeer rtcp_peer(cast_environment_, - &mock_sender_feedback_, - NULL, - NULL, - NULL, - kRtcpReducedSize, - base::TimeDelta::FromMilliseconds(kRtcpIntervalMs), - kReceiverSsrc, - kSenderSsrc, - kCName); - int frequency = 32000; - uint32 rtp_timestamp = 64000; - base::TimeTicks rtp_timestamp_in_ticks; - - // Test fail before we get a OnReceivedLipSyncInfo. - EXPECT_FALSE(rtcp_peer.RtpTimestampInSenderTime(frequency, rtp_timestamp, - &rtp_timestamp_in_ticks)); - - uint32 ntp_seconds = 0; - uint32 ntp_fractions = 0; - uint64 input_time_us = 12345678901000LL; - base::TimeTicks input_time; - input_time += base::TimeDelta::FromMicroseconds(input_time_us); - - // Test exact match. - ConvertTimeTicksToNtp(input_time, &ntp_seconds, &ntp_fractions); - rtcp_peer.OnReceivedLipSyncInfo(rtp_timestamp, ntp_seconds, ntp_fractions); - EXPECT_TRUE(rtcp_peer.RtpTimestampInSenderTime(frequency, rtp_timestamp, - &rtp_timestamp_in_ticks)); - EXPECT_EQ(input_time, rtp_timestamp_in_ticks); - - // Test older rtp_timestamp. - rtp_timestamp = 32000; - EXPECT_TRUE(rtcp_peer.RtpTimestampInSenderTime(frequency, rtp_timestamp, - &rtp_timestamp_in_ticks)); - EXPECT_EQ(input_time - base::TimeDelta::FromMilliseconds(1000), - rtp_timestamp_in_ticks); - - // Test older rtp_timestamp with wrap. - rtp_timestamp = 4294903296u; - EXPECT_TRUE(rtcp_peer.RtpTimestampInSenderTime(frequency, rtp_timestamp, - &rtp_timestamp_in_ticks)); - EXPECT_EQ(input_time - base::TimeDelta::FromMilliseconds(4000), - rtp_timestamp_in_ticks); - - // Test newer rtp_timestamp. - rtp_timestamp = 128000; - EXPECT_TRUE(rtcp_peer.RtpTimestampInSenderTime(frequency, rtp_timestamp, - &rtp_timestamp_in_ticks)); - EXPECT_EQ(input_time + base::TimeDelta::FromMilliseconds(2000), - rtp_timestamp_in_ticks); - - // Test newer rtp_timestamp with wrap. - rtp_timestamp = 4294903296u; - rtcp_peer.OnReceivedLipSyncInfo(rtp_timestamp, ntp_seconds, ntp_fractions); - rtp_timestamp = 64000; - EXPECT_TRUE(rtcp_peer.RtpTimestampInSenderTime(frequency, rtp_timestamp, - &rtp_timestamp_in_ticks)); - EXPECT_EQ(input_time + base::TimeDelta::FromMilliseconds(4000), - rtp_timestamp_in_ticks); + EXPECT_NEAR((ntp_fraction_3 - ntp_fraction_2), 0xffffffff / 2, 1); } } // namespace cast diff --git a/chromium/media/cast/rtcp/rtcp_utility.cc b/chromium/media/cast/rtcp/rtcp_utility.cc index daeaa8aaceb..e29f82e9cf9 100644 --- a/chromium/media/cast/rtcp/rtcp_utility.cc +++ b/chromium/media/cast/rtcp/rtcp_utility.cc @@ -4,8 +4,9 @@ #include "media/cast/rtcp/rtcp_utility.h" +#include "base/big_endian.h" #include "base/logging.h" -#include "net/base/big_endian.h" +#include "media/cast/transport/cast_transport_defines.h" namespace media { namespace cast { @@ -19,18 +20,15 @@ RtcpParser::RtcpParser(const uint8* rtcpData, size_t rtcpDataLength) state_(kStateTopLevel), number_of_blocks_(0), field_type_(kRtcpNotValidCode) { + memset(&field_, 0, sizeof(field_)); Validate(); } RtcpParser::~RtcpParser() {} -RtcpFieldTypes RtcpParser::FieldType() const { - return field_type_; -} +RtcpFieldTypes RtcpParser::FieldType() const { return field_type_; } -const RtcpField& RtcpParser::Field() const { - return field_; -} +const RtcpField& RtcpParser::Field() const { return field_; } RtcpFieldTypes RtcpParser::Begin() { rtcp_data_ = rtcp_data_begin_; @@ -41,7 +39,8 @@ RtcpFieldTypes RtcpParser::Iterate() { // Reset packet type field_type_ = kRtcpNotValidCode; - if (!IsValid()) return kRtcpNotValidCode; + if (!IsValid()) + return kRtcpNotValidCode; switch (state_) { case kStateTopLevel: @@ -62,9 +61,6 @@ RtcpFieldTypes RtcpParser::Iterate() { case kStateApplicationSpecificCastReceiverEventLog: IterateCastReceiverLogEvent(); break; - case kStateApplicationSpecificCastSenderLog: - IterateCastSenderLog(); - break; case kStateExtendedReportBlock: IterateExtendedReportItem(); break; @@ -101,51 +97,53 @@ void RtcpParser::IterateTopLevel() { RtcpCommonHeader header; bool success = RtcpParseCommonHeader(rtcp_data_, rtcp_data_end_, &header); - if (!success) return; + if (!success) + return; rtcp_block_end_ = rtcp_data_ + header.length_in_octets; - if (rtcp_block_end_ > rtcp_data_end_) return; // Bad block! + if (rtcp_block_end_ > rtcp_data_end_) + return; // Bad block! switch (header.PT) { - case kPacketTypeSenderReport: + case transport::kPacketTypeSenderReport: // number of Report blocks number_of_blocks_ = header.IC; ParseSR(); return; - case kPacketTypeReceiverReport: + case transport::kPacketTypeReceiverReport: // number of Report blocks number_of_blocks_ = header.IC; ParseRR(); return; - case kPacketTypeSdes: + case transport::kPacketTypeSdes: // number of Sdes blocks number_of_blocks_ = header.IC; if (!ParseSdes()) { break; // Nothing supported found, continue to next block! } return; - case kPacketTypeBye: + case transport::kPacketTypeBye: number_of_blocks_ = header.IC; if (!ParseBye()) { // Nothing supported found, continue to next block! break; } return; - case kPacketTypeApplicationDefined: + case transport::kPacketTypeApplicationDefined: if (!ParseApplicationDefined(header.IC)) { // Nothing supported found, continue to next block! break; } return; - case kPacketTypeGenericRtpFeedback: // Fall through! - case kPacketTypePayloadSpecific: + case transport::kPacketTypeGenericRtpFeedback: // Fall through! + case transport::kPacketTypePayloadSpecific: if (!ParseFeedBackCommon(header)) { // Nothing supported found, continue to next block! break; } return; - case kPacketTypeXr: + case transport::kPacketTypeXr: if (!ParseExtendedReport()) { break; // Nothing supported found, continue to next block! } @@ -160,103 +158,111 @@ void RtcpParser::IterateTopLevel() { void RtcpParser::IterateReportBlockItem() { bool success = ParseReportBlockItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IterateSdesItem() { bool success = ParseSdesItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IterateByeItem() { bool success = ParseByeItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IterateExtendedReportItem() { bool success = ParseExtendedReportItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IterateExtendedReportDelaySinceLastReceiverReportItem() { bool success = ParseExtendedReportDelaySinceLastReceiverReport(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IterateNackItem() { bool success = ParseNackItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IterateRpsiItem() { bool success = ParseRpsiItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IterateFirItem() { bool success = ParseFirItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IteratePayloadSpecificAppItem() { bool success = ParsePayloadSpecificAppItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IteratePayloadSpecificRembItem() { bool success = ParsePayloadSpecificRembItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IteratePayloadSpecificCastItem() { bool success = ParsePayloadSpecificCastItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IteratePayloadSpecificCastNackItem() { bool success = ParsePayloadSpecificCastNackItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IterateCastReceiverLogFrame() { bool success = ParseCastReceiverLogFrameItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::IterateCastReceiverLogEvent() { bool success = ParseCastReceiverLogEventItem(); - if (!success) Iterate(); -} - -void RtcpParser::IterateCastSenderLog() { - bool success = ParseCastSenderLogItem(); - if (!success) Iterate(); + if (!success) + Iterate(); } void RtcpParser::Validate() { - if (rtcp_data_ == NULL) return; // NOT VALID + if (rtcp_data_ == NULL) + return; // NOT VALID RtcpCommonHeader header; - bool success = RtcpParseCommonHeader(rtcp_data_begin_, rtcp_data_end_, - &header); + bool success = + RtcpParseCommonHeader(rtcp_data_begin_, rtcp_data_end_, &header); - if (!success) return; // NOT VALID! + if (!success) + return; // NOT VALID! valid_packet_ = true; } -bool RtcpParser::IsValid() const { - return valid_packet_; -} +bool RtcpParser::IsValid() const { return valid_packet_; } -void RtcpParser::EndCurrentBlock() { - rtcp_data_ = rtcp_block_end_; -} +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; + if (!data_begin || !data_end) + return false; // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -266,31 +272,36 @@ bool RtcpParser::RtcpParseCommonHeader(const uint8* data_begin, // // Common header for all Rtcp packets, 4 octets. - if ((data_end - data_begin) < 4) return false; + if ((data_end - data_begin) < 4) + return false; - parsed_header->V = data_begin[0] >> 6; - parsed_header->P = ((data_begin[0] & 0x20) == 0) ? false : true; + parsed_header->V = data_begin[0] >> 6; + parsed_header->P = ((data_begin[0] & 0x20) == 0) ? false : true; parsed_header->IC = data_begin[0] & 0x1f; parsed_header->PT = data_begin[1]; parsed_header->length_in_octets = ((data_begin[2] << 8) + data_begin[3] + 1) * 4; - if (parsed_header->length_in_octets == 0) return false; + if (parsed_header->length_in_octets == 0) + return false; // Check if RTP version field == 2. - if (parsed_header->V != 2) return false; + if (parsed_header->V != 2) + return false; return true; } bool RtcpParser::ParseRR() { ptrdiff_t length = rtcp_block_end_ - rtcp_data_; - if (length < 8) return false; + if (length < 8) + return false; field_type_ = kRtcpRrCode; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + 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_; @@ -309,7 +320,8 @@ bool RtcpParser::ParseSR() { } field_type_ = kRtcpSrCode; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + 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); @@ -339,7 +351,8 @@ bool RtcpParser::ParseReportBlockItem() { return false; } - net::BigEndianReader big_endian_reader(rtcp_data_, length); + 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); @@ -399,7 +412,8 @@ bool RtcpParser::ParseSdesItem() { } uint32 ssrc; - net::BigEndianReader big_endian_reader(rtcp_data_, data_length); + base::BigEndianReader big_endian_reader( + reinterpret_cast<const char*>(rtcp_data_), data_length); big_endian_reader.ReadU32(&ssrc); rtcp_data_ += 4; @@ -418,7 +432,8 @@ bool RtcpParser::ParseSdesTypes() { // Only the c_name item is mandatory. RFC 3550 page 46. bool found_c_name = false; ptrdiff_t length = rtcp_block_end_ - rtcp_data_; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + base::BigEndianReader big_endian_reader( + reinterpret_cast<const char*>(rtcp_data_), length); while (big_endian_reader.remaining() > 0) { uint8 tag; @@ -484,7 +499,8 @@ bool RtcpParser::ParseByeItem() { field_type_ = kRtcpByeCode; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + base::BigEndianReader big_endian_reader( + reinterpret_cast<const char*>(rtcp_data_), length); big_endian_reader.ReadU32(&field_.bye.sender_ssrc); rtcp_data_ += 4; @@ -498,8 +514,7 @@ bool RtcpParser::ParseByeItem() { bool RtcpParser::ParseApplicationDefined(uint8 subtype) { ptrdiff_t length = rtcp_block_end_ - rtcp_data_; - if (length < 16 || - !(subtype == kSenderLogSubtype || subtype == kReceiverLogSubtype)) { + if (length < 16 || subtype != kReceiverLogSubtype) { state_ = kStateTopLevel; EndCurrentBlock(); return false; @@ -508,7 +523,8 @@ bool RtcpParser::ParseApplicationDefined(uint8 subtype) { uint32 sender_ssrc; uint32 name; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + 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); @@ -520,11 +536,6 @@ bool RtcpParser::ParseApplicationDefined(uint8 subtype) { } rtcp_data_ += 12; switch (subtype) { - case kSenderLogSubtype: - state_ = kStateApplicationSpecificCastSenderLog; - field_type_ = kRtcpApplicationSpecificCastSenderLogCode; - field_.cast_sender_log.sender_ssrc = sender_ssrc; - break; case kReceiverLogSubtype: state_ = kStateApplicationSpecificCastReceiverFrameLog; field_type_ = kRtcpApplicationSpecificCastReceiverLogCode; @@ -545,7 +556,8 @@ bool RtcpParser::ParseCastReceiverLogFrameItem() { } uint32 rtp_timestamp; uint32 data; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + base::BigEndianReader big_endian_reader( + reinterpret_cast<const char*>(rtcp_data_), length); big_endian_reader.ReadU32(&rtp_timestamp); big_endian_reader.ReadU32(&data); @@ -577,7 +589,8 @@ bool RtcpParser::ParseCastReceiverLogEventItem() { uint16 delay_delta_or_packet_id; uint16 event_type_and_timestamp_delta; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + 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); @@ -585,7 +598,9 @@ bool RtcpParser::ParseCastReceiverLogEventItem() { field_.cast_receiver_log.event = static_cast<uint8>(event_type_and_timestamp_delta >> 12); - field_.cast_receiver_log.delay_delta_or_packet_id = delay_delta_or_packet_id; + // 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; @@ -593,30 +608,10 @@ bool RtcpParser::ParseCastReceiverLogEventItem() { return true; } -bool RtcpParser::ParseCastSenderLogItem() { - ptrdiff_t length = rtcp_block_end_ - rtcp_data_; - - if (length < 4) { - state_ = kStateTopLevel; - EndCurrentBlock(); - return false; - } - uint32 data; - net::BigEndianReader big_endian_reader(rtcp_data_, length); - big_endian_reader.ReadU32(&data); - - rtcp_data_ += 4; - - field_.cast_sender_log.status = static_cast<uint8>(data >> 24); - // We have 24 LSB of the RTP timestamp on the wire. - field_.cast_sender_log.rtp_timestamp = data & 0xffffff; - field_type_ = kRtcpApplicationSpecificCastSenderLogCode; - return true; -} - bool RtcpParser::ParseFeedBackCommon(const RtcpCommonHeader& header) { - DCHECK((header.PT == kPacketTypeGenericRtpFeedback) || - (header.PT == kPacketTypePayloadSpecific)) << "Invalid state"; + DCHECK((header.PT == transport::kPacketTypeGenericRtpFeedback) || + (header.PT == transport::kPacketTypePayloadSpecific)) + << "Invalid state"; ptrdiff_t length = rtcp_block_end_ - rtcp_data_; @@ -627,21 +622,22 @@ bool RtcpParser::ParseFeedBackCommon(const RtcpCommonHeader& header) { uint32 sender_ssrc; uint32 media_ssrc; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + 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 == kPacketTypeGenericRtpFeedback) { + if (header.PT == transport::kPacketTypeGenericRtpFeedback) { // Transport layer feedback switch (header.IC) { case 1: // Nack field_type_ = kRtcpGenericRtpFeedbackNackCode; field_.nack.sender_ssrc = sender_ssrc; - field_.nack.media_ssrc = media_ssrc; + field_.nack.media_ssrc = media_ssrc; state_ = kStateGenericRtpFeedbackNack; return true; case 2: @@ -667,14 +663,14 @@ bool RtcpParser::ParseFeedBackCommon(const RtcpCommonHeader& header) { EndCurrentBlock(); return false; - } else if (header.PT == kPacketTypePayloadSpecific) { + } else if (header.PT == transport::kPacketTypePayloadSpecific) { // Payload specific feedback switch (header.IC) { case 1: // PLI field_type_ = kRtcpPayloadSpecificPliCode; field_.pli.sender_ssrc = sender_ssrc; - field_.pli.media_ssrc = media_ssrc; + field_.pli.media_ssrc = media_ssrc; // Note: No state transition, PLI FCI is empty! return true; @@ -684,7 +680,7 @@ bool RtcpParser::ParseFeedBackCommon(const RtcpCommonHeader& header) { case 3: field_type_ = kRtcpPayloadSpecificRpsiCode; field_.rpsi.sender_ssrc = sender_ssrc; - field_.rpsi.media_ssrc = media_ssrc; + field_.rpsi.media_ssrc = media_ssrc; state_ = kStatePayloadSpecificRpsi; return true; case 4: @@ -693,7 +689,7 @@ bool RtcpParser::ParseFeedBackCommon(const RtcpCommonHeader& header) { case 15: field_type_ = kRtcpPayloadSpecificAppCode; field_.application_specific.sender_ssrc = sender_ssrc; - field_.application_specific.media_ssrc = media_ssrc; + field_.application_specific.media_ssrc = media_ssrc; state_ = kStatePayloadSpecificApplication; return true; default: @@ -736,7 +732,8 @@ bool RtcpParser::ParseRpsiItem() { field_type_ = kRtcpPayloadSpecificRpsiCode; uint8 padding_bits; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + base::BigEndianReader big_endian_reader( + reinterpret_cast<const char*>(rtcp_data_), length); big_endian_reader.ReadU8(&padding_bits); big_endian_reader.ReadU8(&field_.rpsi.payload_type); big_endian_reader.ReadBytes(&field_.rpsi.native_bit_string, length - 2); @@ -759,7 +756,8 @@ bool RtcpParser::ParseNackItem() { field_type_ = kRtcpGenericRtpFeedbackNackItemCode; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + base::BigEndianReader big_endian_reader( + reinterpret_cast<const char*>(rtcp_data_), length); big_endian_reader.ReadU16(&field_.nack_item.packet_id); big_endian_reader.ReadU16(&field_.nack_item.bitmask); rtcp_data_ += 4; @@ -775,7 +773,8 @@ bool RtcpParser::ParsePayloadSpecificAppItem() { return false; } uint32 name; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + base::BigEndianReader big_endian_reader( + reinterpret_cast<const char*>(rtcp_data_), length); big_endian_reader.ReadU32(&name); rtcp_data_ += 4; @@ -802,7 +801,8 @@ bool RtcpParser::ParsePayloadSpecificRembItem() { return false; } - net::BigEndianReader big_endian_reader(rtcp_data_, length); + base::BigEndianReader big_endian_reader( + reinterpret_cast<const char*>(rtcp_data_), length); big_endian_reader.ReadU8(&field_.remb_item.number_of_ssrcs); uint8 byte_1; @@ -841,9 +841,11 @@ bool RtcpParser::ParsePayloadSpecificCastItem() { } field_type_ = kRtcpPayloadSpecificCastCode; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + 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; @@ -867,7 +869,8 @@ bool RtcpParser::ParsePayloadSpecificCastNackItem() { } field_type_ = kRtcpPayloadSpecificCastNackItemCode; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + 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); @@ -887,7 +890,8 @@ bool RtcpParser::ParseFirItem() { } field_type_ = kRtcpPayloadSpecificFirItemCode; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + base::BigEndianReader big_endian_reader( + reinterpret_cast<const char*>(rtcp_data_), length); big_endian_reader.ReadU32(&field_.fir_item.ssrc); big_endian_reader.ReadU8(&field_.fir_item.command_sequence_number); @@ -897,11 +901,13 @@ bool RtcpParser::ParseFirItem() { bool RtcpParser::ParseExtendedReport() { ptrdiff_t length = rtcp_block_end_ - rtcp_data_; - if (length < 8) return false; + if (length < 8) + return false; field_type_ = kRtcpXrCode; - net::BigEndianReader big_endian_reader(rtcp_data_, length); + 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); @@ -921,7 +927,8 @@ bool RtcpParser::ParseExtendedReportItem() { uint8 block_type; uint16 block_length; - net::BigEndianReader big_endian_reader(rtcp_data_, 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); @@ -970,7 +977,8 @@ bool RtcpParser::ParseExtendedReportReceiverReferenceTimeReport() { return false; } - net::BigEndianReader big_endian_reader(rtcp_data_, length); + 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); @@ -993,7 +1001,8 @@ bool RtcpParser::ParseExtendedReportDelaySinceLastReceiverReport() { return false; } - net::BigEndianReader big_endian_reader(rtcp_data_, length); + 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); @@ -1005,5 +1014,53 @@ bool RtcpParser::ParseExtendedReportDelaySinceLastReceiverReport() { return true; } +// Converts a log event type to an integer value. +// NOTE: We have only allocated 4 bits to represent the type of event over the +// wire. Therefore, this function can only return values from 0 to 15. +uint8 ConvertEventTypeToWireFormat(CastLoggingEvent event) { + switch (event) { + case FRAME_ACK_SENT: + return 11; + case FRAME_PLAYOUT: + return 12; + case FRAME_DECODED: + return 13; + case PACKET_RECEIVED: + return 14; + default: + return 0; // Not an interesting event. + } +} + +CastLoggingEvent TranslateToLogEventFromWireFormat(uint8 event) { + // TODO(imcheng): Remove the old mappings once they are no longer used. + switch (event) { + case 1: // AudioAckSent + case 5: // VideoAckSent + case 11: // Unified + return FRAME_ACK_SENT; + case 2: // AudioPlayoutDelay + case 7: // VideoRenderDelay + case 12: // Unified + return FRAME_PLAYOUT; + case 3: // AudioFrameDecoded + case 6: // VideoFrameDecoded + case 13: // Unified + return FRAME_DECODED; + case 4: // AudioPacketReceived + case 8: // VideoPacketReceived + case 14: // Unified + return PACKET_RECEIVED; + case 9: // DuplicateAudioPacketReceived + case 10: // DuplicateVideoPacketReceived + default: + // If the sender adds new log messages we will end up here until we add + // the new messages in the receiver. + VLOG(1) << "Unexpected log message received: " << static_cast<int>(event); + NOTREACHED(); + return UNKNOWN; + } +} + } // namespace cast } // namespace media diff --git a/chromium/media/cast/rtcp/rtcp_utility.h b/chromium/media/cast/rtcp/rtcp_utility.h index 5cf55d91060..34f3f25a889 100644 --- a/chromium/media/cast/rtcp/rtcp_utility.h +++ b/chromium/media/cast/rtcp/rtcp_utility.h @@ -7,6 +7,7 @@ #include "media/cast/cast_config.h" #include "media/cast/cast_defines.h" +#include "media/cast/logging/logging_defines.h" #include "media/cast/rtcp/rtcp_defines.h" namespace media { @@ -21,7 +22,6 @@ static const int kRtcpMaxNumberOfRembFeedbackSsrcs = 255; static const uint32 kRemb = ('R' << 24) + ('E' << 16) + ('M' << 8) + 'B'; static const uint32 kCast = ('C' << 24) + ('A' << 16) + ('S' << 8) + 'T'; -static const uint8 kSenderLogSubtype = 1; static const uint8 kReceiverLogSubtype = 2; static const size_t kRtcpMaxReceiverLogMessages = 256; @@ -37,7 +37,7 @@ struct RtcpFieldReceiverReport { struct RtcpFieldSenderReport { // RFC 3550. uint32 sender_ssrc; - uint8 number_of_report_blocks; + uint8 number_of_report_blocks; uint32 ntp_most_significant; uint32 ntp_least_significant; uint32 rtp_timestamp; @@ -48,7 +48,7 @@ struct RtcpFieldSenderReport { struct RtcpFieldReportBlockItem { // RFC 3550. uint32 ssrc; - uint8 fraction_lost; + uint8 fraction_lost; uint32 cumulative_number_of_packets_lost; uint32 extended_highest_sequence_number; uint32 jitter; @@ -101,9 +101,9 @@ struct RtcpFieldPayloadSpecificRpsi { // RFC 4585. uint32 sender_ssrc; uint32 media_ssrc; - uint8 payload_type; + uint8 payload_type; uint16 number_of_valid_bits; - uint8 native_bit_string[kRtcpRpsiDataSize]; + uint8 native_bit_string[kRtcpRpsiDataSize]; }; struct RtcpFieldXr { @@ -138,6 +138,7 @@ struct RtcpFieldPayloadSpecificRembItem { struct RtcpFieldPayloadSpecificCastItem { uint8 last_frame_id; uint8 number_of_lost_fields; + uint16 target_delay_ms; }; struct RtcpFieldPayloadSpecificCastNackItem { @@ -151,41 +152,37 @@ struct RtcpFieldApplicationSpecificCastReceiverLogItem { uint32 rtp_timestamp; uint32 event_timestamp_base; uint8 event; - uint16 delay_delta_or_packet_id; + union { + uint16 packet_id; + int16 delay_delta; + } delay_delta_or_packet_id; uint16 event_timestamp_delta; }; -struct RtcpFieldApplicationSpecificCastSenderLogItem { - uint32 sender_ssrc; - uint8 status; - uint32 rtp_timestamp; -}; - union RtcpField { - RtcpFieldReceiverReport receiver_report; - RtcpFieldSenderReport sender_report; - RtcpFieldReportBlockItem report_block_item; - RtcpFieldSdesCName c_name; - RtcpFieldBye bye; - - RtcpFieldXr extended_report; - RtcpFieldXrRrtr rrtr; - RtcpFieldXrDlrr dlrr; - - RtcpFieldGenericRtpFeedbackNack nack; - RtcpFieldGenericRtpFeedbackNackItem nack_item; - - RtcpFieldPayloadSpecificPli pli; - RtcpFieldPayloadSpecificRpsi rpsi; - RtcpFieldPayloadSpecificFir fir; - RtcpFieldPayloadSpecificFirItem fir_item; - RtcpFieldPayloadSpecificApplication application_specific; - RtcpFieldPayloadSpecificRembItem remb_item; - RtcpFieldPayloadSpecificCastItem cast_item; - RtcpFieldPayloadSpecificCastNackItem cast_nack_item; + RtcpFieldReceiverReport receiver_report; + RtcpFieldSenderReport sender_report; + RtcpFieldReportBlockItem report_block_item; + RtcpFieldSdesCName c_name; + RtcpFieldBye bye; + + RtcpFieldXr extended_report; + RtcpFieldXrRrtr rrtr; + RtcpFieldXrDlrr dlrr; + + RtcpFieldGenericRtpFeedbackNack nack; + RtcpFieldGenericRtpFeedbackNackItem nack_item; + + RtcpFieldPayloadSpecificPli pli; + RtcpFieldPayloadSpecificRpsi rpsi; + RtcpFieldPayloadSpecificFir fir; + RtcpFieldPayloadSpecificFirItem fir_item; + RtcpFieldPayloadSpecificApplication application_specific; + RtcpFieldPayloadSpecificRembItem remb_item; + RtcpFieldPayloadSpecificCastItem cast_item; + RtcpFieldPayloadSpecificCastNackItem cast_nack_item; RtcpFieldApplicationSpecificCastReceiverLogItem cast_receiver_log; - RtcpFieldApplicationSpecificCastSenderLogItem cast_sender_log; }; enum RtcpFieldTypes { @@ -195,7 +192,6 @@ enum RtcpFieldTypes { kRtcpRrCode, kRtcpSrCode, kRtcpReportBlockItemCode, - kRtcpSdesCode, kRtcpSdesChunkCode, kRtcpByeCode, @@ -209,7 +205,6 @@ enum RtcpFieldTypes { // RFC 4585. kRtcpGenericRtpFeedbackNackCode, kRtcpGenericRtpFeedbackNackItemCode, - kRtcpPayloadSpecificPliCode, kRtcpPayloadSpecificRpsiCode, kRtcpPayloadSpecificAppCode, @@ -222,7 +217,6 @@ enum RtcpFieldTypes { kRtcpApplicationSpecificCastReceiverLogCode, kRtcpApplicationSpecificCastReceiverLogFrameCode, kRtcpApplicationSpecificCastReceiverLogEventCode, - kRtcpApplicationSpecificCastSenderLogCode, // RFC 5104. kRtcpPayloadSpecificFirCode, @@ -233,27 +227,13 @@ enum RtcpFieldTypes { }; struct RtcpCommonHeader { - uint8 V; // Version. - bool P; // Padding. - uint8 IC; // Item count / subtype. - uint8 PT; // Packet Type. + uint8 V; // Version. + bool P; // Padding. + uint8 IC; // Item count / subtype. + uint8 PT; // Packet Type. uint16 length_in_octets; }; -enum RtcpPacketTypes { - kPacketTypeLow = 194, // SMPTE time-code mapping. - kPacketTypeInterArrivalJitterReport = 195, - kPacketTypeSenderReport = 200, - kPacketTypeReceiverReport = 201, - kPacketTypeSdes = 202, - kPacketTypeBye = 203, - kPacketTypeApplicationDefined = 204, - kPacketTypeGenericRtpFeedback = 205, - kPacketTypePayloadSpecific = 206, - kPacketTypeXr = 207, - kPacketTypeHigh = 210, // Port Mapping. -}; - class RtcpParser { public: RtcpParser(const uint8* rtcp_data, size_t rtcp_length); @@ -275,7 +255,6 @@ class RtcpParser { kStateBye, kStateApplicationSpecificCastReceiverFrameLog, kStateApplicationSpecificCastReceiverEventLog, - kStateApplicationSpecificCastSenderLog, kStateExtendedReportBlock, kStateExtendedReportDelaySinceLastReceiverReport, kStateGenericRtpFeedbackNack, @@ -297,7 +276,6 @@ class RtcpParser { void IterateByeItem(); void IterateCastReceiverLogFrame(); void IterateCastReceiverLogEvent(); - void IterateCastSenderLog(); void IterateExtendedReportItem(); void IterateExtendedReportDelaySinceLastReceiverReportItem(); void IterateNackItem(); @@ -323,7 +301,6 @@ class RtcpParser { bool ParseApplicationDefined(uint8 subtype); bool ParseCastReceiverLogFrameItem(); bool ParseCastReceiverLogEventItem(); - bool ParseCastSenderLogItem(); bool ParseExtendedReport(); bool ParseExtendedReportItem(); @@ -355,6 +332,14 @@ class RtcpParser { DISALLOW_COPY_AND_ASSIGN(RtcpParser); }; +// Converts a log event type to an integer value. +// NOTE: We have only allocated 4 bits to represent the type of event over the +// wire. Therefore, this function can only return values from 0 to 15. +uint8 ConvertEventTypeToWireFormat(CastLoggingEvent event); + +// The inverse of |ConvertEventTypeToWireFormat()|. +CastLoggingEvent TranslateToLogEventFromWireFormat(uint8 event); + } // namespace cast } // namespace media diff --git a/chromium/media/cast/rtcp/test_rtcp_packet_builder.cc b/chromium/media/cast/rtcp/test_rtcp_packet_builder.cc index f4117f53dec..8d0809d928e 100644 --- a/chromium/media/cast/rtcp/test_rtcp_packet_builder.cc +++ b/chromium/media/cast/rtcp/test_rtcp_packet_builder.cc @@ -5,14 +5,14 @@ #include "media/cast/rtcp/test_rtcp_packet_builder.h" #include "base/logging.h" +#include "media/cast/rtcp/rtcp_utility.h" namespace media { namespace cast { TestRtcpPacketBuilder::TestRtcpPacketBuilder() : ptr_of_length_(NULL), - big_endian_writer_(buffer_, kIpPacketSize) { -} + big_endian_writer_(reinterpret_cast<char*>(buffer_), kMaxIpPacketSize) {} void TestRtcpPacketBuilder::AddSr(uint32 sender_ssrc, int number_of_report_blocks) { @@ -91,8 +91,8 @@ void TestRtcpPacketBuilder::AddXrHeader(uint32 sender_ssrc) { } void TestRtcpPacketBuilder::AddXrUnknownBlock() { - big_endian_writer_.WriteU8(9); // Block type. - big_endian_writer_.WriteU8(0); // Reserved. + big_endian_writer_.WriteU8(9); // Block type. + big_endian_writer_.WriteU8(0); // Reserved. big_endian_writer_.WriteU16(4); // Block length. // First receiver same as sender of this report. big_endian_writer_.WriteU32(0); @@ -102,8 +102,8 @@ void TestRtcpPacketBuilder::AddXrUnknownBlock() { } void TestRtcpPacketBuilder::AddXrDlrrBlock(uint32 sender_ssrc) { - big_endian_writer_.WriteU8(5); // Block type. - big_endian_writer_.WriteU8(0); // Reserved. + big_endian_writer_.WriteU8(5); // Block type. + big_endian_writer_.WriteU8(0); // Reserved. big_endian_writer_.WriteU16(3); // Block length. // First receiver same as sender of this report. @@ -113,8 +113,8 @@ void TestRtcpPacketBuilder::AddXrDlrrBlock(uint32 sender_ssrc) { } void TestRtcpPacketBuilder::AddXrExtendedDlrrBlock(uint32 sender_ssrc) { - big_endian_writer_.WriteU8(5); // Block type. - big_endian_writer_.WriteU8(0); // Reserved. + big_endian_writer_.WriteU8(5); // Block type. + big_endian_writer_.WriteU8(0); // Reserved. big_endian_writer_.WriteU16(9); // Block length. big_endian_writer_.WriteU32(0xaaaaaaaa); big_endian_writer_.WriteU32(0xaaaaaaaa); @@ -130,8 +130,8 @@ void TestRtcpPacketBuilder::AddXrExtendedDlrrBlock(uint32 sender_ssrc) { } void TestRtcpPacketBuilder::AddXrRrtrBlock() { - big_endian_writer_.WriteU8(4); // Block type. - big_endian_writer_.WriteU8(0); // Reserved. + big_endian_writer_.WriteU8(4); // Block type. + big_endian_writer_.WriteU8(0); // Reserved. big_endian_writer_.WriteU16(2); // Block length. big_endian_writer_.WriteU32(kNtpHigh); big_endian_writer_.WriteU32(kNtpLow); @@ -167,8 +167,8 @@ void TestRtcpPacketBuilder::AddRpsi(uint32 sender_ssrc, uint32 media_ssrc) { uint64 picture_id = kPictureId; for (int i = 9; i > 0; i--) { - big_endian_writer_.WriteU8( - 0x80 | static_cast<uint8>(picture_id >> (i * 7))); + big_endian_writer_.WriteU8(0x80 | + static_cast<uint8>(picture_id >> (i * 7))); } // Add last byte of picture ID. big_endian_writer_.WriteU8(static_cast<uint8>(picture_id & 0x7f)); @@ -189,7 +189,9 @@ void TestRtcpPacketBuilder::AddRemb(uint32 sender_ssrc, uint32 media_ssrc) { big_endian_writer_.WriteU32(media_ssrc); } -void TestRtcpPacketBuilder::AddCast(uint32 sender_ssrc, uint32 media_ssrc) { +void TestRtcpPacketBuilder::AddCast(uint32 sender_ssrc, + uint32 media_ssrc, + uint16 target_delay_ms) { AddRtcpHeader(206, 15); big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU32(media_ssrc); @@ -198,8 +200,8 @@ void TestRtcpPacketBuilder::AddCast(uint32 sender_ssrc, uint32 media_ssrc) { big_endian_writer_.WriteU8('S'); big_endian_writer_.WriteU8('T'); big_endian_writer_.WriteU8(kAckFrameId); - big_endian_writer_.WriteU8(3); // Loss fields. - big_endian_writer_.WriteU16(0); // Reserved. + big_endian_writer_.WriteU8(3); // Loss fields. + big_endian_writer_.WriteU16(target_delay_ms); big_endian_writer_.WriteU8(kLostFrameId); big_endian_writer_.WriteU16(kRtcpCastAllPacketsLost); big_endian_writer_.WriteU8(0); // Lost packet id mask. @@ -211,21 +213,6 @@ void TestRtcpPacketBuilder::AddCast(uint32 sender_ssrc, uint32 media_ssrc) { big_endian_writer_.WriteU8(0); // Lost packet id mask. } -void TestRtcpPacketBuilder::AddSenderLog(uint32 sender_ssrc) { - AddRtcpHeader(204, 1); - big_endian_writer_.WriteU32(sender_ssrc); - big_endian_writer_.WriteU8('C'); - big_endian_writer_.WriteU8('A'); - big_endian_writer_.WriteU8('S'); - big_endian_writer_.WriteU8('T'); -} - -void TestRtcpPacketBuilder::AddSenderFrameLog(uint8 event_id, - uint32 rtp_timestamp) { - big_endian_writer_.WriteU32( - (static_cast<uint32>(event_id) << 24) + (rtp_timestamp & 0xffffff)); -} - void TestRtcpPacketBuilder::AddReceiverLog(uint32 sender_ssrc) { AddRtcpHeader(204, 2); big_endian_writer_.WriteU32(sender_ssrc); @@ -236,7 +223,8 @@ void TestRtcpPacketBuilder::AddReceiverLog(uint32 sender_ssrc) { } void TestRtcpPacketBuilder::AddReceiverFrameLog(uint32 rtp_timestamp, - int num_events, uint32 event_timesamp_base) { + int num_events, + uint32 event_timesamp_base) { big_endian_writer_.WriteU32(rtp_timestamp); big_endian_writer_.WriteU8(static_cast<uint8>(num_events - 1)); big_endian_writer_.WriteU8(static_cast<uint8>(event_timesamp_base >> 16)); @@ -245,14 +233,22 @@ void TestRtcpPacketBuilder::AddReceiverFrameLog(uint32 rtp_timestamp, } void TestRtcpPacketBuilder::AddReceiverEventLog(uint16 event_data, - uint8 event_id, uint16 event_timesamp_delta) { + CastLoggingEvent event, + uint16 event_timesamp_delta) { big_endian_writer_.WriteU16(event_data); + uint8 event_id = ConvertEventTypeToWireFormat(event); uint16 type_and_delta = static_cast<uint16>(event_id) << 12; type_and_delta += event_timesamp_delta & 0x0fff; big_endian_writer_.WriteU16(type_and_delta); } -const uint8* TestRtcpPacketBuilder::Packet() { +scoped_ptr<media::cast::Packet> TestRtcpPacketBuilder::GetPacket() { + PatchLengthField(); + return scoped_ptr<media::cast::Packet>( + new media::cast::Packet(buffer_, buffer_ + Length())); +} + +const uint8* TestRtcpPacketBuilder::Data() { PatchLengthField(); return buffer_; } diff --git a/chromium/media/cast/rtcp/test_rtcp_packet_builder.h b/chromium/media/cast/rtcp/test_rtcp_packet_builder.h index 9b63a37fa4a..d4266670aba 100644 --- a/chromium/media/cast/rtcp/test_rtcp_packet_builder.h +++ b/chromium/media/cast/rtcp/test_rtcp_packet_builder.h @@ -7,8 +7,9 @@ #ifndef MEDIA_CAST_RTCP_TEST_RTCP_PACKET_BUILDER_H_ #define MEDIA_CAST_RTCP_TEST_RTCP_PACKET_BUILDER_H_ +#include "base/big_endian.h" +#include "media/cast/cast_config.h" #include "media/cast/rtcp/rtcp_defines.h" -#include "net/base/big_endian.h" namespace media { namespace cast { @@ -58,7 +59,9 @@ class TestRtcpPacketBuilder { TestRtcpPacketBuilder(); void AddSr(uint32 sender_ssrc, int number_of_report_blocks); - void AddSrWithNtp(uint32 sender_ssrc, uint32 ntp_high, uint32 ntp_low, + void AddSrWithNtp(uint32 sender_ssrc, + uint32 ntp_high, + uint32 ntp_low, uint32 rtp_timestamp); void AddRr(uint32 sender_ssrc, int number_of_report_blocks); void AddRb(uint32 rtp_ssrc); @@ -76,17 +79,18 @@ class TestRtcpPacketBuilder { void AddPli(uint32 sender_ssrc, uint32 media_ssrc); void AddRpsi(uint32 sender_ssrc, uint32 media_ssrc); void AddRemb(uint32 sender_ssrc, uint32 media_ssrc); - void AddCast(uint32 sender_ssrc, uint32 media_ssrc); - void AddSenderLog(uint32 sender_ssrc); - void AddSenderFrameLog(uint8 event_id, uint32 rtp_timestamp); + void AddCast(uint32 sender_ssrc, uint32 media_ssrc, uint16 target_delay_ms); void AddReceiverLog(uint32 sender_ssrc); - void AddReceiverFrameLog(uint32 rtp_timestamp, int num_events, + void AddReceiverFrameLog(uint32 rtp_timestamp, + int num_events, uint32 event_timesamp_base); - void AddReceiverEventLog(uint16 event_data, uint8 event_id, + void AddReceiverEventLog(uint16 event_data, + CastLoggingEvent event, uint16 event_timesamp_delta); - const uint8* Packet(); - int Length() { return kIpPacketSize - big_endian_writer_.remaining(); } + scoped_ptr<Packet> GetPacket(); + const uint8* Data(); + int Length() { return kMaxIpPacketSize - big_endian_writer_.remaining(); } private: void AddRtcpHeader(int payload, int format_or_count); @@ -94,12 +98,14 @@ class TestRtcpPacketBuilder { // Where the length field of the current packet is. // Note: 0 is not a legal value, it is used for "uninitialized". - uint8 buffer_[kIpPacketSize]; + uint8 buffer_[kMaxIpPacketSize]; char* ptr_of_length_; - net::BigEndianWriter big_endian_writer_; + base::BigEndianWriter big_endian_writer_; + + DISALLOW_COPY_AND_ASSIGN(TestRtcpPacketBuilder); }; } // namespace cast } // namespace media -#endif // MEDIA_CAST_RTCP_TEST_RTCP_PACKET_BUILDER_H_ +#endif // MEDIA_CAST_RTCP_TEST_RTCP_PACKET_BUILDER_H_ |