summaryrefslogtreecommitdiffstats
path: root/media/cast
diff options
context:
space:
mode:
authorimcheng@chromium.org <imcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-05 00:10:51 +0000
committerimcheng@chromium.org <imcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-05 00:10:51 +0000
commitd581e9bc28de6160090eb3c4afc46d06cba71178 (patch)
tree764dfaaaa095083b2611400578937065e2f18aca /media/cast
parent792d7c68d27f191fe453531ee2003a3e59ebf590 (diff)
downloadchromium_src-d581e9bc28de6160090eb3c4afc46d06cba71178.zip
chromium_src-d581e9bc28de6160090eb3c4afc46d06cba71178.tar.gz
chromium_src-d581e9bc28de6160090eb3c4afc46d06cba71178.tar.bz2
Cast: Better redundancy for receiver RTCP events
Previously we always take the latest RTCP events from ReceiverRtcpEventSubscriber (without clearing explicitly) and stuff the packet with at most 200 bytes of data. This patch reintroduces the resetting of ReceiverRtcpEventSubscriber map when data is read from it, and it will be used as follows: - Get data from ReceiverRtcpEventSubscriber and reset its map - (Same as before) Impose 200 byte limit on rtcp receiver logs - Fill packet with data - Push a copy of data to redundancy buffer in RtcpSender - If there is enough space left, fill packet with data that was used X_1 receiver logs ago - If there is enough space left, fill packet with data that was used X_2 receiver logs ago -- Where 0 < X_1 < X_2 <= B where B is the buffer size. - Truncate buffer to discard old receiver logs if necessary. This gives a more consistent redudancy factor of 3 for each event. In here, X_1 = 10, X_2 = B = 20. So an event will be sent at reports N, N+10, and N+20. Additional items: - fix ssrc mismatch in receiver app. - removed unused function in cast_sender.{h,cc}. BUG=349265 Review URL: https://codereview.chromium.org/203293009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@261921 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/cast')
-rw-r--r--media/cast/audio_receiver/audio_receiver.cc4
-rw-r--r--media/cast/rtcp/receiver_rtcp_event_subscriber.cc8
-rw-r--r--media/cast/rtcp/receiver_rtcp_event_subscriber.h4
-rw-r--r--media/cast/rtcp/receiver_rtcp_event_subscriber_unittest.cc13
-rw-r--r--media/cast/rtcp/rtcp.cc13
-rw-r--r--media/cast/rtcp/rtcp.h10
-rw-r--r--media/cast/rtcp/rtcp_sender.cc224
-rw-r--r--media/cast/rtcp/rtcp_sender.h41
-rw-r--r--media/cast/rtcp/rtcp_sender_unittest.cc99
-rw-r--r--media/cast/test/sender.cc41
-rw-r--r--media/cast/video_receiver/video_receiver.cc4
11 files changed, 314 insertions, 147 deletions
diff --git a/media/cast/audio_receiver/audio_receiver.cc b/media/cast/audio_receiver/audio_receiver.cc
index b214c52..b01a54f 100644
--- a/media/cast/audio_receiver/audio_receiver.cc
+++ b/media/cast/audio_receiver/audio_receiver.cc
@@ -271,7 +271,9 @@ void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) {
cast_environment_->Logging()->InsertFrameEvent(
now, kAudioAckSent, rtp_timestamp, cast_message.ack_frame_id_);
- rtcp_.SendRtcpFromRtpReceiver(&cast_message, &event_subscriber_);
+ ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
+ event_subscriber_.GetRtcpEventsAndReset(&rtcp_events);
+ rtcp_.SendRtcpFromRtpReceiver(&cast_message, &rtcp_events);
}
base::TimeTicks AudioReceiver::GetPlayoutTime(base::TimeTicks now,
diff --git a/media/cast/rtcp/receiver_rtcp_event_subscriber.cc b/media/cast/rtcp/receiver_rtcp_event_subscriber.cc
index e23783c..d16aacd 100644
--- a/media/cast/rtcp/receiver_rtcp_event_subscriber.cc
+++ b/media/cast/rtcp/receiver_rtcp_event_subscriber.cc
@@ -79,6 +79,14 @@ void ReceiverRtcpEventSubscriber::OnReceiveGenericEvent(
// Do nothing as RTP receiver is not interested in generic events for RTCP.
}
+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.
diff --git a/media/cast/rtcp/receiver_rtcp_event_subscriber.h b/media/cast/rtcp/receiver_rtcp_event_subscriber.h
index 4a98735..665ffcf 100644
--- a/media/cast/rtcp/receiver_rtcp_event_subscriber.h
+++ b/media/cast/rtcp/receiver_rtcp_event_subscriber.h
@@ -55,7 +55,9 @@ class ReceiverRtcpEventSubscriber : public RawEventSubscriber {
virtual void OnReceiveGenericEvent(const GenericEvent& generic_event)
OVERRIDE;
- const RtcpEventMultiMap& get_rtcp_events() const { return rtcp_events_; }
+ // 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
diff --git a/media/cast/rtcp/receiver_rtcp_event_subscriber_unittest.cc b/media/cast/rtcp/receiver_rtcp_event_subscriber_unittest.cc
index 41411c3..5b86879 100644
--- a/media/cast/rtcp/receiver_rtcp_event_subscriber_unittest.cc
+++ b/media/cast/rtcp/receiver_rtcp_event_subscriber_unittest.cc
@@ -95,14 +95,18 @@ TEST_F(ReceiverRtcpEventSubscriberTest, LogVideoEvents) {
Init(ReceiverRtcpEventSubscriber::kVideoEventSubscriber);
InsertEvents();
- EXPECT_EQ(3u, event_subscriber_->get_rtcp_events().size());
+ ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
+ event_subscriber_->GetRtcpEventsAndReset(&rtcp_events);
+ EXPECT_EQ(3u, rtcp_events.size());
}
TEST_F(ReceiverRtcpEventSubscriberTest, LogAudioEvents) {
Init(ReceiverRtcpEventSubscriber::kAudioEventSubscriber);
InsertEvents();
- EXPECT_EQ(3u, event_subscriber_->get_rtcp_events().size());
+ ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
+ event_subscriber_->GetRtcpEventsAndReset(&rtcp_events);
+ EXPECT_EQ(3u, rtcp_events.size());
}
TEST_F(ReceiverRtcpEventSubscriberTest, DropEventsWhenSizeExceeded) {
@@ -113,7 +117,10 @@ TEST_F(ReceiverRtcpEventSubscriberTest, DropEventsWhenSizeExceeded) {
testing_clock_->NowTicks(), kVideoFrameDecoded,
/*rtp_timestamp*/ i * 10, /*frame_id*/ i);
}
- EXPECT_EQ(10u, event_subscriber_->get_rtcp_events().size());
+
+ ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
+ event_subscriber_->GetRtcpEventsAndReset(&rtcp_events);
+ EXPECT_EQ(10u, rtcp_events.size());
}
} // namespace cast
diff --git a/media/cast/rtcp/rtcp.cc b/media/cast/rtcp/rtcp.cc
index c5fbbad..a8842f1 100644
--- a/media/cast/rtcp/rtcp.cc
+++ b/media/cast/rtcp/rtcp.cc
@@ -230,7 +230,7 @@ void Rtcp::IncomingRtcpPacket(const uint8* rtcp_buffer, size_t length) {
void Rtcp::SendRtcpFromRtpReceiver(
const RtcpCastMessage* cast_message,
- const ReceiverRtcpEventSubscriber* event_subscriber) {
+ const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events) {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
uint32 packet_type_flags = 0;
@@ -247,7 +247,7 @@ void Rtcp::SendRtcpFromRtpReceiver(
if (cast_message) {
packet_type_flags |= transport::kRtcpCast;
}
- if (event_subscriber) {
+ if (rtcp_events) {
packet_type_flags |= transport::kRtcpReceiverLog;
}
if (rtcp_mode_ == kRtcpCompound || now >= next_time_to_send_rtcp_) {
@@ -279,9 +279,12 @@ void Rtcp::SendRtcpFromRtpReceiver(
}
UpdateNextTimeToSendRtcp();
}
- rtcp_sender_->SendRtcpFromRtpReceiver(
- packet_type_flags, &report_block, &rrtr, cast_message, event_subscriber,
- target_delay_ms_);
+ rtcp_sender_->SendRtcpFromRtpReceiver(packet_type_flags,
+ &report_block,
+ &rrtr,
+ cast_message,
+ rtcp_events,
+ target_delay_ms_);
}
void Rtcp::SendRtcpFromRtpSender(
diff --git a/media/cast/rtcp/rtcp.h b/media/cast/rtcp/rtcp.h
index 30a155d..15bbe11 100644
--- a/media/cast/rtcp/rtcp.h
+++ b/media/cast/rtcp/rtcp.h
@@ -18,6 +18,7 @@
#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"
@@ -29,7 +30,6 @@ namespace cast {
class LocalRtcpReceiverFeedback;
class LocalRtcpRttFeedback;
class PacedPacketSender;
-class ReceiverRtcpEventSubscriber;
class RtcpReceiver;
class RtcpSender;
@@ -87,13 +87,13 @@ class Rtcp {
const transport::RtcpSenderLogMessage& sender_log_message,
transport::RtcpSenderInfo sender_info);
- // |cast_message| and |event_subscriber| is optional; if |cast_message| is
+ // |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 |event_subscriber| is provided the RTCP receiver report
- // will append the log messages from the subscriber.
+ // 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* event_subscriber);
+ const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events);
void IncomingRtcpPacket(const uint8* rtcp_buffer, size_t length);
bool Rtt(base::TimeDelta* rtt,
diff --git a/media/cast/rtcp/rtcp_sender.cc b/media/cast/rtcp/rtcp_sender.cc
index 1175945..d723f72 100644
--- a/media/cast/rtcp/rtcp_sender.cc
+++ b/media/cast/rtcp/rtcp_sender.cc
@@ -77,88 +77,31 @@ bool EventTimestampLessThan(const RtcpReceiverEventLogMessage& lhs,
return lhs.event_timestamp < rhs.event_timestamp;
}
-bool BuildRtcpReceiverLogMessage(
- const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events,
- size_t start_size,
+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,
- 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 >=
+ 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) {
- const RtpTimestamp rtp_timestamp = rit->first;
- RtcpReceiverFrameLogMessage frame_log(rtp_timestamp);
- remaining_space -= kRtcpReceiverFrameLogSize;
+ 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;
-
- // 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);
+ *total_number_of_messages_to_send += event_log_messages.size();
+ ++it;
}
-
- *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;
}
// A class to build a string representing the NACK list in Cast message.
@@ -247,17 +190,12 @@ RtcpSender::RtcpSender(scoped_refptr<CastEnvironment> cast_environment,
RtcpSender::~RtcpSender() {}
-// static
-bool RtcpSender::IsReceiverEvent(const CastLoggingEvent& event) {
- return ConvertEventTypeToWireFormat(event) != 0;
-}
-
void RtcpSender::SendRtcpFromRtpReceiver(
uint32 packet_type_flags,
const transport::RtcpReportBlock* report_block,
const RtcpReceiverReferenceTimeReport* rrtr,
const RtcpCastMessage* cast_message,
- const ReceiverRtcpEventSubscriber* event_subscriber,
+ const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events,
uint16 target_delay_ms) {
if (packet_type_flags & transport::kRtcpSr ||
packet_type_flags & transport::kRtcpDlrr ||
@@ -292,8 +230,8 @@ void RtcpSender::SendRtcpFromRtpReceiver(
BuildCast(cast_message, target_delay_ms, &packet);
}
if (packet_type_flags & transport::kRtcpReceiverLog) {
- DCHECK(event_subscriber) << "Invalid argument";
- BuildReceiverLog(event_subscriber->get_rtcp_events(), &packet);
+ DCHECK(rtcp_events) << "Invalid argument";
+ BuildReceiverLog(*rtcp_events, &packet);
}
if (packet.empty())
@@ -716,7 +654,7 @@ void RtcpSender::BuildCast(const RtcpCastMessage* cast,
void RtcpSender::BuildReceiverLog(
const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events,
- Packet* packet) const {
+ 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;
@@ -808,5 +746,119 @@ void RtcpSender::BuildReceiverLog(
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
} // namespace media
diff --git a/media/cast/rtcp/rtcp_sender.h b/media/cast/rtcp/rtcp_sender.h
index dbc93a8..f09a4fb 100644
--- a/media/cast/rtcp/rtcp_sender.h
+++ b/media/cast/rtcp/rtcp_sender.h
@@ -5,6 +5,7 @@
#ifndef MEDIA_CAST_RTCP_RTCP_SENDER_H_
#define MEDIA_CAST_RTCP_RTCP_SENDER_H_
+#include <deque>
#include <list>
#include <string>
@@ -19,13 +20,25 @@
namespace media {
namespace cast {
-// We limit the size of receiver logs to avoid queuing up packets. We also
-// do not need the amount of redundancy that results from filling up every
-// RTCP packet with log messages. This number should give a redundancy of
-// about 2-3 per log message.
+// We limit the size of receiver logs to avoid queuing up packets.
const size_t kMaxReceiverLogBytes = 200;
-class ReceiverRtcpEventSubscriber;
+// 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 {
@@ -37,16 +50,12 @@ class RtcpSender {
virtual ~RtcpSender();
- // Returns true if |event| is an interesting receiver event.
- // Such an event should be sent via RTCP.
- static bool IsReceiverEvent(const media::cast::CastLoggingEvent& event);
-
void SendRtcpFromRtpReceiver(
uint32 packet_type_flags,
const transport::RtcpReportBlock* report_block,
const RtcpReceiverReferenceTimeReport* rrtr,
const RtcpCastMessage* cast_message,
- const ReceiverRtcpEventSubscriber* event_subscriber,
+ const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events,
uint16 target_delay_ms);
private:
@@ -77,7 +86,15 @@ class RtcpSender {
void BuildReceiverLog(
const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events,
- Packet* packet) const;
+ Packet* packet);
+
+ 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,
@@ -100,6 +117,8 @@ class RtcpSender {
transport::PacedPacketSender* const transport_;
scoped_refptr<CastEnvironment> cast_environment_;
+ std::deque<RtcpReceiverLogMessage> rtcp_events_history_;
+
DISALLOW_COPY_AND_ASSIGN(RtcpSender);
};
diff --git a/media/cast/rtcp/rtcp_sender_unittest.cc b/media/cast/rtcp/rtcp_sender_unittest.cc
index 8e6ceb2..cd8ca72 100644
--- a/media/cast/rtcp/rtcp_sender_unittest.cc
+++ b/media/cast/rtcp/rtcp_sender_unittest.cc
@@ -251,6 +251,7 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtrCastMessageAndLog) {
ReceiverRtcpEventSubscriber event_subscriber(
500, ReceiverRtcpEventSubscriber::kVideoEventSubscriber);
+ ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpRrtr | transport::kRtcpCast |
@@ -258,7 +259,7 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtrCastMessageAndLog) {
&report_block,
&rrtr,
&cast_message,
- &event_subscriber,
+ &rtcp_events,
kDefaultDelay);
base::SimpleTestTickClock testing_clock;
@@ -284,7 +285,8 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtrCastMessageAndLog) {
packet_event.timestamp = testing_clock.NowTicks();
packet_event.packet_id = kLostPacketId1;
event_subscriber.OnReceivePacketEvent(packet_event);
- EXPECT_EQ(2u, event_subscriber.get_rtcp_events().size());
+ event_subscriber.GetRtcpEventsAndReset(&rtcp_events);
+ EXPECT_EQ(2u, rtcp_events.size());
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpRrtr | transport::kRtcpCast |
@@ -292,22 +294,10 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtrCastMessageAndLog) {
&report_block,
&rrtr,
&cast_message,
- &event_subscriber,
+ &rtcp_events,
kDefaultDelay);
EXPECT_EQ(2, test_transport_.packet_count());
-
- // We expect to see the same packet because we send redundant events.
- rtcp_sender_->SendRtcpFromRtpReceiver(
- transport::kRtcpRr | transport::kRtcpRrtr | transport::kRtcpCast |
- transport::kRtcpReceiverLog,
- &report_block,
- &rrtr,
- &cast_message,
- &event_subscriber,
- kDefaultDelay);
-
- EXPECT_EQ(3, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithOversizedFrameLog) {
@@ -362,12 +352,15 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithOversizedFrameLog) {
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
}
+ ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
+ event_subscriber.GetRtcpEventsAndReset(&rtcp_events);
+
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpReceiverLog,
&report_block,
NULL,
NULL,
- &event_subscriber,
+ &rtcp_events,
kDefaultDelay);
EXPECT_EQ(1, test_transport_.packet_count());
@@ -416,12 +409,15 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithTooManyLogFrames) {
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
}
+ ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
+ event_subscriber.GetRtcpEventsAndReset(&rtcp_events);
+
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpReceiverLog,
&report_block,
NULL,
NULL,
- &event_subscriber,
+ &rtcp_events,
kDefaultDelay);
EXPECT_EQ(1, test_transport_.packet_count());
@@ -464,16 +460,83 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithOldLogFrames) {
base::TimeDelta::FromMilliseconds(kTimeBetweenEventsMs));
}
+ ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
+ event_subscriber.GetRtcpEventsAndReset(&rtcp_events);
+
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpReceiverLog,
&report_block,
NULL,
NULL,
- &event_subscriber,
+ &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, ReceiverRtcpEventSubscriber::kVideoEventSubscriber);
+ 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, 5, 0);
+ }
+ if (i >= kFirstRedundancyOffset) {
+ p.AddReceiverFrameLog(
+ kRtpTimestamp,
+ 1,
+ time_base_ms - kFirstRedundancyOffset * kTimeBetweenEventsMs);
+ p.AddReceiverEventLog(0, 5, 0);
+ }
+ p.AddReceiverFrameLog(kRtpTimestamp, 1, time_base_ms);
+ p.AddReceiverEventLog(0, 5, 0);
+
+ test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass());
+
+ FrameEvent frame_event;
+ frame_event.rtp_timestamp = kRtpTimestamp;
+ frame_event.type = media::cast::kVideoAckSent;
+ 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
} // namespace media
diff --git a/media/cast/test/sender.cc b/media/cast/test/sender.cc
index 8c2681b..1accf4b 100644
--- a/media/cast/test/sender.cc
+++ b/media/cast/test/sender.cc
@@ -371,17 +371,11 @@ net::IPEndPoint CreateUDPAddress(std::string ip_str, int port) {
return net::IPEndPoint(ip_number, port);
}
-void DumpLoggingData(
- scoped_ptr<media::cast::EncodingEventSubscriber> event_subscriber,
- base::ScopedFILE log_file,
- bool compress) {
- media::cast::FrameEventMap frame_events;
- media::cast::PacketEventMap packet_events;
- media::cast::proto::LogMetadata log_metadata;
-
- event_subscriber->GetEventsAndReset(
- &log_metadata, &frame_events, &packet_events);
-
+void DumpLoggingData(const media::cast::proto::LogMetadata& log_metadata,
+ const media::cast::FrameEventMap& frame_events,
+ const media::cast::PacketEventMap& packet_events,
+ bool compress,
+ base::ScopedFILE log_file) {
VLOG(0) << "Frame map size: " << frame_events.size();
VLOG(0) << "Packet map size: " << packet_events.size();
@@ -412,19 +406,33 @@ void WriteLogsToFileAndStopSubscribing(
base::ScopedFILE video_log_file,
base::ScopedFILE audio_log_file,
bool compress) {
- // Serialize video events.
cast_environment->Logging()->RemoveRawEventSubscriber(
video_event_subscriber.get());
cast_environment->Logging()->RemoveRawEventSubscriber(
audio_event_subscriber.get());
VLOG(0) << "Dumping logging data for video stream.";
- DumpLoggingData(
- video_event_subscriber.Pass(), video_log_file.Pass(), compress);
+ media::cast::proto::LogMetadata log_metadata;
+ media::cast::FrameEventMap frame_events;
+ media::cast::PacketEventMap packet_events;
+ video_event_subscriber->GetEventsAndReset(
+ &log_metadata, &frame_events, &packet_events);
+
+ DumpLoggingData(log_metadata,
+ frame_events,
+ packet_events,
+ compress,
+ video_log_file.Pass());
VLOG(0) << "Dumping logging data for audio stream.";
- DumpLoggingData(
- audio_event_subscriber.Pass(), audio_log_file.Pass(), compress);
+ audio_event_subscriber->GetEventsAndReset(
+ &log_metadata, &frame_events, &packet_events);
+
+ DumpLoggingData(log_metadata,
+ frame_events,
+ packet_events,
+ compress,
+ audio_log_file.Pass());
}
} // namespace
@@ -460,6 +468,7 @@ int main(int argc, char** argv) {
net::IPEndPoint remote_endpoint =
CreateUDPAddress(remote_ip_address, remote_port);
transport_audio_config.base.ssrc = audio_config.sender_ssrc;
+ VLOG(0) << "Audio ssrc: " << transport_audio_config.base.ssrc;
transport_audio_config.base.rtp_config = audio_config.rtp_config;
transport_video_config.base.ssrc = video_config.sender_ssrc;
transport_video_config.base.rtp_config = video_config.rtp_config;
diff --git a/media/cast/video_receiver/video_receiver.cc b/media/cast/video_receiver/video_receiver.cc
index 95b1d51..bb07b79 100644
--- a/media/cast/video_receiver/video_receiver.cc
+++ b/media/cast/video_receiver/video_receiver.cc
@@ -447,7 +447,9 @@ void VideoReceiver::CastFeedback(const RtcpCastMessage& cast_message) {
cast_environment_->Logging()->InsertFrameEvent(
now, kVideoAckSent, rtp_timestamp, cast_message.ack_frame_id_);
- rtcp_->SendRtcpFromRtpReceiver(&cast_message, &event_subscriber_);
+ ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
+ event_subscriber_.GetRtcpEventsAndReset(&rtcp_events);
+ rtcp_->SendRtcpFromRtpReceiver(&cast_message, &rtcp_events);
}
// Cast messages should be sent within a maximum interval. Schedule a call