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 |