| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/video_sender/video_sender.h" | 5 #include "media/cast/video_sender/video_sender.h" |
| 6 | 6 |
| 7 #include <cstring> | 7 #include <cstring> |
| 8 #include <list> | 8 #include <list> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/debug/trace_event.h" | 11 #include "base/debug/trace_event.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
| 14 #include "media/cast/cast_defines.h" | 14 #include "media/cast/cast_defines.h" |
| 15 #include "media/cast/rtcp/rtcp_defines.h" | 15 #include "media/cast/rtcp/rtcp_defines.h" |
| 16 #include "media/cast/transport/cast_transport_config.h" | 16 #include "media/cast/transport/cast_transport_config.h" |
| 17 #include "media/cast/video_sender/external_video_encoder.h" | 17 #include "media/cast/video_sender/external_video_encoder.h" |
| 18 #include "media/cast/video_sender/video_encoder_impl.h" | 18 #include "media/cast/video_sender/video_encoder_impl.h" |
| 19 | 19 |
| 20 namespace media { | 20 namespace media { |
| 21 namespace cast { | 21 namespace cast { |
| 22 | 22 |
| 23 const int64 kMinSchedulingDelayMs = 1; | 23 const int kNumAggressiveReportsSentAtStart = 100; |
| 24 | 24 const int kMinSchedulingDelayMs = 1; |
| 25 class LocalRtcpVideoSenderFeedback : public RtcpSenderFeedback { | |
| 26 public: | |
| 27 explicit LocalRtcpVideoSenderFeedback(VideoSender* video_sender) | |
| 28 : video_sender_(video_sender) {} | |
| 29 | |
| 30 virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) | |
| 31 OVERRIDE { | |
| 32 video_sender_->OnReceivedCastFeedback(cast_feedback); | |
| 33 } | |
| 34 | |
| 35 private: | |
| 36 VideoSender* video_sender_; | |
| 37 | |
| 38 DISALLOW_IMPLICIT_CONSTRUCTORS(LocalRtcpVideoSenderFeedback); | |
| 39 }; | |
| 40 | 25 |
| 41 VideoSender::VideoSender( | 26 VideoSender::VideoSender( |
| 42 scoped_refptr<CastEnvironment> cast_environment, | 27 scoped_refptr<CastEnvironment> cast_environment, |
| 43 const VideoSenderConfig& video_config, | 28 const VideoSenderConfig& video_config, |
| 44 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, | 29 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, |
| 45 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, | 30 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, |
| 46 const CastInitializationCallback& cast_initialization_cb, | 31 const CastInitializationCallback& cast_initialization_cb, |
| 47 transport::CastTransportSender* const transport_sender) | 32 transport::CastTransportSender* const transport_sender) |
| 48 : rtp_max_delay_(base::TimeDelta::FromMilliseconds( | 33 : rtp_max_delay_(base::TimeDelta::FromMilliseconds( |
| 49 video_config.rtp_config.max_delay_ms)), | 34 video_config.rtp_config.max_delay_ms)), |
| 50 max_frame_rate_(video_config.max_frame_rate), | 35 max_frame_rate_(video_config.max_frame_rate), |
| 51 cast_environment_(cast_environment), | 36 cast_environment_(cast_environment), |
| 52 transport_sender_(transport_sender), | 37 transport_sender_(transport_sender), |
| 53 rtp_timestamp_helper_(kVideoFrequency), | 38 rtp_timestamp_helper_(kVideoFrequency), |
| 54 rtcp_feedback_(new LocalRtcpVideoSenderFeedback(this)), | 39 num_aggressive_rtcp_reports_sent_(0), |
| 55 last_acked_frame_id_(-1), | 40 last_acked_frame_id_(-1), |
| 56 last_sent_frame_id_(-1), | 41 last_sent_frame_id_(-1), |
| 57 frames_in_encoder_(0), | 42 frames_in_encoder_(0), |
| 58 duplicate_ack_(0), | 43 duplicate_ack_(0), |
| 59 last_skip_count_(0), | 44 last_skip_count_(0), |
| 60 current_requested_bitrate_(video_config.start_bitrate), | 45 current_requested_bitrate_(video_config.start_bitrate), |
| 61 congestion_control_(cast_environment->Clock(), | 46 congestion_control_(cast_environment->Clock(), |
| 62 video_config.congestion_control_back_off, | 47 video_config.congestion_control_back_off, |
| 63 video_config.max_bitrate, | 48 video_config.max_bitrate, |
| 64 video_config.min_bitrate, | 49 video_config.min_bitrate, |
| (...skipping 19 matching lines...) Expand all Loading... |
| 84 | 69 |
| 85 | 70 |
| 86 media::cast::transport::CastTransportVideoConfig transport_config; | 71 media::cast::transport::CastTransportVideoConfig transport_config; |
| 87 transport_config.codec = video_config.codec; | 72 transport_config.codec = video_config.codec; |
| 88 transport_config.rtp.config = video_config.rtp_config; | 73 transport_config.rtp.config = video_config.rtp_config; |
| 89 transport_config.rtp.max_outstanding_frames = max_unacked_frames_ + 1; | 74 transport_config.rtp.max_outstanding_frames = max_unacked_frames_ + 1; |
| 90 transport_sender_->InitializeVideo(transport_config); | 75 transport_sender_->InitializeVideo(transport_config); |
| 91 | 76 |
| 92 rtcp_.reset( | 77 rtcp_.reset( |
| 93 new Rtcp(cast_environment_, | 78 new Rtcp(cast_environment_, |
| 94 rtcp_feedback_.get(), | 79 this, |
| 95 transport_sender_, | 80 transport_sender_, |
| 96 NULL, // paced sender. | 81 NULL, // paced sender. |
| 97 NULL, | 82 NULL, |
| 98 video_config.rtcp_mode, | 83 video_config.rtcp_mode, |
| 99 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval), | 84 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval), |
| 100 video_config.rtp_config.ssrc, | 85 video_config.rtp_config.ssrc, |
| 101 video_config.incoming_feedback_ssrc, | 86 video_config.incoming_feedback_ssrc, |
| 102 video_config.rtcp_c_name, | 87 video_config.rtcp_c_name, |
| 103 false)); | 88 false)); |
| 104 rtcp_->SetCastReceiverEventHistorySize(kReceiverRtcpEventHistorySize); | 89 rtcp_->SetCastReceiverEventHistorySize(kReceiverRtcpEventHistorySize); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 TRACE_EVENT_SCOPE_THREAD, | 167 TRACE_EVENT_SCOPE_THREAD, |
| 183 "rtp_timestamp", encoded_frame->rtp_timestamp); | 168 "rtp_timestamp", encoded_frame->rtp_timestamp); |
| 184 | 169 |
| 185 // Only use lowest 8 bits as key. | 170 // Only use lowest 8 bits as key. |
| 186 frame_id_to_rtp_timestamp_[frame_id & 0xff] = encoded_frame->rtp_timestamp; | 171 frame_id_to_rtp_timestamp_[frame_id & 0xff] = encoded_frame->rtp_timestamp; |
| 187 | 172 |
| 188 last_sent_frame_id_ = static_cast<int>(encoded_frame->frame_id); | 173 last_sent_frame_id_ = static_cast<int>(encoded_frame->frame_id); |
| 189 DCHECK(!encoded_frame->reference_time.is_null()); | 174 DCHECK(!encoded_frame->reference_time.is_null()); |
| 190 rtp_timestamp_helper_.StoreLatestTime(encoded_frame->reference_time, | 175 rtp_timestamp_helper_.StoreLatestTime(encoded_frame->reference_time, |
| 191 encoded_frame->rtp_timestamp); | 176 encoded_frame->rtp_timestamp); |
| 177 |
| 178 // At the start of the session, it's important to send reports before each |
| 179 // frame so that the receiver can properly compute playout times. The reason |
| 180 // more than one report is sent is because transmission is not guaranteed, |
| 181 // only best effort, so send enough that one should almost certainly get |
| 182 // through. |
| 183 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { |
| 184 // SendRtcpReport() will schedule future reports to be made if this is the |
| 185 // last "aggressive report." |
| 186 ++num_aggressive_rtcp_reports_sent_; |
| 187 const bool is_last_aggressive_report = |
| 188 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart); |
| 189 VLOG_IF(1, is_last_aggressive_report) << "Sending last aggressive report."; |
| 190 SendRtcpReport(is_last_aggressive_report); |
| 191 } |
| 192 |
| 192 transport_sender_->InsertCodedVideoFrame(*encoded_frame); | 193 transport_sender_->InsertCodedVideoFrame(*encoded_frame); |
| 193 UpdateFramesInFlight(); | 194 UpdateFramesInFlight(); |
| 194 InitializeTimers(); | 195 InitializeTimers(); |
| 195 } | 196 } |
| 196 | 197 |
| 197 void VideoSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) { | 198 void VideoSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) { |
| 198 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 199 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 199 rtcp_->IncomingRtcpPacket(&packet->front(), packet->size()); | 200 rtcp_->IncomingRtcpPacket(&packet->front(), packet->size()); |
| 200 } | 201 } |
| 201 | 202 |
| 202 void VideoSender::ScheduleNextRtcpReport() { | 203 void VideoSender::ScheduleNextRtcpReport() { |
| 203 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 204 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 204 base::TimeDelta time_to_next = rtcp_->TimeToSendNextRtcpReport() - | 205 base::TimeDelta time_to_next = rtcp_->TimeToSendNextRtcpReport() - |
| 205 cast_environment_->Clock()->NowTicks(); | 206 cast_environment_->Clock()->NowTicks(); |
| 206 | 207 |
| 207 time_to_next = std::max( | 208 time_to_next = std::max( |
| 208 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 209 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); |
| 209 | 210 |
| 210 cast_environment_->PostDelayedTask( | 211 cast_environment_->PostDelayedTask( |
| 211 CastEnvironment::MAIN, | 212 CastEnvironment::MAIN, |
| 212 FROM_HERE, | 213 FROM_HERE, |
| 213 base::Bind(&VideoSender::SendRtcpReport, weak_factory_.GetWeakPtr()), | 214 base::Bind(&VideoSender::SendRtcpReport, |
| 215 weak_factory_.GetWeakPtr(), |
| 216 true), |
| 214 time_to_next); | 217 time_to_next); |
| 215 } | 218 } |
| 216 | 219 |
| 217 void VideoSender::SendRtcpReport() { | 220 void VideoSender::SendRtcpReport(bool schedule_future_reports) { |
| 218 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 221 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 219 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 222 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
| 220 uint32 now_as_rtp_timestamp = 0; | 223 uint32 now_as_rtp_timestamp = 0; |
| 221 if (rtp_timestamp_helper_.GetCurrentTimeAsRtpTimestamp( | 224 if (rtp_timestamp_helper_.GetCurrentTimeAsRtpTimestamp( |
| 222 now, &now_as_rtp_timestamp)) { | 225 now, &now_as_rtp_timestamp)) { |
| 223 rtcp_->SendRtcpFromRtpSender(now, now_as_rtp_timestamp); | 226 rtcp_->SendRtcpFromRtpSender(now, now_as_rtp_timestamp); |
| 227 } else { |
| 228 // |rtp_timestamp_helper_| should have stored a mapping by this point. |
| 229 NOTREACHED(); |
| 224 } | 230 } |
| 225 ScheduleNextRtcpReport(); | 231 if (schedule_future_reports) |
| 232 ScheduleNextRtcpReport(); |
| 226 } | 233 } |
| 227 | 234 |
| 228 void VideoSender::ScheduleNextResendCheck() { | 235 void VideoSender::ScheduleNextResendCheck() { |
| 229 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 236 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 230 base::TimeDelta time_to_next; | 237 base::TimeDelta time_to_next; |
| 231 if (last_send_time_.is_null()) { | 238 if (last_send_time_.is_null()) { |
| 232 time_to_next = rtp_max_delay_; | 239 time_to_next = rtp_max_delay_; |
| 233 } else { | 240 } else { |
| 234 time_to_next = last_send_time_ - cast_environment_->Clock()->NowTicks() + | 241 time_to_next = last_send_time_ - cast_environment_->Clock()->NowTicks() + |
| 235 rtp_max_delay_; | 242 rtp_max_delay_; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { | 313 void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { |
| 307 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 314 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 308 base::TimeDelta rtt; | 315 base::TimeDelta rtt; |
| 309 base::TimeDelta avg_rtt; | 316 base::TimeDelta avg_rtt; |
| 310 base::TimeDelta min_rtt; | 317 base::TimeDelta min_rtt; |
| 311 base::TimeDelta max_rtt; | 318 base::TimeDelta max_rtt; |
| 312 | 319 |
| 313 if (rtcp_->Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)) { | 320 if (rtcp_->Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)) { |
| 314 // Don't use a RTT lower than our average. | 321 // Don't use a RTT lower than our average. |
| 315 rtt = std::max(rtt, avg_rtt); | 322 rtt = std::max(rtt, avg_rtt); |
| 323 |
| 324 // Having the RTT values implies the receiver sent back a receiver report |
| 325 // based on it having received a report from here. Therefore, ensure this |
| 326 // sender stops aggressively sending reports. |
| 327 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { |
| 328 VLOG(1) << "No longer a need to send reports aggressively (sent " |
| 329 << num_aggressive_rtcp_reports_sent_ << ")."; |
| 330 num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart; |
| 331 ScheduleNextRtcpReport(); |
| 332 } |
| 316 } else { | 333 } else { |
| 317 // We have no measured value use default. | 334 // We have no measured value use default. |
| 318 rtt = base::TimeDelta::FromMilliseconds(kStartRttMs); | 335 rtt = base::TimeDelta::FromMilliseconds(kStartRttMs); |
| 319 } | 336 } |
| 320 if (cast_feedback.missing_frames_and_packets_.empty()) { | 337 if (cast_feedback.missing_frames_and_packets_.empty()) { |
| 321 // No lost packets. | 338 // No lost packets. |
| 322 int resend_frame = -1; | 339 int resend_frame = -1; |
| 323 if (last_sent_frame_id_ == -1) | 340 if (last_sent_frame_id_ == -1) |
| 324 return; | 341 return; |
| 325 | 342 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 ReceivedAck(cast_feedback.ack_frame_id_); | 378 ReceivedAck(cast_feedback.ack_frame_id_); |
| 362 } | 379 } |
| 363 | 380 |
| 364 void VideoSender::ReceivedAck(uint32 acked_frame_id) { | 381 void VideoSender::ReceivedAck(uint32 acked_frame_id) { |
| 365 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 382 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 366 if (acked_frame_id == UINT32_C(0xFFFFFFFF)) { | 383 if (acked_frame_id == UINT32_C(0xFFFFFFFF)) { |
| 367 // Receiver is sending a status message before any frames are ready to | 384 // Receiver is sending a status message before any frames are ready to |
| 368 // be acked. Ignore. | 385 // be acked. Ignore. |
| 369 return; | 386 return; |
| 370 } | 387 } |
| 371 // Start sending RTCP packets only after receiving the first ACK, i.e. only | |
| 372 // after establishing that the receiver is active. | |
| 373 if (last_acked_frame_id_ == -1) { | |
| 374 ScheduleNextRtcpReport(); | |
| 375 } | |
| 376 last_acked_frame_id_ = static_cast<int>(acked_frame_id); | 388 last_acked_frame_id_ = static_cast<int>(acked_frame_id); |
| 377 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 389 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
| 378 | 390 |
| 379 RtpTimestamp rtp_timestamp = | 391 RtpTimestamp rtp_timestamp = |
| 380 frame_id_to_rtp_timestamp_[acked_frame_id & 0xff]; | 392 frame_id_to_rtp_timestamp_[acked_frame_id & 0xff]; |
| 381 cast_environment_->Logging()->InsertFrameEvent( | 393 cast_environment_->Logging()->InsertFrameEvent( |
| 382 now, FRAME_ACK_RECEIVED, VIDEO_EVENT, rtp_timestamp, acked_frame_id); | 394 now, FRAME_ACK_RECEIVED, VIDEO_EVENT, rtp_timestamp, acked_frame_id); |
| 383 | 395 |
| 384 VLOG(2) << "ReceivedAck:" << static_cast<int>(acked_frame_id); | 396 VLOG(2) << "ReceivedAck:" << static_cast<int>(acked_frame_id); |
| 385 active_session_ = true; | 397 active_session_ = true; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 | 435 |
| 424 void VideoSender::UpdateBitrate(int new_bitrate) { | 436 void VideoSender::UpdateBitrate(int new_bitrate) { |
| 425 // Make sure we don't set the bitrate too insanely low. | 437 // Make sure we don't set the bitrate too insanely low. |
| 426 DCHECK_GT(new_bitrate, 1000); | 438 DCHECK_GT(new_bitrate, 1000); |
| 427 video_encoder_->SetBitRate(new_bitrate); | 439 video_encoder_->SetBitRate(new_bitrate); |
| 428 current_requested_bitrate_ = new_bitrate; | 440 current_requested_bitrate_ = new_bitrate; |
| 429 } | 441 } |
| 430 | 442 |
| 431 } // namespace cast | 443 } // namespace cast |
| 432 } // namespace media | 444 } // namespace media |
| OLD | NEW |