| 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 <limits> |
| 8 |
| 7 #include "base/trace_event/trace_event.h" | 9 #include "base/trace_event/trace_event.h" |
| 8 #include "media/cast/cast_defines.h" | 10 #include "media/cast/cast_defines.h" |
| 9 #include "media/cast/constants.h" | 11 #include "media/cast/constants.h" |
| 10 #include "media/cast/sender/sender_encoded_frame.h" | 12 #include "media/cast/sender/sender_encoded_frame.h" |
| 11 | 13 |
| 12 namespace media { | 14 namespace media { |
| 13 namespace cast { | 15 namespace cast { |
| 14 namespace { | 16 namespace { |
| 15 | 17 |
| 16 const int kMinSchedulingDelayMs = 1; | 18 const int kMinSchedulingDelayMs = 1; |
| 17 const int kNumAggressiveReportsSentAtStart = 100; | 19 const int kNumAggressiveReportsSentAtStart = 100; |
| 18 | 20 |
| 19 // The additional number of frames that can be in-flight when input exceeds the | 21 // The additional number of frames that can be in-flight when input exceeds the |
| 20 // maximum frame rate. | 22 // maximum frame rate. |
| 21 const int kMaxFrameBurst = 5; | 23 const int kMaxFrameBurst = 5; |
| 22 | 24 |
| 23 } // namespace | 25 } // namespace |
| 24 | 26 |
| 25 // Convenience macro used in logging statements throughout this file. | 27 // Convenience macro used in logging statements throughout this file. |
| 26 #define SENDER_SSRC (is_audio_ ? "AUDIO[" : "VIDEO[") << ssrc_ << "] " | 28 #define SENDER_SSRC (is_audio_ ? "AUDIO[" : "VIDEO[") << ssrc_ << "] " |
| 27 | 29 |
| 28 FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment, | 30 FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment, |
| 29 bool is_audio, | 31 bool is_audio, |
| 30 CastTransportSender* const transport_sender, | 32 CastTransportSender* const transport_sender, |
| 31 int rtp_timebase, | 33 int rtp_timebase, |
| 32 uint32 ssrc, | 34 uint32_t ssrc, |
| 33 double max_frame_rate, | 35 double max_frame_rate, |
| 34 base::TimeDelta min_playout_delay, | 36 base::TimeDelta min_playout_delay, |
| 35 base::TimeDelta max_playout_delay, | 37 base::TimeDelta max_playout_delay, |
| 36 CongestionControl* congestion_control) | 38 CongestionControl* congestion_control) |
| 37 : cast_environment_(cast_environment), | 39 : cast_environment_(cast_environment), |
| 38 transport_sender_(transport_sender), | 40 transport_sender_(transport_sender), |
| 39 ssrc_(ssrc), | 41 ssrc_(ssrc), |
| 40 min_playout_delay_(min_playout_delay == base::TimeDelta() ? | 42 min_playout_delay_(min_playout_delay == base::TimeDelta() |
| 41 max_playout_delay : min_playout_delay), | 43 ? max_playout_delay |
| 44 : min_playout_delay), |
| 42 max_playout_delay_(max_playout_delay), | 45 max_playout_delay_(max_playout_delay), |
| 43 send_target_playout_delay_(false), | 46 send_target_playout_delay_(false), |
| 44 max_frame_rate_(max_frame_rate), | 47 max_frame_rate_(max_frame_rate), |
| 45 num_aggressive_rtcp_reports_sent_(0), | 48 num_aggressive_rtcp_reports_sent_(0), |
| 46 last_sent_frame_id_(0), | 49 last_sent_frame_id_(0), |
| 47 latest_acked_frame_id_(0), | 50 latest_acked_frame_id_(0), |
| 48 duplicate_ack_counter_(0), | 51 duplicate_ack_counter_(0), |
| 49 congestion_control_(congestion_control), | 52 congestion_control_(congestion_control), |
| 50 rtp_timebase_(rtp_timebase), | 53 rtp_timebase_(rtp_timebase), |
| 51 is_audio_(is_audio), | 54 is_audio_(is_audio), |
| (...skipping 27 matching lines...) Expand all Loading... |
| 79 | 82 |
| 80 // Create lip-sync info for the sender report. The last sent frame's | 83 // Create lip-sync info for the sender report. The last sent frame's |
| 81 // reference time and RTP timestamp are used to estimate an RTP timestamp in | 84 // reference time and RTP timestamp are used to estimate an RTP timestamp in |
| 82 // terms of "now." Note that |now| is never likely to be precise to an exact | 85 // terms of "now." Note that |now| is never likely to be precise to an exact |
| 83 // frame boundary; and so the computation here will result in a | 86 // frame boundary; and so the computation here will result in a |
| 84 // |now_as_rtp_timestamp| value that is rarely equal to any one emitted by the | 87 // |now_as_rtp_timestamp| value that is rarely equal to any one emitted by the |
| 85 // encoder. | 88 // encoder. |
| 86 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 89 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
| 87 const base::TimeDelta time_delta = | 90 const base::TimeDelta time_delta = |
| 88 now - GetRecordedReferenceTime(last_sent_frame_id_); | 91 now - GetRecordedReferenceTime(last_sent_frame_id_); |
| 89 const int64 rtp_delta = TimeDeltaToRtpDelta(time_delta, rtp_timebase_); | 92 const int64_t rtp_delta = TimeDeltaToRtpDelta(time_delta, rtp_timebase_); |
| 90 const uint32 now_as_rtp_timestamp = | 93 const uint32_t now_as_rtp_timestamp = |
| 91 GetRecordedRtpTimestamp(last_sent_frame_id_) + | 94 GetRecordedRtpTimestamp(last_sent_frame_id_) + |
| 92 static_cast<uint32>(rtp_delta); | 95 static_cast<uint32_t>(rtp_delta); |
| 93 transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp); | 96 transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp); |
| 94 | 97 |
| 95 if (schedule_future_reports) | 98 if (schedule_future_reports) |
| 96 ScheduleNextRtcpReport(); | 99 ScheduleNextRtcpReport(); |
| 97 } | 100 } |
| 98 | 101 |
| 99 void FrameSender::OnMeasuredRoundTripTime(base::TimeDelta rtt) { | 102 void FrameSender::OnMeasuredRoundTripTime(base::TimeDelta rtt) { |
| 100 DCHECK(rtt > base::TimeDelta()); | 103 DCHECK(rtt > base::TimeDelta()); |
| 101 current_round_trip_time_ = rtt; | 104 current_round_trip_time_ = rtt; |
| 102 } | 105 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 | 156 |
| 154 void FrameSender::ResendForKickstart() { | 157 void FrameSender::ResendForKickstart() { |
| 155 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 158 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 156 DCHECK(!last_send_time_.is_null()); | 159 DCHECK(!last_send_time_.is_null()); |
| 157 VLOG(1) << SENDER_SSRC << "Resending last packet of frame " | 160 VLOG(1) << SENDER_SSRC << "Resending last packet of frame " |
| 158 << last_sent_frame_id_ << " to kick-start."; | 161 << last_sent_frame_id_ << " to kick-start."; |
| 159 last_send_time_ = cast_environment_->Clock()->NowTicks(); | 162 last_send_time_ = cast_environment_->Clock()->NowTicks(); |
| 160 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); | 163 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); |
| 161 } | 164 } |
| 162 | 165 |
| 163 void FrameSender::RecordLatestFrameTimestamps(uint32 frame_id, | 166 void FrameSender::RecordLatestFrameTimestamps(uint32_t frame_id, |
| 164 base::TimeTicks reference_time, | 167 base::TimeTicks reference_time, |
| 165 RtpTimestamp rtp_timestamp) { | 168 RtpTimestamp rtp_timestamp) { |
| 166 DCHECK(!reference_time.is_null()); | 169 DCHECK(!reference_time.is_null()); |
| 167 frame_reference_times_[frame_id % arraysize(frame_reference_times_)] = | 170 frame_reference_times_[frame_id % arraysize(frame_reference_times_)] = |
| 168 reference_time; | 171 reference_time; |
| 169 frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)] = | 172 frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)] = |
| 170 rtp_timestamp; | 173 rtp_timestamp; |
| 171 } | 174 } |
| 172 | 175 |
| 173 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32 frame_id) const { | 176 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32_t frame_id) const { |
| 174 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)]; | 177 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)]; |
| 175 } | 178 } |
| 176 | 179 |
| 177 RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32 frame_id) const { | 180 RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32_t frame_id) const { |
| 178 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)]; | 181 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)]; |
| 179 } | 182 } |
| 180 | 183 |
| 181 int FrameSender::GetUnacknowledgedFrameCount() const { | 184 int FrameSender::GetUnacknowledgedFrameCount() const { |
| 182 const int count = | 185 const int count = |
| 183 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_); | 186 static_cast<int32_t>(last_sent_frame_id_ - latest_acked_frame_id_); |
| 184 DCHECK_GE(count, 0); | 187 DCHECK_GE(count, 0); |
| 185 return count; | 188 return count; |
| 186 } | 189 } |
| 187 | 190 |
| 188 base::TimeDelta FrameSender::GetAllowedInFlightMediaDuration() const { | 191 base::TimeDelta FrameSender::GetAllowedInFlightMediaDuration() const { |
| 189 // The total amount allowed in-flight media should equal the amount that fits | 192 // 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 | 193 // within the entire playout delay window, plus the amount of time it takes to |
| 191 // receive an ACK from the receiver. | 194 // receive an ACK from the receiver. |
| 192 // TODO(miu): Research is needed, but there is likely a better formula. | 195 // TODO(miu): Research is needed, but there is likely a better formula. |
| 193 return target_playout_delay_ + (current_round_trip_time_ / 2); | 196 return target_playout_delay_ + (current_round_trip_time_ / 2); |
| 194 } | 197 } |
| 195 | 198 |
| 196 void FrameSender::SendEncodedFrame( | 199 void FrameSender::SendEncodedFrame( |
| 197 int requested_bitrate_before_encode, | 200 int requested_bitrate_before_encode, |
| 198 scoped_ptr<SenderEncodedFrame> encoded_frame) { | 201 scoped_ptr<SenderEncodedFrame> encoded_frame) { |
| 199 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 202 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 200 | 203 |
| 201 VLOG(2) << SENDER_SSRC << "About to send another frame: last_sent=" | 204 VLOG(2) << SENDER_SSRC << "About to send another frame: last_sent=" |
| 202 << last_sent_frame_id_ << ", latest_acked=" << latest_acked_frame_id_; | 205 << last_sent_frame_id_ << ", latest_acked=" << latest_acked_frame_id_; |
| 203 | 206 |
| 204 const uint32 frame_id = encoded_frame->frame_id; | 207 const uint32_t frame_id = encoded_frame->frame_id; |
| 205 | 208 |
| 206 const bool is_first_frame_to_be_sent = last_send_time_.is_null(); | 209 const bool is_first_frame_to_be_sent = last_send_time_.is_null(); |
| 207 last_send_time_ = cast_environment_->Clock()->NowTicks(); | 210 last_send_time_ = cast_environment_->Clock()->NowTicks(); |
| 208 last_sent_frame_id_ = frame_id; | 211 last_sent_frame_id_ = frame_id; |
| 209 // If this is the first frame about to be sent, fake the value of | 212 // If this is the first frame about to be sent, fake the value of |
| 210 // |latest_acked_frame_id_| to indicate the receiver starts out all caught up. | 213 // |latest_acked_frame_id_| to indicate the receiver starts out all caught up. |
| 211 // Also, schedule the periodic frame re-send checks. | 214 // Also, schedule the periodic frame re-send checks. |
| 212 if (is_first_frame_to_be_sent) { | 215 if (is_first_frame_to_be_sent) { |
| 213 latest_acked_frame_id_ = frame_id - 1; | 216 latest_acked_frame_id_ = frame_id - 1; |
| 214 ScheduleNextResendCheck(); | 217 ScheduleNextResendCheck(); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 scoped_ptr<FrameEvent> ack_event(new FrameEvent()); | 331 scoped_ptr<FrameEvent> ack_event(new FrameEvent()); |
| 329 ack_event->timestamp = now; | 332 ack_event->timestamp = now; |
| 330 ack_event->type = FRAME_ACK_RECEIVED; | 333 ack_event->type = FRAME_ACK_RECEIVED; |
| 331 ack_event->media_type = is_audio_ ? AUDIO_EVENT : VIDEO_EVENT; | 334 ack_event->media_type = is_audio_ ? AUDIO_EVENT : VIDEO_EVENT; |
| 332 ack_event->rtp_timestamp = | 335 ack_event->rtp_timestamp = |
| 333 GetRecordedRtpTimestamp(cast_feedback.ack_frame_id); | 336 GetRecordedRtpTimestamp(cast_feedback.ack_frame_id); |
| 334 ack_event->frame_id = cast_feedback.ack_frame_id; | 337 ack_event->frame_id = cast_feedback.ack_frame_id; |
| 335 cast_environment_->logger()->DispatchFrameEvent(ack_event.Pass()); | 338 cast_environment_->logger()->DispatchFrameEvent(ack_event.Pass()); |
| 336 | 339 |
| 337 const bool is_acked_out_of_order = | 340 const bool is_acked_out_of_order = |
| 338 static_cast<int32>(cast_feedback.ack_frame_id - | 341 static_cast<int32_t>(cast_feedback.ack_frame_id - |
| 339 latest_acked_frame_id_) < 0; | 342 latest_acked_frame_id_) < 0; |
| 340 VLOG(2) << SENDER_SSRC | 343 VLOG(2) << SENDER_SSRC |
| 341 << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "") | 344 << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "") |
| 342 << " for frame " << cast_feedback.ack_frame_id; | 345 << " for frame " << cast_feedback.ack_frame_id; |
| 343 if (is_acked_out_of_order) { | 346 if (is_acked_out_of_order) { |
| 344 TRACE_EVENT_INSTANT2( | 347 TRACE_EVENT_INSTANT2( |
| 345 "cast.stream", "ACK out of order", TRACE_EVENT_SCOPE_THREAD, | 348 "cast.stream", "ACK out of order", TRACE_EVENT_SCOPE_THREAD, |
| 346 "ack_frame_id", cast_feedback.ack_frame_id, | 349 "ack_frame_id", cast_feedback.ack_frame_id, |
| 347 "latest_acked_frame_id", latest_acked_frame_id_); | 350 "latest_acked_frame_id", latest_acked_frame_id_); |
| 348 } else { | 351 } else { |
| 349 // Cancel resends of acked frames. | 352 // Cancel resends of acked frames. |
| 350 std::vector<uint32> cancel_sending_frames; | 353 std::vector<uint32_t> cancel_sending_frames; |
| 351 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) { | 354 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) { |
| 352 latest_acked_frame_id_++; | 355 latest_acked_frame_id_++; |
| 353 cancel_sending_frames.push_back(latest_acked_frame_id_); | 356 cancel_sending_frames.push_back(latest_acked_frame_id_); |
| 354 // This is a good place to match the trace for frame ids | 357 // This is a good place to match the trace for frame ids |
| 355 // since this ensures we not only track frame ids that are | 358 // since this ensures we not only track frame ids that are |
| 356 // implicitly ACKed, but also handles duplicate ACKs | 359 // implicitly ACKed, but also handles duplicate ACKs |
| 357 TRACE_EVENT_ASYNC_END1("cast.stream", | 360 TRACE_EVENT_ASYNC_END1("cast.stream", |
| 358 is_audio_ ? "Audio Transport" : "Video Transport", | 361 is_audio_ ? "Audio Transport" : "Video Transport", |
| 359 cast_feedback.ack_frame_id, | 362 cast_feedback.ack_frame_id, |
| 360 "RTT_usecs", current_round_trip_time_.InMicroseconds()); | 363 "RTT_usecs", current_round_trip_time_.InMicroseconds()); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 383 VLOG(1) << SENDER_SSRC << "Dropping: Burst threshold would be exceeded."; | 386 VLOG(1) << SENDER_SSRC << "Dropping: Burst threshold would be exceeded."; |
| 384 return true; | 387 return true; |
| 385 } | 388 } |
| 386 | 389 |
| 387 // Check that accepting the next frame won't exceed the allowed in-flight | 390 // Check that accepting the next frame won't exceed the allowed in-flight |
| 388 // media duration. | 391 // media duration. |
| 389 const base::TimeDelta duration_would_be_in_flight = | 392 const base::TimeDelta duration_would_be_in_flight = |
| 390 duration_in_flight + frame_duration; | 393 duration_in_flight + frame_duration; |
| 391 const base::TimeDelta allowed_in_flight = GetAllowedInFlightMediaDuration(); | 394 const base::TimeDelta allowed_in_flight = GetAllowedInFlightMediaDuration(); |
| 392 if (VLOG_IS_ON(1)) { | 395 if (VLOG_IS_ON(1)) { |
| 393 const int64 percent = allowed_in_flight > base::TimeDelta() ? | 396 const int64_t percent = |
| 394 100 * duration_would_be_in_flight / allowed_in_flight : kint64max; | 397 allowed_in_flight > base::TimeDelta() |
| 398 ? 100 * duration_would_be_in_flight / allowed_in_flight |
| 399 : std::numeric_limits<int64_t>::max(); |
| 395 VLOG_IF(1, percent > 50) | 400 VLOG_IF(1, percent > 50) |
| 396 << SENDER_SSRC | 401 << SENDER_SSRC |
| 397 << duration_in_flight.InMicroseconds() << " usec in-flight + " | 402 << duration_in_flight.InMicroseconds() << " usec in-flight + " |
| 398 << frame_duration.InMicroseconds() << " usec for next frame --> " | 403 << frame_duration.InMicroseconds() << " usec for next frame --> " |
| 399 << percent << "% of allowed in-flight."; | 404 << percent << "% of allowed in-flight."; |
| 400 } | 405 } |
| 401 if (duration_would_be_in_flight > allowed_in_flight) { | 406 if (duration_would_be_in_flight > allowed_in_flight) { |
| 402 VLOG(1) << SENDER_SSRC << "Dropping: In-flight duration would be too high."; | 407 VLOG(1) << SENDER_SSRC << "Dropping: In-flight duration would be too high."; |
| 403 return true; | 408 return true; |
| 404 } | 409 } |
| 405 | 410 |
| 406 // Next frame is accepted. | 411 // Next frame is accepted. |
| 407 return false; | 412 return false; |
| 408 } | 413 } |
| 409 | 414 |
| 410 } // namespace cast | 415 } // namespace cast |
| 411 } // namespace media | 416 } // namespace media |
| OLD | NEW |