summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-20 07:13:24 +0000
committerhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-20 07:13:24 +0000
commitabd5fb257d7dbf92f99b75e3cefad7c58ca485bb (patch)
treeb01cb29d240492a83c2e87453308bcf031cba47f /media
parentc5b1db7f8e90e0d118bac3b01484c69f1c4ef5e9 (diff)
downloadchromium_src-abd5fb257d7dbf92f99b75e3cefad7c58ca485bb.zip
chromium_src-abd5fb257d7dbf92f99b75e3cefad7c58ca485bb.tar.gz
chromium_src-abd5fb257d7dbf92f99b75e3cefad7c58ca485bb.tar.bz2
Cast: Refactor RTCP handling
OBJECTIVES This change is to refactor RTCP handling in media/cast such that RTCP message parsing is done in CastTransportSender. This side effect of this refactoring is much cleaner code: RTCP handling code are grouped under one module. VideoSender and AudioSender do not handle packets directly. This also affect the architectutre in Chrome that RTCP message parsing is now done in the browser process. A parsed RTCP message is passed to the renderer instead of raw packets. REATIONALE RTCP is used as a feedback mechanism in Cast Streaming. It used to be parsed and handled by VideoSender and AudioSender in the render process. This was very ineffective because packetization and sending is done in the browser process. This created inefficiencies in packet retransmission. It also made improvement to the transport protocol / algorithm much more difficult. A side effect is very messy code. DETAILS Rtcp - This class is responsibile for maintaining a bi-directional RTCP session. It is now owned by CastTransportSender. CastTransportSender - It now performs packetization and also parsing of incoming RTCP packets. RTCP packets are small UDP packets for signaling only. Eventually retransmission can also be moved to this class. It will handle all packet level send transport. AudioSender / VideoSender - They don't handle packet directly any more. Which means render process doesn't see raw packets. FrameSender - Base class for AudioSender and VideoSender to share code for RTCP message handling. Eventually AudioSender and VideoSender will merge here but it is not the point of this change. RtcpBuilder - Removed and merged with RtcpSender. Net deleted 400 lines of code and simulation shows the same results. BUG=393042 Review URL: https://codereview.chromium.org/387933005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284363 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/cast/cast.gyp4
-rw-r--r--media/cast/cast_config.cc3
-rw-r--r--media/cast/cast_config.h6
-rw-r--r--media/cast/cast_sender.h4
-rw-r--r--media/cast/cast_sender_impl.cc68
-rw-r--r--media/cast/cast_sender_impl.h2
-rw-r--r--media/cast/cast_testing.gypi2
-rw-r--r--media/cast/net/cast_transport_config.cc6
-rw-r--r--media/cast/net/cast_transport_config.h24
-rw-r--r--media/cast/net/cast_transport_sender.h46
-rw-r--r--media/cast/net/cast_transport_sender_impl.cc183
-rw-r--r--media/cast/net/cast_transport_sender_impl.h79
-rw-r--r--media/cast/net/cast_transport_sender_impl_unittest.cc22
-rw-r--r--media/cast/net/rtcp/mock_rtcp_receiver_feedback.cc4
-rw-r--r--media/cast/net/rtcp/mock_rtcp_receiver_feedback.h16
-rw-r--r--media/cast/net/rtcp/rtcp.cc245
-rw-r--r--media/cast/net/rtcp/rtcp.h106
-rw-r--r--media/cast/net/rtcp/rtcp_defines.cc16
-rw-r--r--media/cast/net/rtcp/rtcp_defines.h36
-rw-r--r--media/cast/net/rtcp/rtcp_receiver.cc93
-rw-r--r--media/cast/net/rtcp/rtcp_receiver.h31
-rw-r--r--media/cast/net/rtcp/rtcp_receiver_unittest.cc193
-rw-r--r--media/cast/net/rtcp/rtcp_sender.cc136
-rw-r--r--media/cast/net/rtcp/rtcp_sender.h33
-rw-r--r--media/cast/net/rtcp/rtcp_sender_unittest.cc76
-rw-r--r--media/cast/net/rtcp/rtcp_unittest.cc298
-rw-r--r--media/cast/net/rtp/cast_message_builder.cc20
-rw-r--r--media/cast/net/rtp/cast_message_builder_unittest.cc8
-rw-r--r--media/cast/receiver/cast_receiver_impl.cc5
-rw-r--r--media/cast/receiver/frame_receiver.cc31
-rw-r--r--media/cast/receiver/frame_receiver.h3
-rw-r--r--media/cast/sender/audio_sender.cc102
-rw-r--r--media/cast/sender/audio_sender.h34
-rw-r--r--media/cast/sender/audio_sender_unittest.cc4
-rw-r--r--media/cast/sender/frame_sender.cc72
-rw-r--r--media/cast/sender/frame_sender.h77
-rw-r--r--media/cast/sender/video_sender.cc128
-rw-r--r--media/cast/sender/video_sender.h35
-rw-r--r--media/cast/sender/video_sender_unittest.cc59
-rw-r--r--media/cast/test/cast_benchmarks.cc71
-rw-r--r--media/cast/test/end2end_unittest.cc33
-rw-r--r--media/cast/test/sender.cc15
-rw-r--r--media/cast/test/simulator.cc17
43 files changed, 1235 insertions, 1211 deletions
diff --git a/media/cast/cast.gyp b/media/cast/cast.gyp
index fb1ee64..eb00855 100644
--- a/media/cast/cast.gyp
+++ b/media/cast/cast.gyp
@@ -149,6 +149,8 @@
'sender/external_video_encoder.cc',
'sender/fake_software_video_encoder.h',
'sender/fake_software_video_encoder.cc',
+ 'sender/frame_sender.cc',
+ 'sender/frame_sender.h',
'sender/rtp_timestamp_helper.cc',
'sender/rtp_timestamp_helper.h',
'sender/software_video_encoder.h',
@@ -182,8 +184,6 @@
'net/pacing/paced_sender.cc',
'net/pacing/paced_sender.h',
'net/rtcp/receiver_rtcp_event_subscriber.cc',
- 'net/rtcp/rtcp_builder.cc',
- 'net/rtcp/rtcp_builder.h',
'net/rtcp/rtcp_defines.cc',
'net/rtcp/rtcp_defines.h',
'net/rtcp/rtcp.h',
diff --git a/media/cast/cast_config.cc b/media/cast/cast_config.cc
index f741216..b0e0828 100644
--- a/media/cast/cast_config.cc
+++ b/media/cast/cast_config.cc
@@ -25,7 +25,6 @@ VideoSenderConfig::VideoSenderConfig()
: ssrc(0),
incoming_feedback_ssrc(0),
rtcp_interval(kDefaultRtcpIntervalMs),
- rtcp_mode(kRtcpReducedSize),
target_playout_delay(
base::TimeDelta::FromMilliseconds(kDefaultRtpMaxDelayMs)),
rtp_payload_type(0),
@@ -49,7 +48,6 @@ AudioSenderConfig::AudioSenderConfig()
: ssrc(0),
incoming_feedback_ssrc(0),
rtcp_interval(kDefaultRtcpIntervalMs),
- rtcp_mode(kRtcpReducedSize),
target_playout_delay(
base::TimeDelta::FromMilliseconds(kDefaultRtpMaxDelayMs)),
rtp_payload_type(0),
@@ -65,7 +63,6 @@ FrameReceiverConfig::FrameReceiverConfig()
: feedback_ssrc(0),
incoming_ssrc(0),
rtcp_interval(kDefaultRtcpIntervalMs),
- rtcp_mode(kRtcpReducedSize),
rtp_max_delay_ms(kDefaultRtpMaxDelayMs),
rtp_payload_type(0),
frequency(0),
diff --git a/media/cast/cast_config.h b/media/cast/cast_config.h
index c2e797b6..c2d8db3 100644
--- a/media/cast/cast_config.h
+++ b/media/cast/cast_config.h
@@ -37,7 +37,6 @@ struct AudioSenderConfig {
int rtcp_interval;
std::string rtcp_c_name;
- RtcpMode rtcp_mode;
// The total amount of time between a frame's capture/recording on the sender
// and its playback on the receiver (i.e., shown to a user). This is fixed as
@@ -75,7 +74,6 @@ struct VideoSenderConfig {
int rtcp_interval;
std::string rtcp_c_name;
- RtcpMode rtcp_mode;
// The total amount of time between a frame's capture/recording on the sender
// and its playback on the receiver (i.e., shown to a user). This is fixed as
@@ -130,10 +128,6 @@ struct FrameReceiverConfig {
// the transport layer).
std::string rtcp_c_name;
- // Determines amount of detail in RTCP reports.
- // TODO(miu): Remove this since it's never anything but kRtcpReducedSize.
- RtcpMode rtcp_mode;
-
// The total amount of time between a frame's capture/recording on the sender
// and its playback on the receiver (i.e., shown to a user). This is fixed as
// a value large enough to give the system sufficient time to encode,
diff --git a/media/cast/cast_sender.h b/media/cast/cast_sender.h
index abe0a01..c9bad7a 100644
--- a/media/cast/cast_sender.h
+++ b/media/cast/cast_sender.h
@@ -73,10 +73,6 @@ class CastSender {
// All audio frames for the session should be inserted to this object.
virtual scoped_refptr<AudioFrameInput> audio_frame_input() = 0;
- // All RTCP packets for the session should be inserted to this object.
- // This function and the callback must be called on the main thread.
- virtual PacketReceiverCallback packet_receiver() = 0;
-
// Initialize the audio stack. Must be called in order to send audio frames.
// Status of the initialization will be returned on cast_initialization_cb.
virtual void InitializeAudio(
diff --git a/media/cast/cast_sender_impl.cc b/media/cast/cast_sender_impl.cc
index a120d3a..c684858 100644
--- a/media/cast/cast_sender_impl.cc
+++ b/media/cast/cast_sender_impl.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "media/base/video_frame.h"
+#include "media/cast/net/rtcp/rtcp_receiver.h"
namespace media {
namespace cast {
@@ -142,68 +143,6 @@ CastSenderImpl::~CastSenderImpl() {
VLOG(1) << "CastSenderImpl@" << this << "::~CastSenderImpl()";
}
-// ReceivedPacket handle the incoming packets to the cast sender
-// it's only expected to receive RTCP feedback packets from the remote cast
-// receiver. The class verifies that that it is a RTCP packet and based on the
-// SSRC of the incoming packet route the packet to the correct sender; audio or
-// video.
-//
-// Definition of SSRC as defined in RFC 3550.
-// Synchronization source (SSRC): The source of a stream of RTP
-// packets, identified by a 32-bit numeric SSRC identifier carried in
-// the RTP header so as not to be dependent upon the network address.
-// All packets from a synchronization source form part of the same
-// timing and sequence number space, so a receiver groups packets by
-// synchronization source for playback. Examples of synchronization
-// sources include the sender of a stream of packets derived from a
-// signal source such as a microphone or a camera, or an RTP mixer
-// (see below). A synchronization source may change its data format,
-// e.g., audio encoding, over time. The SSRC identifier is a
-// randomly chosen value meant to be globally unique within a
-// particular RTP session (see Section 8). A participant need not
-// use the same SSRC identifier for all the RTP sessions in a
-// multimedia session; the binding of the SSRC identifiers is
-// provided through RTCP (see Section 6.5.1). If a participant
-// generates multiple streams in one RTP session, for example from
-// separate video cameras, each MUST be identified as a different
-// SSRC.
-void CastSenderImpl::ReceivedPacket(scoped_ptr<Packet> packet) {
- DCHECK(cast_environment_);
- size_t length = packet->size();
- const uint8_t* data = &packet->front();
- if (!Rtcp::IsRtcpPacket(data, length)) {
- VLOG(1) << "CastSenderImpl@" << this << "::ReceivedPacket() -- "
- << "Received an invalid (non-RTCP?) packet in the cast sender.";
- return;
- }
- uint32 ssrc_of_sender = Rtcp::GetSsrcOfSender(data, length);
- if (ssrc_of_sender == ssrc_of_audio_sender_) {
- if (!audio_sender_) {
- NOTREACHED();
- return;
- }
- cast_environment_->PostTask(CastEnvironment::MAIN,
- FROM_HERE,
- base::Bind(&AudioSender::IncomingRtcpPacket,
- audio_sender_->AsWeakPtr(),
- base::Passed(&packet)));
- } else if (ssrc_of_sender == ssrc_of_video_sender_) {
- if (!video_sender_) {
- NOTREACHED();
- return;
- }
- cast_environment_->PostTask(CastEnvironment::MAIN,
- FROM_HERE,
- base::Bind(&VideoSender::IncomingRtcpPacket,
- video_sender_->AsWeakPtr(),
- base::Passed(&packet)));
- } else {
- VLOG(1) << "CastSenderImpl@" << this << "::ReceivedPacket() -- "
- << "Received a RTCP packet with a non matching sender SSRC "
- << ssrc_of_sender;
- }
-}
-
scoped_refptr<AudioFrameInput> CastSenderImpl::audio_frame_input() {
return audio_frame_input_;
}
@@ -212,10 +151,5 @@ scoped_refptr<VideoFrameInput> CastSenderImpl::video_frame_input() {
return video_frame_input_;
}
-PacketReceiverCallback CastSenderImpl::packet_receiver() {
- return base::Bind(&CastSenderImpl::ReceivedPacket,
- weak_factory_.GetWeakPtr());
-}
-
} // namespace cast
} // namespace media
diff --git a/media/cast/cast_sender_impl.h b/media/cast/cast_sender_impl.h
index bc320f7..c34fccf 100644
--- a/media/cast/cast_sender_impl.h
+++ b/media/cast/cast_sender_impl.h
@@ -42,8 +42,6 @@ class CastSenderImpl : public CastSender {
virtual scoped_refptr<AudioFrameInput> audio_frame_input() OVERRIDE;
virtual scoped_refptr<VideoFrameInput> video_frame_input() OVERRIDE;
- virtual PacketReceiverCallback packet_receiver() OVERRIDE;
-
private:
void ReceivedPacket(scoped_ptr<Packet> packet);
diff --git a/media/cast/cast_testing.gypi b/media/cast/cast_testing.gypi
index 97e831e..58dc642 100644
--- a/media/cast/cast_testing.gypi
+++ b/media/cast/cast_testing.gypi
@@ -85,8 +85,6 @@
'net/pacing/paced_sender_unittest.cc',
'net/rtcp/mock_rtcp_receiver_feedback.cc',
'net/rtcp/mock_rtcp_receiver_feedback.h',
- 'net/rtcp/mock_rtcp_sender_feedback.cc',
- 'net/rtcp/mock_rtcp_sender_feedback.h',
'net/rtcp/rtcp_receiver_unittest.cc',
'net/rtcp/rtcp_sender_unittest.cc',
'net/rtcp/rtcp_unittest.cc',
diff --git a/media/cast/net/cast_transport_config.cc b/media/cast/net/cast_transport_config.cc
index ae8ec60..a607f6f 100644
--- a/media/cast/net/cast_transport_config.cc
+++ b/media/cast/net/cast_transport_config.cc
@@ -8,7 +8,7 @@ namespace media {
namespace cast {
CastTransportRtpConfig::CastTransportRtpConfig()
- : ssrc(0), rtp_payload_type(0), stored_frames(0) {}
+ : ssrc(0), feedback_ssrc(0), rtp_payload_type(0), stored_frames(0) {}
CastTransportRtpConfig::~CastTransportRtpConfig() {}
@@ -52,9 +52,5 @@ RtcpDlrrReportBlock::RtcpDlrrReportBlock()
: last_rr(0), delay_since_last_rr(0) {}
RtcpDlrrReportBlock::~RtcpDlrrReportBlock() {}
-SendRtcpFromRtpSenderData::SendRtcpFromRtpSenderData()
- : packet_type_flags(0), sending_ssrc(0) {}
-SendRtcpFromRtpSenderData::~SendRtcpFromRtpSenderData() {}
-
} // namespace cast
} // namespace media
diff --git a/media/cast/net/cast_transport_config.h b/media/cast/net/cast_transport_config.h
index db87b8c..088aa62 100644
--- a/media/cast/net/cast_transport_config.h
+++ b/media/cast/net/cast_transport_config.h
@@ -18,11 +18,6 @@
namespace media {
namespace cast {
-enum RtcpMode {
- kRtcpCompound, // Compound RTCP mode is described by RFC 4585.
- kRtcpReducedSize, // Reduced-size RTCP mode is described by RFC 5506.
-};
-
enum Codec {
CODEC_UNKNOWN,
CODEC_AUDIO_OPUS,
@@ -40,6 +35,12 @@ struct CastTransportRtpConfig {
// Identifier refering to this sender.
uint32 ssrc;
+ // Identifier for incoming RTCP traffic.
+ uint32 feedback_ssrc;
+
+ // Identifier for this stream.
+ std::string c_name;
+
// RTP payload type enum: Specifies the type/encoding of frame data.
int rtp_payload_type;
@@ -172,19 +173,6 @@ struct RtcpDlrrReportBlock {
uint32 delay_since_last_rr;
};
-// This is only needed because IPC messages don't support more than
-// 5 arguments.
-struct SendRtcpFromRtpSenderData {
- SendRtcpFromRtpSenderData();
- ~SendRtcpFromRtpSenderData();
- uint32 packet_type_flags;
- uint32 sending_ssrc;
- std::string c_name;
- uint32 ntp_seconds;
- uint32 ntp_fraction;
- uint32 rtp_timestamp;
-};
-
inline bool operator==(RtcpSenderInfo lhs, RtcpSenderInfo rhs) {
return lhs.ntp_seconds == rhs.ntp_seconds &&
lhs.ntp_fraction == rhs.ntp_fraction &&
diff --git a/media/cast/net/cast_transport_sender.h b/media/cast/net/cast_transport_sender.h
index 3f8a119..31166f5 100644
--- a/media/cast/net/cast_transport_sender.h
+++ b/media/cast/net/cast_transport_sender.h
@@ -10,15 +10,10 @@
// in the following order:
// 1. Create CastTransportSender.
// 2. Create CastSender (accepts CastTransportSender as an input).
-// 3. Call CastTransportSender::SetPacketReceiver to ensure that the packets
-// received by the CastTransportSender will be sent to the CastSender.
-// Steps 3 can be done interchangeably.
// Destruction: The CastTransportSender is assumed to be valid as long as the
// CastSender is alive. Therefore the CastSender should be destructed before the
// CastTransportSender.
-// This also works when the CastSender acts as a receiver for the RTCP packets
-// due to the weak pointers in the ReceivedPacket method in cast_sender_impl.cc.
#ifndef MEDIA_CAST_NET_CAST_TRANSPORT_SENDER_H_
#define MEDIA_CAST_NET_CAST_TRANSPORT_SENDER_H_
@@ -31,6 +26,8 @@
#include "media/cast/logging/logging_defines.h"
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/cast_transport_defines.h"
+#include "media/cast/net/rtcp/receiver_rtcp_event_subscriber.h"
+#include "media/cast/net/rtcp/rtcp_defines.h"
#include "net/base/ip_endpoint.h"
namespace net {
@@ -45,7 +42,8 @@ namespace cast {
typedef base::Callback<void(CastTransportStatus status)>
CastTransportStatusCallback;
-typedef base::Callback<void(const std::vector<PacketEvent>&)>
+typedef base::Callback<void(const std::vector<PacketEvent>&,
+ const std::vector<FrameEvent>&)>
BulkRawEventsCallback;
// The application should only trigger this class from the transport thread.
@@ -64,14 +62,13 @@ class CastTransportSender : public base::NonThreadSafe {
// Audio/Video initialization.
// Encoded frames cannot be transmitted until the relevant initialize method
- // is called. Usually called by CastSender.
- virtual void InitializeAudio(const CastTransportRtpConfig& config) = 0;
- virtual void InitializeVideo(const CastTransportRtpConfig& config) = 0;
-
- // Sets the Cast packet receiver. Should be called after creation on the
- // Cast sender. Packets won't be received until this function is called.
- virtual void SetPacketReceiver(
- const PacketReceiverCallback& packet_receiver) = 0;
+ // is called.
+ virtual void InitializeAudio(const CastTransportRtpConfig& config,
+ const RtcpCastMessageCallback& cast_message_cb,
+ const RtcpRttCallback& rtt_cb) = 0;
+ virtual void InitializeVideo(const CastTransportRtpConfig& config,
+ const RtcpCastMessageCallback& cast_message_cb,
+ const RtcpRttCallback& rtt_cb) = 0;
// The following two functions handle the encoded media frames (audio and
// video) to be processed.
@@ -79,16 +76,14 @@ class CastTransportSender : public base::NonThreadSafe {
virtual void InsertCodedAudioFrame(const EncodedFrame& audio_frame) = 0;
virtual void InsertCodedVideoFrame(const EncodedFrame& video_frame) = 0;
- // Builds an RTCP packet and sends it to the network.
- // |ntp_seconds|, |ntp_fraction| and |rtp_timestamp| are used in the
- // RTCP Sender Report.
- virtual void SendRtcpFromRtpSender(uint32 packet_type_flags,
- uint32 ntp_seconds,
- uint32 ntp_fraction,
- uint32 rtp_timestamp,
- const RtcpDlrrReportBlock& dlrr,
- uint32 sending_ssrc,
- const std::string& c_name) = 0;
+ // Sends a RTCP sender report to the receiver.
+ // |ssrc| is the SSRC for this report.
+ // |current_time| is the current time reported by a tick clock.
+ // |current_time_as_rtp_timestamp| is the corresponding RTP timestamp.
+ virtual void SendSenderReport(
+ uint32 ssrc,
+ base::TimeTicks current_time,
+ uint32 current_time_as_rtp_timestamp) = 0;
// Retransmission request.
// |missing_packets| includes the list of frames and packets in each
@@ -103,6 +98,9 @@ class CastTransportSender : public base::NonThreadSafe {
const MissingFramesAndPacketsMap& missing_packets,
bool cancel_rtx_if_not_in_list,
base::TimeDelta dedupe_window) = 0;
+
+ // Returns a callback for receiving packets for testing purposes.
+ virtual PacketReceiverCallback PacketReceiverForTesting();
};
} // namespace cast
diff --git a/media/cast/net/cast_transport_sender_impl.cc b/media/cast/net/cast_transport_sender_impl.cc
index 973f341..a13be94 100644
--- a/media/cast/net/cast_transport_sender_impl.cc
+++ b/media/cast/net/cast_transport_sender_impl.cc
@@ -32,6 +32,10 @@ scoped_ptr<CastTransportSender> CastTransportSender::Create(
NULL));
}
+PacketReceiverCallback CastTransportSender::PacketReceiverForTesting() {
+ return PacketReceiverCallback();
+}
+
CastTransportSenderImpl::CastTransportSenderImpl(
net::NetLog* net_log,
base::TickClock* clock,
@@ -50,22 +54,23 @@ CastTransportSenderImpl::CastTransportSenderImpl(
net::IPEndPoint(),
remote_end_point,
status_callback)),
- logging_(),
pacer_(clock,
&logging_,
external_transport ? external_transport : transport_.get(),
transport_task_runner),
- rtcp_builder_(&pacer_),
- raw_events_callback_(raw_events_callback) {
+ raw_events_callback_(raw_events_callback),
+ raw_events_callback_interval_(raw_events_callback_interval),
+ weak_factory_(this) {
DCHECK(clock_);
if (!raw_events_callback_.is_null()) {
DCHECK(raw_events_callback_interval > base::TimeDelta());
event_subscriber_.reset(new SimpleEventSubscriber);
logging_.AddRawEventSubscriber(event_subscriber_.get());
- raw_events_timer_.Start(FROM_HERE,
- raw_events_callback_interval,
- this,
- &CastTransportSenderImpl::SendRawEvents);
+ transport_task_runner->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&CastTransportSenderImpl::SendRawEvents,
+ weak_factory_.GetWeakPtr()),
+ raw_events_callback_interval);
}
if (transport_) {
// The default DSCP value for cast is AF41. Which gives it a higher
@@ -80,13 +85,16 @@ CastTransportSenderImpl::~CastTransportSenderImpl() {
}
void CastTransportSenderImpl::InitializeAudio(
- const CastTransportRtpConfig& config) {
+ const CastTransportRtpConfig& config,
+ const RtcpCastMessageCallback& cast_message_cb,
+ const RtcpRttCallback& rtt_cb) {
LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty())
<< "Unsafe to send audio with encryption DISABLED.";
if (!audio_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) {
status_callback_.Run(TRANSPORT_AUDIO_UNINITIALIZED);
return;
}
+
audio_sender_.reset(new RtpSender(clock_, transport_task_runner_, &pacer_));
if (audio_sender_->Initialize(config)) {
// Audio packets have a higher priority.
@@ -96,30 +104,61 @@ void CastTransportSenderImpl::InitializeAudio(
} else {
audio_sender_.reset();
status_callback_.Run(TRANSPORT_AUDIO_UNINITIALIZED);
+ return;
}
+
+ audio_rtcp_session_.reset(
+ new Rtcp(cast_message_cb,
+ rtt_cb,
+ base::Bind(&CastTransportSenderImpl::OnReceivedLogMessage,
+ weak_factory_.GetWeakPtr(), AUDIO_EVENT),
+ clock_,
+ &pacer_,
+ config.ssrc,
+ config.feedback_ssrc,
+ config.c_name));
+ pacer_.RegisterAudioSsrc(config.ssrc);
+
+ // Only start receiving once.
+ if (!video_sender_)
+ StartReceiving();
+ status_callback_.Run(TRANSPORT_AUDIO_INITIALIZED);
}
void CastTransportSenderImpl::InitializeVideo(
- const CastTransportRtpConfig& config) {
+ const CastTransportRtpConfig& config,
+ const RtcpCastMessageCallback& cast_message_cb,
+ const RtcpRttCallback& rtt_cb) {
LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty())
<< "Unsafe to send video with encryption DISABLED.";
if (!video_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) {
status_callback_.Run(TRANSPORT_VIDEO_UNINITIALIZED);
return;
}
+
video_sender_.reset(new RtpSender(clock_, transport_task_runner_, &pacer_));
- if (video_sender_->Initialize(config)) {
- pacer_.RegisterVideoSsrc(config.ssrc);
- status_callback_.Run(TRANSPORT_VIDEO_INITIALIZED);
- } else {
+ if (!video_sender_->Initialize(config)) {
video_sender_.reset();
status_callback_.Run(TRANSPORT_VIDEO_UNINITIALIZED);
+ return;
}
-}
-void CastTransportSenderImpl::SetPacketReceiver(
- const PacketReceiverCallback& packet_receiver) {
- transport_->StartReceiving(packet_receiver);
+ video_rtcp_session_.reset(
+ new Rtcp(cast_message_cb,
+ rtt_cb,
+ base::Bind(&CastTransportSenderImpl::OnReceivedLogMessage,
+ weak_factory_.GetWeakPtr(), VIDEO_EVENT),
+ clock_,
+ &pacer_,
+ config.ssrc,
+ config.feedback_ssrc,
+ config.c_name));
+ pacer_.RegisterVideoSsrc(config.ssrc);
+
+ // Only start receiving once.
+ if (!audio_sender_)
+ StartReceiving();
+ status_callback_.Run(TRANSPORT_VIDEO_INITIALIZED);
}
namespace {
@@ -153,30 +192,21 @@ void CastTransportSenderImpl::InsertCodedVideoFrame(
EncryptAndSendFrame(video_frame, &video_encryptor_, video_sender_.get());
}
-void CastTransportSenderImpl::SendRtcpFromRtpSender(
- uint32 packet_type_flags,
- uint32 ntp_seconds,
- uint32 ntp_fraction,
- uint32 rtp_timestamp,
- const RtcpDlrrReportBlock& dlrr,
- uint32 sending_ssrc,
- const std::string& c_name) {
- RtcpSenderInfo sender_info;
- sender_info.ntp_seconds = ntp_seconds;
- sender_info.ntp_fraction = ntp_fraction;
- sender_info.rtp_timestamp = rtp_timestamp;
- if (audio_sender_ && audio_sender_->ssrc() == sending_ssrc) {
- sender_info.send_packet_count = audio_sender_->send_packet_count();
- sender_info.send_octet_count = audio_sender_->send_octet_count();
- } else if (video_sender_ && video_sender_->ssrc() == sending_ssrc) {
- sender_info.send_packet_count = video_sender_->send_packet_count();
- sender_info.send_octet_count = video_sender_->send_octet_count();
+void CastTransportSenderImpl::SendSenderReport(
+ uint32 ssrc,
+ base::TimeTicks current_time,
+ uint32 current_time_as_rtp_timestamp) {
+ if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
+ audio_rtcp_session_->SendRtcpFromRtpSender(
+ current_time, current_time_as_rtp_timestamp,
+ audio_sender_->send_packet_count(), audio_sender_->send_octet_count());
+ } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
+ video_rtcp_session_->SendRtcpFromRtpSender(
+ current_time, current_time_as_rtp_timestamp,
+ video_sender_->send_packet_count(), video_sender_->send_octet_count());
} else {
- LOG(ERROR) << "Sending RTCP with an invalid SSRC.";
- return;
+ NOTREACHED() << "Invalid request for sending RTCP packet.";
}
- rtcp_builder_.SendRtcpFromRtpSender(
- packet_type_flags, sender_info, dlrr, sending_ssrc, c_name);
}
void CastTransportSenderImpl::ResendPackets(
@@ -197,12 +227,85 @@ void CastTransportSenderImpl::ResendPackets(
}
}
+PacketReceiverCallback CastTransportSenderImpl::PacketReceiverForTesting() {
+ return base::Bind(&CastTransportSenderImpl::OnReceivedPacket,
+ weak_factory_.GetWeakPtr());
+}
+
void CastTransportSenderImpl::SendRawEvents() {
DCHECK(event_subscriber_.get());
DCHECK(!raw_events_callback_.is_null());
std::vector<PacketEvent> packet_events;
+ std::vector<FrameEvent> frame_events;
event_subscriber_->GetPacketEventsAndReset(&packet_events);
- raw_events_callback_.Run(packet_events);
+ event_subscriber_->GetFrameEventsAndReset(&frame_events);
+ raw_events_callback_.Run(packet_events, frame_events);
+
+ transport_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&CastTransportSenderImpl::SendRawEvents,
+ weak_factory_.GetWeakPtr()),
+ raw_events_callback_interval_);
+}
+
+void CastTransportSenderImpl::StartReceiving() {
+ if (!transport_)
+ return;
+ transport_->StartReceiving(
+ base::Bind(&CastTransportSenderImpl::OnReceivedPacket,
+ weak_factory_.GetWeakPtr()));
+}
+
+void CastTransportSenderImpl::OnReceivedPacket(scoped_ptr<Packet> packet) {
+ if (audio_rtcp_session_ &&
+ audio_rtcp_session_->IncomingRtcpPacket(&packet->front(),
+ packet->size())) {
+ return;
+ }
+ if (video_rtcp_session_ &&
+ video_rtcp_session_->IncomingRtcpPacket(&packet->front(),
+ packet->size())) {
+ return;
+ }
+ VLOG(1) << "Stale packet received.";
+}
+
+void CastTransportSenderImpl::OnReceivedLogMessage(
+ EventMediaType media_type,
+ const RtcpReceiverLogMessage& log) {
+ // Add received log messages into our log system.
+ RtcpReceiverLogMessage::const_iterator it = log.begin();
+ for (; it != 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:
+ logging_.InsertPacketEvent(
+ event_it->event_timestamp, event_it->type,
+ media_type, rtp_timestamp,
+ kFrameIdUnknown, event_it->packet_id, 0, 0);
+ break;
+ case FRAME_ACK_SENT:
+ case FRAME_DECODED:
+ logging_.InsertFrameEvent(
+ event_it->event_timestamp, event_it->type, media_type,
+ rtp_timestamp, kFrameIdUnknown);
+ break;
+ case FRAME_PLAYOUT:
+ logging_.InsertFrameEventWithDelay(
+ event_it->event_timestamp, event_it->type, 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
diff --git a/media/cast/net/cast_transport_sender_impl.h b/media/cast/net/cast_transport_sender_impl.h
index 5d34fde..9cc3b46 100644
--- a/media/cast/net/cast_transport_sender_impl.h
+++ b/media/cast/net/cast_transport_sender_impl.h
@@ -2,12 +2,32 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This class maintains a send transport for audio and video in a Cast
+// Streaming session.
+// Audio, video frames and RTCP messages are submitted to this object
+// and then packetized and paced to the underlying UDP socket.
+//
+// The hierarchy of send transport in a Cast Streaming session:
+//
+// CastTransportSender RTP RTCP
+// ------------------------------------------------------------------
+// TransportEncryptionHandler (A/V)
+// RtpSender (A/V) Rtcp (A/V)
+// PacedSender (Shared)
+// UdpTransport (Shared)
+//
+// There are objects of TransportEncryptionHandler, RtpSender and Rtcp
+// for each audio and video stream.
+// PacedSender and UdpTransport are shared between all RTP and RTCP
+// streams.
+
#ifndef MEDIA_CAST_NET_CAST_TRANSPORT_IMPL_H_
#define MEDIA_CAST_NET_CAST_TRANSPORT_IMPL_H_
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
@@ -17,7 +37,7 @@
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/cast_transport_sender.h"
#include "media/cast/net/pacing/paced_sender.h"
-#include "media/cast/net/rtcp/rtcp_builder.h"
+#include "media/cast/net/rtcp/rtcp.h"
#include "media/cast/net/rtp/rtp_sender.h"
namespace media {
@@ -27,9 +47,7 @@ class UdpTransport;
class CastTransportSenderImpl : public CastTransportSender {
public:
- // external_transport is only used for testing.
- // Note that SetPacketReceiver does not work if an external
- // transport is provided.
+ // |external_transport| is only used for testing.
// |raw_events_callback|: Raw events will be returned on this callback
// which will be invoked every |raw_events_callback_interval|.
// This can be a null callback, i.e. if user is not interested in raw events.
@@ -47,23 +65,19 @@ class CastTransportSenderImpl : public CastTransportSender {
virtual ~CastTransportSenderImpl();
- virtual void InitializeAudio(const CastTransportRtpConfig& config) OVERRIDE;
- virtual void InitializeVideo(const CastTransportRtpConfig& config) OVERRIDE;
-
- // CastTransportSender implementation.
- virtual void SetPacketReceiver(const PacketReceiverCallback& packet_receiver)
- OVERRIDE;
-
+ virtual void InitializeAudio(const CastTransportRtpConfig& config,
+ const RtcpCastMessageCallback& cast_message_cb,
+ const RtcpRttCallback& rtt_cb) OVERRIDE;
+ virtual void InitializeVideo(const CastTransportRtpConfig& config,
+ const RtcpCastMessageCallback& cast_message_cb,
+ const RtcpRttCallback& rtt_cb) OVERRIDE;
virtual void InsertCodedAudioFrame(const EncodedFrame& audio_frame) OVERRIDE;
virtual void InsertCodedVideoFrame(const EncodedFrame& video_frame) OVERRIDE;
- virtual void SendRtcpFromRtpSender(uint32 packet_type_flags,
- uint32 ntp_seconds,
- uint32 ntp_fraction,
- uint32 rtp_timestamp,
- const RtcpDlrrReportBlock& dlrr,
- uint32 sending_ssrc,
- const std::string& c_name) OVERRIDE;
+ virtual void SendSenderReport(
+ uint32 ssrc,
+ base::TimeTicks current_time,
+ uint32 current_time_as_rtp_timestamp) OVERRIDE;
virtual void ResendPackets(bool is_audio,
const MissingFramesAndPacketsMap& missing_packets,
@@ -71,22 +85,43 @@ class CastTransportSenderImpl : public CastTransportSender {
base::TimeDelta dedupe_window)
OVERRIDE;
+ virtual PacketReceiverCallback PacketReceiverForTesting() OVERRIDE;
+
private:
// If |raw_events_callback_| is non-null, calls it with events collected
// by |event_subscriber_| since last call.
void SendRawEvents();
+ // Start receiving packets.
+ void StartReceiving();
+
+ // Called when a packet is received.
+ void OnReceivedPacket(scoped_ptr<Packet> packet);
+
+ // Called when a log message is received.
+ void OnReceivedLogMessage(EventMediaType media_type,
+ const RtcpReceiverLogMessage& log);
+
base::TickClock* clock_; // Not owned by this class.
CastTransportStatusCallback status_callback_;
scoped_refptr<base::SingleThreadTaskRunner> transport_task_runner_;
- scoped_ptr<UdpTransport> transport_;
LoggingImpl logging_;
+
+ // Interface to a UDP socket.
+ scoped_ptr<UdpTransport> transport_;
+
+ // Packet sender that performs pacing.
PacedSender pacer_;
- RtcpBuilder rtcp_builder_;
+
+ // Packetizer for audio and video frames.
scoped_ptr<RtpSender> audio_sender_;
scoped_ptr<RtpSender> video_sender_;
+ // Maintains RTCP session for audio and video.
+ scoped_ptr<Rtcp> audio_rtcp_session_;
+ scoped_ptr<Rtcp> video_rtcp_session_;
+
// Encrypts data in EncodedFrames before they are sent. Note that it's
// important for the encryption to happen here, in code that would execute in
// the main browser process, for security reasons. This helps to mitigate
@@ -96,9 +131,11 @@ class CastTransportSenderImpl : public CastTransportSender {
// This is non-null iff |raw_events_callback_| is non-null.
scoped_ptr<SimpleEventSubscriber> event_subscriber_;
- base::RepeatingTimer<CastTransportSenderImpl> raw_events_timer_;
BulkRawEventsCallback raw_events_callback_;
+ base::TimeDelta raw_events_callback_interval_;
+
+ base::WeakPtrFactory<CastTransportSenderImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(CastTransportSenderImpl);
};
diff --git a/media/cast/net/cast_transport_sender_impl_unittest.cc b/media/cast/net/cast_transport_sender_impl_unittest.cc
index b1d29b9..b8a49cc 100644
--- a/media/cast/net/cast_transport_sender_impl_unittest.cc
+++ b/media/cast/net/cast_transport_sender_impl_unittest.cc
@@ -8,8 +8,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
#include "base/test/simple_test_tick_clock.h"
#include "media/cast/cast_config.h"
#include "media/cast/net/cast_transport_config.h"
@@ -70,11 +68,9 @@ class CastTransportSenderImplTest : public ::testing::Test {
task_runner_->RunTasks();
}
- void LogRawEvents(const std::vector<PacketEvent>& packet_events) {
+ void LogRawEvents(const std::vector<PacketEvent>& packet_events,
+ const std::vector<FrameEvent>& frame_events) {
num_times_callback_called_++;
- if (num_times_callback_called_ == 3) {
- run_loop_.Quit();
- }
}
static void UpdateCastTransportStatus(CastTransportStatus status) {
@@ -84,27 +80,19 @@ class CastTransportSenderImplTest : public ::testing::Test {
scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
scoped_ptr<CastTransportSenderImpl> transport_sender_;
FakePacketSender transport_;
- base::MessageLoopForIO message_loop_;
- base::RunLoop run_loop_;
int num_times_callback_called_;
};
TEST_F(CastTransportSenderImplTest, InitWithoutLogging) {
InitWithoutLogging();
- message_loop_.PostDelayedTask(FROM_HERE,
- run_loop_.QuitClosure(),
- base::TimeDelta::FromMilliseconds(50));
- run_loop_.Run();
+ task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
EXPECT_EQ(0, num_times_callback_called_);
}
TEST_F(CastTransportSenderImplTest, InitWithLogging) {
InitWithLogging();
- message_loop_.PostDelayedTask(FROM_HERE,
- run_loop_.QuitClosure(),
- base::TimeDelta::FromMilliseconds(50));
- run_loop_.Run();
- EXPECT_GT(num_times_callback_called_, 1);
+ task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
+ EXPECT_EQ(5, num_times_callback_called_);
}
} // namespace cast
diff --git a/media/cast/net/rtcp/mock_rtcp_receiver_feedback.cc b/media/cast/net/rtcp/mock_rtcp_receiver_feedback.cc
index 0ea6606..d9818ff 100644
--- a/media/cast/net/rtcp/mock_rtcp_receiver_feedback.cc
+++ b/media/cast/net/rtcp/mock_rtcp_receiver_feedback.cc
@@ -11,9 +11,5 @@ MockRtcpReceiverFeedback::MockRtcpReceiverFeedback() {}
MockRtcpReceiverFeedback::~MockRtcpReceiverFeedback() {}
-MockRtcpRttFeedback::MockRtcpRttFeedback() {}
-
-MockRtcpRttFeedback::~MockRtcpRttFeedback() {}
-
} // namespace cast
} // namespace media
diff --git a/media/cast/net/rtcp/mock_rtcp_receiver_feedback.h b/media/cast/net/rtcp/mock_rtcp_receiver_feedback.h
index 38bf0ee..ae6b96e 100644
--- a/media/cast/net/rtcp/mock_rtcp_receiver_feedback.h
+++ b/media/cast/net/rtcp/mock_rtcp_receiver_feedback.h
@@ -15,7 +15,8 @@
namespace media {
namespace cast {
-class MockRtcpReceiverFeedback : public RtcpReceiverFeedback {
+// TODO(hclam): Should be renamed to MockRtcpMessageHandler.
+class MockRtcpReceiverFeedback : public RtcpMessageHandler {
public:
MockRtcpReceiverFeedback();
virtual ~MockRtcpReceiverFeedback();
@@ -30,17 +31,12 @@ class MockRtcpReceiverFeedback : public RtcpReceiverFeedback {
MOCK_METHOD1(OnReceivedReceiverLog,
void(const RtcpReceiverLogMessage& receiver_log));
-};
-class MockRtcpRttFeedback : public RtcpRttFeedback {
- public:
- MockRtcpRttFeedback();
- virtual ~MockRtcpRttFeedback();
+ MOCK_METHOD2(OnReceivedDelaySinceLastReport,
+ void(uint32 last_report, uint32 delay_since_last_report));
- MOCK_METHOD3(OnReceivedDelaySinceLastReport,
- void(uint32 media_ssrc,
- uint32 last_report,
- uint32 delay_since_last_report));
+ MOCK_METHOD1(OnReceivedCastFeedback,
+ void(const RtcpCastMessage& cast_message));
};
} // namespace cast
diff --git a/media/cast/net/rtcp/rtcp.cc b/media/cast/net/rtcp/rtcp.cc
index c0e6c19..92abb3e 100644
--- a/media/cast/net/rtcp/rtcp.cc
+++ b/media/cast/net/rtcp/rtcp.cc
@@ -4,7 +4,6 @@
#include "media/cast/net/rtcp/rtcp.h"
-#include "base/big_endian.h"
#include "media/cast/cast_config.h"
#include "media/cast/cast_defines.h"
#include "media/cast/cast_environment.h"
@@ -20,28 +19,11 @@ namespace media {
namespace cast {
static const int32 kMaxRttMs = 10000; // 10 seconds.
-static const int32 kMaxDelayMs = 2000; // 2 seconds.
-class LocalRtcpRttFeedback : public RtcpRttFeedback {
+class Rtcp::RtcpMessageHandlerImpl : public RtcpMessageHandler {
public:
- explicit LocalRtcpRttFeedback(Rtcp* rtcp) : rtcp_(rtcp) {}
-
- virtual void OnReceivedDelaySinceLastReport(
- uint32 receivers_ssrc, uint32 last_report,
- uint32 delay_since_last_report) OVERRIDE {
- rtcp_->OnReceivedDelaySinceLastReport(receivers_ssrc, last_report,
- delay_since_last_report);
- }
-
- private:
- Rtcp* rtcp_;
-};
-
-class LocalRtcpReceiverFeedback : public RtcpReceiverFeedback {
- public:
- LocalRtcpReceiverFeedback(Rtcp* rtcp,
- scoped_refptr<CastEnvironment> cast_environment)
- : rtcp_(rtcp), cast_environment_(cast_environment) {}
+ explicit RtcpMessageHandlerImpl(Rtcp* rtcp)
+ : rtcp_(rtcp) {}
virtual void OnReceivedSenderReport(
const RtcpSenderInfo& remote_sender_info) OVERRIDE {
@@ -60,103 +42,91 @@ class LocalRtcpReceiverFeedback : public RtcpReceiverFeedback {
remote_time_report.ntp_fraction);
}
- virtual void OnReceivedSendReportRequest() OVERRIDE {
- rtcp_->OnReceivedSendReportRequest();
- }
-
virtual void OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log)
OVERRIDE {
rtcp_->OnReceivedReceiverLog(receiver_log);
}
+ virtual void OnReceivedDelaySinceLastReport(
+ uint32 last_report,
+ uint32 delay_since_last_report) OVERRIDE {
+ rtcp_->OnReceivedDelaySinceLastReport(last_report, delay_since_last_report);
+ }
+
+ virtual void OnReceivedCastFeedback(
+ const RtcpCastMessage& cast_message) OVERRIDE {
+ rtcp_->OnReceivedCastFeedback(cast_message);
+ }
+
private:
Rtcp* rtcp_;
- scoped_refptr<CastEnvironment> cast_environment_;
};
-Rtcp::Rtcp(scoped_refptr<CastEnvironment> cast_environment,
- RtcpSenderFeedback* sender_feedback,
- CastTransportSender* const transport_sender,
- 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),
+Rtcp::Rtcp(const RtcpCastMessageCallback& cast_callback,
+ const RtcpRttCallback& rtt_callback,
+ const RtcpLogMessageCallback& log_callback,
+ base::TickClock* clock,
+ PacedPacketSender* packet_sender,
+ uint32 local_ssrc,
+ uint32 remote_ssrc, const std::string& c_name)
+ : cast_callback_(cast_callback),
+ rtt_callback_(rtt_callback),
+ log_callback_(log_callback),
+ clock_(clock),
+ rtcp_sender_(new RtcpSender(packet_sender, local_ssrc, c_name)),
local_ssrc_(local_ssrc),
remote_ssrc_(remote_ssrc),
c_name_(c_name),
- event_media_type_(event_media_type),
- rtp_receiver_statistics_(rtp_receiver_statistics),
- 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)),
+ handler_(new RtcpMessageHandlerImpl(this)),
+ rtcp_receiver_(new RtcpReceiver(handler_.get(), local_ssrc)),
last_report_truncated_ntp_(0),
local_clock_ahead_by_(ClockDriftSmoother::GetDefaultTimeConstant()),
lip_sync_rtp_timestamp_(0),
lip_sync_ntp_timestamp_(0),
min_rtt_(TimeDelta::FromMilliseconds(kMaxRttMs)),
number_of_rtt_in_avg_(0) {
- rtcp_receiver_.reset(new RtcpReceiver(cast_environment, sender_feedback,
- receiver_feedback_.get(),
- rtt_feedback_.get(), local_ssrc));
rtcp_receiver_->SetRemoteSSRC(remote_ssrc);
+
+ // This value is the same in FrameReceiver.
+ rtcp_receiver_->SetCastReceiverEventHistorySize(
+ kReceiverRtcpEventHistorySize);
}
Rtcp::~Rtcp() {}
-// static
-bool Rtcp::IsRtcpPacket(const uint8* packet, size_t length) {
- DCHECK_GE(length, kMinLengthOfRtcp) << "Invalid RTCP packet";
- if (length < kMinLengthOfRtcp) return false;
-
- uint8 packet_type = packet[1];
- if (packet_type >= kPacketTypeLow &&
- packet_type <= kPacketTypeHigh) {
- return true;
+bool Rtcp::IncomingRtcpPacket(const uint8* data, size_t length) {
+ // Check if this is a valid RTCP packet.
+ if (!RtcpReceiver::IsRtcpPacket(data, length)) {
+ VLOG(1) << "Rtcp@" << this << "::IncomingRtcpPacket() -- "
+ << "Received an invalid (non-RTCP?) packet.";
+ return false;
}
- return false;
-}
-
-// static
-uint32 Rtcp::GetSsrcOfSender(const uint8* rtcp_buffer, size_t length) {
- DCHECK_GE(length, kMinLengthOfRtcp) << "Invalid RTCP packet";
- uint32 ssrc_of_sender;
- base::BigEndianReader big_endian_reader(
- reinterpret_cast<const char*>(rtcp_buffer), length);
- big_endian_reader.Skip(4); // Skip header
- big_endian_reader.ReadU32(&ssrc_of_sender);
- return ssrc_of_sender;
-}
-base::TimeTicks Rtcp::TimeToSendNextRtcpReport() {
- if (next_time_to_send_rtcp_.is_null()) {
- UpdateNextTimeToSendRtcp();
+ // Check if this packet is to us.
+ uint32 ssrc_of_sender = RtcpReceiver::GetSsrcOfSender(data, length);
+ if (ssrc_of_sender != remote_ssrc_) {
+ return false;
}
- return next_time_to_send_rtcp_;
-}
-void Rtcp::IncomingRtcpPacket(const uint8* rtcp_buffer, size_t length) {
- RtcpParser rtcp_parser(rtcp_buffer, length);
+ // Parse this packet.
+ RtcpParser rtcp_parser(data, length);
if (!rtcp_parser.IsValid()) {
// Silently ignore packet.
- DLOG(ERROR) << "Received invalid RTCP packet";
- return;
+ VLOG(1) << "Received invalid RTCP packet";
+ return false;
}
rtcp_receiver_->IncomingRtcpPacket(&rtcp_parser);
+ return true;
}
void Rtcp::SendRtcpFromRtpReceiver(
const RtcpCastMessage* cast_message,
- const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events) {
- DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
+ base::TimeDelta target_delay,
+ const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events,
+ RtpReceiverStatistics* rtp_receiver_statistics) {
uint32 packet_type_flags = 0;
- base::TimeTicks now = cast_environment_->Clock()->NowTicks();
+ base::TimeTicks now = clock_->NowTicks();
RtcpReportBlock report_block;
RtcpReceiverReferenceTimeReport rrtr;
@@ -172,13 +142,14 @@ void Rtcp::SendRtcpFromRtpReceiver(
if (rtcp_events) {
packet_type_flags |= kRtcpReceiverLog;
}
- if (rtcp_mode_ == kRtcpCompound || now >= next_time_to_send_rtcp_) {
+ // If RTCP is in compound mode then we always send a RR.
+ if (rtp_receiver_statistics) {
packet_type_flags |= kRtcpRr;
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(
+ 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);
}
@@ -188,6 +159,14 @@ void Rtcp::SendRtcpFromRtpReceiver(
uint32 delay_seconds = 0;
uint32 delay_fraction = 0;
base::TimeDelta delta = now - time_last_report_received_;
+
+ // TODO(hclam): DLRR is not used by any receiver. Consider removing
+ // it. There is one race condition in the computation of the time for
+ // DLRR: current time is submitted to this method while
+ // |time_last_report_received_| is updated just before that. This can
+ // happen if current time is not submitted synchronously.
+ if (delta < base::TimeDelta())
+ delta = base::TimeDelta();
ConvertTimeToFractions(delta.InMicroseconds(), &delay_seconds,
&delay_fraction);
report_block.delay_since_last_sr =
@@ -195,19 +174,19 @@ void Rtcp::SendRtcpFromRtpReceiver(
} else {
report_block.delay_since_last_sr = 0;
}
- UpdateNextTimeToSendRtcp();
}
rtcp_sender_->SendRtcpFromRtpReceiver(packet_type_flags,
&report_block,
&rrtr,
cast_message,
rtcp_events,
- target_delay_);
+ target_delay);
}
void Rtcp::SendRtcpFromRtpSender(base::TimeTicks current_time,
- uint32 current_time_as_rtp_timestamp) {
- DCHECK(transport_sender_);
+ uint32 current_time_as_rtp_timestamp,
+ uint32 send_packet_count,
+ size_t send_octet_count) {
uint32 packet_type_flags = kRtcpSr;
uint32 current_ntp_seconds = 0;
uint32 current_ntp_fractions = 0;
@@ -229,16 +208,20 @@ void Rtcp::SendRtcpFromRtpSender(base::TimeTicks current_time,
dlrr.delay_since_last_rr = ConvertToNtpDiff(delay_seconds, delay_fraction);
}
- transport_sender_->SendRtcpFromRtpSender(
- packet_type_flags, current_ntp_seconds, current_ntp_fractions,
- current_time_as_rtp_timestamp, dlrr, local_ssrc_, c_name_);
- UpdateNextTimeToSendRtcp();
+ RtcpSenderInfo sender_info;
+ sender_info.ntp_seconds = current_ntp_seconds;
+ sender_info.ntp_fraction = current_ntp_fractions;
+ sender_info.rtp_timestamp = current_time_as_rtp_timestamp;
+ sender_info.send_packet_count = send_packet_count;
+ sender_info.send_octet_count = send_octet_count;
+
+ rtcp_sender_->SendRtcpFromRtpSender(packet_type_flags, sender_info, dlrr);
}
void Rtcp::OnReceivedNtp(uint32 ntp_seconds, uint32 ntp_fraction) {
last_report_truncated_ntp_ = ConvertToNtpDiff(ntp_seconds, ntp_fraction);
- const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
+ const base::TimeTicks now = clock_->NowTicks();
time_last_report_received_ = now;
// TODO(miu): This clock offset calculation does not account for packet
@@ -283,43 +266,31 @@ bool Rtcp::GetLatestLipSyncTimes(uint32* rtp_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));
+ DCHECK((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() {
- base::TimeTicks now = cast_environment_->Clock()->NowTicks();
-
- // Trigger a new RTCP report at next timer.
- next_time_to_send_rtcp_ = now;
-}
-
-void Rtcp::SetCastReceiverEventHistorySize(size_t size) {
- rtcp_receiver_->SetCastReceiverEventHistorySize(size);
-}
-
-void Rtcp::SetTargetDelay(base::TimeDelta target_delay) {
- DCHECK(target_delay < TimeDelta::FromMilliseconds(kMaxDelayMs));
- target_delay_ = target_delay;
-}
-
-void Rtcp::OnReceivedDelaySinceLastReport(uint32 receivers_ssrc,
- uint32 last_report,
+void Rtcp::OnReceivedDelaySinceLastReport(uint32 last_report,
uint32 delay_since_last_report) {
RtcpSendTimeMap::iterator it = last_reports_sent_map_.find(last_report);
if (it == last_reports_sent_map_.end()) {
return; // Feedback on another report.
}
- base::TimeDelta sender_delay =
- cast_environment_->Clock()->NowTicks() - it->second;
+ base::TimeDelta sender_delay = clock_->NowTicks() - it->second;
UpdateRtt(sender_delay, ConvertFromNtpDiff(delay_since_last_report));
}
+void Rtcp::OnReceivedCastFeedback(const RtcpCastMessage& cast_message) {
+ if (cast_callback_.is_null())
+ return;
+ cast_callback_.Run(cast_message);
+}
+
void Rtcp::SaveLastSentNtpTime(const base::TimeTicks& now,
uint32 last_ntp_seconds,
uint32 last_ntp_fraction) {
@@ -367,6 +338,9 @@ void Rtcp::UpdateRtt(const base::TimeDelta& sender_delay,
avg_rtt_ = rtt;
}
number_of_rtt_in_avg_++;
+
+ if (!rtt_callback_.is_null())
+ rtt_callback_.Run(rtt, avg_rtt_, min_rtt_, max_rtt_);
}
bool Rtcp::Rtt(base::TimeDelta* rtt, base::TimeDelta* avg_rtt,
@@ -385,45 +359,10 @@ bool Rtcp::Rtt(base::TimeDelta* rtt, base::TimeDelta* avg_rtt,
return true;
}
-void Rtcp::UpdateNextTimeToSendRtcp() {
- base::TimeTicks now = cast_environment_->Clock()->NowTicks();
- next_time_to_send_rtcp_ = now + rtcp_interval_;
-}
-
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;
- }
- }
- }
+ if (log_callback_.is_null())
+ return;
+ log_callback_.Run(receiver_log);
}
} // namespace cast
diff --git a/media/cast/net/rtcp/rtcp.h b/media/cast/net/rtcp/rtcp.h
index 2bf0367..b84998b 100644
--- a/media/cast/net/rtcp/rtcp.h
+++ b/media/cast/net/rtcp/rtcp.h
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This class maintains a bi-directional RTCP connection with a remote
+// peer.
+
#ifndef MEDIA_CAST_RTCP_RTCP_H_
#define MEDIA_CAST_RTCP_RTCP_H_
@@ -11,15 +14,14 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "media/cast/cast_config.h"
#include "media/cast/cast_defines.h"
-#include "media/cast/cast_environment.h"
#include "media/cast/common/clock_drift_smoother.h"
#include "media/cast/net/cast_transport_defines.h"
#include "media/cast/net/cast_transport_sender.h"
-#include "media/cast/net/pacing/paced_sender.h"
#include "media/cast/net/rtcp/receiver_rtcp_event_subscriber.h"
#include "media/cast/net/rtcp/rtcp_defines.h"
@@ -27,7 +29,6 @@ namespace media {
namespace cast {
class LocalRtcpReceiverFeedback;
-class LocalRtcpRttFeedback;
class PacedPacketSender;
class RtcpReceiver;
class RtcpSender;
@@ -36,13 +37,6 @@ typedef std::pair<uint32, base::TimeTicks> RtcpSendTimePair;
typedef std::map<uint32, base::TimeTicks> RtcpSendTimeMap;
typedef std::queue<RtcpSendTimePair> RtcpSendTimeQueue;
-class RtcpSenderFeedback {
- public:
- virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) = 0;
-
- virtual ~RtcpSenderFeedback() {}
-};
-
class RtpReceiverStatistics {
public:
virtual void GetStatistics(uint8* fraction_lost,
@@ -53,46 +47,47 @@ class RtpReceiverStatistics {
virtual ~RtpReceiverStatistics() {}
};
+// TODO(hclam): This should be renamed to RtcpSession.
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,
- CastTransportSender* const transport_sender, // Send-side.
- PacedPacketSender* paced_packet_sender, // Receive side.
- RtpReceiverStatistics* rtp_receiver_statistics,
- RtcpMode rtcp_mode,
- const base::TimeDelta& rtcp_interval,
+ Rtcp(const RtcpCastMessageCallback& cast_callback,
+ const RtcpRttCallback& rtt_callback,
+ const RtcpLogMessageCallback& log_callback,
+ base::TickClock* clock, // Not owned.
+ PacedPacketSender* packet_sender, // Not owned.
uint32 local_ssrc,
uint32 remote_ssrc,
- const std::string& c_name,
- EventMediaType event_media_type);
+ const std::string& c_name);
virtual ~Rtcp();
- static bool IsRtcpPacket(const uint8* rtcp_buffer, size_t length);
-
- static uint32 GetSsrcOfSender(const uint8* rtcp_buffer, size_t length);
-
- base::TimeTicks TimeToSendNextRtcpReport();
-
// 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);
+ // |send_packet_count| is the number of packets sent.
+ // |send_octet_count| is the number of octets sent.
+ void SendRtcpFromRtpSender(
+ base::TimeTicks current_time,
+ uint32 current_time_as_rtp_timestamp,
+ uint32 send_packet_count,
+ size_t send_octet_count);
// |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 |rtcp_events| is provided the RTCP receiver report
- // will append the log messages.
+ // Acks and Nacks; |target_delay| is sent together with |cast_message|.
+ // 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);
+ base::TimeDelta target_delay,
+ const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events,
+ RtpReceiverStatistics* rtp_receiver_statistics);
- void IncomingRtcpPacket(const uint8* rtcp_buffer, size_t length);
+ // Submit a received packet to this object. The packet will be parsed
+ // and used to maintain a RTCP session.
+ // Returns false if this is not a RTCP packet or it is not directed to
+ // this session, e.g. SSRC doesn't match.
+ bool IncomingRtcpPacket(const uint8* data, size_t length);
// 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
@@ -103,8 +98,6 @@ class Rtcp {
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
@@ -113,15 +106,6 @@ class Rtcp {
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:
@@ -131,42 +115,31 @@ class Rtcp {
uint32 ntp_fraction);
private:
- friend class LocalRtcpRttFeedback;
- friend class LocalRtcpReceiverFeedback;
+ class RtcpMessageHandlerImpl;
- void OnReceivedDelaySinceLastReport(uint32 receivers_ssrc,
- uint32 last_report,
+ void OnReceivedDelaySinceLastReport(uint32 last_report,
uint32 delay_since_last_report);
- void OnReceivedSendReportRequest();
+ void OnReceivedCastFeedback(const RtcpCastMessage& cast_message);
void UpdateRtt(const base::TimeDelta& sender_delay,
const base::TimeDelta& receiver_delay);
- void UpdateNextTimeToSendRtcp();
-
void SaveLastSentNtpTime(const base::TimeTicks& now,
uint32 last_ntp_seconds,
uint32 last_ntp_fraction);
- scoped_refptr<CastEnvironment> cast_environment_;
- CastTransportSender* const transport_sender_;
- const base::TimeDelta rtcp_interval_;
- const RtcpMode rtcp_mode_;
+ const RtcpCastMessageCallback cast_callback_;
+ const RtcpRttCallback rtt_callback_;
+ const RtcpLogMessageCallback log_callback_;
+ base::TickClock* const clock_; // Not owned by this class.
+ const scoped_ptr<RtcpSender> rtcp_sender_;
const uint32 local_ssrc_;
const uint32 remote_ssrc_;
const std::string c_name_;
- const EventMediaType event_media_type_;
-
- // Not owned by this class.
- RtpReceiverStatistics* const rtp_receiver_statistics_;
-
- scoped_ptr<LocalRtcpRttFeedback> rtt_feedback_;
- scoped_ptr<LocalRtcpReceiverFeedback> receiver_feedback_;
- scoped_ptr<RtcpSender> rtcp_sender_;
- scoped_ptr<RtcpReceiver> rtcp_receiver_;
+ const scoped_ptr<RtcpMessageHandlerImpl> handler_;
+ const scoped_ptr<RtcpReceiver> rtcp_receiver_;
- base::TimeTicks next_time_to_send_rtcp_;
RtcpSendTimeMap last_reports_sent_map_;
RtcpSendTimeQueue last_reports_sent_queue_;
@@ -195,7 +168,6 @@ class Rtcp {
base::TimeDelta max_rtt_;
int number_of_rtt_in_avg_;
base::TimeDelta avg_rtt_;
- base::TimeDelta target_delay_;
DISALLOW_COPY_AND_ASSIGN(Rtcp);
};
diff --git a/media/cast/net/rtcp/rtcp_defines.cc b/media/cast/net/rtcp/rtcp_defines.cc
index 63799a9..9012468 100644
--- a/media/cast/net/rtcp/rtcp_defines.cc
+++ b/media/cast/net/rtcp/rtcp_defines.cc
@@ -9,17 +9,12 @@
namespace media {
namespace cast {
-RtcpCastMessage::RtcpCastMessage(uint32 media_ssrc)
- : media_ssrc_(media_ssrc), ack_frame_id_(0u), target_delay_ms_(0) {}
+RtcpCastMessage::RtcpCastMessage(uint32 ssrc)
+ : media_ssrc(ssrc), ack_frame_id(0u), target_delay_ms(0) {}
+RtcpCastMessage::RtcpCastMessage()
+ : media_ssrc(0), 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() {}
@@ -45,5 +40,8 @@ RtcpReceiverReferenceTimeReport::~RtcpReceiverReferenceTimeReport() {}
RtcpEvent::RtcpEvent() : type(UNKNOWN), packet_id(0u) {}
RtcpEvent::~RtcpEvent() {}
+RtcpRttReport::RtcpRttReport() {}
+RtcpRttReport::~RtcpRttReport() {}
+
} // namespace cast
} // namespace media
diff --git a/media/cast/net/rtcp/rtcp_defines.h b/media/cast/net/rtcp/rtcp_defines.h
index 28f69e1..0207edc 100644
--- a/media/cast/net/rtcp/rtcp_defines.h
+++ b/media/cast/net/rtcp/rtcp_defines.h
@@ -21,19 +21,15 @@ 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);
+struct RtcpCastMessage {
+ explicit RtcpCastMessage(uint32 ssrc);
+ RtcpCastMessage();
~RtcpCastMessage();
- void Copy(const RtcpCastMessage& cast_message);
-
- uint32 media_ssrc_;
- uint32 ack_frame_id_;
- uint16 target_delay_ms_;
- MissingFramesAndPacketsMap missing_frames_and_packets_;
-
- DISALLOW_COPY_AND_ASSIGN(RtcpCastMessage);
+ uint32 media_ssrc;
+ uint32 ack_frame_id;
+ uint16 target_delay_ms;
+ MissingFramesAndPacketsMap missing_frames_and_packets;
};
// Log messages from receiver to sender.
@@ -127,6 +123,24 @@ struct RtcpEvent {
uint16 packet_id;
};
+struct RtcpRttReport {
+ RtcpRttReport();
+ ~RtcpRttReport();
+
+ base::TimeDelta rtt;
+ base::TimeDelta avg_rtt;
+ base::TimeDelta min_rtt;
+ base::TimeDelta max_rtt;
+};
+
+typedef base::Callback<void(const RtcpCastMessage&)> RtcpCastMessageCallback;
+typedef base::Callback<void(base::TimeDelta,
+ base::TimeDelta,
+ base::TimeDelta,
+ base::TimeDelta)> RtcpRttCallback;
+typedef
+base::Callback<void(const RtcpReceiverLogMessage&)> RtcpLogMessageCallback;
+
} // namespace cast
} // namespace media
diff --git a/media/cast/net/rtcp/rtcp_receiver.cc b/media/cast/net/rtcp/rtcp_receiver.cc
index 99fd917..d8b81b1 100644
--- a/media/cast/net/rtcp/rtcp_receiver.cc
+++ b/media/cast/net/rtcp/rtcp_receiver.cc
@@ -4,6 +4,7 @@
#include "media/cast/net/rtcp/rtcp_receiver.h"
+#include "base/big_endian.h"
#include "base/logging.h"
#include "media/cast/net/cast_transport_defines.h"
#include "media/cast/net/rtcp/rtcp_utility.h"
@@ -38,21 +39,44 @@ std::pair<uint64, uint64> GetReceiverEventKey(
namespace media {
namespace cast {
-RtcpReceiver::RtcpReceiver(scoped_refptr<CastEnvironment> cast_environment,
- RtcpSenderFeedback* sender_feedback,
- RtcpReceiverFeedback* receiver_feedback,
- RtcpRttFeedback* rtt_feedback,
+RtcpReceiver::RtcpReceiver(RtcpMessageHandler* handler,
uint32 local_ssrc)
: ssrc_(local_ssrc),
remote_ssrc_(0),
- sender_feedback_(sender_feedback),
- receiver_feedback_(receiver_feedback),
- rtt_feedback_(rtt_feedback),
- cast_environment_(cast_environment),
- receiver_event_history_size_(0) {}
+ handler_(handler),
+ receiver_event_history_size_(0) {
+ DCHECK(handler_);
+}
RtcpReceiver::~RtcpReceiver() {}
+// static
+bool RtcpReceiver::IsRtcpPacket(const uint8* packet, size_t length) {
+ if (length < kMinLengthOfRtcp) {
+ LOG(ERROR) << "Invalid RTCP packet received.";
+ return false;
+ }
+
+ uint8 packet_type = packet[1];
+ if (packet_type >= kPacketTypeLow &&
+ packet_type <= kPacketTypeHigh) {
+ return true;
+ }
+ return false;
+}
+
+// static
+uint32 RtcpReceiver::GetSsrcOfSender(const uint8* rtcp_buffer, size_t length) {
+ if (length < kMinLengthOfRtcp)
+ return 0;
+ uint32 ssrc_of_sender;
+ base::BigEndianReader big_endian_reader(
+ reinterpret_cast<const char*>(rtcp_buffer), length);
+ big_endian_reader.Skip(4); // Skip header
+ big_endian_reader.ReadU32(&ssrc_of_sender);
+ return ssrc_of_sender;
+}
+
void RtcpReceiver::SetRemoteSSRC(uint32 ssrc) { remote_ssrc_ = ssrc; }
void RtcpReceiver::SetCastReceiverEventHistorySize(size_t size) {
@@ -83,9 +107,6 @@ void RtcpReceiver::IncomingRtcpPacket(RtcpParser* rtcp_parser) {
case kRtcpGenericRtpFeedbackNackCode:
HandleNACK(rtcp_parser);
break;
- case kRtcpGenericRtpFeedbackSrReqCode:
- HandleSendReportRequest(rtcp_parser);
- break;
case kRtcpPayloadSpecificPliCode:
HandlePLI(rtcp_parser);
break;
@@ -110,6 +131,7 @@ void RtcpReceiver::IncomingRtcpPacket(RtcpParser* rtcp_parser) {
case kRtcpNotValidCode:
case kRtcpReportBlockItemCode:
case kRtcpSdesChunkCode:
+ case kRtcpGenericRtpFeedbackSrReqCode:
case kRtcpGenericRtpFeedbackNackItemCode:
case kRtcpPayloadSpecificFirItemCode:
case kRtcpXrRrtrCode:
@@ -145,9 +167,7 @@ void RtcpReceiver::HandleSenderReport(RtcpParser* rtcp_parser) {
rtcp_field.sender_report.sender_packet_count;
remote_sender_info.send_octet_count =
rtcp_field.sender_report.sender_octet_count;
- if (receiver_feedback_) {
- receiver_feedback_->OnReceivedSenderReport(remote_sender_info);
- }
+ handler_->OnReceivedSenderReport(remote_sender_info);
}
rtcp_field_type = rtcp_parser->Iterate();
while (rtcp_field_type == kRtcpReportBlockItemCode) {
@@ -203,11 +223,8 @@ void RtcpReceiver::HandleReportBlock(const RtcpField* rtcp_field,
report_block.jitter = rb.jitter;
report_block.last_sr = rb.last_sender_report;
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);
- }
+ handler_->OnReceivedDelaySinceLastReport(
+ rb.last_sender_report, rb.delay_last_sender_report);
}
void RtcpReceiver::HandleSDES(RtcpParser* rtcp_parser) {
@@ -254,10 +271,7 @@ void RtcpReceiver::HandleRrtr(RtcpParser* rtcp_parser, uint32 remote_ssrc) {
remote_time_report.remote_ssrc = remote_ssrc;
remote_time_report.ntp_seconds = rtcp_field.rrtr.ntp_most_significant;
remote_time_report.ntp_fraction = rtcp_field.rrtr.ntp_least_significant;
-
- if (receiver_feedback_) {
- receiver_feedback_->OnReceiverReferenceTimeReport(remote_time_report);
- }
+ handler_->OnReceiverReferenceTimeReport(remote_time_report);
}
void RtcpReceiver::HandleDlrr(RtcpParser* rtcp_parser) {
@@ -266,12 +280,9 @@ void RtcpReceiver::HandleDlrr(RtcpParser* rtcp_parser) {
// Not to us.
return;
}
- if (rtt_feedback_) {
- rtt_feedback_->OnReceivedDelaySinceLastReport(
- rtcp_field.dlrr.receivers_ssrc,
- rtcp_field.dlrr.last_receiver_report,
- rtcp_field.dlrr.delay_last_receiver_report);
- }
+ handler_->OnReceivedDelaySinceLastReport(
+ rtcp_field.dlrr.last_receiver_report,
+ rtcp_field.dlrr.delay_last_receiver_report);
}
void RtcpReceiver::HandleNACK(RtcpParser* rtcp_parser) {
@@ -326,13 +337,6 @@ void RtcpReceiver::HandlePLI(RtcpParser* rtcp_parser) {
rtcp_parser->Iterate();
}
-void RtcpReceiver::HandleSendReportRequest(RtcpParser* rtcp_parser) {
- if (receiver_feedback_) {
- receiver_feedback_->OnReceivedSendReportRequest();
- }
- rtcp_parser->Iterate();
-}
-
void RtcpReceiver::HandleRpsi(RtcpParser* rtcp_parser) {
const RtcpField& rtcp_field = rtcp_parser->Field();
if (rtcp_parser->Iterate() != kRtcpPayloadSpecificRpsiCode) {
@@ -436,9 +440,8 @@ void RtcpReceiver::HandleApplicationSpecificCastReceiverLog(
receiver_log.push_back(frame_log);
}
- if (receiver_feedback_ && !receiver_log.empty()) {
- receiver_feedback_->OnReceivedReceiverLog(receiver_log);
- }
+ if (!receiver_log.empty())
+ handler_->OnReceivedReceiverLog(receiver_log);
}
void RtcpReceiver::HandleApplicationSpecificCastReceiverEventLog(
@@ -491,20 +494,18 @@ void RtcpReceiver::HandleApplicationSpecificCastReceiverEventLog(
void RtcpReceiver::HandlePayloadSpecificCastItem(RtcpParser* rtcp_parser) {
const RtcpField& rtcp_field = rtcp_parser->Field();
RtcpCastMessage cast_message(remote_ssrc_);
- cast_message.ack_frame_id_ = ack_frame_id_wrap_helper_.MapTo32bitsFrameId(
+ 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;
+ cast_message.target_delay_ms = rtcp_field.cast_item.target_delay_ms;
RtcpFieldTypes packet_type = rtcp_parser->Iterate();
while (packet_type == kRtcpPayloadSpecificCastNackItemCode) {
const RtcpField& rtcp_field = rtcp_parser->Field();
HandlePayloadSpecificCastNackItem(
- &rtcp_field, &cast_message.missing_frames_and_packets_);
+ &rtcp_field, &cast_message.missing_frames_and_packets);
packet_type = rtcp_parser->Iterate();
}
- if (sender_feedback_) {
- sender_feedback_->OnReceivedCastFeedback(cast_message);
- }
+ handler_->OnReceivedCastFeedback(cast_message);
}
void RtcpReceiver::HandlePayloadSpecificCastNackItem(
diff --git a/media/cast/net/rtcp/rtcp_receiver.h b/media/cast/net/rtcp/rtcp_receiver.h
index aea4584..9cd39ff 100644
--- a/media/cast/net/rtcp/rtcp_receiver.h
+++ b/media/cast/net/rtcp/rtcp_receiver.h
@@ -16,7 +16,8 @@
namespace media {
namespace cast {
-class RtcpReceiverFeedback {
+// Interface for receiving RTCP messages.
+class RtcpMessageHandler {
public:
virtual void OnReceivedSenderReport(
const RtcpSenderInfo& remote_sender_info) = 0;
@@ -24,33 +25,28 @@ class RtcpReceiverFeedback {
virtual void OnReceiverReferenceTimeReport(
const RtcpReceiverReferenceTimeReport& remote_time_report) = 0;
- virtual void OnReceivedSendReportRequest() = 0;
-
virtual void OnReceivedReceiverLog(
const RtcpReceiverLogMessage& receiver_log) = 0;
- virtual ~RtcpReceiverFeedback() {}
-};
-
-class RtcpRttFeedback {
- public:
virtual void OnReceivedDelaySinceLastReport(
- uint32 receivers_ssrc,
uint32 last_report,
uint32 delay_since_last_report) = 0;
- virtual ~RtcpRttFeedback() {}
+ virtual void OnReceivedCastFeedback(
+ const RtcpCastMessage& cast_message) = 0;
+
+ virtual ~RtcpMessageHandler() {}
};
class RtcpReceiver {
public:
- explicit RtcpReceiver(scoped_refptr<CastEnvironment> cast_environment,
- RtcpSenderFeedback* sender_feedback,
- RtcpReceiverFeedback* receiver_feedback,
- RtcpRttFeedback* rtt_feedback,
- uint32 local_ssrc);
+ RtcpReceiver(RtcpMessageHandler* handler, uint32 local_ssrc);
virtual ~RtcpReceiver();
+ static bool IsRtcpPacket(const uint8* rtcp_buffer, size_t length);
+
+ static uint32 GetSsrcOfSender(const uint8* rtcp_buffer, size_t length);
+
void SetRemoteSSRC(uint32 ssrc);
// Set the history size to record Cast receiver events. Event history is
@@ -111,10 +107,7 @@ class RtcpReceiver {
uint32 remote_ssrc_;
// Not owned by this class.
- RtcpSenderFeedback* const sender_feedback_;
- RtcpReceiverFeedback* const receiver_feedback_;
- RtcpRttFeedback* const rtt_feedback_;
- scoped_refptr<CastEnvironment> cast_environment_;
+ RtcpMessageHandler* const handler_;
FrameIdWrapHelper ack_frame_id_wrap_helper_;
diff --git a/media/cast/net/rtcp/rtcp_receiver_unittest.cc b/media/cast/net/rtcp/rtcp_receiver_unittest.cc
index f4010cb..47ae24b 100644
--- a/media/cast/net/rtcp/rtcp_receiver_unittest.cc
+++ b/media/cast/net/rtcp/rtcp_receiver_unittest.cc
@@ -7,7 +7,6 @@
#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_defines.h"
#include "media/cast/net/rtcp/mock_rtcp_receiver_feedback.h"
-#include "media/cast/net/rtcp/mock_rtcp_sender_feedback.h"
#include "media/cast/net/rtcp/rtcp_receiver.h"
#include "media/cast/net/rtcp/rtcp_utility.h"
#include "media/cast/net/rtcp/test_rtcp_packet_builder.h"
@@ -27,58 +26,13 @@ static const base::TimeDelta kTargetDelay =
static const std::string kCName("test@10.1.1.1");
namespace {
-class SenderFeedbackCastVerification : public RtcpSenderFeedback {
- public:
- SenderFeedbackCastVerification() : called_(false) {}
-
- virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback)
- OVERRIDE {
- EXPECT_EQ(cast_feedback.media_ssrc_, kSenderSsrc);
- EXPECT_EQ(cast_feedback.ack_frame_id_, kAckFrameId);
-
- MissingFramesAndPacketsMap::const_iterator frame_it =
- cast_feedback.missing_frames_and_packets_.begin();
- EXPECT_TRUE(frame_it != cast_feedback.missing_frames_and_packets_.end());
- EXPECT_EQ(kLostFrameId, frame_it->first);
- EXPECT_EQ(frame_it->second.size(), 1UL);
- EXPECT_EQ(*frame_it->second.begin(), kRtcpCastAllPacketsLost);
- ++frame_it;
- EXPECT_TRUE(frame_it != cast_feedback.missing_frames_and_packets_.end());
- EXPECT_EQ(kFrameIdWithLostPackets, frame_it->first);
- EXPECT_EQ(3UL, frame_it->second.size());
- PacketIdSet::const_iterator packet_it = frame_it->second.begin();
- EXPECT_EQ(kLostPacketId1, *packet_it);
- ++packet_it;
- EXPECT_EQ(kLostPacketId2, *packet_it);
- ++packet_it;
- EXPECT_EQ(kLostPacketId3, *packet_it);
- ++frame_it;
- EXPECT_EQ(frame_it, cast_feedback.missing_frames_and_packets_.end());
- called_ = true;
- }
-
- bool called() const { return called_; }
-
- private:
- bool called_;
-
- DISALLOW_COPY_AND_ASSIGN(SenderFeedbackCastVerification);
-};
-
-class RtcpReceiverCastLogVerification : public RtcpReceiverFeedback {
+class RtcpMessageVerification : public MockRtcpReceiverFeedback {
public:
- RtcpReceiverCastLogVerification()
+ RtcpMessageVerification()
: called_on_received_sender_log_(false),
- called_on_received_receiver_log_(false) {}
-
- virtual void OnReceivedSenderReport(
- const RtcpSenderInfo& remote_sender_info) OVERRIDE{};
-
- virtual void OnReceiverReferenceTimeReport(
- const RtcpReceiverReferenceTimeReport& remote_time_report) OVERRIDE{};
-
- virtual void OnReceivedSendReportRequest() OVERRIDE{};
+ called_on_received_receiver_log_(false),
+ called_on_received_cast_message_(false) {}
virtual void OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log)
OVERRIDE {
@@ -113,10 +67,41 @@ class RtcpReceiverCastLogVerification : public RtcpReceiverFeedback {
called_on_received_receiver_log_ = true;
}
- bool OnReceivedReceiverLogCalled() {
+ virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_message)
+ OVERRIDE {
+ EXPECT_EQ(cast_message.media_ssrc, kSenderSsrc);
+ EXPECT_EQ(cast_message.ack_frame_id, kAckFrameId);
+
+ MissingFramesAndPacketsMap::const_iterator frame_it =
+ cast_message.missing_frames_and_packets.begin();
+
+ EXPECT_TRUE(frame_it != cast_message.missing_frames_and_packets.end());
+ EXPECT_EQ(kLostFrameId, frame_it->first);
+ EXPECT_EQ(frame_it->second.size(), 1UL);
+ EXPECT_EQ(*frame_it->second.begin(), kRtcpCastAllPacketsLost);
+ ++frame_it;
+ EXPECT_TRUE(frame_it != cast_message.missing_frames_and_packets.end());
+ EXPECT_EQ(kFrameIdWithLostPackets, frame_it->first);
+ EXPECT_EQ(3UL, frame_it->second.size());
+ PacketIdSet::const_iterator packet_it = frame_it->second.begin();
+ EXPECT_EQ(kLostPacketId1, *packet_it);
+ ++packet_it;
+ EXPECT_EQ(kLostPacketId2, *packet_it);
+ ++packet_it;
+ EXPECT_EQ(kLostPacketId3, *packet_it);
+ ++frame_it;
+ EXPECT_EQ(frame_it, cast_message.missing_frames_and_packets.end());
+ called_on_received_cast_message_ = true;
+ }
+
+ bool OnReceivedReceiverLogCalled() const {
return called_on_received_receiver_log_ && expected_receiver_log_.empty();
}
+ bool OnReceivedCastFeedbackCalled() const {
+ return called_on_received_cast_message_;
+ }
+
void SetExpectedReceiverLog(const RtcpReceiverLogMessage& receiver_log) {
expected_receiver_log_ = receiver_log;
}
@@ -125,8 +110,9 @@ class RtcpReceiverCastLogVerification : public RtcpReceiverFeedback {
RtcpReceiverLogMessage expected_receiver_log_;
bool called_on_received_sender_log_;
bool called_on_received_receiver_log_;
+ bool called_on_received_cast_message_;
- DISALLOW_COPY_AND_ASSIGN(RtcpReceiverCastLogVerification);
+ DISALLOW_COPY_AND_ASSIGN(RtcpMessageVerification);
};
} // namespace
@@ -136,23 +122,13 @@ class RtcpReceiverTest : public ::testing::Test {
RtcpReceiverTest()
: 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_,
+ rtcp_receiver_(new RtcpReceiver(&mock_receiver_feedback_,
kSourceSsrc)) {
EXPECT_CALL(mock_receiver_feedback_, OnReceivedSenderReport(_)).Times(0);
EXPECT_CALL(mock_receiver_feedback_, OnReceiverReferenceTimeReport(_))
.Times(0);
- EXPECT_CALL(mock_receiver_feedback_, OnReceivedSendReportRequest())
- .Times(0);
- EXPECT_CALL(mock_sender_feedback_, OnReceivedCastFeedback(_)).Times(0);
- EXPECT_CALL(mock_rtt_feedback_, OnReceivedDelaySinceLastReport(_, _, _))
+ EXPECT_CALL(mock_receiver_feedback_, OnReceivedCastFeedback(_)).Times(0);
+ EXPECT_CALL(mock_receiver_feedback_, OnReceivedDelaySinceLastReport(_, _))
.Times(0);
expected_sender_info_.ntp_seconds = kNtpHigh;
@@ -184,10 +160,7 @@ class RtcpReceiverTest : public ::testing::Test {
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_;
@@ -226,9 +199,8 @@ TEST_F(RtcpReceiverTest, InjectReceiveReportPacket) {
// local ssrc.
InjectRtcpPacket(p1.Data(), p1.Length());
- EXPECT_CALL(mock_rtt_feedback_,
- OnReceivedDelaySinceLastReport(
- kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);
+ EXPECT_CALL(mock_receiver_feedback_,
+ OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
TestRtcpPacketBuilder p2;
p2.AddRr(kSenderSsrc, 1);
@@ -260,9 +232,8 @@ TEST_F(RtcpReceiverTest, InjectSenderReportWithReportBlockPacket) {
InjectRtcpPacket(p1.Data(), p1.Length());
EXPECT_CALL(mock_receiver_feedback_, OnReceivedSenderReport(_)).Times(0);
- EXPECT_CALL(mock_rtt_feedback_,
- OnReceivedDelaySinceLastReport(
- kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);
+ EXPECT_CALL(mock_receiver_feedback_,
+ OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
rtcp_receiver_->SetRemoteSSRC(0);
@@ -278,9 +249,8 @@ TEST_F(RtcpReceiverTest, InjectSenderReportWithReportBlockPacket) {
EXPECT_CALL(mock_receiver_feedback_,
OnReceivedSenderReport(expected_sender_info_)).Times(1);
- EXPECT_CALL(mock_rtt_feedback_,
- OnReceivedDelaySinceLastReport(
- kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);
+ EXPECT_CALL(mock_receiver_feedback_,
+ OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);
@@ -306,9 +276,8 @@ TEST_F(RtcpReceiverTest, InjectSenderReportPacketWithDlrr) {
EXPECT_CALL(mock_receiver_feedback_,
OnReceivedSenderReport(expected_sender_info_)).Times(1);
- EXPECT_CALL(mock_rtt_feedback_,
- OnReceivedDelaySinceLastReport(
- kSenderSsrc, kLastSr, kDelayLastSr)).Times(1);
+ EXPECT_CALL(mock_receiver_feedback_,
+ OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
// Enable receiving sender report.
rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);
@@ -328,9 +297,8 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithRrtr) {
// local ssrc.
InjectRtcpPacket(p1.Data(), p1.Length());
- EXPECT_CALL(mock_rtt_feedback_,
- OnReceivedDelaySinceLastReport(
- kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);
+ EXPECT_CALL(mock_receiver_feedback_,
+ OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
EXPECT_CALL(mock_receiver_feedback_,
OnReceiverReferenceTimeReport(
expected_receiver_reference_report_)).Times(1);
@@ -358,9 +326,8 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithIntraFrameRequest) {
// local ssrc.
InjectRtcpPacket(p1.Data(), p1.Length());
- EXPECT_CALL(mock_rtt_feedback_,
- OnReceivedDelaySinceLastReport(
- kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);
+ EXPECT_CALL(mock_receiver_feedback_,
+ OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
TestRtcpPacketBuilder p2;
p2.AddRr(kSenderSsrc, 1);
@@ -381,10 +348,9 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastFeedback) {
// local ssrc.
InjectRtcpPacket(p1.Data(), p1.Length());
- EXPECT_CALL(mock_rtt_feedback_,
- OnReceivedDelaySinceLastReport(
- kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);
- EXPECT_CALL(mock_sender_feedback_, OnReceivedCastFeedback(_)).Times(1);
+ EXPECT_CALL(mock_receiver_feedback_,
+ OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
+ EXPECT_CALL(mock_receiver_feedback_, OnReceivedCastFeedback(_)).Times(1);
// Enable receiving the cast feedback.
rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);
@@ -399,16 +365,11 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastFeedback) {
}
TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastVerification) {
- SenderFeedbackCastVerification sender_feedback_cast_verification;
- RtcpReceiver rtcp_receiver(cast_environment_,
- &sender_feedback_cast_verification,
- &mock_receiver_feedback_,
- &mock_rtt_feedback_,
- kSourceSsrc);
+ RtcpMessageVerification verification;
+ RtcpReceiver rtcp_receiver(&verification, kSourceSsrc);
- EXPECT_CALL(mock_rtt_feedback_,
- OnReceivedDelaySinceLastReport(
- kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);
+ EXPECT_CALL(verification,
+ OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
// Enable receiving the cast feedback.
rtcp_receiver.SetRemoteSSRC(kSenderSsrc);
@@ -422,7 +383,7 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastVerification) {
RtcpParser rtcp_parser(p.Data(), p.Length());
rtcp_receiver.IncomingRtcpPacket(&rtcp_parser);
- EXPECT_TRUE(sender_feedback_cast_verification.called());
+ EXPECT_TRUE(verification.OnReceivedCastFeedbackCalled());
}
TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationBase) {
@@ -432,11 +393,8 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationBase) {
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
- RtcpReceiverCastLogVerification cast_log_verification;
- RtcpReceiver rtcp_receiver(cast_environment_,
- &mock_sender_feedback_,
- &cast_log_verification,
- &mock_rtt_feedback_,
+ RtcpMessageVerification verification;
+ RtcpReceiver rtcp_receiver(&verification,
kSourceSsrc);
rtcp_receiver.SetRemoteSSRC(kSenderSsrc);
rtcp_receiver.SetCastReceiverEventHistorySize(100);
@@ -463,7 +421,7 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationBase) {
receiver_log.push_back(frame_log);
- cast_log_verification.SetExpectedReceiverLog(receiver_log);
+ verification.SetExpectedReceiverLog(receiver_log);
TestRtcpPacketBuilder p;
p.AddRr(kSenderSsrc, 1);
@@ -480,14 +438,13 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationBase) {
p.AddReceiverEventLog(kLostPacketId1, PACKET_RECEIVED, kTimeDelayMs);
p.AddReceiverEventLog(kLostPacketId2, PACKET_RECEIVED, kTimeDelayMs);
- EXPECT_CALL(mock_rtt_feedback_,
- OnReceivedDelaySinceLastReport(
- kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);
+ EXPECT_CALL(verification,
+ OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
RtcpParser rtcp_parser(p.Data(), p.Length());
rtcp_receiver.IncomingRtcpPacket(&rtcp_parser);
- EXPECT_TRUE(cast_log_verification.OnReceivedReceiverLogCalled());
+ EXPECT_TRUE(verification.OnReceivedReceiverLogCalled());
}
TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationMulti) {
@@ -497,11 +454,8 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationMulti) {
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
- RtcpReceiverCastLogVerification cast_log_verification;
- RtcpReceiver rtcp_receiver(cast_environment_,
- &mock_sender_feedback_,
- &cast_log_verification,
- &mock_rtt_feedback_,
+ RtcpMessageVerification verification;
+ RtcpReceiver rtcp_receiver(&verification,
kSourceSsrc);
rtcp_receiver.SetRemoteSSRC(kSenderSsrc);
@@ -518,7 +472,7 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationMulti) {
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
}
- cast_log_verification.SetExpectedReceiverLog(receiver_log);
+ verification.SetExpectedReceiverLog(receiver_log);
TestRtcpPacketBuilder p;
p.AddRr(kSenderSsrc, 1);
@@ -529,14 +483,13 @@ TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationMulti) {
p.AddReceiverEventLog(kDelayDeltaMs, FRAME_ACK_SENT, 0);
}
- EXPECT_CALL(mock_rtt_feedback_,
- OnReceivedDelaySinceLastReport(
- kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);
+ EXPECT_CALL(verification,
+ OnReceivedDelaySinceLastReport(kLastSr, kDelayLastSr)).Times(1);
RtcpParser rtcp_parser(p.Data(), p.Length());
rtcp_receiver.IncomingRtcpPacket(&rtcp_parser);
- EXPECT_TRUE(cast_log_verification.OnReceivedReceiverLogCalled());
+ EXPECT_TRUE(verification.OnReceivedReceiverLogCalled());
}
} // namespace cast
diff --git a/media/cast/net/rtcp/rtcp_sender.cc b/media/cast/net/rtcp/rtcp_sender.cc
index a44f87e..61f620f 100644
--- a/media/cast/net/rtcp/rtcp_sender.cc
+++ b/media/cast/net/rtcp/rtcp_sender.cc
@@ -11,7 +11,6 @@
#include "base/big_endian.h"
#include "base/logging.h"
-#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_defines.h"
#include "media/cast/net/pacing/paced_sender.h"
#include "media/cast/net/rtcp/rtcp_defines.h"
@@ -146,15 +145,12 @@ class NackStringBuilder {
};
} // namespace
-// TODO(mikhal): This is only used by the receiver. Consider renaming.
-RtcpSender::RtcpSender(scoped_refptr<CastEnvironment> cast_environment,
- PacedPacketSender* outgoing_transport,
+RtcpSender::RtcpSender(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) {
+ transport_(outgoing_transport) {
DCHECK_LT(c_name_.length(), kRtcpCnameSize) << "Invalid config";
}
@@ -181,7 +177,6 @@ void RtcpSender::SendRtcpFromRtpReceiver(
}
PacketRef packet(new base::RefCountedData<Packet>);
packet->data.reserve(kMaxIpPacketSize);
-
if (packet_type_flags & kRtcpRr) {
BuildRR(report_block, &packet->data);
if (!c_name_.empty()) {
@@ -204,8 +199,44 @@ void RtcpSender::SendRtcpFromRtpReceiver(
BuildReceiverLog(*rtcp_events, &packet->data);
}
- if (packet->data.empty())
+ if (packet->data.empty()) {
+ NOTREACHED() << "Empty packet.";
return; // Sanity don't send empty packets.
+ }
+
+ transport_->SendRtcpPacket(ssrc_, packet);
+}
+
+void RtcpSender::SendRtcpFromRtpSender(
+ uint32 packet_type_flags,
+ const RtcpSenderInfo& sender_info,
+ const RtcpDlrrReportBlock& dlrr) {
+ 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";
+ }
+ PacketRef packet(new base::RefCountedData<Packet>);
+ packet->data.reserve(kMaxIpPacketSize);
+ if (packet_type_flags & kRtcpSr) {
+ BuildSR(sender_info, &packet->data);
+ BuildSdec(&packet->data);
+ }
+ if (packet_type_flags & kRtcpBye) {
+ BuildBye(&packet->data);
+ }
+ if (packet_type_flags & kRtcpDlrr) {
+ BuildDlrrRb(dlrr, &packet->data);
+ }
+ if (packet->data.empty()) {
+ NOTREACHED() << "Empty packet.";
+ return; // Sanity - don't send empty packets.
+ }
transport_->SendRtcpPacket(ssrc_, packet);
}
@@ -334,7 +365,8 @@ void RtcpSender::BuildPli(uint32 remote_ssrc, Packet* packet) const {
| defined per codec ... | Padding (0) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
-void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi, Packet* packet) const {
+void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi,
+ Packet* packet) const {
size_t start_size = packet->size();
DCHECK_LT(start_size + 24, kMaxIpPacketSize) << "Not enough buffer space";
if (start_size + 24 > kMaxIpPacketSize)
@@ -388,7 +420,8 @@ void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi, Packet* packet) const {
}
}
-void RtcpSender::BuildRemb(const RtcpRembMessage* remb, Packet* 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, kMaxIpPacketSize)
@@ -429,7 +462,8 @@ void RtcpSender::BuildRemb(const RtcpRembMessage* remb, Packet* packet) const {
}
}
-void RtcpSender::BuildNack(const RtcpNackMessage* nack, Packet* packet) const {
+void RtcpSender::BuildNack(const RtcpNackMessage* nack,
+ Packet* packet) const {
size_t start_size = packet->size();
DCHECK_LT(start_size + 16, kMaxIpPacketSize) << "Not enough buffer space";
if (start_size + 16 > kMaxIpPacketSize)
@@ -547,9 +581,9 @@ void RtcpSender::BuildCast(const RtcpCastMessage* cast,
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(cast->media_ssrc_); // Remote 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_));
+ 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.
DCHECK_LE(target_delay.InMilliseconds(),
@@ -561,10 +595,10 @@ void RtcpSender::BuildCast(const RtcpCastMessage* cast,
kRtcpMaxCastLossFields, (kMaxIpPacketSize - packet->size()) / 4);
MissingFramesAndPacketsMap::const_iterator frame_it =
- cast->missing_frames_and_packets_.begin();
+ cast->missing_frames_and_packets.begin();
NackStringBuilder nack_string_builder;
- for (; frame_it != cast->missing_frames_and_packets_.end() &&
+ for (; frame_it != cast->missing_frames_and_packets.end() &&
number_of_loss_fields < max_number_of_loss_fields;
++frame_it) {
nack_string_builder.PushFrame(frame_it->first);
@@ -613,14 +647,82 @@ void RtcpSender::BuildCast(const RtcpCastMessage* cast,
}
}
VLOG_IF(1, !nack_string_builder.Empty())
- << "SSRC: " << cast->media_ssrc_
- << ", ACK: " << cast->ack_frame_id_
+ << "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::BuildSR(const RtcpSenderInfo& sender_info,
+ Packet* packet) const {
+ // Sender report.
+ size_t start_size = packet->size();
+ if (start_size + 52 > kMaxIpPacketSize) {
+ DLOG(FATAL) << "Not enough buffer space";
+ return;
+ }
+
+ uint16 number_of_rows = 6;
+ packet->resize(start_size + 28);
+
+ base::BigEndianWriter big_endian_writer(
+ reinterpret_cast<char*>(&((*packet)[start_size])), 28);
+ big_endian_writer.WriteU8(0x80);
+ 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));
+ return;
+}
+
+/*
+ 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 |
+ +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ | SSRC1 (SSRC of first receiver) | sub-
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
+ | last RR (LRR) | 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | delay since last RR (DLRR) |
+ +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*/
+void RtcpSender::BuildDlrrRb(const RtcpDlrrReportBlock& dlrr,
+ Packet* packet) const {
+ size_t start_size = packet->size();
+ if (start_size + 24 > kMaxIpPacketSize) {
+ DLOG(FATAL) << "Not enough buffer space";
+ return;
+ }
+
+ packet->resize(start_size + 24);
+
+ base::BigEndianWriter big_endian_writer(
+ reinterpret_cast<char*>(&((*packet)[start_size])), 24);
+ big_endian_writer.WriteU8(0x80);
+ big_endian_writer.WriteU8(kPacketTypeXr);
+ big_endian_writer.WriteU16(5); // 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);
+ return;
+}
+
void RtcpSender::BuildReceiverLog(
const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events,
Packet* packet) {
diff --git a/media/cast/net/rtcp/rtcp_sender.h b/media/cast/net/rtcp/rtcp_sender.h
index fe5af0d..e55d5f4 100644
--- a/media/cast/net/rtcp/rtcp_sender.h
+++ b/media/cast/net/rtcp/rtcp_sender.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef MEDIA_CAST_RTCP_RTCP_SENDER_H_
-#define MEDIA_CAST_RTCP_RTCP_SENDER_H_
+#ifndef MEDIA_CAST_NET_RTCP_RTCP_SENDER_H_
+#define MEDIA_CAST_NET_RTCP_RTCP_SENDER_H_
#include <deque>
#include <list>
@@ -13,8 +13,6 @@
#include "media/cast/cast_defines.h"
#include "media/cast/net/cast_transport_defines.h"
#include "media/cast/net/rtcp/receiver_rtcp_event_subscriber.h"
-#include "media/cast/net/rtcp/rtcp.h"
-#include "media/cast/net/rtcp/rtcp_builder.h"
#include "media/cast/net/rtcp/rtcp_defines.h"
namespace media {
@@ -40,16 +38,19 @@ COMPILE_ASSERT(kSecondRedundancyOffset >
kReceiveLogMessageHistorySize,
redundancy_offset_out_of_range);
-// TODO(mikhal): Resolve duplication between this and RtcpBuilder.
+class PacedPacketSender;
+
+// TODO(hclam): This should be renamed to RtcpPacketBuilder. The function
+// of this class is to only to build a RTCP packet but not to send it.
class RtcpSender {
public:
- RtcpSender(scoped_refptr<CastEnvironment> cast_environment,
- PacedPacketSender* outgoing_transport,
+ RtcpSender(PacedPacketSender* outgoing_transport,
uint32 sending_ssrc,
const std::string& c_name);
+ ~RtcpSender();
- virtual ~RtcpSender();
-
+ // TODO(hclam): This method should be to build a packet instead of
+ // sending it.
void SendRtcpFromRtpReceiver(
uint32 packet_type_flags,
const RtcpReportBlock* report_block,
@@ -58,6 +59,12 @@ class RtcpSender {
const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events,
base::TimeDelta target_delay);
+ // TODO(hclam): This method should be to build a packet instead of
+ // sending it.
+ void SendRtcpFromRtpSender(uint32 packet_type_flags,
+ const RtcpSenderInfo& sender_info,
+ const RtcpDlrrReportBlock& dlrr);
+
private:
void BuildRR(const RtcpReportBlock* report_block,
Packet* packet) const;
@@ -84,6 +91,10 @@ class RtcpSender {
base::TimeDelta target_delay,
Packet* packet) const;
+ void BuildSR(const RtcpSenderInfo& sender_info, Packet* packet) const;
+
+ void BuildDlrrRb(const RtcpDlrrReportBlock& dlrr, Packet* packet) const;
+
void BuildReceiverLog(
const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events,
Packet* packet);
@@ -115,7 +126,6 @@ class RtcpSender {
// Not owned by this class.
PacedPacketSender* const transport_;
- scoped_refptr<CastEnvironment> cast_environment_;
std::deque<RtcpReceiverLogMessage> rtcp_events_history_;
@@ -124,4 +134,5 @@ class RtcpSender {
} // namespace cast
} // namespace media
-#endif // MEDIA_CAST_RTCP_RTCP_SENDER_H_
+
+#endif // MEDIA_CAST_NET_RTCP_RTCP_SENDER_H_
diff --git a/media/cast/net/rtcp/rtcp_sender_unittest.cc b/media/cast/net/rtcp/rtcp_sender_unittest.cc
index c0c321e..b78915d 100644
--- a/media/cast/net/rtcp/rtcp_sender_unittest.cc
+++ b/media/cast/net/rtcp/rtcp_sender_unittest.cc
@@ -92,10 +92,7 @@ class RtcpSenderTest : public ::testing::Test {
task_runner_,
task_runner_,
task_runner_)),
- rtcp_sender_(new RtcpSender(cast_environment_,
- &test_transport_,
- kSendingSsrc,
- kCName)) {}
+ rtcp_sender_(new RtcpSender(&test_transport_, kSendingSsrc, kCName)) {}
base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment.
TestRtcpTransport test_transport_;
@@ -172,14 +169,14 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithCast) {
RtcpReportBlock report_block = GetReportBlock();
RtcpCastMessage cast_message(kMediaSsrc);
- cast_message.ack_frame_id_ = kAckFrameId;
+ 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);
missing_packets.insert(kLostPacketId3);
- cast_message.missing_frames_and_packets_[kFrameIdWithLostPackets] =
+ cast_message.missing_frames_and_packets[kFrameIdWithLostPackets] =
missing_packets;
rtcp_sender_->SendRtcpFromRtpReceiver(
@@ -210,14 +207,14 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtraAndCastMessage) {
rrtr.ntp_fraction = kNtpLow;
RtcpCastMessage cast_message(kMediaSsrc);
- cast_message.ack_frame_id_ = kAckFrameId;
+ 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);
missing_packets.insert(kLostPacketId3);
- cast_message.missing_frames_and_packets_[kFrameIdWithLostPackets] =
+ cast_message.missing_frames_and_packets[kFrameIdWithLostPackets] =
missing_packets;
rtcp_sender_->SendRtcpFromRtpReceiver(
@@ -251,14 +248,14 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtrCastMessageAndLog) {
rrtr.ntp_fraction = kNtpLow;
RtcpCastMessage cast_message(kMediaSsrc);
- cast_message.ack_frame_id_ = kAckFrameId;
+ 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);
missing_packets.insert(kLostPacketId3);
- cast_message.missing_frames_and_packets_[kFrameIdWithLostPackets] =
+ cast_message.missing_frames_and_packets[kFrameIdWithLostPackets] =
missing_packets;
ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT);
@@ -553,5 +550,58 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportRedundancy) {
EXPECT_EQ(static_cast<int>(packet_count), test_transport_.packet_count());
}
+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;
+
+ RtcpDlrrReportBlock dlrr_rb;
+ dlrr_rb.last_rr = kLastRr;
+ dlrr_rb.delay_since_last_rr = kDelayLastRr;
+
+ // Sender report + c_name.
+ TestRtcpPacketBuilder p;
+ p.AddSr(kSendingSsrc, 0);
+ p.AddSdesCname(kSendingSsrc, kCName);
+ test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass());
+
+ rtcp_sender_->SendRtcpFromRtpSender(kRtcpSr,
+ sender_info,
+ dlrr_rb);
+
+ EXPECT_EQ(1, 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.GetPacket().Pass());
+
+ RtcpDlrrReportBlock dlrr_rb;
+ dlrr_rb.last_rr = kLastRr;
+ dlrr_rb.delay_since_last_rr = kDelayLastRr;
+
+ rtcp_sender_->SendRtcpFromRtpSender(
+ kRtcpSr | kRtcpDlrr,
+ sender_info,
+ dlrr_rb);
+
+ EXPECT_EQ(1, test_transport_.packet_count());
+}
+
} // namespace cast
} // namespace media
diff --git a/media/cast/net/rtcp/rtcp_unittest.cc b/media/cast/net/rtcp/rtcp_unittest.cc
index 25d05b2..fa232a9 100644
--- a/media/cast/net/rtcp/rtcp_unittest.cc
+++ b/media/cast/net/rtcp/rtcp_unittest.cc
@@ -6,12 +6,10 @@
#include "base/test/simple_test_tick_clock.h"
#include "media/cast/cast_defines.h"
-#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/cast_transport_sender_impl.h"
#include "media/cast/net/pacing/paced_sender.h"
#include "media/cast/net/rtcp/mock_rtcp_receiver_feedback.h"
-#include "media/cast/net/rtcp/mock_rtcp_sender_feedback.h"
#include "media/cast/net/rtcp/rtcp.h"
#include "media/cast/net/rtcp/test_rtcp_packet_builder.h"
#include "media/cast/test/fake_single_thread_task_runner.h"
@@ -25,7 +23,6 @@ using testing::_;
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 kAddedDelay = 123;
static const int64 kAddedShortDelay = 100;
@@ -71,8 +68,7 @@ class RtcpTestPacketSender : public PacketSender {
class LocalRtcpTransport : public PacedPacketSender {
public:
- LocalRtcpTransport(scoped_refptr<CastEnvironment> cast_environment,
- base::SimpleTestTickClock* testing_clock)
+ explicit LocalRtcpTransport(base::SimpleTestTickClock* testing_clock)
: drop_packets_(false),
short_delay_(false),
testing_clock_(testing_clock) {}
@@ -118,37 +114,43 @@ class LocalRtcpTransport : public PacedPacketSender {
bool short_delay_;
Rtcp* rtcp_;
base::SimpleTestTickClock* testing_clock_;
- scoped_refptr<CastEnvironment> cast_environment_;
DISALLOW_COPY_AND_ASSIGN(LocalRtcpTransport);
};
-class RtcpPeer : public Rtcp {
+class MockReceiverStats : public RtpReceiverStatistics {
public:
- RtcpPeer(scoped_refptr<CastEnvironment> cast_environment,
- RtcpSenderFeedback* sender_feedback,
- CastTransportSender* const transport_sender,
- 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)
- : Rtcp(cast_environment,
- sender_feedback,
- transport_sender,
- paced_packet_sender,
- rtp_receiver_statistics,
- rtcp_mode,
- rtcp_interval,
- local_ssrc,
- remote_ssrc,
- c_name,
- AUDIO_EVENT) {}
-
- using Rtcp::OnReceivedNtp;
- using Rtcp::OnReceivedLipSyncInfo;
+ MockReceiverStats() {}
+ virtual ~MockReceiverStats() {}
+
+ virtual void GetStatistics(uint8* fraction_lost,
+ uint32* cumulative_lost,
+ uint32* extended_high_sequence_number,
+ uint32* jitter) OVERRIDE {
+ *fraction_lost = 0;
+ *cumulative_lost = 0;
+ *extended_high_sequence_number = 0;
+ *jitter = 0;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockReceiverStats);
+};
+
+class MockFrameSender {
+ public:
+ MockFrameSender() {}
+ virtual ~MockFrameSender() {}
+
+ MOCK_METHOD1(OnReceivedCastFeedback,
+ void(const RtcpCastMessage& cast_message));
+ MOCK_METHOD4(OnReceivedRtt,
+ void(base::TimeDelta rtt,
+ base::TimeDelta avg_rtt,
+ base::TimeDelta min_rtt,
+ base::TimeDelta max_rtt));
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockFrameSender);
};
class RtcpTest : public ::testing::Test {
@@ -156,30 +158,9 @@ class RtcpTest : public ::testing::Test {
RtcpTest()
: 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_) {
+ receiver_to_sender_(testing_clock_) {
testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
- net::IPEndPoint dummy_endpoint;
- transport_sender_.reset(new CastTransportSenderImpl(
- NULL,
- testing_clock_,
- dummy_endpoint,
- base::Bind(&UpdateCastTransportStatus),
- BulkRawEventsCallback(),
- base::TimeDelta(),
- task_runner_,
- &sender_to_receiver_));
- CastTransportRtpConfig config;
- config.ssrc = kSenderSsrc;
- config.rtp_payload_type = 127;
- config.stored_frames = 1;
- transport_sender_->InitializeAudio(config);
- EXPECT_CALL(mock_sender_feedback_, OnReceivedCastFeedback(_)).Times(0);
}
virtual ~RtcpTest() {}
@@ -200,125 +181,94 @@ class RtcpTest : public ::testing::Test {
base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment.
scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
- scoped_refptr<CastEnvironment> cast_environment_;
- RtcpTestPacketSender sender_to_receiver_;
- scoped_ptr<CastTransportSenderImpl> transport_sender_;
+ LocalRtcpTransport sender_to_receiver_;
LocalRtcpTransport receiver_to_sender_;
- MockRtcpSenderFeedback mock_sender_feedback_;
+ MockFrameSender mock_frame_sender_;
+ MockReceiverStats stats_;
DISALLOW_COPY_AND_ASSIGN(RtcpTest);
};
-TEST_F(RtcpTest, TimeToSend) {
- const base::TimeTicks start_time = testing_clock_->NowTicks();
- Rtcp rtcp(cast_environment_,
- &mock_sender_feedback_,
- transport_sender_.get(),
- &receiver_to_sender_,
- NULL,
- kRtcpCompound,
- base::TimeDelta::FromMilliseconds(kRtcpIntervalMs),
- kSenderSsrc,
- kReceiverSsrc,
- 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());
- base::TimeDelta delta = rtcp.TimeToSendNextRtcpReport() - start_time;
- testing_clock_->Advance(delta);
- EXPECT_EQ(testing_clock_->NowTicks(), rtcp.TimeToSendNextRtcpReport());
-}
-
TEST_F(RtcpTest, BasicSenderReport) {
- Rtcp rtcp(cast_environment_,
- &mock_sender_feedback_,
- transport_sender_.get(),
- NULL,
- NULL,
- kRtcpCompound,
- base::TimeDelta::FromMilliseconds(kRtcpIntervalMs),
+ Rtcp rtcp(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
+ base::Unretained(&mock_frame_sender_)),
+ base::Bind(&MockFrameSender::OnReceivedRtt,
+ base::Unretained(&mock_frame_sender_)),
+ RtcpLogMessageCallback(),
+ testing_clock_,
+ &sender_to_receiver_,
kSenderSsrc,
kReceiverSsrc,
- kCName,
- AUDIO_EVENT);
+ kCName);
sender_to_receiver_.set_rtcp_receiver(&rtcp);
- rtcp.SendRtcpFromRtpSender(base::TimeTicks(), 0);
+ rtcp.SendRtcpFromRtpSender(base::TimeTicks(), 0, 1, 1);
}
TEST_F(RtcpTest, BasicReceiverReport) {
- Rtcp rtcp(cast_environment_,
- &mock_sender_feedback_,
- NULL,
+ Rtcp rtcp(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
+ base::Unretained(&mock_frame_sender_)),
+ base::Bind(&MockFrameSender::OnReceivedRtt,
+ base::Unretained(&mock_frame_sender_)),
+ RtcpLogMessageCallback(),
+ testing_clock_,
&receiver_to_sender_,
- NULL,
- kRtcpCompound,
- base::TimeDelta::FromMilliseconds(kRtcpIntervalMs),
kSenderSsrc,
kReceiverSsrc,
- kCName,
- AUDIO_EVENT);
+ kCName);
receiver_to_sender_.set_rtcp_receiver(&rtcp);
- rtcp.SendRtcpFromRtpReceiver(NULL, NULL);
+ rtcp.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
}
TEST_F(RtcpTest, BasicCast) {
- EXPECT_CALL(mock_sender_feedback_, OnReceivedCastFeedback(_)).Times(1);
+ EXPECT_CALL(mock_frame_sender_, OnReceivedCastFeedback(_)).Times(1);
- // Media receiver.
- Rtcp rtcp(cast_environment_,
- &mock_sender_feedback_,
- NULL,
+ // Media sender.
+ Rtcp rtcp(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
+ base::Unretained(&mock_frame_sender_)),
+ base::Bind(&MockFrameSender::OnReceivedRtt,
+ base::Unretained(&mock_frame_sender_)),
+ RtcpLogMessageCallback(),
+ testing_clock_,
&receiver_to_sender_,
- NULL,
- kRtcpReducedSize,
- base::TimeDelta::FromMilliseconds(kRtcpIntervalMs),
kSenderSsrc,
kSenderSsrc,
- kCName,
- AUDIO_EVENT);
+ kCName);
receiver_to_sender_.set_rtcp_receiver(&rtcp);
RtcpCastMessage cast_message(kSenderSsrc);
- cast_message.ack_frame_id_ = kAckFrameId;
+ 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);
missing_packets.insert(kLostPacketId3);
- cast_message.missing_frames_and_packets_[kFrameIdWithLostPackets] =
+ cast_message.missing_frames_and_packets[kFrameIdWithLostPackets] =
missing_packets;
- rtcp.SendRtcpFromRtpReceiver(&cast_message, NULL);
+ rtcp.SendRtcpFromRtpReceiver(&cast_message, base::TimeDelta(), NULL, NULL);
}
TEST_F(RtcpTest, RttReducedSizeRtcp) {
// Media receiver.
- Rtcp rtcp_receiver(cast_environment_,
- &mock_sender_feedback_,
- NULL,
+ Rtcp rtcp_receiver(RtcpCastMessageCallback(),
+ RtcpRttCallback(),
+ RtcpLogMessageCallback(),
+ testing_clock_,
&receiver_to_sender_,
- NULL,
- kRtcpReducedSize,
- base::TimeDelta::FromMilliseconds(kRtcpIntervalMs),
kReceiverSsrc,
kSenderSsrc,
- kCName,
- AUDIO_EVENT);
+ kCName);
// Media sender.
- Rtcp rtcp_sender(cast_environment_,
- &mock_sender_feedback_,
- transport_sender_.get(),
- NULL,
- NULL,
- kRtcpReducedSize,
- base::TimeDelta::FromMilliseconds(kRtcpIntervalMs),
+ Rtcp rtcp_sender(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
+ base::Unretained(&mock_frame_sender_)),
+ base::Bind(&MockFrameSender::OnReceivedRtt,
+ base::Unretained(&mock_frame_sender_)),
+ RtcpLogMessageCallback(),
+ testing_clock_,
+ &sender_to_receiver_,
kSenderSsrc,
kReceiverSsrc,
- kCName,
- AUDIO_EVENT);
+ kCName);
sender_to_receiver_.set_rtcp_receiver(&rtcp_receiver);
receiver_to_sender_.set_rtcp_receiver(&rtcp_sender);
@@ -330,16 +280,16 @@ TEST_F(RtcpTest, RttReducedSizeRtcp) {
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(testing_clock_->NowTicks(), 1);
+ rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 1, 1, 1);
RunTasks(33);
- rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL);
+ rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
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);
+ rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 2, 1, 1);
RunTasks(33);
EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
@@ -351,30 +301,26 @@ TEST_F(RtcpTest, RttReducedSizeRtcp) {
TEST_F(RtcpTest, Rtt) {
// Media receiver.
- Rtcp rtcp_receiver(cast_environment_,
- &mock_sender_feedback_,
- NULL,
+ Rtcp rtcp_receiver(RtcpCastMessageCallback(),
+ RtcpRttCallback(),
+ RtcpLogMessageCallback(),
+ testing_clock_,
&receiver_to_sender_,
- NULL,
- kRtcpCompound,
- base::TimeDelta::FromMilliseconds(kRtcpIntervalMs),
kReceiverSsrc,
kSenderSsrc,
- kCName,
- AUDIO_EVENT);
+ kCName);
// Media sender.
- Rtcp rtcp_sender(cast_environment_,
- &mock_sender_feedback_,
- transport_sender_.get(),
- NULL,
- NULL,
- kRtcpCompound,
- base::TimeDelta::FromMilliseconds(kRtcpIntervalMs),
+ Rtcp rtcp_sender(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
+ base::Unretained(&mock_frame_sender_)),
+ base::Bind(&MockFrameSender::OnReceivedRtt,
+ base::Unretained(&mock_frame_sender_)),
+ RtcpLogMessageCallback(),
+ testing_clock_,
+ &sender_to_receiver_,
kSenderSsrc,
kReceiverSsrc,
- kCName,
- AUDIO_EVENT);
+ kCName);
receiver_to_sender_.set_rtcp_receiver(&rtcp_sender);
sender_to_receiver_.set_rtcp_receiver(&rtcp_receiver);
@@ -386,9 +332,9 @@ TEST_F(RtcpTest, 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(testing_clock_->NowTicks(), 1);
+ rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 1, 1, 1);
RunTasks(33);
- rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL);
+ rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
RunTasks(33);
@@ -401,7 +347,7 @@ TEST_F(RtcpTest, Rtt) {
EXPECT_NEAR(2 * kAddedDelay, min_rtt.InMilliseconds(), 2);
EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2);
- rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 2);
+ rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 2, 1, 1);
RunTasks(33);
EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
EXPECT_NEAR(2 * kAddedDelay, rtt.InMilliseconds(), 2);
@@ -411,7 +357,7 @@ TEST_F(RtcpTest, Rtt) {
receiver_to_sender_.set_short_delay();
sender_to_receiver_.set_short_delay();
- rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL);
+ rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
EXPECT_NEAR(kAddedDelay + kAddedShortDelay, rtt.InMilliseconds(), 2);
EXPECT_NEAR(
@@ -419,7 +365,7 @@ TEST_F(RtcpTest, Rtt) {
EXPECT_NEAR(kAddedDelay + kAddedShortDelay, min_rtt.InMilliseconds(), 2);
EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2);
- rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 3);
+ rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 3, 1, 1);
RunTasks(33);
EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
EXPECT_NEAR(2 * kAddedShortDelay, rtt.InMilliseconds(), 1);
@@ -429,13 +375,13 @@ TEST_F(RtcpTest, Rtt) {
EXPECT_NEAR(2 * kAddedShortDelay, min_rtt.InMilliseconds(), 2);
EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2);
- rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL);
+ rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
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);
+ rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
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);
@@ -444,36 +390,32 @@ TEST_F(RtcpTest, Rtt) {
TEST_F(RtcpTest, RttWithPacketLoss) {
// Media receiver.
- Rtcp rtcp_receiver(cast_environment_,
- &mock_sender_feedback_,
- NULL,
+ Rtcp rtcp_receiver(RtcpCastMessageCallback(),
+ RtcpRttCallback(),
+ RtcpLogMessageCallback(),
+ testing_clock_,
&receiver_to_sender_,
- NULL,
- kRtcpReducedSize,
- base::TimeDelta::FromMilliseconds(kRtcpIntervalMs),
kReceiverSsrc,
kSenderSsrc,
- kCName,
- AUDIO_EVENT);
+ kCName);
// Media sender.
- Rtcp rtcp_sender(cast_environment_,
- &mock_sender_feedback_,
- transport_sender_.get(),
- NULL,
- NULL,
- kRtcpReducedSize,
- base::TimeDelta::FromMilliseconds(kRtcpIntervalMs),
+ Rtcp rtcp_sender(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
+ base::Unretained(&mock_frame_sender_)),
+ base::Bind(&MockFrameSender::OnReceivedRtt,
+ base::Unretained(&mock_frame_sender_)),
+ RtcpLogMessageCallback(),
+ testing_clock_,
+ &sender_to_receiver_,
kSenderSsrc,
kReceiverSsrc,
- kCName,
- AUDIO_EVENT);
+ kCName);
receiver_to_sender_.set_rtcp_receiver(&rtcp_sender);
sender_to_receiver_.set_rtcp_receiver(&rtcp_receiver);
- rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL);
- rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 0);
+ rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
+ rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 0, 1, 1);
RunTasks(33);
base::TimeDelta rtt;
@@ -491,8 +433,8 @@ TEST_F(RtcpTest, RttWithPacketLoss) {
sender_to_receiver_.set_short_delay();
receiver_to_sender_.set_drop_packets(true);
- rtcp_receiver.SendRtcpFromRtpReceiver(NULL, NULL);
- rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 1);
+ rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
+ rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 1, 1, 1);
RunTasks(33);
EXPECT_TRUE(rtcp_receiver.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
diff --git a/media/cast/net/rtp/cast_message_builder.cc b/media/cast/net/rtp/cast_message_builder.cc
index bb36613..42d6b98 100644
--- a/media/cast/net/rtp/cast_message_builder.cc
+++ b/media/cast/net/rtp/cast_message_builder.cc
@@ -26,7 +26,7 @@ CastMessageBuilder::CastMessageBuilder(
slowing_down_ack_(false),
acked_last_frame_(true),
last_acked_frame_id_(kStartFrameId) {
- cast_msg_.ack_frame_id_ = kStartFrameId;
+ cast_msg_.ack_frame_id = kStartFrameId;
}
CastMessageBuilder::~CastMessageBuilder() {}
@@ -86,8 +86,8 @@ bool CastMessageBuilder::UpdateAckMessage(uint32 frame_id) {
}
acked_last_frame_ = true;
last_acked_frame_id_ = frame_id;
- cast_msg_.ack_frame_id_ = last_acked_frame_id_;
- cast_msg_.missing_frames_and_packets_.clear();
+ cast_msg_.ack_frame_id = last_acked_frame_id_;
+ cast_msg_.missing_frames_and_packets.clear();
last_update_time_ = clock_->NowTicks();
return true;
}
@@ -113,8 +113,8 @@ void CastMessageBuilder::UpdateCastMessage() {
}
void CastMessageBuilder::Reset() {
- cast_msg_.ack_frame_id_ = kStartFrameId;
- cast_msg_.missing_frames_and_packets_.clear();
+ cast_msg_.ack_frame_id = kStartFrameId;
+ cast_msg_.missing_frames_and_packets.clear();
time_last_nacked_map_.clear();
}
@@ -137,7 +137,7 @@ bool CastMessageBuilder::UpdateCastMessageInternal(RtcpCastMessage* message) {
// Needed to cover when a frame is skipped.
UpdateAckMessage(last_acked_frame_id_);
BuildPacketList();
- message->Copy(cast_msg_);
+ *message = cast_msg_;
return true;
}
@@ -145,14 +145,14 @@ void CastMessageBuilder::BuildPacketList() {
base::TimeTicks now = clock_->NowTicks();
// Clear message NACK list.
- cast_msg_.missing_frames_and_packets_.clear();
+ cast_msg_.missing_frames_and_packets.clear();
// Are we missing packets?
if (frame_id_map_->Empty())
return;
uint32 newest_frame_id = frame_id_map_->NewestFrameId();
- uint32 next_expected_frame_id = cast_msg_.ack_frame_id_ + 1;
+ uint32 next_expected_frame_id = cast_msg_.ack_frame_id + 1;
// Iterate over all frames.
for (; !IsNewerFrameId(next_expected_frame_id, newest_frame_id);
@@ -175,13 +175,13 @@ void CastMessageBuilder::BuildPacketList() {
next_expected_frame_id, last_frame, &missing);
if (!missing.empty()) {
time_last_nacked_map_[next_expected_frame_id] = now;
- cast_msg_.missing_frames_and_packets_.insert(
+ cast_msg_.missing_frames_and_packets.insert(
std::make_pair(next_expected_frame_id, missing));
}
} else {
time_last_nacked_map_[next_expected_frame_id] = now;
missing.insert(kRtcpCastAllPacketsLost);
- cast_msg_.missing_frames_and_packets_[next_expected_frame_id] = missing;
+ cast_msg_.missing_frames_and_packets[next_expected_frame_id] = missing;
}
}
}
diff --git a/media/cast/net/rtp/cast_message_builder_unittest.cc b/media/cast/net/rtp/cast_message_builder_unittest.cc
index b0e30c4..e8a9aef 100644
--- a/media/cast/net/rtp/cast_message_builder_unittest.cc
+++ b/media/cast/net/rtp/cast_message_builder_unittest.cc
@@ -28,16 +28,16 @@ class NackFeedbackVerification : public RtpPayloadFeedback {
: triggered_(false), missing_packets_(), last_frame_acked_(0) {}
virtual void CastFeedback(const RtcpCastMessage& cast_feedback) OVERRIDE {
- EXPECT_EQ(kSsrc, cast_feedback.media_ssrc_);
+ EXPECT_EQ(kSsrc, cast_feedback.media_ssrc);
- last_frame_acked_ = cast_feedback.ack_frame_id_;
+ last_frame_acked_ = cast_feedback.ack_frame_id;
MissingFramesAndPacketsMap::const_iterator frame_it =
- cast_feedback.missing_frames_and_packets_.begin();
+ cast_feedback.missing_frames_and_packets.begin();
// Keep track of the number of missing packets per frame.
missing_packets_.clear();
- while (frame_it != cast_feedback.missing_frames_and_packets_.end()) {
+ while (frame_it != cast_feedback.missing_frames_and_packets.end()) {
// Check for complete frame lost.
if ((frame_it->second.size() == 1) &&
(*frame_it->second.begin() == kRtcpCastAllPacketsLost)) {
diff --git a/media/cast/receiver/cast_receiver_impl.cc b/media/cast/receiver/cast_receiver_impl.cc
index 36669b9..91821bb 100644
--- a/media/cast/receiver/cast_receiver_impl.cc
+++ b/media/cast/receiver/cast_receiver_impl.cc
@@ -10,6 +10,7 @@
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "media/cast/net/rtcp/rtcp_receiver.h"
#include "media/cast/receiver/audio_decoder.h"
#include "media/cast/receiver/video_decoder.h"
@@ -51,8 +52,8 @@ void CastReceiverImpl::DispatchReceivedPacket(scoped_ptr<Packet> packet) {
const size_t length = packet->size();
uint32 ssrc_of_sender;
- if (Rtcp::IsRtcpPacket(data, length)) {
- ssrc_of_sender = Rtcp::GetSsrcOfSender(data, length);
+ if (RtcpReceiver::IsRtcpPacket(data, length)) {
+ ssrc_of_sender = RtcpReceiver::GetSsrcOfSender(data, length);
} else if (!FrameReceiver::ParseSenderSsrc(data, length, &ssrc_of_sender)) {
VLOG(1) << "Invalid RTP packet.";
return;
diff --git a/media/cast/receiver/frame_receiver.cc b/media/cast/receiver/frame_receiver.cc
index 951e958..31620cd 100644
--- a/media/cast/receiver/frame_receiver.cc
+++ b/media/cast/receiver/frame_receiver.cc
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "media/cast/cast_environment.h"
+#include "media/cast/net/rtcp/rtcp_receiver.h"
namespace {
const int kMinSchedulingDelayMs = 1;
@@ -40,24 +41,21 @@ FrameReceiver::FrameReceiver(
config.incoming_ssrc,
true,
config.rtp_max_delay_ms * config.max_frame_rate / 1000),
- rtcp_(cast_environment_,
- NULL,
- NULL,
+ rtcp_(RtcpCastMessageCallback(),
+ RtcpRttCallback(),
+ RtcpLogMessageCallback(),
+ cast_environment_->Clock(),
packet_sender,
- &stats_,
- config.rtcp_mode,
- base::TimeDelta::FromMilliseconds(config.rtcp_interval),
config.feedback_ssrc,
config.incoming_ssrc,
- config.rtcp_c_name,
- event_media_type),
+ config.rtcp_c_name),
is_waiting_for_consecutive_frame_(false),
lip_sync_drift_(ClockDriftSmoother::GetDefaultTimeConstant()),
+ rtcp_interval_(base::TimeDelta::FromMilliseconds(config.rtcp_interval)),
weak_factory_(this) {
DCHECK_GT(config.rtp_max_delay_ms, 0);
DCHECK_GT(config.max_frame_rate, 0);
decryptor_.Initialize(config.aes_key, config.aes_iv_mask);
- rtcp_.SetTargetDelay(target_playout_delay_);
cast_environment_->Logging()->AddRawEventSubscriber(&event_subscriber_);
memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_));
}
@@ -77,7 +75,7 @@ void FrameReceiver::RequestEncodedFrame(
bool FrameReceiver::ProcessPacket(scoped_ptr<Packet> packet) {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) {
+ if (RtcpReceiver::IsRtcpPacket(&packet->front(), packet->size())) {
rtcp_.IncomingRtcpPacket(&packet->front(), packet->size());
} else {
RtpCastHeader rtp_header;
@@ -176,14 +174,15 @@ void FrameReceiver::CastFeedback(const RtcpCastMessage& cast_message) {
base::TimeTicks now = cast_environment_->Clock()->NowTicks();
RtpTimestamp rtp_timestamp =
- frame_id_to_rtp_timestamp_[cast_message.ack_frame_id_ & 0xff];
+ frame_id_to_rtp_timestamp_[cast_message.ack_frame_id & 0xff];
cast_environment_->Logging()->InsertFrameEvent(
now, FRAME_ACK_SENT, event_media_type_,
- rtp_timestamp, cast_message.ack_frame_id_);
+ rtp_timestamp, cast_message.ack_frame_id);
ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
event_subscriber_.GetRtcpEventsAndReset(&rtcp_events);
- rtcp_.SendRtcpFromRtpReceiver(&cast_message, &rtcp_events);
+ rtcp_.SendRtcpFromRtpReceiver(&cast_message, target_playout_delay_,
+ &rtcp_events, NULL);
}
void FrameReceiver::EmitAvailableEncodedFrames() {
@@ -302,9 +301,7 @@ void FrameReceiver::SendNextCastMessage() {
void FrameReceiver::ScheduleNextRtcpReport() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- base::TimeDelta time_to_next = rtcp_.TimeToSendNextRtcpReport() -
- cast_environment_->Clock()->NowTicks();
-
+ base::TimeDelta time_to_next = rtcp_interval_;
time_to_next = std::max(
time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
@@ -318,7 +315,7 @@ void FrameReceiver::ScheduleNextRtcpReport() {
void FrameReceiver::SendNextRtcpReport() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- rtcp_.SendRtcpFromRtpReceiver(NULL, NULL);
+ rtcp_.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
ScheduleNextRtcpReport();
}
diff --git a/media/cast/receiver/frame_receiver.h b/media/cast/receiver/frame_receiver.h
index f8e4481..2ddeeb9 100644
--- a/media/cast/receiver/frame_receiver.h
+++ b/media/cast/receiver/frame_receiver.h
@@ -172,6 +172,9 @@ class FrameReceiver : public RtpPayloadFeedback,
base::TimeTicks lip_sync_reference_time_;
ClockDriftSmoother lip_sync_drift_;
+ // Time interval for sending a RTCP report.
+ const base::TimeDelta rtcp_interval_;
+
// NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<FrameReceiver> weak_factory_;
diff --git a/media/cast/sender/audio_sender.cc b/media/cast/sender/audio_sender.cc
index 7c7c696..ae9653f 100644
--- a/media/cast/sender/audio_sender.cc
+++ b/media/cast/sender/audio_sender.cc
@@ -9,7 +9,6 @@
#include "base/message_loop/message_loop.h"
#include "media/cast/cast_defines.h"
#include "media/cast/net/cast_transport_config.h"
-#include "media/cast/net/rtcp/rtcp_defines.h"
#include "media/cast/sender/audio_encoder.h"
namespace media {
@@ -39,23 +38,15 @@ int GetMaxUnackedFrames(base::TimeDelta target_delay) {
AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
const AudioSenderConfig& audio_config,
CastTransportSender* const transport_sender)
- : cast_environment_(cast_environment),
+ : FrameSender(
+ cast_environment,
+ transport_sender,
+ base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval),
+ audio_config.frequency,
+ audio_config.ssrc),
target_playout_delay_(audio_config.target_playout_delay),
- transport_sender_(transport_sender),
max_unacked_frames_(GetMaxUnackedFrames(target_playout_delay_)),
configured_encoder_bitrate_(audio_config.bitrate),
- rtcp_(cast_environment,
- this,
- transport_sender_,
- NULL, // paced sender.
- NULL,
- audio_config.rtcp_mode,
- base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval),
- audio_config.ssrc,
- audio_config.incoming_feedback_ssrc,
- audio_config.rtcp_c_name,
- AUDIO_EVENT),
- rtp_timestamp_helper_(audio_config.frequency),
num_aggressive_rtcp_reports_sent_(0),
last_sent_frame_id_(0),
latest_acked_frame_id_(0),
@@ -82,16 +73,20 @@ AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
media::cast::CastTransportRtpConfig transport_config;
transport_config.ssrc = audio_config.ssrc;
+ transport_config.feedback_ssrc = audio_config.incoming_feedback_ssrc;
+ transport_config.c_name = audio_config.rtcp_c_name;
transport_config.rtp_payload_type = audio_config.rtp_payload_type;
// TODO(miu): AudioSender needs to be like VideoSender in providing an upper
// limit on the number of in-flight frames.
transport_config.stored_frames = max_unacked_frames_;
transport_config.aes_key = audio_config.aes_key;
transport_config.aes_iv_mask = audio_config.aes_iv_mask;
- transport_sender_->InitializeAudio(transport_config);
-
- rtcp_.SetCastReceiverEventHistorySize(kReceiverRtcpEventHistorySize);
+ transport_sender->InitializeAudio(
+ transport_config,
+ base::Bind(&AudioSender::OnReceivedCastFeedback,
+ weak_factory_.GetWeakPtr()),
+ base::Bind(&AudioSender::OnReceivedRtt, weak_factory_.GetWeakPtr()));
memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_));
}
@@ -161,43 +156,6 @@ void AudioSender::SendEncodedAudioFrame(
transport_sender_->InsertCodedAudioFrame(*encoded_frame);
}
-void AudioSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) {
- DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- rtcp_.IncomingRtcpPacket(&packet->front(), packet->size());
-}
-
-void AudioSender::ScheduleNextRtcpReport() {
- DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- base::TimeDelta time_to_next =
- rtcp_.TimeToSendNextRtcpReport() - cast_environment_->Clock()->NowTicks();
-
- time_to_next = std::max(
- time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
-
- cast_environment_->PostDelayedTask(
- CastEnvironment::MAIN,
- FROM_HERE,
- base::Bind(&AudioSender::SendRtcpReport,
- weak_factory_.GetWeakPtr(),
- true),
- time_to_next);
-}
-
-void AudioSender::SendRtcpReport(bool schedule_future_reports) {
- DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
- uint32 now_as_rtp_timestamp = 0;
- if (rtp_timestamp_helper_.GetCurrentTimeAsRtpTimestamp(
- now, &now_as_rtp_timestamp)) {
- rtcp_.SendRtcpFromRtpSender(now, now_as_rtp_timestamp);
- } else {
- // |rtp_timestamp_helper_| should have stored a mapping by this point.
- NOTREACHED();
- }
- if (schedule_future_reports)
- ScheduleNextRtcpReport();
-}
-
void AudioSender::ScheduleNextResendCheck() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
DCHECK(!last_send_time_.is_null());
@@ -232,7 +190,7 @@ void AudioSender::ResendCheck() {
void AudioSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- if (rtcp_.is_rtt_available()) {
+ if (is_rtt_available()) {
// Having the RTT values implies the receiver sent back a receiver report
// based on it having received a report from here. Therefore, ensure this
// sender stops aggressively sending reports.
@@ -247,9 +205,9 @@ void AudioSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
if (last_send_time_.is_null())
return; // Cannot get an ACK without having first sent a frame.
- if (cast_feedback.missing_frames_and_packets_.empty()) {
+ if (cast_feedback.missing_frames_and_packets.empty()) {
// We only count duplicate ACKs when we have sent newer frames.
- if (latest_acked_frame_id_ == cast_feedback.ack_frame_id_ &&
+ if (latest_acked_frame_id_ == cast_feedback.ack_frame_id &&
latest_acked_frame_id_ != last_sent_frame_id_) {
duplicate_ack_counter_++;
} else {
@@ -265,43 +223,37 @@ void AudioSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
// This is to avoid aggresive resend.
duplicate_ack_counter_ = 0;
- base::TimeDelta rtt;
- base::TimeDelta avg_rtt;
- base::TimeDelta min_rtt;
- base::TimeDelta max_rtt;
- rtcp_.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt);
-
// A NACK is also used to cancel pending re-transmissions.
transport_sender_->ResendPackets(
- true, cast_feedback.missing_frames_and_packets_, false, min_rtt);
+ true, cast_feedback.missing_frames_and_packets, false, min_rtt_);
}
const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
const RtpTimestamp rtp_timestamp =
- frame_id_to_rtp_timestamp_[cast_feedback.ack_frame_id_ & 0xff];
+ frame_id_to_rtp_timestamp_[cast_feedback.ack_frame_id & 0xff];
cast_environment_->Logging()->InsertFrameEvent(now,
FRAME_ACK_RECEIVED,
AUDIO_EVENT,
rtp_timestamp,
- cast_feedback.ack_frame_id_);
+ cast_feedback.ack_frame_id);
const bool is_acked_out_of_order =
- static_cast<int32>(cast_feedback.ack_frame_id_ -
+ static_cast<int32>(cast_feedback.ack_frame_id -
latest_acked_frame_id_) < 0;
VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "")
- << " for frame " << cast_feedback.ack_frame_id_;
+ << " for frame " << cast_feedback.ack_frame_id;
if (!is_acked_out_of_order) {
// Cancel resends of acked frames.
MissingFramesAndPacketsMap missing_frames_and_packets;
PacketIdSet missing;
- while (latest_acked_frame_id_ != cast_feedback.ack_frame_id_) {
+ while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) {
latest_acked_frame_id_++;
missing_frames_and_packets[latest_acked_frame_id_] = missing;
}
transport_sender_->ResendPackets(
true, missing_frames_and_packets, true, base::TimeDelta());
- latest_acked_frame_id_ = cast_feedback.ack_frame_id_;
+ latest_acked_frame_id_ = cast_feedback.ack_frame_id;
}
}
@@ -333,16 +285,10 @@ void AudioSender::ResendForKickstart() {
std::make_pair(last_sent_frame_id_, missing));
last_send_time_ = cast_environment_->Clock()->NowTicks();
- base::TimeDelta rtt;
- base::TimeDelta avg_rtt;
- base::TimeDelta min_rtt;
- base::TimeDelta max_rtt;
- rtcp_.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt);
-
// Sending this extra packet is to kick-start the session. There is
// no need to optimize re-transmission for this case.
transport_sender_->ResendPackets(
- true, missing_frames_and_packets, false, min_rtt);
+ true, missing_frames_and_packets, false, min_rtt_);
}
} // namespace cast
diff --git a/media/cast/sender/audio_sender.h b/media/cast/sender/audio_sender.h
index efaa2b3..02582ae 100644
--- a/media/cast/sender/audio_sender.h
+++ b/media/cast/sender/audio_sender.h
@@ -14,10 +14,7 @@
#include "base/time/time.h"
#include "media/base/audio_bus.h"
#include "media/cast/cast_config.h"
-#include "media/cast/cast_environment.h"
-#include "media/cast/logging/logging_defines.h"
-#include "media/cast/net/rtcp/rtcp.h"
-#include "media/cast/sender/rtp_timestamp_helper.h"
+#include "media/cast/sender/frame_sender.h"
namespace media {
namespace cast {
@@ -30,7 +27,7 @@ class AudioEncoder;
// RTCP packets.
// Additionally it posts a bunch of delayed tasks to the main thread for various
// timeouts.
-class AudioSender : public RtcpSenderFeedback,
+class AudioSender : public FrameSender,
public base::NonThreadSafe,
public base::SupportsWeakPtr<AudioSender> {
public:
@@ -53,19 +50,11 @@ class AudioSender : public RtcpSenderFeedback,
void InsertAudio(scoped_ptr<AudioBus> audio_bus,
const base::TimeTicks& recorded_time);
- // Only called from the main cast thread.
- void IncomingRtcpPacket(scoped_ptr<Packet> packet);
-
protected:
// Protected for testability.
- virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback)
- OVERRIDE;
+ void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback);
private:
- // Schedule and execute periodic sending of RTCP report.
- void ScheduleNextRtcpReport();
- void SendRtcpReport(bool schedule_future_reports);
-
// Schedule and execute periodic checks for re-sending packets. If no
// acknowledgements have been received for "too long," AudioSender will
// speculatively re-send certain packets of an unacked frame to kick-start
@@ -84,8 +73,6 @@ class AudioSender : public RtcpSenderFeedback,
// Called by the |audio_encoder_| with the next EncodedFrame to send.
void SendEncodedAudioFrame(scoped_ptr<EncodedFrame> audio_frame);
- const scoped_refptr<CastEnvironment> cast_environment_;
-
// The total amount of time between a frame's capture/recording on the sender
// and its playback on the receiver (i.e., shown to a user). This is fixed as
// a value large enough to give the system sufficient time to encode,
@@ -94,13 +81,6 @@ class AudioSender : public RtcpSenderFeedback,
// etc.).
const base::TimeDelta target_playout_delay_;
- // Sends encoded frames over the configured transport (e.g., UDP). In
- // Chromium, this could be a proxy that first sends the frames from a renderer
- // process to the browser process over IPC, with the browser process being
- // responsible for "packetizing" the frames and pushing packets into the
- // network layer.
- CastTransportSender* const transport_sender_;
-
// Maximum number of outstanding frames before the encoding and sending of
// new frames shall halt.
const int max_unacked_frames_;
@@ -109,14 +89,6 @@ class AudioSender : public RtcpSenderFeedback,
scoped_ptr<AudioEncoder> audio_encoder_;
const int configured_encoder_bitrate_;
- // Manages sending/receiving of RTCP packets, including sender/receiver
- // reports.
- Rtcp rtcp_;
-
- // Records lip-sync (i.e., mapping of RTP <--> NTP timestamps), and
- // extrapolates this mapping to any other point in time.
- RtpTimestampHelper rtp_timestamp_helper_;
-
// Counts how many RTCP reports are being "aggressively" sent (i.e., one per
// frame) at the start of the session. Once a threshold is reached, RTCP
// reports are instead sent at the configured interval + random drift.
diff --git a/media/cast/sender/audio_sender_unittest.cc b/media/cast/sender/audio_sender_unittest.cc
index ab92381..287630d 100644
--- a/media/cast/sender/audio_sender_unittest.cc
+++ b/media/cast/sender/audio_sender_unittest.cc
@@ -13,7 +13,7 @@
#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/cast_transport_sender_impl.h"
-#include "media/cast/net/rtcp/rtcp.h"
+#include "media/cast/net/rtcp/rtcp_receiver.h"
#include "media/cast/sender/audio_sender.h"
#include "media/cast/test/fake_single_thread_task_runner.h"
#include "media/cast/test/utility/audio_utility.h"
@@ -28,7 +28,7 @@ class TestPacketSender : public PacketSender {
virtual bool SendPacket(PacketRef packet,
const base::Closure& cb) OVERRIDE {
- if (Rtcp::IsRtcpPacket(&packet->data[0], packet->data.size())) {
+ if (RtcpReceiver::IsRtcpPacket(&packet->data[0], packet->data.size())) {
++number_of_rtcp_packets_;
} else {
// Check that at least one RTCP packet was sent before the first RTP
diff --git a/media/cast/sender/frame_sender.cc b/media/cast/sender/frame_sender.cc
new file mode 100644
index 0000000..e5bc95c
--- /dev/null
+++ b/media/cast/sender/frame_sender.cc
@@ -0,0 +1,72 @@
+// 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/sender/frame_sender.h"
+
+namespace media {
+namespace cast {
+namespace {
+const int kMinSchedulingDelayMs = 1;
+} // namespace
+
+FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment,
+ CastTransportSender* const transport_sender,
+ base::TimeDelta rtcp_interval,
+ int frequency,
+ uint32 ssrc)
+ : cast_environment_(cast_environment),
+ transport_sender_(transport_sender),
+ rtp_timestamp_helper_(frequency),
+ rtt_available_(false),
+ rtcp_interval_(rtcp_interval),
+ ssrc_(ssrc),
+ weak_factory_(this) {
+}
+
+FrameSender::~FrameSender() {
+}
+
+void FrameSender::ScheduleNextRtcpReport() {
+ DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
+ base::TimeDelta time_to_next = rtcp_interval_;
+
+ time_to_next = std::max(
+ time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
+
+ cast_environment_->PostDelayedTask(
+ CastEnvironment::MAIN,
+ FROM_HERE,
+ base::Bind(&FrameSender::SendRtcpReport, weak_factory_.GetWeakPtr(),
+ true),
+ time_to_next);
+}
+
+void FrameSender::SendRtcpReport(bool schedule_future_reports) {
+ DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
+ const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
+ uint32 now_as_rtp_timestamp = 0;
+ if (rtp_timestamp_helper_.GetCurrentTimeAsRtpTimestamp(
+ now, &now_as_rtp_timestamp)) {
+ transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp);
+ } else {
+ // |rtp_timestamp_helper_| should have stored a mapping by this point.
+ NOTREACHED();
+ }
+ if (schedule_future_reports)
+ ScheduleNextRtcpReport();
+}
+
+void FrameSender::OnReceivedRtt(base::TimeDelta rtt,
+ base::TimeDelta avg_rtt,
+ base::TimeDelta min_rtt,
+ base::TimeDelta max_rtt) {
+ rtt_available_ = true;
+ rtt_ = rtt;
+ avg_rtt_ = avg_rtt;
+ min_rtt_ = min_rtt;
+ max_rtt_ = max_rtt;
+}
+
+} // namespace cast
+} // namespace media
diff --git a/media/cast/sender/frame_sender.h b/media/cast/sender/frame_sender.h
new file mode 100644
index 0000000..70eccba
--- /dev/null
+++ b/media/cast/sender/frame_sender.h
@@ -0,0 +1,77 @@
+// 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.
+//
+// This is the base class for an object that send frames to a receiver.
+// TODO(hclam): Refactor such that there is no separate AudioSender vs.
+// VideoSender, and the functionality of both is rolled into this class.
+
+#ifndef MEDIA_CAST_SENDER_FRAME_SENDER_H_
+#define MEDIA_CAST_SENDER_FRAME_SENDER_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "media/cast/cast_environment.h"
+#include "media/cast/net/rtcp/rtcp.h"
+#include "media/cast/sender/rtp_timestamp_helper.h"
+
+namespace media {
+namespace cast {
+
+class FrameSender {
+ public:
+ FrameSender(scoped_refptr<CastEnvironment> cast_environment,
+ CastTransportSender* const transport_sender,
+ base::TimeDelta rtcp_interval,
+ int frequency,
+ uint32 ssrc);
+ virtual ~FrameSender();
+
+ protected:
+ // Schedule and execute periodic sending of RTCP report.
+ void ScheduleNextRtcpReport();
+ void SendRtcpReport(bool schedule_future_reports);
+
+ void OnReceivedRtt(base::TimeDelta rtt,
+ base::TimeDelta avg_rtt,
+ base::TimeDelta min_rtt,
+ base::TimeDelta max_rtt);
+
+ bool is_rtt_available() const { return rtt_available_; }
+
+ const scoped_refptr<CastEnvironment> cast_environment_;
+
+ // Sends encoded frames over the configured transport (e.g., UDP). In
+ // Chromium, this could be a proxy that first sends the frames from a renderer
+ // process to the browser process over IPC, with the browser process being
+ // responsible for "packetizing" the frames and pushing packets into the
+ // network layer.
+ CastTransportSender* const transport_sender_;
+
+ // Records lip-sync (i.e., mapping of RTP <--> NTP timestamps), and
+ // extrapolates this mapping to any other point in time.
+ RtpTimestampHelper rtp_timestamp_helper_;
+
+ // RTT information from RTCP.
+ bool rtt_available_;
+ base::TimeDelta rtt_;
+ base::TimeDelta avg_rtt_;
+ base::TimeDelta min_rtt_;
+ base::TimeDelta max_rtt_;
+
+ private:
+ const base::TimeDelta rtcp_interval_;
+ const uint32 ssrc_;
+
+ // NOTE: Weak pointers must be invalidated before all other member variables.
+ base::WeakPtrFactory<FrameSender> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameSender);
+};
+
+} // namespace cast
+} // namespace media
+
+#endif // MEDIA_CAST_SENDER_FRAME_SENDER_H_
diff --git a/media/cast/sender/video_sender.cc b/media/cast/sender/video_sender.cc
index 0d82690..aff09c1 100644
--- a/media/cast/sender/video_sender.cc
+++ b/media/cast/sender/video_sender.cc
@@ -13,7 +13,6 @@
#include "base/message_loop/message_loop.h"
#include "media/cast/cast_defines.h"
#include "media/cast/net/cast_transport_config.h"
-#include "media/cast/net/rtcp/rtcp_defines.h"
#include "media/cast/sender/external_video_encoder.h"
#include "media/cast/sender/video_encoder_impl.h"
@@ -29,26 +28,18 @@ VideoSender::VideoSender(
const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb,
CastTransportSender* const transport_sender)
- : cast_environment_(cast_environment),
+ : FrameSender(
+ cast_environment,
+ transport_sender,
+ base::TimeDelta::FromMilliseconds(video_config.rtcp_interval),
+ kVideoFrequency,
+ video_config.ssrc),
target_playout_delay_(video_config.target_playout_delay),
- transport_sender_(transport_sender),
max_unacked_frames_(
std::min(kMaxUnackedFrames,
1 + static_cast<int>(target_playout_delay_ *
video_config.max_frame_rate /
base::TimeDelta::FromSeconds(1)))),
- rtcp_(cast_environment_,
- this,
- transport_sender_,
- NULL, // paced sender.
- NULL,
- video_config.rtcp_mode,
- base::TimeDelta::FromMilliseconds(video_config.rtcp_interval),
- video_config.ssrc,
- video_config.incoming_feedback_ssrc,
- video_config.rtcp_c_name,
- VIDEO_EVENT),
- rtp_timestamp_helper_(kVideoFrequency),
num_aggressive_rtcp_reports_sent_(0),
frames_in_encoder_(0),
last_sent_frame_id_(0),
@@ -76,13 +67,18 @@ VideoSender::VideoSender(
media::cast::CastTransportRtpConfig transport_config;
transport_config.ssrc = video_config.ssrc;
+ transport_config.feedback_ssrc = video_config.incoming_feedback_ssrc;
+ transport_config.c_name = video_config.rtcp_c_name;
transport_config.rtp_payload_type = video_config.rtp_payload_type;
transport_config.stored_frames = max_unacked_frames_;
transport_config.aes_key = video_config.aes_key;
transport_config.aes_iv_mask = video_config.aes_iv_mask;
- transport_sender_->InitializeVideo(transport_config);
- rtcp_.SetCastReceiverEventHistorySize(kReceiverRtcpEventHistorySize);
+ transport_sender->InitializeVideo(
+ transport_config,
+ base::Bind(&VideoSender::OnReceivedCastFeedback,
+ weak_factory_.GetWeakPtr()),
+ base::Bind(&VideoSender::OnReceivedRtt, weak_factory_.GetWeakPtr()));
memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_));
}
@@ -202,41 +198,20 @@ void VideoSender::SendEncodedVideoFrame(
transport_sender_->InsertCodedVideoFrame(*encoded_frame);
}
-void VideoSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) {
- DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- rtcp_.IncomingRtcpPacket(&packet->front(), packet->size());
-}
-
-void VideoSender::ScheduleNextRtcpReport() {
- DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- base::TimeDelta time_to_next = rtcp_.TimeToSendNextRtcpReport() -
- cast_environment_->Clock()->NowTicks();
-
- time_to_next = std::max(
- time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
-
- cast_environment_->PostDelayedTask(
- CastEnvironment::MAIN,
- FROM_HERE,
- base::Bind(&VideoSender::SendRtcpReport,
- weak_factory_.GetWeakPtr(),
- true),
- time_to_next);
-}
-
-void VideoSender::SendRtcpReport(bool schedule_future_reports) {
+void VideoSender::ResendCheck() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
- uint32 now_as_rtp_timestamp = 0;
- if (rtp_timestamp_helper_.GetCurrentTimeAsRtpTimestamp(
- now, &now_as_rtp_timestamp)) {
- rtcp_.SendRtcpFromRtpSender(now, now_as_rtp_timestamp);
- } else {
- // |rtp_timestamp_helper_| should have stored a mapping by this point.
- NOTREACHED();
+ DCHECK(!last_send_time_.is_null());
+ const base::TimeDelta time_since_last_send =
+ cast_environment_->Clock()->NowTicks() - last_send_time_;
+ if (time_since_last_send > target_playout_delay_) {
+ if (latest_acked_frame_id_ == last_sent_frame_id_) {
+ // Last frame acked, no point in doing anything
+ } else {
+ VLOG(1) << "ACK timeout; last acked frame: " << latest_acked_frame_id_;
+ ResendForKickstart();
+ }
}
- if (schedule_future_reports)
- ScheduleNextRtcpReport();
+ ScheduleNextResendCheck();
}
void VideoSender::ScheduleNextResendCheck() {
@@ -254,22 +229,6 @@ void VideoSender::ScheduleNextResendCheck() {
time_to_next);
}
-void VideoSender::ResendCheck() {
- DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
- DCHECK(!last_send_time_.is_null());
- const base::TimeDelta time_since_last_send =
- cast_environment_->Clock()->NowTicks() - last_send_time_;
- if (time_since_last_send > target_playout_delay_) {
- if (latest_acked_frame_id_ == last_sent_frame_id_) {
- // Last frame acked, no point in doing anything
- } else {
- VLOG(1) << "ACK timeout; last acked frame: " << latest_acked_frame_id_;
- ResendForKickstart();
- }
- }
- ScheduleNextResendCheck();
-}
-
void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
@@ -277,7 +236,12 @@ void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
base::TimeDelta avg_rtt;
base::TimeDelta min_rtt;
base::TimeDelta max_rtt;
- if (rtcp_.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)) {
+ if (is_rtt_available()) {
+ rtt = rtt_;
+ avg_rtt = avg_rtt_;
+ min_rtt = min_rtt_;
+ max_rtt = max_rtt_;
+
congestion_control_.UpdateRtt(rtt);
// Don't use a RTT lower than our average.
@@ -300,11 +264,11 @@ void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
if (last_send_time_.is_null())
return; // Cannot get an ACK without having first sent a frame.
- if (cast_feedback.missing_frames_and_packets_.empty()) {
- video_encoder_->LatestFrameIdToReference(cast_feedback.ack_frame_id_);
+ if (cast_feedback.missing_frames_and_packets.empty()) {
+ video_encoder_->LatestFrameIdToReference(cast_feedback.ack_frame_id);
// We only count duplicate ACKs when we have sent newer frames.
- if (latest_acked_frame_id_ == cast_feedback.ack_frame_id_ &&
+ if (latest_acked_frame_id_ == cast_feedback.ack_frame_id &&
latest_acked_frame_id_ != last_sent_frame_id_) {
duplicate_ack_counter_++;
} else {
@@ -322,36 +286,36 @@ void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
// A NACK is also used to cancel pending re-transmissions.
transport_sender_->ResendPackets(
- false, cast_feedback.missing_frames_and_packets_, true, rtt);
+ false, cast_feedback.missing_frames_and_packets, true, rtt);
}
base::TimeTicks now = cast_environment_->Clock()->NowTicks();
- congestion_control_.AckFrame(cast_feedback.ack_frame_id_, now);
+ congestion_control_.AckFrame(cast_feedback.ack_frame_id, now);
RtpTimestamp rtp_timestamp =
- frame_id_to_rtp_timestamp_[cast_feedback.ack_frame_id_ & 0xff];
+ frame_id_to_rtp_timestamp_[cast_feedback.ack_frame_id & 0xff];
cast_environment_->Logging()->InsertFrameEvent(now,
FRAME_ACK_RECEIVED,
VIDEO_EVENT,
rtp_timestamp,
- cast_feedback.ack_frame_id_);
+ cast_feedback.ack_frame_id);
const bool is_acked_out_of_order =
- static_cast<int32>(cast_feedback.ack_frame_id_ -
+ static_cast<int32>(cast_feedback.ack_frame_id -
latest_acked_frame_id_) < 0;
VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "")
- << " for frame " << cast_feedback.ack_frame_id_;
+ << " for frame " << cast_feedback.ack_frame_id;
if (!is_acked_out_of_order) {
// Cancel resends of acked frames.
MissingFramesAndPacketsMap missing_frames_and_packets;
PacketIdSet missing;
- while (latest_acked_frame_id_ != cast_feedback.ack_frame_id_) {
+ while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) {
latest_acked_frame_id_++;
missing_frames_and_packets[latest_acked_frame_id_] = missing;
}
transport_sender_->ResendPackets(
false, missing_frames_and_packets, true, rtt);
- latest_acked_frame_id_ = cast_feedback.ack_frame_id_;
+ latest_acked_frame_id_ = cast_feedback.ack_frame_id;
}
}
@@ -384,16 +348,10 @@ void VideoSender::ResendForKickstart() {
std::make_pair(last_sent_frame_id_, missing));
last_send_time_ = cast_environment_->Clock()->NowTicks();
- base::TimeDelta rtt;
- base::TimeDelta avg_rtt;
- base::TimeDelta min_rtt;
- base::TimeDelta max_rtt;
- rtcp_.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt);
-
// Sending this extra packet is to kick-start the session. There is
// no need to optimize re-transmission for this case.
transport_sender_->ResendPackets(false, missing_frames_and_packets,
- false, rtt);
+ false, rtt_);
}
} // namespace cast
diff --git a/media/cast/sender/video_sender.h b/media/cast/sender/video_sender.h
index 6587572..09fac8d 100644
--- a/media/cast/sender/video_sender.h
+++ b/media/cast/sender/video_sender.h
@@ -13,11 +13,8 @@
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "media/cast/cast_config.h"
-#include "media/cast/cast_environment.h"
-#include "media/cast/logging/logging_defines.h"
-#include "media/cast/net/rtcp/rtcp.h"
#include "media/cast/sender/congestion_control.h"
-#include "media/cast/sender/rtp_timestamp_helper.h"
+#include "media/cast/sender/frame_sender.h"
namespace media {
@@ -26,7 +23,6 @@ class VideoFrame;
namespace cast {
class CastTransportSender;
-class LocalVideoEncoderCallback;
class VideoEncoder;
// Not thread safe. Only called from the main cast thread.
@@ -35,7 +31,7 @@ class VideoEncoder;
// RTCP packets.
// Additionally it posts a bunch of delayed tasks to the main thread for various
// timeouts.
-class VideoSender : public RtcpSenderFeedback,
+class VideoSender : public FrameSender,
public base::NonThreadSafe,
public base::SupportsWeakPtr<VideoSender> {
public:
@@ -60,19 +56,11 @@ class VideoSender : public RtcpSenderFeedback,
void InsertRawVideoFrame(const scoped_refptr<media::VideoFrame>& video_frame,
const base::TimeTicks& capture_time);
- // Only called from the main cast thread.
- void IncomingRtcpPacket(scoped_ptr<Packet> packet);
-
protected:
// Protected for testability.
- virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback)
- OVERRIDE;
+ void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback);
private:
- // Schedule and execute periodic sending of RTCP report.
- void ScheduleNextRtcpReport();
- void SendRtcpReport(bool schedule_future_reports);
-
// Schedule and execute periodic checks for re-sending packets. If no
// acknowledgements have been received for "too long," VideoSender will
// speculatively re-send certain packets of an unacked frame to kick-start
@@ -92,8 +80,6 @@ class VideoSender : public RtcpSenderFeedback,
void SendEncodedVideoFrame(int requested_bitrate_before_encode,
scoped_ptr<EncodedFrame> encoded_frame);
- const scoped_refptr<CastEnvironment> cast_environment_;
-
// The total amount of time between a frame's capture/recording on the sender
// and its playback on the receiver (i.e., shown to a user). This is fixed as
// a value large enough to give the system sufficient time to encode,
@@ -102,13 +88,6 @@ class VideoSender : public RtcpSenderFeedback,
// etc.).
const base::TimeDelta target_playout_delay_;
- // Sends encoded frames over the configured transport (e.g., UDP). In
- // Chromium, this could be a proxy that first sends the frames from a renderer
- // process to the browser process over IPC, with the browser process being
- // responsible for "packetizing" the frames and pushing packets into the
- // network layer.
- CastTransportSender* const transport_sender_;
-
// Maximum number of outstanding frames before the encoding and sending of
// new frames shall halt.
const int max_unacked_frames_;
@@ -118,14 +97,6 @@ class VideoSender : public RtcpSenderFeedback,
// a hardware-based encoder.
scoped_ptr<VideoEncoder> video_encoder_;
- // Manages sending/receiving of RTCP packets, including sender/receiver
- // reports.
- Rtcp rtcp_;
-
- // Records lip-sync (i.e., mapping of RTP <--> NTP timestamps), and
- // extrapolates this mapping to any other point in time.
- RtpTimestampHelper rtp_timestamp_helper_;
-
// Counts how many RTCP reports are being "aggressively" sent (i.e., one per
// frame) at the start of the session. Once a threshold is reached, RTCP
// reports are instead sent at the configured interval + random drift.
diff --git a/media/cast/sender/video_sender_unittest.cc b/media/cast/sender/video_sender_unittest.cc
index bccc248..8ae3ca3 100644
--- a/media/cast/sender/video_sender_unittest.cc
+++ b/media/cast/sender/video_sender_unittest.cc
@@ -15,6 +15,7 @@
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/cast_transport_sender_impl.h"
#include "media/cast/net/pacing/paced_sender.h"
+#include "media/cast/net/rtcp/rtcp_receiver.h"
#include "media/cast/sender/video_sender.h"
#include "media/cast/test/fake_single_thread_task_runner.h"
#include "media/cast/test/fake_video_encode_accelerator.h"
@@ -66,7 +67,7 @@ class TestPacketSender : public PacketSender {
callback_ = cb;
return false;
}
- if (Rtcp::IsRtcpPacket(&packet->data[0], packet->data.size())) {
+ if (RtcpReceiver::IsRtcpPacket(&packet->data[0], packet->data.size())) {
++number_of_rtcp_packets_;
} else {
// Check that at least one RTCP packet was sent before the first RTP
@@ -272,8 +273,8 @@ TEST_F(VideoSenderTest, RtcpTimer) {
EXPECT_LE(1, transport_.number_of_rtcp_packets());
// Build Cast msg and expect RTCP packet.
RtcpCastMessage cast_feedback(1);
- cast_feedback.media_ssrc_ = 2;
- cast_feedback.ack_frame_id_ = 0;
+ cast_feedback.media_ssrc = 2;
+ cast_feedback.ack_frame_id = 0;
video_sender_->OnReceivedCastFeedback(cast_feedback);
RunTasks(max_rtcp_timeout.InMilliseconds());
EXPECT_LE(1, transport_.number_of_rtcp_packets());
@@ -289,8 +290,8 @@ TEST_F(VideoSenderTest, ResendTimer) {
// ACK the key frame.
RtcpCastMessage cast_feedback(1);
- cast_feedback.media_ssrc_ = 2;
- cast_feedback.ack_frame_id_ = 0;
+ cast_feedback.media_ssrc = 2;
+ cast_feedback.ack_frame_id = 0;
video_sender_->OnReceivedCastFeedback(cast_feedback);
video_frame = GetNewVideoFrame();
@@ -324,7 +325,7 @@ TEST_F(VideoSenderTest, LogAckReceivedEvent) {
task_runner_->RunTasks();
RtcpCastMessage cast_feedback(1);
- cast_feedback.ack_frame_id_ = num_frames - 1;
+ cast_feedback.ack_frame_id = num_frames - 1;
video_sender_->OnReceivedCastFeedback(cast_feedback);
@@ -370,8 +371,8 @@ TEST_F(VideoSenderTest, StopSendingInTheAbsenceOfAck) {
// Start acking and make sure we're back to steady-state.
RtcpCastMessage cast_feedback(1);
- cast_feedback.media_ssrc_ = 2;
- cast_feedback.ack_frame_id_ = 0;
+ cast_feedback.media_ssrc = 2;
+ cast_feedback.ack_frame_id = 0;
video_sender_->OnReceivedCastFeedback(cast_feedback);
EXPECT_LE(
4,
@@ -391,8 +392,8 @@ TEST_F(VideoSenderTest, DuplicateAckRetransmit) {
video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
RunTasks(33);
RtcpCastMessage cast_feedback(1);
- cast_feedback.media_ssrc_ = 2;
- cast_feedback.ack_frame_id_ = 0;
+ cast_feedback.media_ssrc = 2;
+ cast_feedback.ack_frame_id = 0;
// Send 3 more frames but don't ACK.
for (int i = 0; i < 3; ++i) {
@@ -405,11 +406,11 @@ TEST_F(VideoSenderTest, DuplicateAckRetransmit) {
// Send duplicated ACKs and mix some invalid NACKs.
for (int i = 0; i < 10; ++i) {
RtcpCastMessage ack_feedback(1);
- ack_feedback.media_ssrc_ = 2;
- ack_feedback.ack_frame_id_ = 0;
+ ack_feedback.media_ssrc = 2;
+ ack_feedback.ack_frame_id = 0;
RtcpCastMessage nack_feedback(1);
- nack_feedback.media_ssrc_ = 2;
- nack_feedback.missing_frames_and_packets_[255] = PacketIdSet();
+ nack_feedback.media_ssrc = 2;
+ nack_feedback.missing_frames_and_packets[255] = PacketIdSet();
video_sender_->OnReceivedCastFeedback(ack_feedback);
video_sender_->OnReceivedCastFeedback(nack_feedback);
}
@@ -418,8 +419,8 @@ TEST_F(VideoSenderTest, DuplicateAckRetransmit) {
// Re-transmit one packet because of duplicated ACKs.
for (int i = 0; i < 3; ++i) {
RtcpCastMessage ack_feedback(1);
- ack_feedback.media_ssrc_ = 2;
- ack_feedback.ack_frame_id_ = 0;
+ ack_feedback.media_ssrc = 2;
+ ack_feedback.ack_frame_id = 0;
video_sender_->OnReceivedCastFeedback(ack_feedback);
}
EXPECT_EQ(number_of_packets_sent + 1, transport_.number_of_rtp_packets());
@@ -431,8 +432,8 @@ TEST_F(VideoSenderTest, DuplicateAckRetransmitDoesNotCancelRetransmits) {
video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
RunTasks(33);
RtcpCastMessage cast_feedback(1);
- cast_feedback.media_ssrc_ = 2;
- cast_feedback.ack_frame_id_ = 0;
+ cast_feedback.media_ssrc = 2;
+ cast_feedback.ack_frame_id = 0;
// Send 2 more frames but don't ACK.
for (int i = 0; i < 2; ++i) {
@@ -453,11 +454,11 @@ TEST_F(VideoSenderTest, DuplicateAckRetransmitDoesNotCancelRetransmits) {
// Send duplicated ACKs and mix some invalid NACKs.
for (int i = 0; i < 10; ++i) {
RtcpCastMessage ack_feedback(1);
- ack_feedback.media_ssrc_ = 2;
- ack_feedback.ack_frame_id_ = 0;
+ ack_feedback.media_ssrc = 2;
+ ack_feedback.ack_frame_id = 0;
RtcpCastMessage nack_feedback(1);
- nack_feedback.media_ssrc_ = 2;
- nack_feedback.missing_frames_and_packets_[255] = PacketIdSet();
+ nack_feedback.media_ssrc = 2;
+ nack_feedback.missing_frames_and_packets[255] = PacketIdSet();
video_sender_->OnReceivedCastFeedback(ack_feedback);
video_sender_->OnReceivedCastFeedback(nack_feedback);
}
@@ -466,8 +467,8 @@ TEST_F(VideoSenderTest, DuplicateAckRetransmitDoesNotCancelRetransmits) {
// Re-transmit one packet because of duplicated ACKs.
for (int i = 0; i < 3; ++i) {
RtcpCastMessage ack_feedback(1);
- ack_feedback.media_ssrc_ = 2;
- ack_feedback.ack_frame_id_ = 0;
+ ack_feedback.media_ssrc = 2;
+ ack_feedback.ack_frame_id = 0;
video_sender_->OnReceivedCastFeedback(ack_feedback);
}
@@ -485,8 +486,8 @@ TEST_F(VideoSenderTest, AcksCancelRetransmits) {
// Frame should be in buffer, waiting. Now let's ack it.
RtcpCastMessage cast_feedback(1);
- cast_feedback.media_ssrc_ = 2;
- cast_feedback.ack_frame_id_ = 0;
+ cast_feedback.media_ssrc = 2;
+ cast_feedback.ack_frame_id = 0;
video_sender_->OnReceivedCastFeedback(cast_feedback);
transport_.SetPause(false);
@@ -508,11 +509,11 @@ TEST_F(VideoSenderTest, NAcksCancelRetransmits) {
// Frames should be in buffer, waiting. Now let's ack the first one and nack
// one packet in the second one.
RtcpCastMessage cast_feedback(1);
- cast_feedback.media_ssrc_ = 2;
- cast_feedback.ack_frame_id_ = 0;
+ cast_feedback.media_ssrc = 2;
+ cast_feedback.ack_frame_id = 0;
PacketIdSet missing_packets;
missing_packets.insert(0);
- cast_feedback.missing_frames_and_packets_[1] = missing_packets;
+ cast_feedback.missing_frames_and_packets[1] = missing_packets;
video_sender_->OnReceivedCastFeedback(cast_feedback);
transport_.SetPause(false);
diff --git a/media/cast/test/cast_benchmarks.cc b/media/cast/test/cast_benchmarks.cc
index a2483fa..57806b3 100644
--- a/media/cast/test/cast_benchmarks.cc
+++ b/media/cast/test/cast_benchmarks.cc
@@ -89,7 +89,8 @@ void VideoInitializationStatus(CastInitializationStatus status) {
EXPECT_EQ(STATUS_VIDEO_INITIALIZED, status);
}
-void IgnoreRawEvents(const std::vector<PacketEvent>& packet_events) {
+void IgnoreRawEvents(const std::vector<PacketEvent>& packet_events,
+ const std::vector<FrameEvent>& frame_events) {
}
} // namespace
@@ -108,18 +109,17 @@ class CastTransportSenderWrapper : public CastTransportSender {
}
virtual void InitializeAudio(
- const CastTransportRtpConfig& config) OVERRIDE {
- transport_->InitializeAudio(config);
+ const CastTransportRtpConfig& config,
+ const RtcpCastMessageCallback& cast_message_cb,
+ const RtcpRttCallback& rtt_cb) OVERRIDE {
+ transport_->InitializeAudio(config, cast_message_cb, rtt_cb);
}
virtual void InitializeVideo(
- const CastTransportRtpConfig& config) OVERRIDE {
- transport_->InitializeVideo(config);
- }
-
- virtual void SetPacketReceiver(
- const PacketReceiverCallback& packet_receiver) OVERRIDE {
- transport_->SetPacketReceiver(packet_receiver);
+ const CastTransportRtpConfig& config,
+ const RtcpCastMessageCallback& cast_message_cb,
+ const RtcpRttCallback& rtt_cb) OVERRIDE {
+ transport_->InitializeVideo(config, cast_message_cb, rtt_cb);
}
virtual void InsertCodedAudioFrame(
@@ -134,20 +134,13 @@ class CastTransportSenderWrapper : public CastTransportSender {
transport_->InsertCodedVideoFrame(video_frame);
}
- virtual void SendRtcpFromRtpSender(uint32 packet_type_flags,
- uint32 ntp_seconds,
- uint32 ntp_fraction,
- uint32 rtp_timestamp,
- const RtcpDlrrReportBlock& dlrr,
- uint32 sending_ssrc,
- const std::string& c_name) OVERRIDE {
- transport_->SendRtcpFromRtpSender(packet_type_flags,
- ntp_seconds,
- ntp_fraction,
- rtp_timestamp,
- dlrr,
- sending_ssrc,
- c_name);
+ virtual void SendSenderReport(
+ uint32 ssrc,
+ base::TimeTicks current_time,
+ uint32 current_time_as_rtp_timestamp) OVERRIDE {
+ transport_->SendSenderReport(ssrc,
+ current_time,
+ current_time_as_rtp_timestamp);
}
// Retransmission request.
@@ -160,6 +153,10 @@ class CastTransportSenderWrapper : public CastTransportSender {
is_audio, missing_packets, cancel_rtx_if_not_in_list, dedupe_window);
}
+ virtual PacketReceiverCallback PacketReceiverForTesting() OVERRIDE {
+ return transport_->PacketReceiverForTesting();
+ }
+
private:
scoped_ptr<CastTransportSender> transport_;
uint64* encoded_video_bytes_;
@@ -298,17 +295,18 @@ class RunOneBenchmark {
video_receiver_config_,
&receiver_to_sender_);
net::IPEndPoint dummy_endpoint;
- transport_sender_.Init(new CastTransportSenderImpl(
- NULL,
- testing_clock_sender_,
- dummy_endpoint,
- base::Bind(&UpdateCastTransportStatus),
- base::Bind(&IgnoreRawEvents),
- base::TimeDelta::FromSeconds(1),
- task_runner_sender_,
- &sender_to_receiver_),
- &video_bytes_encoded_,
- &audio_bytes_encoded_);
+ transport_sender_.Init(
+ new CastTransportSenderImpl(
+ NULL,
+ testing_clock_sender_,
+ dummy_endpoint,
+ base::Bind(&UpdateCastTransportStatus),
+ base::Bind(&IgnoreRawEvents),
+ base::TimeDelta::FromSeconds(1),
+ task_runner_sender_,
+ &sender_to_receiver_),
+ &video_bytes_encoded_,
+ &audio_bytes_encoded_);
cast_sender_ =
CastSender::Create(cast_environment_sender_, &transport_sender_);
@@ -322,7 +320,8 @@ class RunOneBenchmark {
CreateDefaultVideoEncodeMemoryCallback());
receiver_to_sender_.Initialize(
- CreateSimplePipe(p).Pass(), cast_sender_->packet_receiver(),
+ CreateSimplePipe(p).Pass(),
+ transport_sender_.PacketReceiverForTesting(),
task_runner_, &testing_clock_);
sender_to_receiver_.Initialize(
CreateSimplePipe(p).Pass(), cast_receiver_->packet_receiver(),
diff --git a/media/cast/test/end2end_unittest.cc b/media/cast/test/end2end_unittest.cc
index a1d4a3a..bfd9fab 100644
--- a/media/cast/test/end2end_unittest.cc
+++ b/media/cast/test/end2end_unittest.cc
@@ -588,7 +588,7 @@ class End2EndTest : public ::testing::Test {
dummy_endpoint,
base::Bind(&UpdateCastTransportStatus),
base::Bind(&End2EndTest::LogRawEvents, base::Unretained(this)),
- base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromMilliseconds(1),
task_runner_sender_,
&sender_to_receiver_));
@@ -603,9 +603,10 @@ class End2EndTest : public ::testing::Test {
CreateDefaultVideoEncodeAcceleratorCallback(),
CreateDefaultVideoEncodeMemoryCallback());
- receiver_to_sender_.SetPacketReceiver(cast_sender_->packet_receiver(),
- task_runner_,
- &testing_clock_);
+ receiver_to_sender_.SetPacketReceiver(
+ transport_sender_->PacketReceiverForTesting(),
+ task_runner_,
+ &testing_clock_);
sender_to_receiver_.SetPacketReceiver(cast_receiver_->packet_receiver(),
task_runner_,
&testing_clock_);
@@ -715,8 +716,8 @@ class End2EndTest : public ::testing::Test {
base::Unretained(this)));
}
- void LogRawEvents(const std::vector<PacketEvent>& packet_events) {
- EXPECT_FALSE(packet_events.empty());
+ void LogRawEvents(const std::vector<PacketEvent>& packet_events,
+ const std::vector<FrameEvent>& frame_events) {
for (std::vector<media::cast::PacketEvent>::const_iterator it =
packet_events.begin();
it != packet_events.end();
@@ -730,6 +731,16 @@ class End2EndTest : public ::testing::Test {
it->max_packet_id,
it->size);
}
+ for (std::vector<media::cast::FrameEvent>::const_iterator it =
+ frame_events.begin();
+ it != frame_events.end();
+ ++it) {
+ cast_environment_sender_->Logging()->InsertFrameEvent(it->timestamp,
+ it->type,
+ it->media_type,
+ it->rtp_timestamp,
+ it->frame_id);
+ }
}
FrameReceiverConfig audio_receiver_config_;
@@ -1254,14 +1265,14 @@ TEST_F(End2EndTest, VideoLogging) {
total_event_count_for_packet += map_it->second.counter[i];
}
- int expected_event_count_for_packet = 0;
EXPECT_GT(map_it->second.counter[PACKET_RECEIVED], 0);
- expected_event_count_for_packet +=
- map_it->second.counter[PACKET_RECEIVED];
+ int packets_received = map_it->second.counter[PACKET_RECEIVED];
+ int packets_sent = map_it->second.counter[PACKET_SENT_TO_NETWORK];
+ EXPECT_EQ(packets_sent, packets_received);
// Verify that there were no other events logged with respect to this
- // packet. (i.e. Total event count = expected event count)
- EXPECT_EQ(total_event_count_for_packet, expected_event_count_for_packet);
+ // packet. (i.e. Total event count = packets sent + packets received)
+ EXPECT_EQ(packets_received + packets_sent, total_event_count_for_packet);
}
}
diff --git a/media/cast/test/sender.cc b/media/cast/test/sender.cc
index 6f9074f..0ce23c8 100644
--- a/media/cast/test/sender.cc
+++ b/media/cast/test/sender.cc
@@ -123,7 +123,8 @@ void UpdateCastTransportStatus(
void LogRawEvents(
const scoped_refptr<media::cast::CastEnvironment>& cast_environment,
- const std::vector<media::cast::PacketEvent>& packet_events) {
+ const std::vector<media::cast::PacketEvent>& packet_events,
+ const std::vector<media::cast::FrameEvent>& frame_events) {
VLOG(1) << "Got packet events from transport, size: " << packet_events.size();
for (std::vector<media::cast::PacketEvent>::const_iterator it =
packet_events.begin();
@@ -138,6 +139,17 @@ void LogRawEvents(
it->max_packet_id,
it->size);
}
+ VLOG(1) << "Got frame events from transport, size: " << frame_events.size();
+ for (std::vector<media::cast::FrameEvent>::const_iterator it =
+ frame_events.begin();
+ it != frame_events.end();
+ ++it) {
+ cast_environment->Logging()->InsertFrameEvent(it->timestamp,
+ it->type,
+ it->media_type,
+ it->rtp_timestamp,
+ it->frame_id);
+ }
}
void InitializationResult(media::cast::CastInitializationStatus result) {
@@ -327,7 +339,6 @@ int main(int argc, char** argv) {
media::cast::CreateDefaultVideoEncodeAcceleratorCallback(),
media::cast::CreateDefaultVideoEncodeMemoryCallback());
cast_sender->InitializeAudio(audio_config, base::Bind(&InitializationResult));
- transport_sender->SetPacketReceiver(cast_sender->packet_receiver());
// Set up event subscribers.
scoped_ptr<media::cast::EncodingEventSubscriber> video_event_subscriber;
diff --git a/media/cast/test/simulator.cc b/media/cast/test/simulator.cc
index 43b3a02..27812c3 100644
--- a/media/cast/test/simulator.cc
+++ b/media/cast/test/simulator.cc
@@ -85,7 +85,8 @@ void VideoInitializationStatus(CastInitializationStatus status) {
}
void LogTransportEvents(const scoped_refptr<CastEnvironment>& env,
- const std::vector<PacketEvent>& packet_events) {
+ const std::vector<PacketEvent>& packet_events,
+ const std::vector<FrameEvent>& frame_events) {
for (std::vector<media::cast::PacketEvent>::const_iterator it =
packet_events.begin();
it != packet_events.end();
@@ -99,6 +100,16 @@ void LogTransportEvents(const scoped_refptr<CastEnvironment>& env,
it->max_packet_id,
it->size);
}
+ for (std::vector<media::cast::FrameEvent>::const_iterator it =
+ frame_events.begin();
+ it != frame_events.end();
+ ++it) {
+ env->Logging()->InsertFrameEvent(it->timestamp,
+ it->type,
+ it->media_type,
+ it->rtp_timestamp,
+ it->frame_id);
+ }
}
void GotVideoFrame(
@@ -265,8 +276,8 @@ void RunSimulation(const base::FilePath& source_path,
// Connect sender to receiver. This initializes the pipe.
receiver_to_sender.Initialize(
- ipp.NewBuffer(128 * 1024), cast_sender->packet_receiver(), task_runner,
- &testing_clock);
+ ipp.NewBuffer(128 * 1024), transport_sender->PacketReceiverForTesting(),
+ task_runner, &testing_clock);
sender_to_receiver.Initialize(
ipp.NewBuffer(128 * 1024), cast_receiver->packet_receiver(), task_runner,
&testing_clock);