diff options
Diffstat (limited to 'media')
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); |