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"
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
,
32 if (options
.GetInteger(path
, &ret
)) {
39 int32
GetTransportSendBufferSize(const base::DictionaryValue
& options
) {
40 // Socket send buffer size needs to be at least greater than one burst
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
);
52 scoped_ptr
<CastTransportSender
> CastTransportSender::Create(
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
,
68 raw_events_callback_interval
,
69 transport_task_runner
.get(),
73 PacketReceiverCallback
CastTransportSender::PacketReceiverForTesting() {
74 return PacketReceiverCallback();
77 CastTransportSenderImpl::CastTransportSenderImpl(
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
)
88 status_callback_(status_callback
),
89 transport_task_runner_(transport_task_runner
),
93 new UdpTransport(net_log
,
94 transport_task_runner
,
97 GetTransportSendBufferSize(*options
),
99 pacer_(LookupOptionWithDefault(*options
,
100 kOptionPacerTargetBurstSize
,
102 LookupOptionWithDefault(*options
,
103 kOptionPacerMaxBurstSize
,
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) {
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(
120 base::Bind(&CastTransportSenderImpl::SendRawEvents
,
121 weak_factory_
.GetWeakPtr()),
122 raw_events_callback_interval
);
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
;
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
);
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
);
169 audio_sender_
.reset();
170 status_callback_
.Run(TRANSPORT_AUDIO_UNINITIALIZED
);
174 audio_rtcp_session_
.reset(
175 new Rtcp(base::Bind(&CastTransportSenderImpl::OnReceivedCastMessage
,
176 weak_factory_
.GetWeakPtr(), config
.ssrc
,
179 base::Bind(&CastTransportSenderImpl::OnReceivedLogMessage
,
180 weak_factory_
.GetWeakPtr(), AUDIO_EVENT
),
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
);
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
);
207 video_rtcp_session_
.reset(
208 new Rtcp(base::Bind(&CastTransportSenderImpl::OnReceivedCastMessage
,
209 weak_factory_
.GetWeakPtr(), config
.ssrc
,
212 base::Bind(&CastTransportSenderImpl::OnReceivedLogMessage
,
213 weak_factory_
.GetWeakPtr(), VIDEO_EVENT
),
217 config
.feedback_ssrc
));
218 pacer_
.RegisterVideoSsrc(config
.ssrc
);
219 status_callback_
.Run(TRANSPORT_VIDEO_INITIALIZED
);
223 void EncryptAndSendFrame(const EncodedFrame
& frame
,
224 TransportEncryptionHandler
* encryptor
,
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
);
232 LOG(ERROR
) << "Encryption failed. Not sending frame with ID "
236 sender
->SendFrame(frame
);
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());
248 NOTREACHED() << "Invalid InsertFrame call.";
252 void CastTransportSenderImpl::SendSenderReport(
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());
265 NOTREACHED() << "Invalid request for sending RTCP packet.";
269 void CastTransportSenderImpl::CancelSendingFrames(
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
);
277 NOTREACHED() << "Invalid request for cancel sending.";
281 void CastTransportSenderImpl::ResendFrameForKickstart(uint32 ssrc
,
283 if (audio_sender_
&& ssrc
== audio_sender_
->ssrc()) {
284 DCHECK(audio_rtcp_session_
);
285 audio_sender_
->ResendFrameForKickstart(
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(
292 video_rtcp_session_
->current_round_trip_time());
294 NOTREACHED() << "Invalid request for kickstart.";
298 void CastTransportSenderImpl::ResendPackets(
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
,
307 } else if (video_sender_
&& ssrc
== video_sender_
->ssrc()) {
308 video_sender_
->ResendPackets(missing_packets
,
309 cancel_rtx_if_not_in_list
,
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(
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(),
343 if (video_rtcp_session_
&&
344 video_rtcp_session_
->IncomingRtcpPacket(&packet
->front(),
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);
371 logging_
.InsertFrameEvent(
372 event_it
->event_timestamp
, event_it
->type
, media_type
,
373 rtp_timestamp
, kFrameIdUnknown
);
376 logging_
.InsertFrameEventWithDelay(
377 event_it
->event_timestamp
, event_it
->type
, media_type
,
378 rtp_timestamp
, kFrameIdUnknown
, event_it
->delay_delta
);
381 VLOG(2) << "Received log message via RTCP that we did not expect: "
382 << static_cast<int>(event_it
->type
);
389 void CastTransportSenderImpl::OnReceivedCastMessage(
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.
407 dedup_info
.last_byte_acked_for_audio
= last_byte_acked_for_audio_
;
411 if (cast_message
.missing_frames_and_packets
.empty())
414 // This call does two things.
415 // 1. Specifies that retransmissions for packets not listed in the set are
417 // 2. Specifies a deduplication window. For video this would be the most
418 // recent RTT. For audio there is no deduplication.
420 cast_message
.missing_frames_and_packets
,