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.
4
5 #include "media/cast/net/cast_transport_sender_impl.h"
6
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_util.h"
13
14 namespace media {
15 namespace cast {
16
17 namespace {
LookupOptionWithDefault(const base::DictionaryValue & options,const std::string & path,int default_value)18 int LookupOptionWithDefault(const base::DictionaryValue& options,
19 const std::string& path,
20 int default_value) {
21 int ret;
22 if (options.GetInteger(path, &ret)) {
23 return ret;
24 } else {
25 return default_value;
26 }
27 };
28
29 } // namespace
30
Create(net::NetLog * net_log,base::TickClock * clock,const net::IPEndPoint & remote_end_point,scoped_ptr<base::DictionaryValue> options,const CastTransportStatusCallback & status_callback,const BulkRawEventsCallback & raw_events_callback,base::TimeDelta raw_events_callback_interval,const scoped_refptr<base::SingleThreadTaskRunner> & transport_task_runner)31 scoped_ptr<CastTransportSender> CastTransportSender::Create(
32 net::NetLog* net_log,
33 base::TickClock* clock,
34 const net::IPEndPoint& remote_end_point,
35 scoped_ptr<base::DictionaryValue> options,
36 const CastTransportStatusCallback& status_callback,
37 const BulkRawEventsCallback& raw_events_callback,
38 base::TimeDelta raw_events_callback_interval,
39 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner) {
40 return scoped_ptr<CastTransportSender>(
41 new CastTransportSenderImpl(net_log,
42 clock,
43 remote_end_point,
44 options.Pass(),
45 status_callback,
46 raw_events_callback,
47 raw_events_callback_interval,
48 transport_task_runner.get(),
49 NULL));
50 }
51
PacketReceiverForTesting()52 PacketReceiverCallback CastTransportSender::PacketReceiverForTesting() {
53 return PacketReceiverCallback();
54 }
55
CastTransportSenderImpl(net::NetLog * net_log,base::TickClock * clock,const net::IPEndPoint & remote_end_point,scoped_ptr<base::DictionaryValue> options,const CastTransportStatusCallback & status_callback,const BulkRawEventsCallback & raw_events_callback,base::TimeDelta raw_events_callback_interval,const scoped_refptr<base::SingleThreadTaskRunner> & transport_task_runner,PacketSender * external_transport)56 CastTransportSenderImpl::CastTransportSenderImpl(
57 net::NetLog* net_log,
58 base::TickClock* clock,
59 const net::IPEndPoint& remote_end_point,
60 scoped_ptr<base::DictionaryValue> options,
61 const CastTransportStatusCallback& status_callback,
62 const BulkRawEventsCallback& raw_events_callback,
63 base::TimeDelta raw_events_callback_interval,
64 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner,
65 PacketSender* external_transport)
66 : clock_(clock),
67 status_callback_(status_callback),
68 transport_task_runner_(transport_task_runner),
69 transport_(external_transport ? NULL
70 : new UdpTransport(net_log,
71 transport_task_runner,
72 net::IPEndPoint(),
73 remote_end_point,
74 status_callback)),
75 pacer_(LookupOptionWithDefault(*options.get(),
76 "pacer_target_burst_size",
77 kTargetBurstSize),
78 LookupOptionWithDefault(*options.get(),
79 "pacer_max_burst_size",
80 kMaxBurstSize),
81 clock,
82 &logging_,
83 external_transport ? external_transport : transport_.get(),
84 transport_task_runner),
85 raw_events_callback_(raw_events_callback),
86 raw_events_callback_interval_(raw_events_callback_interval),
87 last_byte_acked_for_audio_(0),
88 weak_factory_(this) {
89 DCHECK(clock_);
90 if (!raw_events_callback_.is_null()) {
91 DCHECK(raw_events_callback_interval > base::TimeDelta());
92 event_subscriber_.reset(new SimpleEventSubscriber);
93 logging_.AddRawEventSubscriber(event_subscriber_.get());
94 transport_task_runner->PostDelayedTask(
95 FROM_HERE,
96 base::Bind(&CastTransportSenderImpl::SendRawEvents,
97 weak_factory_.GetWeakPtr()),
98 raw_events_callback_interval);
99 }
100 if (transport_) {
101 if (options->HasKey("DSCP")) {
102 // The default DSCP value for cast is AF41. Which gives it a higher
103 // priority over other traffic.
104 transport_->SetDscp(net::DSCP_AF41);
105 }
106 transport_->StartReceiving(
107 base::Bind(&CastTransportSenderImpl::OnReceivedPacket,
108 weak_factory_.GetWeakPtr()));
109 int wifi_options = 0;
110 if (options->HasKey("disable_wifi_scan")) {
111 wifi_options |= net::WIFI_OPTIONS_DISABLE_SCAN;
112 }
113 if (options->HasKey("media_streaming_mode")) {
114 wifi_options |= net::WIFI_OPTIONS_MEDIA_STREAMING_MODE;
115 }
116 if (wifi_options) {
117 wifi_options_autoreset_ = net::SetWifiOptions(wifi_options);
118 }
119 }
120 }
121
~CastTransportSenderImpl()122 CastTransportSenderImpl::~CastTransportSenderImpl() {
123 if (event_subscriber_.get())
124 logging_.RemoveRawEventSubscriber(event_subscriber_.get());
125 }
126
InitializeAudio(const CastTransportRtpConfig & config,const RtcpCastMessageCallback & cast_message_cb,const RtcpRttCallback & rtt_cb)127 void CastTransportSenderImpl::InitializeAudio(
128 const CastTransportRtpConfig& config,
129 const RtcpCastMessageCallback& cast_message_cb,
130 const RtcpRttCallback& rtt_cb) {
131 LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty())
132 << "Unsafe to send audio with encryption DISABLED.";
133 if (!audio_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) {
134 status_callback_.Run(TRANSPORT_AUDIO_UNINITIALIZED);
135 return;
136 }
137
138 audio_sender_.reset(new RtpSender(clock_, transport_task_runner_, &pacer_));
139 if (audio_sender_->Initialize(config)) {
140 // Audio packets have a higher priority.
141 pacer_.RegisterAudioSsrc(config.ssrc);
142 pacer_.RegisterPrioritySsrc(config.ssrc);
143 status_callback_.Run(TRANSPORT_AUDIO_INITIALIZED);
144 } else {
145 audio_sender_.reset();
146 status_callback_.Run(TRANSPORT_AUDIO_UNINITIALIZED);
147 return;
148 }
149
150 audio_rtcp_session_.reset(
151 new Rtcp(base::Bind(&CastTransportSenderImpl::OnReceivedCastMessage,
152 weak_factory_.GetWeakPtr(), config.ssrc,
153 cast_message_cb),
154 rtt_cb,
155 base::Bind(&CastTransportSenderImpl::OnReceivedLogMessage,
156 weak_factory_.GetWeakPtr(), AUDIO_EVENT),
157 clock_,
158 &pacer_,
159 config.ssrc,
160 config.feedback_ssrc));
161 pacer_.RegisterAudioSsrc(config.ssrc);
162 status_callback_.Run(TRANSPORT_AUDIO_INITIALIZED);
163 }
164
InitializeVideo(const CastTransportRtpConfig & config,const RtcpCastMessageCallback & cast_message_cb,const RtcpRttCallback & rtt_cb)165 void CastTransportSenderImpl::InitializeVideo(
166 const CastTransportRtpConfig& config,
167 const RtcpCastMessageCallback& cast_message_cb,
168 const RtcpRttCallback& rtt_cb) {
169 LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty())
170 << "Unsafe to send video with encryption DISABLED.";
171 if (!video_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) {
172 status_callback_.Run(TRANSPORT_VIDEO_UNINITIALIZED);
173 return;
174 }
175
176 video_sender_.reset(new RtpSender(clock_, transport_task_runner_, &pacer_));
177 if (!video_sender_->Initialize(config)) {
178 video_sender_.reset();
179 status_callback_.Run(TRANSPORT_VIDEO_UNINITIALIZED);
180 return;
181 }
182
183 video_rtcp_session_.reset(
184 new Rtcp(base::Bind(&CastTransportSenderImpl::OnReceivedCastMessage,
185 weak_factory_.GetWeakPtr(), config.ssrc,
186 cast_message_cb),
187 rtt_cb,
188 base::Bind(&CastTransportSenderImpl::OnReceivedLogMessage,
189 weak_factory_.GetWeakPtr(), VIDEO_EVENT),
190 clock_,
191 &pacer_,
192 config.ssrc,
193 config.feedback_ssrc));
194 pacer_.RegisterVideoSsrc(config.ssrc);
195 status_callback_.Run(TRANSPORT_VIDEO_INITIALIZED);
196 }
197
198 namespace {
EncryptAndSendFrame(const EncodedFrame & frame,TransportEncryptionHandler * encryptor,RtpSender * sender)199 void EncryptAndSendFrame(const EncodedFrame& frame,
200 TransportEncryptionHandler* encryptor,
201 RtpSender* sender) {
202 if (encryptor->is_activated()) {
203 EncodedFrame encrypted_frame;
204 frame.CopyMetadataTo(&encrypted_frame);
205 if (encryptor->Encrypt(frame.frame_id, frame.data, &encrypted_frame.data)) {
206 sender->SendFrame(encrypted_frame);
207 } else {
208 LOG(ERROR) << "Encryption failed. Not sending frame with ID "
209 << frame.frame_id;
210 }
211 } else {
212 sender->SendFrame(frame);
213 }
214 }
215 } // namespace
216
InsertFrame(uint32 ssrc,const EncodedFrame & frame)217 void CastTransportSenderImpl::InsertFrame(uint32 ssrc,
218 const EncodedFrame& frame) {
219 if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
220 EncryptAndSendFrame(frame, &audio_encryptor_, audio_sender_.get());
221 } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
222 EncryptAndSendFrame(frame, &video_encryptor_, video_sender_.get());
223 } else {
224 NOTREACHED() << "Invalid InsertFrame call.";
225 }
226 }
227
SendSenderReport(uint32 ssrc,base::TimeTicks current_time,uint32 current_time_as_rtp_timestamp)228 void CastTransportSenderImpl::SendSenderReport(
229 uint32 ssrc,
230 base::TimeTicks current_time,
231 uint32 current_time_as_rtp_timestamp) {
232 if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
233 audio_rtcp_session_->SendRtcpFromRtpSender(
234 current_time, current_time_as_rtp_timestamp,
235 audio_sender_->send_packet_count(), audio_sender_->send_octet_count());
236 } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
237 video_rtcp_session_->SendRtcpFromRtpSender(
238 current_time, current_time_as_rtp_timestamp,
239 video_sender_->send_packet_count(), video_sender_->send_octet_count());
240 } else {
241 NOTREACHED() << "Invalid request for sending RTCP packet.";
242 }
243 }
244
CancelSendingFrames(uint32 ssrc,const std::vector<uint32> & frame_ids)245 void CastTransportSenderImpl::CancelSendingFrames(
246 uint32 ssrc,
247 const std::vector<uint32>& frame_ids) {
248 if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
249 audio_sender_->CancelSendingFrames(frame_ids);
250 } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
251 video_sender_->CancelSendingFrames(frame_ids);
252 } else {
253 NOTREACHED() << "Invalid request for cancel sending.";
254 }
255 }
256
ResendFrameForKickstart(uint32 ssrc,uint32 frame_id)257 void CastTransportSenderImpl::ResendFrameForKickstart(uint32 ssrc,
258 uint32 frame_id) {
259 if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
260 DCHECK(audio_rtcp_session_);
261 audio_sender_->ResendFrameForKickstart(
262 frame_id,
263 audio_rtcp_session_->current_round_trip_time());
264 } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
265 DCHECK(video_rtcp_session_);
266 video_sender_->ResendFrameForKickstart(
267 frame_id,
268 video_rtcp_session_->current_round_trip_time());
269 } else {
270 NOTREACHED() << "Invalid request for kickstart.";
271 }
272 }
273
ResendPackets(uint32 ssrc,const MissingFramesAndPacketsMap & missing_packets,bool cancel_rtx_if_not_in_list,const DedupInfo & dedup_info)274 void CastTransportSenderImpl::ResendPackets(
275 uint32 ssrc,
276 const MissingFramesAndPacketsMap& missing_packets,
277 bool cancel_rtx_if_not_in_list,
278 const DedupInfo& dedup_info) {
279 if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
280 audio_sender_->ResendPackets(missing_packets,
281 cancel_rtx_if_not_in_list,
282 dedup_info);
283 } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
284 video_sender_->ResendPackets(missing_packets,
285 cancel_rtx_if_not_in_list,
286 dedup_info);
287 } else {
288 NOTREACHED() << "Invalid request for retransmission.";
289 }
290 }
291
PacketReceiverForTesting()292 PacketReceiverCallback CastTransportSenderImpl::PacketReceiverForTesting() {
293 return base::Bind(&CastTransportSenderImpl::OnReceivedPacket,
294 weak_factory_.GetWeakPtr());
295 }
296
SendRawEvents()297 void CastTransportSenderImpl::SendRawEvents() {
298 DCHECK(event_subscriber_.get());
299 DCHECK(!raw_events_callback_.is_null());
300 std::vector<PacketEvent> packet_events;
301 std::vector<FrameEvent> frame_events;
302 event_subscriber_->GetPacketEventsAndReset(&packet_events);
303 event_subscriber_->GetFrameEventsAndReset(&frame_events);
304 raw_events_callback_.Run(packet_events, frame_events);
305
306 transport_task_runner_->PostDelayedTask(
307 FROM_HERE,
308 base::Bind(&CastTransportSenderImpl::SendRawEvents,
309 weak_factory_.GetWeakPtr()),
310 raw_events_callback_interval_);
311 }
312
OnReceivedPacket(scoped_ptr<Packet> packet)313 void CastTransportSenderImpl::OnReceivedPacket(scoped_ptr<Packet> packet) {
314 if (audio_rtcp_session_ &&
315 audio_rtcp_session_->IncomingRtcpPacket(&packet->front(),
316 packet->size())) {
317 return;
318 }
319 if (video_rtcp_session_ &&
320 video_rtcp_session_->IncomingRtcpPacket(&packet->front(),
321 packet->size())) {
322 return;
323 }
324 VLOG(1) << "Stale packet received.";
325 }
326
OnReceivedLogMessage(EventMediaType media_type,const RtcpReceiverLogMessage & log)327 void CastTransportSenderImpl::OnReceivedLogMessage(
328 EventMediaType media_type,
329 const RtcpReceiverLogMessage& log) {
330 // Add received log messages into our log system.
331 RtcpReceiverLogMessage::const_iterator it = log.begin();
332 for (; it != log.end(); ++it) {
333 uint32 rtp_timestamp = it->rtp_timestamp_;
334
335 RtcpReceiverEventLogMessages::const_iterator event_it =
336 it->event_log_messages_.begin();
337 for (; event_it != it->event_log_messages_.end(); ++event_it) {
338 switch (event_it->type) {
339 case PACKET_RECEIVED:
340 logging_.InsertPacketEvent(
341 event_it->event_timestamp, event_it->type,
342 media_type, rtp_timestamp,
343 kFrameIdUnknown, event_it->packet_id, 0, 0);
344 break;
345 case FRAME_ACK_SENT:
346 case FRAME_DECODED:
347 logging_.InsertFrameEvent(
348 event_it->event_timestamp, event_it->type, media_type,
349 rtp_timestamp, kFrameIdUnknown);
350 break;
351 case FRAME_PLAYOUT:
352 logging_.InsertFrameEventWithDelay(
353 event_it->event_timestamp, event_it->type, media_type,
354 rtp_timestamp, kFrameIdUnknown, event_it->delay_delta);
355 break;
356 default:
357 VLOG(2) << "Received log message via RTCP that we did not expect: "
358 << static_cast<int>(event_it->type);
359 break;
360 }
361 }
362 }
363 }
364
OnReceivedCastMessage(uint32 ssrc,const RtcpCastMessageCallback & cast_message_cb,const RtcpCastMessage & cast_message)365 void CastTransportSenderImpl::OnReceivedCastMessage(
366 uint32 ssrc,
367 const RtcpCastMessageCallback& cast_message_cb,
368 const RtcpCastMessage& cast_message) {
369 if (!cast_message_cb.is_null())
370 cast_message_cb.Run(cast_message);
371
372 DedupInfo dedup_info;
373 if (audio_sender_ && audio_sender_->ssrc() == ssrc) {
374 const int64 acked_bytes =
375 audio_sender_->GetLastByteSentForFrame(cast_message.ack_frame_id);
376 last_byte_acked_for_audio_ =
377 std::max(acked_bytes, last_byte_acked_for_audio_);
378 } else if (video_sender_ && video_sender_->ssrc() == ssrc) {
379 dedup_info.resend_interval = video_rtcp_session_->current_round_trip_time();
380
381 // Only use audio stream to dedup if there is one.
382 if (audio_sender_) {
383 dedup_info.last_byte_acked_for_audio = last_byte_acked_for_audio_;
384 }
385 }
386
387 if (cast_message.missing_frames_and_packets.empty())
388 return;
389
390 // This call does two things.
391 // 1. Specifies that retransmissions for packets not listed in the set are
392 // cancelled.
393 // 2. Specifies a deduplication window. For video this would be the most
394 // recent RTT. For audio there is no deduplication.
395 ResendPackets(ssrc,
396 cast_message.missing_frames_and_packets,
397 true,
398 dedup_info);
399 }
400
401 } // namespace cast
402 } // namespace media
403