OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/cast/net/cast_transport_impl.h" | 5 #include "media/cast/net/cast_transport_impl.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <algorithm> | 8 #include <algorithm> |
9 #include <string> | 9 #include <string> |
10 #include <utility> | 10 #include <utility> |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 | 84 |
85 private: | 85 private: |
86 const uint32_t rtp_sender_ssrc_; | 86 const uint32_t rtp_sender_ssrc_; |
87 const std::unique_ptr<RtcpObserver> rtcp_observer_; | 87 const std::unique_ptr<RtcpObserver> rtcp_observer_; |
88 const EventMediaType media_type_; | 88 const EventMediaType media_type_; |
89 CastTransportImpl* const cast_transport_impl_; | 89 CastTransportImpl* const cast_transport_impl_; |
90 | 90 |
91 DISALLOW_COPY_AND_ASSIGN(RtcpClient); | 91 DISALLOW_COPY_AND_ASSIGN(RtcpClient); |
92 }; | 92 }; |
93 | 93 |
| 94 struct CastTransportImpl::RtpStreamSession { |
| 95 explicit RtpStreamSession(bool is_audio_stream) : is_audio(is_audio_stream) {} |
| 96 |
| 97 // Packetizer for audio and video frames. |
| 98 std::unique_ptr<RtpSender> rtp_sender; |
| 99 |
| 100 // Maintains RTCP session for audio and video. |
| 101 std::unique_ptr<SenderRtcpSession> rtcp_session; |
| 102 |
| 103 // RTCP observer for SenderRtcpSession. |
| 104 std::unique_ptr<RtcpObserver> rtcp_observer; |
| 105 |
| 106 // Encrypts data in EncodedFrames before they are sent. Note that it's |
| 107 // important for the encryption to happen here, in code that would execute in |
| 108 // the main browser process, for security reasons. This helps to mitigate |
| 109 // the damage that could be caused by a compromised renderer process. |
| 110 TransportEncryptionHandler encryptor; |
| 111 |
| 112 const bool is_audio; |
| 113 }; |
| 114 |
94 CastTransportImpl::CastTransportImpl( | 115 CastTransportImpl::CastTransportImpl( |
95 base::TickClock* clock, | 116 base::TickClock* clock, |
96 base::TimeDelta logging_flush_interval, | 117 base::TimeDelta logging_flush_interval, |
97 std::unique_ptr<Client> client, | 118 std::unique_ptr<Client> client, |
98 std::unique_ptr<PacketTransport> transport, | 119 std::unique_ptr<PacketTransport> transport, |
99 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner) | 120 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner) |
100 : clock_(clock), | 121 : clock_(clock), |
101 logging_flush_interval_(logging_flush_interval), | 122 logging_flush_interval_(logging_flush_interval), |
102 transport_client_(std::move(client)), | 123 transport_client_(std::move(client)), |
103 transport_(std::move(transport)), | 124 transport_(std::move(transport)), |
(...skipping 18 matching lines...) Expand all Loading... |
122 logging_flush_interval_); | 143 logging_flush_interval_); |
123 } | 144 } |
124 transport_->StartReceiving( | 145 transport_->StartReceiving( |
125 base::Bind(&CastTransportImpl::OnReceivedPacket, base::Unretained(this))); | 146 base::Bind(&CastTransportImpl::OnReceivedPacket, base::Unretained(this))); |
126 } | 147 } |
127 | 148 |
128 CastTransportImpl::~CastTransportImpl() { | 149 CastTransportImpl::~CastTransportImpl() { |
129 transport_->StopReceiving(); | 150 transport_->StopReceiving(); |
130 } | 151 } |
131 | 152 |
132 void CastTransportImpl::InitializeAudio( | 153 void CastTransportImpl::InitializeStream( |
133 const CastTransportRtpConfig& config, | 154 const CastTransportRtpConfig& config, |
134 std::unique_ptr<RtcpObserver> rtcp_observer) { | 155 std::unique_ptr<RtcpObserver> rtcp_observer) { |
| 156 if (sessions_.find(config.ssrc) != sessions_.end()) |
| 157 DVLOG(1) << "Initialize an existing stream on RTP sender." << config.ssrc; |
| 158 |
135 LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty()) | 159 LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty()) |
136 << "Unsafe to send audio with encryption DISABLED."; | 160 << "Unsafe to send stream with encryption DISABLED."; |
137 if (!audio_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) { | 161 |
138 transport_client_->OnStatusChanged(TRANSPORT_AUDIO_UNINITIALIZED); | 162 bool is_audio = config.rtp_payload_type <= RtpPayloadType::AUDIO_LAST; |
| 163 std::unique_ptr<RtpStreamSession> session(new RtpStreamSession(is_audio)); |
| 164 |
| 165 if (!session->encryptor.Initialize(config.aes_key, config.aes_iv_mask)) { |
| 166 transport_client_->OnStatusChanged(TRANSPORT_STREAM_UNINITIALIZED); |
139 return; | 167 return; |
140 } | 168 } |
141 | 169 |
142 audio_sender_.reset(new RtpSender(transport_task_runner_, &pacer_)); | 170 session->rtp_sender.reset(new RtpSender(transport_task_runner_, &pacer_)); |
143 if (audio_sender_->Initialize(config)) { | 171 if (!session->rtp_sender->Initialize(config)) { |
144 // Audio packets have a higher priority. | 172 session->rtp_sender.reset(); |
145 pacer_.RegisterAudioSsrc(config.ssrc); | 173 transport_client_->OnStatusChanged(TRANSPORT_STREAM_UNINITIALIZED); |
146 pacer_.RegisterPrioritySsrc(config.ssrc); | |
147 transport_client_->OnStatusChanged(TRANSPORT_AUDIO_INITIALIZED); | |
148 } else { | |
149 audio_sender_.reset(); | |
150 transport_client_->OnStatusChanged(TRANSPORT_AUDIO_UNINITIALIZED); | |
151 return; | 174 return; |
152 } | 175 } |
153 | 176 |
154 audio_rtcp_observer_.reset( | 177 pacer_.RegisterSsrc(config.ssrc, is_audio); |
155 new RtcpClient(std::move(rtcp_observer), config.ssrc, AUDIO_EVENT, this)); | 178 // Audio packets have a higher priority. |
156 audio_rtcp_session_.reset( | 179 if (is_audio) |
157 new SenderRtcpSession(clock_, &pacer_, audio_rtcp_observer_.get(), | 180 pacer_.RegisterPrioritySsrc(config.ssrc); |
| 181 |
| 182 session->rtcp_observer.reset( |
| 183 new RtcpClient(std::move(rtcp_observer), config.ssrc, |
| 184 is_audio ? AUDIO_EVENT : VIDEO_EVENT, this)); |
| 185 session->rtcp_session.reset( |
| 186 new SenderRtcpSession(clock_, &pacer_, session->rtcp_observer.get(), |
158 config.ssrc, config.feedback_ssrc)); | 187 config.ssrc, config.feedback_ssrc)); |
159 pacer_.RegisterAudioSsrc(config.ssrc); | 188 |
160 valid_sender_ssrcs_.insert(config.feedback_ssrc); | 189 valid_sender_ssrcs_.insert(config.feedback_ssrc); |
161 transport_client_->OnStatusChanged(TRANSPORT_AUDIO_INITIALIZED); | 190 sessions_[config.ssrc] = std::move(session); |
162 } | 191 transport_client_->OnStatusChanged(TRANSPORT_STREAM_INITIALIZED); |
163 | |
164 void CastTransportImpl::InitializeVideo( | |
165 const CastTransportRtpConfig& config, | |
166 std::unique_ptr<RtcpObserver> rtcp_observer) { | |
167 LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty()) | |
168 << "Unsafe to send video with encryption DISABLED."; | |
169 if (!video_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) { | |
170 transport_client_->OnStatusChanged(TRANSPORT_VIDEO_UNINITIALIZED); | |
171 return; | |
172 } | |
173 | |
174 video_sender_.reset(new RtpSender(transport_task_runner_, &pacer_)); | |
175 if (!video_sender_->Initialize(config)) { | |
176 video_sender_.reset(); | |
177 transport_client_->OnStatusChanged(TRANSPORT_VIDEO_UNINITIALIZED); | |
178 return; | |
179 } | |
180 | |
181 video_rtcp_observer_.reset( | |
182 new RtcpClient(std::move(rtcp_observer), config.ssrc, VIDEO_EVENT, this)); | |
183 video_rtcp_session_.reset( | |
184 new SenderRtcpSession(clock_, &pacer_, video_rtcp_observer_.get(), | |
185 config.ssrc, config.feedback_ssrc)); | |
186 pacer_.RegisterVideoSsrc(config.ssrc); | |
187 valid_sender_ssrcs_.insert(config.feedback_ssrc); | |
188 transport_client_->OnStatusChanged(TRANSPORT_VIDEO_INITIALIZED); | |
189 } | 192 } |
190 | 193 |
191 namespace { | 194 namespace { |
192 void EncryptAndSendFrame(const EncodedFrame& frame, | 195 void EncryptAndSendFrame(const EncodedFrame& frame, |
193 TransportEncryptionHandler* encryptor, | 196 TransportEncryptionHandler* encryptor, |
194 RtpSender* sender) { | 197 RtpSender* sender) { |
195 // TODO(miu): We probably shouldn't attempt to send an empty frame, but this | 198 // TODO(miu): We probably shouldn't attempt to send an empty frame, but this |
196 // issue is still under investigation. http://crbug.com/519022 | 199 // issue is still under investigation. http://crbug.com/519022 |
197 if (encryptor->is_activated() && !frame.data.empty()) { | 200 if (encryptor->is_activated() && !frame.data.empty()) { |
198 EncodedFrame encrypted_frame; | 201 EncodedFrame encrypted_frame; |
199 frame.CopyMetadataTo(&encrypted_frame); | 202 frame.CopyMetadataTo(&encrypted_frame); |
200 if (encryptor->Encrypt(frame.frame_id, frame.data, &encrypted_frame.data)) { | 203 if (encryptor->Encrypt(frame.frame_id, frame.data, &encrypted_frame.data)) { |
201 sender->SendFrame(encrypted_frame); | 204 sender->SendFrame(encrypted_frame); |
202 } else { | 205 } else { |
203 LOG(ERROR) << "Encryption failed. Not sending frame with ID " | 206 LOG(ERROR) << "Encryption failed. Not sending frame with ID " |
204 << frame.frame_id; | 207 << frame.frame_id; |
205 } | 208 } |
206 } else { | 209 } else { |
207 sender->SendFrame(frame); | 210 sender->SendFrame(frame); |
208 } | 211 } |
209 } | 212 } |
210 } // namespace | 213 } // namespace |
211 | 214 |
212 void CastTransportImpl::InsertFrame(uint32_t ssrc, const EncodedFrame& frame) { | 215 void CastTransportImpl::InsertFrame(uint32_t ssrc, const EncodedFrame& frame) { |
213 if (audio_sender_ && ssrc == audio_sender_->ssrc()) { | 216 auto it = sessions_.find(ssrc); |
214 audio_rtcp_session_->WillSendFrame(frame.frame_id); | 217 if (it == sessions_.end()) { |
215 EncryptAndSendFrame(frame, &audio_encryptor_, audio_sender_.get()); | |
216 } else if (video_sender_ && ssrc == video_sender_->ssrc()) { | |
217 video_rtcp_session_->WillSendFrame(frame.frame_id); | |
218 EncryptAndSendFrame(frame, &video_encryptor_, video_sender_.get()); | |
219 } else { | |
220 NOTREACHED() << "Invalid InsertFrame call."; | 218 NOTREACHED() << "Invalid InsertFrame call."; |
| 219 return; |
221 } | 220 } |
| 221 |
| 222 it->second->rtcp_session->WillSendFrame(frame.frame_id); |
| 223 EncryptAndSendFrame(frame, &it->second->encryptor, |
| 224 it->second->rtp_sender.get()); |
222 } | 225 } |
223 | 226 |
224 void CastTransportImpl::SendSenderReport( | 227 void CastTransportImpl::SendSenderReport( |
225 uint32_t ssrc, | 228 uint32_t ssrc, |
226 base::TimeTicks current_time, | 229 base::TimeTicks current_time, |
227 RtpTimeTicks current_time_as_rtp_timestamp) { | 230 RtpTimeTicks current_time_as_rtp_timestamp) { |
228 if (audio_sender_ && ssrc == audio_sender_->ssrc()) { | 231 auto it = sessions_.find(ssrc); |
229 audio_rtcp_session_->SendRtcpReport( | 232 if (it == sessions_.end()) { |
230 current_time, current_time_as_rtp_timestamp, | |
231 audio_sender_->send_packet_count(), audio_sender_->send_octet_count()); | |
232 } else if (video_sender_ && ssrc == video_sender_->ssrc()) { | |
233 video_rtcp_session_->SendRtcpReport( | |
234 current_time, current_time_as_rtp_timestamp, | |
235 video_sender_->send_packet_count(), video_sender_->send_octet_count()); | |
236 } else { | |
237 NOTREACHED() << "Invalid request for sending RTCP packet."; | 233 NOTREACHED() << "Invalid request for sending RTCP packet."; |
| 234 return; |
238 } | 235 } |
| 236 |
| 237 it->second->rtcp_session->SendRtcpReport( |
| 238 current_time, current_time_as_rtp_timestamp, |
| 239 it->second->rtp_sender->send_packet_count(), |
| 240 it->second->rtp_sender->send_octet_count()); |
239 } | 241 } |
240 | 242 |
241 void CastTransportImpl::CancelSendingFrames( | 243 void CastTransportImpl::CancelSendingFrames( |
242 uint32_t ssrc, | 244 uint32_t ssrc, |
243 const std::vector<FrameId>& frame_ids) { | 245 const std::vector<FrameId>& frame_ids) { |
244 if (audio_sender_ && ssrc == audio_sender_->ssrc()) { | 246 auto it = sessions_.find(ssrc); |
245 audio_sender_->CancelSendingFrames(frame_ids); | 247 if (it == sessions_.end()) { |
246 } else if (video_sender_ && ssrc == video_sender_->ssrc()) { | |
247 video_sender_->CancelSendingFrames(frame_ids); | |
248 } else { | |
249 NOTREACHED() << "Invalid request for cancel sending."; | 248 NOTREACHED() << "Invalid request for cancel sending."; |
| 249 return; |
250 } | 250 } |
| 251 |
| 252 it->second->rtp_sender->CancelSendingFrames(frame_ids); |
251 } | 253 } |
252 | 254 |
253 void CastTransportImpl::ResendFrameForKickstart(uint32_t ssrc, | 255 void CastTransportImpl::ResendFrameForKickstart(uint32_t ssrc, |
254 FrameId frame_id) { | 256 FrameId frame_id) { |
255 if (audio_sender_ && ssrc == audio_sender_->ssrc()) { | 257 auto it = sessions_.find(ssrc); |
256 DCHECK(audio_rtcp_session_); | 258 if (it == sessions_.end()) { |
257 audio_sender_->ResendFrameForKickstart( | |
258 frame_id, audio_rtcp_session_->current_round_trip_time()); | |
259 } else if (video_sender_ && ssrc == video_sender_->ssrc()) { | |
260 DCHECK(video_rtcp_session_); | |
261 video_sender_->ResendFrameForKickstart( | |
262 frame_id, video_rtcp_session_->current_round_trip_time()); | |
263 } else { | |
264 NOTREACHED() << "Invalid request for kickstart."; | 259 NOTREACHED() << "Invalid request for kickstart."; |
| 260 return; |
265 } | 261 } |
| 262 |
| 263 DCHECK(it->second->rtcp_session); |
| 264 it->second->rtp_sender->ResendFrameForKickstart( |
| 265 frame_id, it->second->rtcp_session->current_round_trip_time()); |
266 } | 266 } |
267 | 267 |
268 void CastTransportImpl::ResendPackets( | 268 void CastTransportImpl::ResendPackets( |
269 uint32_t ssrc, | 269 uint32_t ssrc, |
270 const MissingFramesAndPacketsMap& missing_packets, | 270 const MissingFramesAndPacketsMap& missing_packets, |
271 bool cancel_rtx_if_not_in_list, | 271 bool cancel_rtx_if_not_in_list, |
272 const DedupInfo& dedup_info) { | 272 const DedupInfo& dedup_info) { |
273 if (audio_sender_ && ssrc == audio_sender_->ssrc()) { | 273 auto it = sessions_.find(ssrc); |
274 audio_sender_->ResendPackets(missing_packets, cancel_rtx_if_not_in_list, | 274 if (it == sessions_.end()) { |
275 dedup_info); | |
276 } else if (video_sender_ && ssrc == video_sender_->ssrc()) { | |
277 video_sender_->ResendPackets(missing_packets, cancel_rtx_if_not_in_list, | |
278 dedup_info); | |
279 } else { | |
280 NOTREACHED() << "Invalid request for retransmission."; | 275 NOTREACHED() << "Invalid request for retransmission."; |
| 276 return; |
281 } | 277 } |
| 278 |
| 279 it->second->rtp_sender->ResendPackets(missing_packets, |
| 280 cancel_rtx_if_not_in_list, dedup_info); |
282 } | 281 } |
283 | 282 |
284 PacketReceiverCallback CastTransportImpl::PacketReceiverForTesting() { | 283 PacketReceiverCallback CastTransportImpl::PacketReceiverForTesting() { |
285 return base::Bind(base::IgnoreResult(&CastTransportImpl::OnReceivedPacket), | 284 return base::Bind(base::IgnoreResult(&CastTransportImpl::OnReceivedPacket), |
286 weak_factory_.GetWeakPtr()); | 285 weak_factory_.GetWeakPtr()); |
287 } | 286 } |
288 | 287 |
289 void CastTransportImpl::SendRawEvents() { | 288 void CastTransportImpl::SendRawEvents() { |
290 DCHECK(logging_flush_interval_ > base::TimeDelta()); | 289 DCHECK(logging_flush_interval_ > base::TimeDelta()); |
291 | 290 |
(...skipping 22 matching lines...) Expand all Loading... |
314 ssrc = GetSsrcOfSender(data, length); | 313 ssrc = GetSsrcOfSender(data, length); |
315 } else if (!RtpParser::ParseSsrc(data, length, &ssrc)) { | 314 } else if (!RtpParser::ParseSsrc(data, length, &ssrc)) { |
316 VLOG(1) << "Invalid RTP packet."; | 315 VLOG(1) << "Invalid RTP packet."; |
317 return false; | 316 return false; |
318 } | 317 } |
319 if (valid_sender_ssrcs_.find(ssrc) == valid_sender_ssrcs_.end()) { | 318 if (valid_sender_ssrcs_.find(ssrc) == valid_sender_ssrcs_.end()) { |
320 VLOG(1) << "Stale packet received."; | 319 VLOG(1) << "Stale packet received."; |
321 return false; | 320 return false; |
322 } | 321 } |
323 | 322 |
324 if (audio_rtcp_session_ && | 323 for (const auto& session : sessions_) { |
325 audio_rtcp_session_->IncomingRtcpPacket(data, length)) { | 324 if (session.second->rtcp_session->IncomingRtcpPacket(data, length)) |
326 return true; | 325 return true; |
327 } | 326 } |
328 if (video_rtcp_session_ && | 327 |
329 video_rtcp_session_->IncomingRtcpPacket(data, length)) { | |
330 return true; | |
331 } | |
332 transport_client_->ProcessRtpPacket(std::move(packet)); | 328 transport_client_->ProcessRtpPacket(std::move(packet)); |
333 return true; | 329 return true; |
334 } | 330 } |
335 | 331 |
336 void CastTransportImpl::OnReceivedLogMessage( | 332 void CastTransportImpl::OnReceivedLogMessage( |
337 EventMediaType media_type, | 333 EventMediaType media_type, |
338 const RtcpReceiverLogMessage& log) { | 334 const RtcpReceiverLogMessage& log) { |
339 if (logging_flush_interval_ <= base::TimeDelta()) | 335 if (logging_flush_interval_ <= base::TimeDelta()) |
340 return; | 336 return; |
341 | 337 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 } | 370 } |
375 } | 371 } |
376 } | 372 } |
377 } | 373 } |
378 | 374 |
379 void CastTransportImpl::OnReceivedCastMessage( | 375 void CastTransportImpl::OnReceivedCastMessage( |
380 uint32_t ssrc, | 376 uint32_t ssrc, |
381 const RtcpCastMessage& cast_message) { | 377 const RtcpCastMessage& cast_message) { |
382 | 378 |
383 DedupInfo dedup_info; | 379 DedupInfo dedup_info; |
384 if (audio_sender_ && audio_sender_->ssrc() == ssrc) { | 380 auto it = sessions_.find(ssrc); |
385 const int64_t acked_bytes = | 381 if (it == sessions_.end() || !it->second->rtp_sender) |
386 audio_sender_->GetLastByteSentForFrame(cast_message.ack_frame_id); | 382 return; |
| 383 |
| 384 if (it->second->is_audio) { |
| 385 const int64_t acked_bytes = it->second->rtp_sender->GetLastByteSentForFrame( |
| 386 cast_message.ack_frame_id); |
387 last_byte_acked_for_audio_ = | 387 last_byte_acked_for_audio_ = |
388 std::max(acked_bytes, last_byte_acked_for_audio_); | 388 std::max(acked_bytes, last_byte_acked_for_audio_); |
389 } else if (video_sender_ && video_sender_->ssrc() == ssrc) { | 389 } else { |
390 dedup_info.resend_interval = video_rtcp_session_->current_round_trip_time(); | 390 dedup_info.resend_interval = |
| 391 it->second->rtcp_session->current_round_trip_time(); |
391 | 392 |
392 // Only use audio stream to dedup if there is one. | 393 // Only use audio stream to dedup if there is one. |
393 if (audio_sender_) { | 394 if (last_byte_acked_for_audio_) { |
394 dedup_info.last_byte_acked_for_audio = last_byte_acked_for_audio_; | 395 dedup_info.last_byte_acked_for_audio = last_byte_acked_for_audio_; |
395 } | 396 } |
396 } | 397 } |
397 | 398 |
398 if (!cast_message.missing_frames_and_packets.empty()) { | 399 if (!cast_message.missing_frames_and_packets.empty()) { |
399 VLOG(2) << "feedback_count: " | 400 VLOG(2) << "feedback_count: " |
400 << static_cast<uint32_t>(cast_message.feedback_count); | 401 << static_cast<uint32_t>(cast_message.feedback_count); |
401 // This call does two things. | 402 // This call does two things. |
402 // 1. Specifies that retransmissions for packets not listed in the set are | 403 // 1. Specifies that retransmissions for packets not listed in the set are |
403 // cancelled. | 404 // cancelled. |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 "calling CastTransportImpl::SendRtcpFromRtpReceiver."; | 510 "calling CastTransportImpl::SendRtcpFromRtpReceiver."; |
510 return; | 511 return; |
511 } | 512 } |
512 pacer_.SendRtcpPacket(rtcp_builder_at_rtp_receiver_->local_ssrc(), | 513 pacer_.SendRtcpPacket(rtcp_builder_at_rtp_receiver_->local_ssrc(), |
513 rtcp_builder_at_rtp_receiver_->Finish()); | 514 rtcp_builder_at_rtp_receiver_->Finish()); |
514 rtcp_builder_at_rtp_receiver_.reset(); | 515 rtcp_builder_at_rtp_receiver_.reset(); |
515 } | 516 } |
516 | 517 |
517 } // namespace cast | 518 } // namespace cast |
518 } // namespace media | 519 } // namespace media |
OLD | NEW |