Chromium Code Reviews| 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/sender/frame_sender.h" | 5 #include "media/cast/sender/frame_sender.h" |
| 6 | 6 |
| 7 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
| 8 | 8 |
| 9 namespace media { | 9 namespace media { |
| 10 namespace cast { | 10 namespace cast { |
| 11 namespace { | 11 namespace { |
| 12 | 12 |
| 13 const int kMinSchedulingDelayMs = 1; | 13 const int kMinSchedulingDelayMs = 1; |
| 14 const int kNumAggressiveReportsSentAtStart = 100; | 14 const int kNumAggressiveReportsSentAtStart = 100; |
| 15 | 15 |
| 16 // The additional number of frames that can be in-flight when input exceeds the | |
| 17 // maximum frame rate. | |
| 18 const int kMaxFrameBurst = 5; | |
| 19 | |
| 16 } // namespace | 20 } // namespace |
| 17 | 21 |
| 22 // Convenience macro used in logging statements throughout this file. | |
| 23 #define SENDER_SSRC (is_audio_ ? "AUDIO[" : "VIDEO[") << ssrc_ << "] " | |
| 24 | |
| 18 FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment, | 25 FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment, |
| 19 bool is_audio, | 26 bool is_audio, |
| 20 CastTransportSender* const transport_sender, | 27 CastTransportSender* const transport_sender, |
| 21 base::TimeDelta rtcp_interval, | 28 base::TimeDelta rtcp_interval, |
| 22 int rtp_timebase, | 29 int rtp_timebase, |
| 23 uint32 ssrc, | 30 uint32 ssrc, |
| 24 double max_frame_rate, | 31 double max_frame_rate, |
| 25 base::TimeDelta min_playout_delay, | 32 base::TimeDelta min_playout_delay, |
| 26 base::TimeDelta max_playout_delay, | 33 base::TimeDelta max_playout_delay, |
| 27 CongestionControl* congestion_control) | 34 CongestionControl* congestion_control) |
| 28 : cast_environment_(cast_environment), | 35 : cast_environment_(cast_environment), |
| 29 transport_sender_(transport_sender), | 36 transport_sender_(transport_sender), |
| 30 ssrc_(ssrc), | 37 ssrc_(ssrc), |
| 31 rtcp_interval_(rtcp_interval), | 38 rtcp_interval_(rtcp_interval), |
| 32 min_playout_delay_(min_playout_delay == base::TimeDelta() ? | 39 min_playout_delay_(min_playout_delay == base::TimeDelta() ? |
| 33 max_playout_delay : min_playout_delay), | 40 max_playout_delay : min_playout_delay), |
| 34 max_playout_delay_(max_playout_delay), | 41 max_playout_delay_(max_playout_delay), |
| 35 max_frame_rate_(max_frame_rate), | 42 max_frame_rate_(max_frame_rate), |
| 36 num_aggressive_rtcp_reports_sent_(0), | 43 num_aggressive_rtcp_reports_sent_(0), |
| 37 last_sent_frame_id_(0), | 44 last_sent_frame_id_(0), |
| 38 latest_acked_frame_id_(0), | 45 latest_acked_frame_id_(0), |
| 39 duplicate_ack_counter_(0), | 46 duplicate_ack_counter_(0), |
| 47 congestion_control_(congestion_control), | |
| 40 rtp_timebase_(rtp_timebase), | 48 rtp_timebase_(rtp_timebase), |
| 41 congestion_control_(congestion_control), | |
| 42 is_audio_(is_audio), | 49 is_audio_(is_audio), |
| 43 weak_factory_(this) { | 50 weak_factory_(this) { |
| 44 DCHECK(transport_sender_); | 51 DCHECK(transport_sender_); |
| 45 DCHECK_GT(rtp_timebase_, 0); | 52 DCHECK_GT(rtp_timebase_, 0); |
| 46 DCHECK(congestion_control_); | 53 DCHECK(congestion_control_); |
| 47 SetTargetPlayoutDelay(min_playout_delay_); | 54 SetTargetPlayoutDelay(min_playout_delay_); |
| 48 send_target_playout_delay_ = false; | 55 send_target_playout_delay_ = false; |
| 49 memset(frame_rtp_timestamps_, 0, sizeof(frame_rtp_timestamps_)); | 56 memset(frame_rtp_timestamps_, 0, sizeof(frame_rtp_timestamps_)); |
| 50 } | 57 } |
| 51 | 58 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 114 | 121 |
| 115 void FrameSender::ResendCheck() { | 122 void FrameSender::ResendCheck() { |
| 116 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 123 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 117 DCHECK(!last_send_time_.is_null()); | 124 DCHECK(!last_send_time_.is_null()); |
| 118 const base::TimeDelta time_since_last_send = | 125 const base::TimeDelta time_since_last_send = |
| 119 cast_environment_->Clock()->NowTicks() - last_send_time_; | 126 cast_environment_->Clock()->NowTicks() - last_send_time_; |
| 120 if (time_since_last_send > target_playout_delay_) { | 127 if (time_since_last_send > target_playout_delay_) { |
| 121 if (latest_acked_frame_id_ == last_sent_frame_id_) { | 128 if (latest_acked_frame_id_ == last_sent_frame_id_) { |
| 122 // Last frame acked, no point in doing anything | 129 // Last frame acked, no point in doing anything |
| 123 } else { | 130 } else { |
| 124 VLOG(1) << "ACK timeout; last acked frame: " << latest_acked_frame_id_; | 131 VLOG(1) << SENDER_SSRC << "ACK timeout; last acked frame: " |
| 132 << latest_acked_frame_id_; | |
| 125 ResendForKickstart(); | 133 ResendForKickstart(); |
| 126 } | 134 } |
| 127 } | 135 } |
| 128 ScheduleNextResendCheck(); | 136 ScheduleNextResendCheck(); |
| 129 } | 137 } |
| 130 | 138 |
| 131 void FrameSender::ScheduleNextResendCheck() { | 139 void FrameSender::ScheduleNextResendCheck() { |
| 132 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 140 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 133 DCHECK(!last_send_time_.is_null()); | 141 DCHECK(!last_send_time_.is_null()); |
| 134 base::TimeDelta time_to_next = | 142 base::TimeDelta time_to_next = |
| 135 last_send_time_ - cast_environment_->Clock()->NowTicks() + | 143 last_send_time_ - cast_environment_->Clock()->NowTicks() + |
| 136 target_playout_delay_; | 144 target_playout_delay_; |
| 137 time_to_next = std::max( | 145 time_to_next = std::max( |
| 138 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 146 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); |
| 139 cast_environment_->PostDelayedTask( | 147 cast_environment_->PostDelayedTask( |
| 140 CastEnvironment::MAIN, | 148 CastEnvironment::MAIN, |
| 141 FROM_HERE, | 149 FROM_HERE, |
| 142 base::Bind(&FrameSender::ResendCheck, weak_factory_.GetWeakPtr()), | 150 base::Bind(&FrameSender::ResendCheck, weak_factory_.GetWeakPtr()), |
| 143 time_to_next); | 151 time_to_next); |
| 144 } | 152 } |
| 145 | 153 |
| 146 void FrameSender::ResendForKickstart() { | 154 void FrameSender::ResendForKickstart() { |
| 147 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 155 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 148 DCHECK(!last_send_time_.is_null()); | 156 DCHECK(!last_send_time_.is_null()); |
| 149 VLOG(1) << "Resending last packet of frame " << last_sent_frame_id_ | 157 VLOG(1) << SENDER_SSRC << "Resending last packet of frame " |
| 150 << " to kick-start."; | 158 << last_sent_frame_id_ << " to kick-start."; |
| 151 last_send_time_ = cast_environment_->Clock()->NowTicks(); | 159 last_send_time_ = cast_environment_->Clock()->NowTicks(); |
| 152 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); | 160 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); |
| 153 } | 161 } |
| 154 | 162 |
| 155 void FrameSender::RecordLatestFrameTimestamps(uint32 frame_id, | 163 void FrameSender::RecordLatestFrameTimestamps(uint32 frame_id, |
| 156 base::TimeTicks reference_time, | 164 base::TimeTicks reference_time, |
| 157 RtpTimestamp rtp_timestamp) { | 165 RtpTimestamp rtp_timestamp) { |
| 158 DCHECK(!reference_time.is_null()); | 166 DCHECK(!reference_time.is_null()); |
| 159 frame_reference_times_[frame_id % arraysize(frame_reference_times_)] = | 167 frame_reference_times_[frame_id % arraysize(frame_reference_times_)] = |
| 160 reference_time; | 168 reference_time; |
| 161 frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)] = | 169 frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)] = |
| 162 rtp_timestamp; | 170 rtp_timestamp; |
| 163 } | 171 } |
| 164 | 172 |
| 165 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32 frame_id) const { | 173 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32 frame_id) const { |
| 166 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)]; | 174 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)]; |
| 167 } | 175 } |
| 168 | 176 |
| 169 RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32 frame_id) const { | 177 RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32 frame_id) const { |
| 170 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)]; | 178 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)]; |
| 171 } | 179 } |
| 172 | 180 |
| 181 int FrameSender::GetUnacknowledgedFrameCount() const { | |
| 182 const int count = | |
| 183 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_); | |
| 184 DCHECK_GE(count, 0); | |
| 185 return count; | |
| 186 } | |
| 187 | |
| 188 base::TimeDelta FrameSender::GetAllowedInFlightMediaDuration() const { | |
| 189 // The total amount allowed in-flight media should equal the amount that fits | |
| 190 // within the entire playout delay window, plus the amount of time it takes to | |
| 191 // receive an ACK from the receiver. | |
| 192 // TODO(miu): Research is needed, but there is likely a better formula. | |
| 193 return target_playout_delay_ + (current_round_trip_time_ / 2); | |
| 194 } | |
| 195 | |
| 173 void FrameSender::SendEncodedFrame( | 196 void FrameSender::SendEncodedFrame( |
| 174 int requested_bitrate_before_encode, | 197 int requested_bitrate_before_encode, |
| 175 scoped_ptr<EncodedFrame> encoded_frame) { | 198 scoped_ptr<EncodedFrame> encoded_frame) { |
| 176 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 199 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 177 | 200 |
| 201 VLOG(2) << SENDER_SSRC << "About to send another frame: last_sent=" | |
| 202 << last_sent_frame_id_ << ", latest_acked=" << latest_acked_frame_id_; | |
| 203 | |
| 178 const uint32 frame_id = encoded_frame->frame_id; | 204 const uint32 frame_id = encoded_frame->frame_id; |
| 179 | 205 |
| 180 const bool is_first_frame_to_be_sent = last_send_time_.is_null(); | 206 const bool is_first_frame_to_be_sent = last_send_time_.is_null(); |
| 181 last_send_time_ = cast_environment_->Clock()->NowTicks(); | 207 last_send_time_ = cast_environment_->Clock()->NowTicks(); |
| 182 last_sent_frame_id_ = frame_id; | 208 last_sent_frame_id_ = frame_id; |
| 183 // If this is the first frame about to be sent, fake the value of | 209 // If this is the first frame about to be sent, fake the value of |
| 184 // |latest_acked_frame_id_| to indicate the receiver starts out all caught up. | 210 // |latest_acked_frame_id_| to indicate the receiver starts out all caught up. |
| 185 // Also, schedule the periodic frame re-send checks. | 211 // Also, schedule the periodic frame re-send checks. |
| 186 if (is_first_frame_to_be_sent) { | 212 if (is_first_frame_to_be_sent) { |
| 187 latest_acked_frame_id_ = frame_id - 1; | 213 latest_acked_frame_id_ = frame_id - 1; |
| 188 ScheduleNextResendCheck(); | 214 ScheduleNextResendCheck(); |
| 189 } | 215 } |
| 190 | 216 |
| 191 VLOG_IF(1, encoded_frame->dependency == EncodedFrame::KEY) | 217 VLOG_IF(1, !is_audio_ && encoded_frame->dependency == EncodedFrame::KEY) |
| 192 << "Send encoded key frame; frame_id: " << frame_id; | 218 << SENDER_SSRC << "Sending encoded key frame, id=" << frame_id; |
| 193 | 219 |
| 194 cast_environment_->Logging()->InsertEncodedFrameEvent( | 220 cast_environment_->Logging()->InsertEncodedFrameEvent( |
| 195 last_send_time_, FRAME_ENCODED, | 221 last_send_time_, FRAME_ENCODED, |
| 196 is_audio_ ? AUDIO_EVENT : VIDEO_EVENT, | 222 is_audio_ ? AUDIO_EVENT : VIDEO_EVENT, |
| 197 encoded_frame->rtp_timestamp, | 223 encoded_frame->rtp_timestamp, |
| 198 frame_id, static_cast<int>(encoded_frame->data.size()), | 224 frame_id, static_cast<int>(encoded_frame->data.size()), |
| 199 encoded_frame->dependency == EncodedFrame::KEY, | 225 encoded_frame->dependency == EncodedFrame::KEY, |
| 200 requested_bitrate_before_encode); | 226 requested_bitrate_before_encode); |
| 201 | 227 |
| 202 RecordLatestFrameTimestamps(frame_id, | 228 RecordLatestFrameTimestamps(frame_id, |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 215 // frame so that the receiver can properly compute playout times. The reason | 241 // frame so that the receiver can properly compute playout times. The reason |
| 216 // more than one report is sent is because transmission is not guaranteed, | 242 // more than one report is sent is because transmission is not guaranteed, |
| 217 // only best effort, so send enough that one should almost certainly get | 243 // only best effort, so send enough that one should almost certainly get |
| 218 // through. | 244 // through. |
| 219 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { | 245 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { |
| 220 // SendRtcpReport() will schedule future reports to be made if this is the | 246 // SendRtcpReport() will schedule future reports to be made if this is the |
| 221 // last "aggressive report." | 247 // last "aggressive report." |
| 222 ++num_aggressive_rtcp_reports_sent_; | 248 ++num_aggressive_rtcp_reports_sent_; |
| 223 const bool is_last_aggressive_report = | 249 const bool is_last_aggressive_report = |
| 224 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart); | 250 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart); |
| 225 VLOG_IF(1, is_last_aggressive_report) << "Sending last aggressive report."; | 251 VLOG_IF(1, is_last_aggressive_report) |
| 252 << SENDER_SSRC << "Sending last aggressive report."; | |
| 226 SendRtcpReport(is_last_aggressive_report); | 253 SendRtcpReport(is_last_aggressive_report); |
| 227 } | 254 } |
| 228 | 255 |
| 229 congestion_control_->SendFrameToTransport( | 256 congestion_control_->SendFrameToTransport( |
| 230 frame_id, encoded_frame->data.size() * 8, last_send_time_); | 257 frame_id, encoded_frame->data.size() * 8, last_send_time_); |
| 231 | 258 |
| 232 if (send_target_playout_delay_) { | 259 if (send_target_playout_delay_) { |
| 233 encoded_frame->new_playout_delay_ms = | 260 encoded_frame->new_playout_delay_ms = |
| 234 target_playout_delay_.InMilliseconds(); | 261 target_playout_delay_.InMilliseconds(); |
| 235 } | 262 } |
| 236 transport_sender_->InsertFrame(ssrc_, *encoded_frame); | 263 transport_sender_->InsertFrame(ssrc_, *encoded_frame); |
| 237 } | 264 } |
| 238 | 265 |
| 239 void FrameSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { | 266 void FrameSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { |
| 240 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 267 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 241 | 268 |
| 242 const bool have_valid_rtt = current_round_trip_time_ > base::TimeDelta(); | 269 const bool have_valid_rtt = current_round_trip_time_ > base::TimeDelta(); |
| 243 if (have_valid_rtt) { | 270 if (have_valid_rtt) { |
| 244 congestion_control_->UpdateRtt(current_round_trip_time_); | 271 congestion_control_->UpdateRtt(current_round_trip_time_); |
| 245 | 272 |
| 246 // Having the RTT value implies the receiver sent back a receiver report | 273 // Having the RTT value implies the receiver sent back a receiver report |
| 247 // based on it having received a report from here. Therefore, ensure this | 274 // based on it having received a report from here. Therefore, ensure this |
| 248 // sender stops aggressively sending reports. | 275 // sender stops aggressively sending reports. |
| 249 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { | 276 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { |
| 250 VLOG(1) << "No longer a need to send reports aggressively (sent " | 277 VLOG(1) << SENDER_SSRC |
| 278 << "No longer a need to send reports aggressively (sent " | |
| 251 << num_aggressive_rtcp_reports_sent_ << ")."; | 279 << num_aggressive_rtcp_reports_sent_ << ")."; |
| 252 num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart; | 280 num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart; |
| 253 ScheduleNextRtcpReport(); | 281 ScheduleNextRtcpReport(); |
| 254 } | 282 } |
| 255 } | 283 } |
| 256 | 284 |
| 257 if (last_send_time_.is_null()) | 285 if (last_send_time_.is_null()) |
| 258 return; // Cannot get an ACK without having first sent a frame. | 286 return; // Cannot get an ACK without having first sent a frame. |
| 259 | 287 |
| 260 if (cast_feedback.missing_frames_and_packets.empty()) { | 288 if (cast_feedback.missing_frames_and_packets.empty()) { |
| 261 OnAck(cast_feedback.ack_frame_id); | 289 OnAck(cast_feedback.ack_frame_id); |
| 262 | 290 |
| 263 // We only count duplicate ACKs when we have sent newer frames. | 291 // We only count duplicate ACKs when we have sent newer frames. |
| 264 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id && | 292 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id && |
| 265 latest_acked_frame_id_ != last_sent_frame_id_) { | 293 latest_acked_frame_id_ != last_sent_frame_id_) { |
| 266 duplicate_ack_counter_++; | 294 duplicate_ack_counter_++; |
| 267 } else { | 295 } else { |
| 268 duplicate_ack_counter_ = 0; | 296 duplicate_ack_counter_ = 0; |
| 269 } | 297 } |
| 270 // TODO(miu): The values "2" and "3" should be derived from configuration. | 298 // TODO(miu): The values "2" and "3" should be derived from configuration. |
| 271 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) { | 299 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) { |
| 272 VLOG(1) << "Received duplicate ACK for frame " << latest_acked_frame_id_; | 300 VLOG(1) << SENDER_SSRC << "Received duplicate ACK for frame " |
| 301 << latest_acked_frame_id_; | |
| 273 ResendForKickstart(); | 302 ResendForKickstart(); |
| 274 } | 303 } |
| 275 } else { | 304 } else { |
| 276 // Only count duplicated ACKs if there is no NACK request in between. | 305 // Only count duplicated ACKs if there is no NACK request in between. |
| 277 // This is to avoid aggresive resend. | 306 // This is to avoid aggresive resend. |
| 278 duplicate_ack_counter_ = 0; | 307 duplicate_ack_counter_ = 0; |
| 279 } | 308 } |
| 280 | 309 |
| 281 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 310 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
| 282 congestion_control_->AckFrame(cast_feedback.ack_frame_id, now); | 311 congestion_control_->AckFrame(cast_feedback.ack_frame_id, now); |
| 283 | 312 |
| 284 cast_environment_->Logging()->InsertFrameEvent( | 313 cast_environment_->Logging()->InsertFrameEvent( |
| 285 now, | 314 now, |
| 286 FRAME_ACK_RECEIVED, | 315 FRAME_ACK_RECEIVED, |
| 287 is_audio_ ? AUDIO_EVENT : VIDEO_EVENT, | 316 is_audio_ ? AUDIO_EVENT : VIDEO_EVENT, |
| 288 GetRecordedRtpTimestamp(cast_feedback.ack_frame_id), | 317 GetRecordedRtpTimestamp(cast_feedback.ack_frame_id), |
| 289 cast_feedback.ack_frame_id); | 318 cast_feedback.ack_frame_id); |
| 290 | 319 |
| 291 const bool is_acked_out_of_order = | 320 const bool is_acked_out_of_order = |
| 292 static_cast<int32>(cast_feedback.ack_frame_id - | 321 static_cast<int32>(cast_feedback.ack_frame_id - |
| 293 latest_acked_frame_id_) < 0; | 322 latest_acked_frame_id_) < 0; |
| 294 VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "") | 323 VLOG(2) << SENDER_SSRC |
| 324 << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "") | |
| 295 << " for frame " << cast_feedback.ack_frame_id; | 325 << " for frame " << cast_feedback.ack_frame_id; |
| 296 if (!is_acked_out_of_order) { | 326 if (!is_acked_out_of_order) { |
| 297 // Cancel resends of acked frames. | 327 // Cancel resends of acked frames. |
| 298 std::vector<uint32> cancel_sending_frames; | 328 std::vector<uint32> cancel_sending_frames; |
| 299 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) { | 329 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) { |
| 300 latest_acked_frame_id_++; | 330 latest_acked_frame_id_++; |
| 301 cancel_sending_frames.push_back(latest_acked_frame_id_); | 331 cancel_sending_frames.push_back(latest_acked_frame_id_); |
| 302 } | 332 } |
| 303 transport_sender_->CancelSendingFrames(ssrc_, cancel_sending_frames); | 333 transport_sender_->CancelSendingFrames(ssrc_, cancel_sending_frames); |
| 304 latest_acked_frame_id_ = cast_feedback.ack_frame_id; | 334 latest_acked_frame_id_ = cast_feedback.ack_frame_id; |
| 305 } | 335 } |
| 306 } | 336 } |
| 307 | 337 |
| 308 bool FrameSender::ShouldDropNextFrame(base::TimeTicks capture_time) const { | 338 bool FrameSender::ShouldDropNextFrame(base::TimeDelta frame_duration) const { |
| 309 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 339 // Check that accepting the next frame won't cause more frames to become |
| 310 int frames_in_flight = 0; | 340 // in-flight than the system's design limit. |
| 311 base::TimeDelta duration_in_flight; | 341 const int count_frames_in_flight = |
| 312 if (!last_send_time_.is_null()) { | 342 GetUnacknowledgedFrameCount() + GetNumberOfFramesInEncoder(); |
| 313 frames_in_flight = | 343 if (count_frames_in_flight >= kMaxUnackedFrames) { |
| 314 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_); | 344 VLOG(1) << SENDER_SSRC << "Dropping: Too many frames would be in-flight."; |
| 315 if (frames_in_flight > 0) { | 345 return true; |
| 316 const uint32 oldest_unacked_frame_id = latest_acked_frame_id_ + 1; | |
| 317 duration_in_flight = | |
| 318 capture_time - GetRecordedReferenceTime(oldest_unacked_frame_id); | |
| 319 } | |
| 320 } | 346 } |
| 321 frames_in_flight += GetNumberOfFramesInEncoder(); | 347 |
| 322 VLOG(2) << frames_in_flight | 348 // Check that accepting the next frame won't exceed the configured maximum |
|
hubbe
2014/09/18 17:56:05
Do we really need this part?
We'll still be limite
miu
2014/09/18 21:38:43
IMO, it's an important safety measure to have. It
| |
| 323 << " frames in flight; last sent: " << last_sent_frame_id_ | 349 // frame rate, allowing for short-term bursts. |
| 324 << "; latest acked: " << latest_acked_frame_id_ | 350 base::TimeDelta duration_in_flight = GetInFlightMediaDuration(); |
| 325 << "; frames in encoder: " << GetNumberOfFramesInEncoder() | 351 const double max_frames_in_flight = |
| 326 << "; duration in flight: " | 352 max_frame_rate_ * duration_in_flight.InSecondsF(); |
| 327 << duration_in_flight.InMicroseconds() << " usec (" | 353 if (count_frames_in_flight >= max_frames_in_flight + kMaxFrameBurst) { |
| 328 << (target_playout_delay_ > base::TimeDelta() ? | 354 VLOG(1) << SENDER_SSRC << "Dropping: Burst threshold would be exceeded."; |
| 329 100 * duration_in_flight / target_playout_delay_ : | 355 return true; |
| 330 kint64max) << "%)"; | 356 } |
| 331 return frames_in_flight >= max_unacked_frames_ || | 357 |
| 332 duration_in_flight >= target_playout_delay_; | 358 // Check that accepting the next frame won't exceed the allowed in-flight |
| 359 // media duration. | |
| 360 const base::TimeDelta duration_would_be_in_flight = | |
| 361 duration_in_flight + frame_duration; | |
| 362 const base::TimeDelta allowed_in_flight = GetAllowedInFlightMediaDuration(); | |
| 363 if (VLOG_IS_ON(1)) { | |
| 364 const int64 percent = allowed_in_flight > base::TimeDelta() ? | |
| 365 100 * duration_would_be_in_flight / allowed_in_flight : kint64max; | |
| 366 VLOG_IF(1, percent > 50) | |
| 367 << SENDER_SSRC | |
| 368 << duration_in_flight.InMicroseconds() << " usec in-flight + " | |
| 369 << frame_duration.InMicroseconds() << " usec for next frame --> " | |
| 370 << percent << "% of allowed in-flight."; | |
| 371 } | |
| 372 if (duration_would_be_in_flight > allowed_in_flight) { | |
| 373 VLOG(1) << SENDER_SSRC << "Dropping: In-flight duration would be too high."; | |
| 374 return true; | |
| 375 } | |
| 376 | |
| 377 // Next frame is accepted. | |
| 378 return false; | |
| 333 } | 379 } |
| 334 | 380 |
| 335 } // namespace cast | 381 } // namespace cast |
| 336 } // namespace media | 382 } // namespace media |
| OLD | NEW |