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 "media/cast/net/cast_transport_config.h"
9 #include "media/cast/net/cast_transport_defines.h"
10 #include "media/cast/net/udp_transport.h"
11 #include "net/base/net_util.h"
16 scoped_ptr<CastTransportSender> CastTransportSender::Create(
18 base::TickClock* clock,
19 const net::IPEndPoint& remote_end_point,
20 const CastTransportStatusCallback& status_callback,
21 const BulkRawEventsCallback& raw_events_callback,
22 base::TimeDelta raw_events_callback_interval,
23 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner) {
24 return scoped_ptr<CastTransportSender>(
25 new CastTransportSenderImpl(net_log,
30 raw_events_callback_interval,
31 transport_task_runner.get(),
35 PacketReceiverCallback CastTransportSender::PacketReceiverForTesting() {
36 return PacketReceiverCallback();
39 CastTransportSenderImpl::CastTransportSenderImpl(
41 base::TickClock* clock,
42 const net::IPEndPoint& remote_end_point,
43 const CastTransportStatusCallback& status_callback,
44 const BulkRawEventsCallback& raw_events_callback,
45 base::TimeDelta raw_events_callback_interval,
46 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner,
47 PacketSender* external_transport)
49 status_callback_(status_callback),
50 transport_task_runner_(transport_task_runner),
51 transport_(external_transport ? NULL
52 : new UdpTransport(net_log,
53 transport_task_runner,
59 external_transport ? external_transport : transport_.get(),
60 transport_task_runner),
61 raw_events_callback_(raw_events_callback),
62 raw_events_callback_interval_(raw_events_callback_interval),
65 if (!raw_events_callback_.is_null()) {
66 DCHECK(raw_events_callback_interval > base::TimeDelta());
67 event_subscriber_.reset(new SimpleEventSubscriber);
68 logging_.AddRawEventSubscriber(event_subscriber_.get());
69 transport_task_runner->PostDelayedTask(
71 base::Bind(&CastTransportSenderImpl::SendRawEvents,
72 weak_factory_.GetWeakPtr()),
73 raw_events_callback_interval);
76 // The default DSCP value for cast is AF41. Which gives it a higher
77 // priority over other traffic.
78 transport_->SetDscp(net::DSCP_AF41);
79 transport_->StartReceiving(
80 base::Bind(&CastTransportSenderImpl::OnReceivedPacket,
81 weak_factory_.GetWeakPtr()));
85 CastTransportSenderImpl::~CastTransportSenderImpl() {
86 if (event_subscriber_.get())
87 logging_.RemoveRawEventSubscriber(event_subscriber_.get());
90 void CastTransportSenderImpl::InitializeAudio(
91 const CastTransportRtpConfig& config,
92 const RtcpCastMessageCallback& cast_message_cb,
93 const RtcpRttCallback& rtt_cb) {
94 LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty())
95 << "Unsafe to send audio with encryption DISABLED.";
96 if (!audio_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) {
97 status_callback_.Run(TRANSPORT_AUDIO_UNINITIALIZED);
101 audio_sender_.reset(new RtpSender(clock_, transport_task_runner_, &pacer_));
102 if (audio_sender_->Initialize(config)) {
103 // Audio packets have a higher priority.
104 pacer_.RegisterAudioSsrc(config.ssrc);
105 pacer_.RegisterPrioritySsrc(config.ssrc);
106 status_callback_.Run(TRANSPORT_AUDIO_INITIALIZED);
108 audio_sender_.reset();
109 status_callback_.Run(TRANSPORT_AUDIO_UNINITIALIZED);
113 audio_rtcp_session_.reset(
114 new Rtcp(cast_message_cb,
116 base::Bind(&CastTransportSenderImpl::OnReceivedLogMessage,
117 weak_factory_.GetWeakPtr(), AUDIO_EVENT),
121 config.feedback_ssrc));
122 pacer_.RegisterAudioSsrc(config.ssrc);
123 status_callback_.Run(TRANSPORT_AUDIO_INITIALIZED);
126 void CastTransportSenderImpl::InitializeVideo(
127 const CastTransportRtpConfig& config,
128 const RtcpCastMessageCallback& cast_message_cb,
129 const RtcpRttCallback& rtt_cb) {
130 LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty())
131 << "Unsafe to send video with encryption DISABLED.";
132 if (!video_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) {
133 status_callback_.Run(TRANSPORT_VIDEO_UNINITIALIZED);
137 video_sender_.reset(new RtpSender(clock_, transport_task_runner_, &pacer_));
138 if (!video_sender_->Initialize(config)) {
139 video_sender_.reset();
140 status_callback_.Run(TRANSPORT_VIDEO_UNINITIALIZED);
144 video_rtcp_session_.reset(
145 new Rtcp(cast_message_cb,
147 base::Bind(&CastTransportSenderImpl::OnReceivedLogMessage,
148 weak_factory_.GetWeakPtr(), VIDEO_EVENT),
152 config.feedback_ssrc));
153 pacer_.RegisterVideoSsrc(config.ssrc);
154 status_callback_.Run(TRANSPORT_VIDEO_INITIALIZED);
158 void EncryptAndSendFrame(const EncodedFrame& frame,
159 TransportEncryptionHandler* encryptor,
161 if (encryptor->is_activated()) {
162 EncodedFrame encrypted_frame;
163 frame.CopyMetadataTo(&encrypted_frame);
164 if (encryptor->Encrypt(frame.frame_id, frame.data, &encrypted_frame.data)) {
165 sender->SendFrame(encrypted_frame);
167 LOG(ERROR) << "Encryption failed. Not sending frame with ID "
171 sender->SendFrame(frame);
176 void CastTransportSenderImpl::InsertCodedAudioFrame(
177 const EncodedFrame& audio_frame) {
178 DCHECK(audio_sender_) << "Audio sender uninitialized";
179 EncryptAndSendFrame(audio_frame, &audio_encryptor_, audio_sender_.get());
182 void CastTransportSenderImpl::InsertCodedVideoFrame(
183 const EncodedFrame& video_frame) {
184 DCHECK(video_sender_) << "Video sender uninitialized";
185 EncryptAndSendFrame(video_frame, &video_encryptor_, video_sender_.get());
188 void CastTransportSenderImpl::SendSenderReport(
190 base::TimeTicks current_time,
191 uint32 current_time_as_rtp_timestamp) {
192 if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
193 audio_rtcp_session_->SendRtcpFromRtpSender(
194 current_time, current_time_as_rtp_timestamp,
195 audio_sender_->send_packet_count(), audio_sender_->send_octet_count());
196 } else if (video_sender_ && ssrc == video_sender_->ssrc()) {
197 video_rtcp_session_->SendRtcpFromRtpSender(
198 current_time, current_time_as_rtp_timestamp,
199 video_sender_->send_packet_count(), video_sender_->send_octet_count());
201 NOTREACHED() << "Invalid request for sending RTCP packet.";
205 void CastTransportSenderImpl::ResendPackets(
207 const MissingFramesAndPacketsMap& missing_packets,
208 bool cancel_rtx_if_not_in_list,
209 base::TimeDelta dedupe_window) {
211 DCHECK(audio_sender_) << "Audio sender uninitialized";
212 audio_sender_->ResendPackets(missing_packets,
213 cancel_rtx_if_not_in_list,
216 DCHECK(video_sender_) << "Video sender uninitialized";
217 video_sender_->ResendPackets(missing_packets,
218 cancel_rtx_if_not_in_list,
223 PacketReceiverCallback CastTransportSenderImpl::PacketReceiverForTesting() {
224 return base::Bind(&CastTransportSenderImpl::OnReceivedPacket,
225 weak_factory_.GetWeakPtr());
228 void CastTransportSenderImpl::SendRawEvents() {
229 DCHECK(event_subscriber_.get());
230 DCHECK(!raw_events_callback_.is_null());
231 std::vector<PacketEvent> packet_events;
232 std::vector<FrameEvent> frame_events;
233 event_subscriber_->GetPacketEventsAndReset(&packet_events);
234 event_subscriber_->GetFrameEventsAndReset(&frame_events);
235 raw_events_callback_.Run(packet_events, frame_events);
237 transport_task_runner_->PostDelayedTask(
239 base::Bind(&CastTransportSenderImpl::SendRawEvents,
240 weak_factory_.GetWeakPtr()),
241 raw_events_callback_interval_);
244 void CastTransportSenderImpl::OnReceivedPacket(scoped_ptr<Packet> packet) {
245 if (audio_rtcp_session_ &&
246 audio_rtcp_session_->IncomingRtcpPacket(&packet->front(),
250 if (video_rtcp_session_ &&
251 video_rtcp_session_->IncomingRtcpPacket(&packet->front(),
255 VLOG(1) << "Stale packet received.";
258 void CastTransportSenderImpl::OnReceivedLogMessage(
259 EventMediaType media_type,
260 const RtcpReceiverLogMessage& log) {
261 // Add received log messages into our log system.
262 RtcpReceiverLogMessage::const_iterator it = log.begin();
263 for (; it != log.end(); ++it) {
264 uint32 rtp_timestamp = it->rtp_timestamp_;
266 RtcpReceiverEventLogMessages::const_iterator event_it =
267 it->event_log_messages_.begin();
268 for (; event_it != it->event_log_messages_.end(); ++event_it) {
269 switch (event_it->type) {
270 case PACKET_RECEIVED:
271 logging_.InsertPacketEvent(
272 event_it->event_timestamp, event_it->type,
273 media_type, rtp_timestamp,
274 kFrameIdUnknown, event_it->packet_id, 0, 0);
278 logging_.InsertFrameEvent(
279 event_it->event_timestamp, event_it->type, media_type,
280 rtp_timestamp, kFrameIdUnknown);
283 logging_.InsertFrameEventWithDelay(
284 event_it->event_timestamp, event_it->type, media_type,
285 rtp_timestamp, kFrameIdUnknown, event_it->delay_delta);
288 VLOG(2) << "Received log message via RTCP that we did not expect: "
289 << static_cast<int>(event_it->type);