Adding a memory pressure observer for ChromeOS.
[chromium-blink-merge.git] / media / cast / net / cast_transport_sender_impl.cc
blob390180f131e907a66dd80ce592b324ac5ea5af91
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/cast/net/cast_transport_sender_impl.h"
7 #include "base/single_thread_task_runner.h"
8 #include "base/values.h"
9 #include "media/cast/net/cast_transport_config.h"
10 #include "media/cast/net/cast_transport_defines.h"
11 #include "media/cast/net/udp_transport.h"
12 #include "net/base/net_errors.h"
13 #include "net/base/net_util.h"
15 namespace media {
16 namespace cast {
18 namespace {
20 // See header file for what these mean.
21 const char kOptionPacerTargetBurstSize[] = "pacer_target_burst_size";
22 const char kOptionPacerMaxBurstSize[] = "pacer_max_burst_size";
23 const char kOptionSendBufferMinSize[] = "send_buffer_min_size";
24 const char kOptionDscp[] = "DSCP";
25 const char kOptionWifiDisableScan[] = "disable_wifi_scan";
26 const char kOptionWifiMediaStreamingMode[] = "media_streaming_mode";
28 int LookupOptionWithDefault(const base::DictionaryValue& options,
29 const std::string& path,
30 int default_value) {
31 int ret;
32 if (options.GetInteger(path, &ret)) {
33 return ret;
34 } else {
35 return default_value;
39 int32 GetTransportSendBufferSize(const base::DictionaryValue& options) {
40 // Socket send buffer size needs to be at least greater than one burst
41 // size.
42 int32 max_burst_size =
43 LookupOptionWithDefault(options, kOptionPacerMaxBurstSize,
44 kMaxBurstSize) * kMaxIpPacketSize;
45 int32 min_send_buffer_size =
46 LookupOptionWithDefault(options, kOptionSendBufferMinSize, 0);
47 return std::max(max_burst_size, min_send_buffer_size);
50 } // namespace
52 scoped_ptr<CastTransportSender> CastTransportSender::Create(
53 net::NetLog* net_log,
54 base::TickClock* clock,
55 const net::IPEndPoint& remote_end_point,
56 scoped_ptr<base::DictionaryValue> options,
57 const CastTransportStatusCallback& status_callback,
58 const BulkRawEventsCallback& raw_events_callback,
59 base::TimeDelta raw_events_callback_interval,
60 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner) {
61 return scoped_ptr<CastTransportSender>(
62 new CastTransportSenderImpl(net_log,
63 clock,
64 remote_end_point,
65 options.Pass(),
66 status_callback,
67 raw_events_callback,
68 raw_events_callback_interval,
69 transport_task_runner.get(),
70 NULL));
73 PacketReceiverCallback CastTransportSender::PacketReceiverForTesting() {
74 return PacketReceiverCallback();
77 CastTransportSenderImpl::CastTransportSenderImpl(
78 net::NetLog* net_log,
79 base::TickClock* clock,
80 const net::IPEndPoint& remote_end_point,
81 scoped_ptr<base::DictionaryValue> options,
82 const CastTransportStatusCallback& status_callback,
83 const BulkRawEventsCallback& raw_events_callback,
84 base::TimeDelta raw_events_callback_interval,
85 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner,
86 PacketSender* external_transport)
87 : clock_(clock),
88 status_callback_(status_callback),
89 transport_task_runner_(transport_task_runner),
90 transport_(
91 external_transport ?
92 NULL :
93 new UdpTransport(net_log,
94 transport_task_runner,
95 net::IPEndPoint(),
96 remote_end_point,
97 GetTransportSendBufferSize(*options),
98 status_callback)),
99 pacer_(LookupOptionWithDefault(*options,
100 kOptionPacerTargetBurstSize,
101 kTargetBurstSize),
102 LookupOptionWithDefault(*options,
103 kOptionPacerMaxBurstSize,
104 kMaxBurstSize),
105 clock,
106 &logging_,
107 external_transport ? external_transport : transport_.get(),
108 transport_task_runner),
109 raw_events_callback_(raw_events_callback),
110 raw_events_callback_interval_(raw_events_callback_interval),
111 last_byte_acked_for_audio_(0),
112 weak_factory_(this) {
113 DCHECK(clock_);
114 if (!raw_events_callback_.is_null()) {
115 DCHECK(raw_events_callback_interval > base::TimeDelta());
116 event_subscriber_.reset(new SimpleEventSubscriber);
117 logging_.AddRawEventSubscriber(event_subscriber_.get());
118 transport_task_runner->PostDelayedTask(
119 FROM_HERE,
120 base::Bind(&CastTransportSenderImpl::SendRawEvents,
121 weak_factory_.GetWeakPtr()),
122 raw_events_callback_interval);
124 if (transport_) {
125 if (options->HasKey(kOptionDscp)) {
126 // The default DSCP value for cast is AF41. Which gives it a higher
127 // priority over other traffic.
128 transport_->SetDscp(net::DSCP_AF41);
130 transport_->StartReceiving(
131 base::Bind(&CastTransportSenderImpl::OnReceivedPacket,
132 weak_factory_.GetWeakPtr()));
133 int wifi_options = 0;
134 if (options->HasKey(kOptionWifiDisableScan)) {
135 wifi_options |= net::WIFI_OPTIONS_DISABLE_SCAN;
137 if (options->HasKey(kOptionWifiMediaStreamingMode)) {
138 wifi_options |= net::WIFI_OPTIONS_MEDIA_STREAMING_MODE;
140 if (wifi_options) {
141 wifi_options_autoreset_ = net::SetWifiOptions(wifi_options);
146 CastTransportSenderImpl::~CastTransportSenderImpl() {
147 if (event_subscriber_.get())
148 logging_.RemoveRawEventSubscriber(event_subscriber_.get());
151 void CastTransportSenderImpl::InitializeAudio(
152 const CastTransportRtpConfig& config,
153 const RtcpCastMessageCallback& cast_message_cb,
154 const RtcpRttCallback& rtt_cb) {
155 LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty())
156 << "Unsafe to send audio with encryption DISABLED.";
157 if (!audio_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) {
158 status_callback_.Run(TRANSPORT_AUDIO_UNINITIALIZED);
159 return;
162 audio_sender_.reset(new RtpSender(clock_, transport_task_runner_, &pacer_));
163 if (audio_sender_->Initialize(config)) {
164 // Audio packets have a higher priority.
165 pacer_.RegisterAudioSsrc(config.ssrc);
166 pacer_.RegisterPrioritySsrc(config.ssrc);
167 status_callback_.Run(TRANSPORT_AUDIO_INITIALIZED);
168 } else {
169 audio_sender_.reset();
170 status_callback_.Run(TRANSPORT_AUDIO_UNINITIALIZED);
171 return;
174 audio_rtcp_session_.reset(
175 new Rtcp(base::Bind(&CastTransportSenderImpl::OnReceivedCastMessage,
176 weak_factory_.GetWeakPtr(), config.ssrc,
177 cast_message_cb),
178 rtt_cb,
179 base::Bind(&CastTransportSenderImpl::OnReceivedLogMessage,
180 weak_factory_.GetWeakPtr(), AUDIO_EVENT),
181 clock_,
182 &pacer_,
183 config.ssrc,
184 config.feedback_ssrc));
185 pacer_.RegisterAudioSsrc(config.ssrc);
186 status_callback_.Run(TRANSPORT_AUDIO_INITIALIZED);
189 void CastTransportSenderImpl::InitializeVideo(
190 const CastTransportRtpConfig& config,
191 const RtcpCastMessageCallback& cast_message_cb,
192 const RtcpRttCallback& rtt_cb) {
193 LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty())
194 << "Unsafe to send video with encryption DISABLED.";
195 if (!video_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) {
196 status_callback_.Run(TRANSPORT_VIDEO_UNINITIALIZED);
197 return;
200 video_sender_.reset(new RtpSender(clock_, transport_task_runner_, &pacer_));
201 if (!video_sender_->Initialize(config)) {
202 video_sender_.reset();
203 status_callback_.Run(TRANSPORT_VIDEO_UNINITIALIZED);
204 return;
207 video_rtcp_session_.reset(
208 new Rtcp(base::Bind(&CastTransportSenderImpl::OnReceivedCastMessage,
209 weak_factory_.GetWeakPtr(), config.ssrc,
210 cast_message_cb),
211 rtt_cb,
212 base::Bind(&CastTransportSenderImpl::OnReceivedLogMessage,
213 weak_factory_.GetWeakPtr(), VIDEO_EVENT),
214 clock_,
215 &pacer_,
216 config.ssrc,
217 config.feedback_ssrc));
218 pacer_.RegisterVideoSsrc(config.ssrc);
219 status_callback_.Run(TRANSPORT_VIDEO_INITIALIZED);
222 namespace {
223 void EncryptAndSendFrame(const EncodedFrame& frame,
224 TransportEncryptionHandler* encryptor,
225 RtpSender* sender) {
226 if (encryptor->is_activated()) {
227 EncodedFrame encrypted_frame;
228 frame.CopyMetadataTo(&encrypted_frame);
229 if (encryptor->Encrypt(frame.frame_id, frame.data, &encrypted_frame.data)) {
230 sender->SendFrame(encrypted_frame);
231 } else {
232 LOG(ERROR) << "Encryption failed. Not sending frame with ID "
233 << frame.frame_id;
235 } else {
236 sender->SendFrame(frame);
239 } // namespace
241 void CastTransportSenderImpl::InsertFrame(uint32 ssrc,
242 const EncodedFrame& frame) {
243 if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
244 EncryptAndSendFrame(frame, &audio_encryptor_, audio_sender_.get());
245 } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
246 EncryptAndSendFrame(frame, &video_encryptor_, video_sender_.get());
247 } else {
248 NOTREACHED() << "Invalid InsertFrame call.";
252 void CastTransportSenderImpl::SendSenderReport(
253 uint32 ssrc,
254 base::TimeTicks current_time,
255 uint32 current_time_as_rtp_timestamp) {
256 if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
257 audio_rtcp_session_->SendRtcpFromRtpSender(
258 current_time, current_time_as_rtp_timestamp,
259 audio_sender_->send_packet_count(), audio_sender_->send_octet_count());
260 } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
261 video_rtcp_session_->SendRtcpFromRtpSender(
262 current_time, current_time_as_rtp_timestamp,
263 video_sender_->send_packet_count(), video_sender_->send_octet_count());
264 } else {
265 NOTREACHED() << "Invalid request for sending RTCP packet.";
269 void CastTransportSenderImpl::CancelSendingFrames(
270 uint32 ssrc,
271 const std::vector<uint32>& frame_ids) {
272 if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
273 audio_sender_->CancelSendingFrames(frame_ids);
274 } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
275 video_sender_->CancelSendingFrames(frame_ids);
276 } else {
277 NOTREACHED() << "Invalid request for cancel sending.";
281 void CastTransportSenderImpl::ResendFrameForKickstart(uint32 ssrc,
282 uint32 frame_id) {
283 if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
284 DCHECK(audio_rtcp_session_);
285 audio_sender_->ResendFrameForKickstart(
286 frame_id,
287 audio_rtcp_session_->current_round_trip_time());
288 } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
289 DCHECK(video_rtcp_session_);
290 video_sender_->ResendFrameForKickstart(
291 frame_id,
292 video_rtcp_session_->current_round_trip_time());
293 } else {
294 NOTREACHED() << "Invalid request for kickstart.";
298 void CastTransportSenderImpl::ResendPackets(
299 uint32 ssrc,
300 const MissingFramesAndPacketsMap& missing_packets,
301 bool cancel_rtx_if_not_in_list,
302 const DedupInfo& dedup_info) {
303 if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
304 audio_sender_->ResendPackets(missing_packets,
305 cancel_rtx_if_not_in_list,
306 dedup_info);
307 } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
308 video_sender_->ResendPackets(missing_packets,
309 cancel_rtx_if_not_in_list,
310 dedup_info);
311 } else {
312 NOTREACHED() << "Invalid request for retransmission.";
316 PacketReceiverCallback CastTransportSenderImpl::PacketReceiverForTesting() {
317 return base::Bind(&CastTransportSenderImpl::OnReceivedPacket,
318 weak_factory_.GetWeakPtr());
321 void CastTransportSenderImpl::SendRawEvents() {
322 DCHECK(event_subscriber_.get());
323 DCHECK(!raw_events_callback_.is_null());
324 std::vector<PacketEvent> packet_events;
325 std::vector<FrameEvent> frame_events;
326 event_subscriber_->GetPacketEventsAndReset(&packet_events);
327 event_subscriber_->GetFrameEventsAndReset(&frame_events);
328 raw_events_callback_.Run(packet_events, frame_events);
330 transport_task_runner_->PostDelayedTask(
331 FROM_HERE,
332 base::Bind(&CastTransportSenderImpl::SendRawEvents,
333 weak_factory_.GetWeakPtr()),
334 raw_events_callback_interval_);
337 void CastTransportSenderImpl::OnReceivedPacket(scoped_ptr<Packet> packet) {
338 if (audio_rtcp_session_ &&
339 audio_rtcp_session_->IncomingRtcpPacket(&packet->front(),
340 packet->size())) {
341 return;
343 if (video_rtcp_session_ &&
344 video_rtcp_session_->IncomingRtcpPacket(&packet->front(),
345 packet->size())) {
346 return;
348 VLOG(1) << "Stale packet received.";
351 void CastTransportSenderImpl::OnReceivedLogMessage(
352 EventMediaType media_type,
353 const RtcpReceiverLogMessage& log) {
354 // Add received log messages into our log system.
355 RtcpReceiverLogMessage::const_iterator it = log.begin();
356 for (; it != log.end(); ++it) {
357 uint32 rtp_timestamp = it->rtp_timestamp_;
359 RtcpReceiverEventLogMessages::const_iterator event_it =
360 it->event_log_messages_.begin();
361 for (; event_it != it->event_log_messages_.end(); ++event_it) {
362 switch (event_it->type) {
363 case PACKET_RECEIVED:
364 logging_.InsertPacketEvent(
365 event_it->event_timestamp, event_it->type,
366 media_type, rtp_timestamp,
367 kFrameIdUnknown, event_it->packet_id, 0, 0);
368 break;
369 case FRAME_ACK_SENT:
370 case FRAME_DECODED:
371 logging_.InsertFrameEvent(
372 event_it->event_timestamp, event_it->type, media_type,
373 rtp_timestamp, kFrameIdUnknown);
374 break;
375 case FRAME_PLAYOUT:
376 logging_.InsertFrameEventWithDelay(
377 event_it->event_timestamp, event_it->type, media_type,
378 rtp_timestamp, kFrameIdUnknown, event_it->delay_delta);
379 break;
380 default:
381 VLOG(2) << "Received log message via RTCP that we did not expect: "
382 << static_cast<int>(event_it->type);
383 break;
389 void CastTransportSenderImpl::OnReceivedCastMessage(
390 uint32 ssrc,
391 const RtcpCastMessageCallback& cast_message_cb,
392 const RtcpCastMessage& cast_message) {
393 if (!cast_message_cb.is_null())
394 cast_message_cb.Run(cast_message);
396 DedupInfo dedup_info;
397 if (audio_sender_ && audio_sender_->ssrc() == ssrc) {
398 const int64 acked_bytes =
399 audio_sender_->GetLastByteSentForFrame(cast_message.ack_frame_id);
400 last_byte_acked_for_audio_ =
401 std::max(acked_bytes, last_byte_acked_for_audio_);
402 } else if (video_sender_ && video_sender_->ssrc() == ssrc) {
403 dedup_info.resend_interval = video_rtcp_session_->current_round_trip_time();
405 // Only use audio stream to dedup if there is one.
406 if (audio_sender_) {
407 dedup_info.last_byte_acked_for_audio = last_byte_acked_for_audio_;
411 if (cast_message.missing_frames_and_packets.empty())
412 return;
414 // This call does two things.
415 // 1. Specifies that retransmissions for packets not listed in the set are
416 // cancelled.
417 // 2. Specifies a deduplication window. For video this would be the most
418 // recent RTT. For audio there is no deduplication.
419 ResendPackets(ssrc,
420 cast_message.missing_frames_and_packets,
421 true,
422 dedup_info);
425 } // namespace cast
426 } // namespace media