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
3 // found in the LICENSE file.
4
5 #include "media/cast/sender/frame_sender.h"
6
7 #include "base/debug/trace_event.h"
8
9 namespace media {
10 namespace cast {
11 namespace {
12
13 const int kMinSchedulingDelayMs = 1;
14 const int kNumAggressiveReportsSentAtStart = 100;
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
20 } // namespace
21
22 // Convenience macro used in logging statements throughout this file.
23 #define SENDER_SSRC (is_audio_ ? "AUDIO[" : "VIDEO[") << ssrc_ << "] "
24
FrameSender(scoped_refptr<CastEnvironment> cast_environment,bool is_audio,CastTransportSender * const transport_sender,base::TimeDelta rtcp_interval,int rtp_timebase,uint32 ssrc,double max_frame_rate,base::TimeDelta min_playout_delay,base::TimeDelta max_playout_delay,CongestionControl * congestion_control)25 FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment,
26 bool is_audio,
27 CastTransportSender* const transport_sender,
28 base::TimeDelta rtcp_interval,
29 int rtp_timebase,
30 uint32 ssrc,
31 double max_frame_rate,
32 base::TimeDelta min_playout_delay,
33 base::TimeDelta max_playout_delay,
34 CongestionControl* congestion_control)
35 : cast_environment_(cast_environment),
36 transport_sender_(transport_sender),
37 ssrc_(ssrc),
38 rtcp_interval_(rtcp_interval),
39 min_playout_delay_(min_playout_delay == base::TimeDelta() ?
40 max_playout_delay : min_playout_delay),
41 max_playout_delay_(max_playout_delay),
42 max_frame_rate_(max_frame_rate),
43 num_aggressive_rtcp_reports_sent_(0),
44 last_sent_frame_id_(0),
45 latest_acked_frame_id_(0),
46 duplicate_ack_counter_(0),
47 congestion_control_(congestion_control),
48 rtp_timebase_(rtp_timebase),
49 is_audio_(is_audio),
50 weak_factory_(this) {
51 DCHECK(transport_sender_);
52 DCHECK_GT(rtp_timebase_, 0);
53 DCHECK(congestion_control_);
54 SetTargetPlayoutDelay(min_playout_delay_);
55 send_target_playout_delay_ = false;
56 memset(frame_rtp_timestamps_, 0, sizeof(frame_rtp_timestamps_));
57 }
58
~FrameSender()59 FrameSender::~FrameSender() {
60 }
61
ScheduleNextRtcpReport()62 void FrameSender::ScheduleNextRtcpReport() {
63 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
64 base::TimeDelta time_to_next = rtcp_interval_;
65
66 time_to_next = std::max(
67 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
68
69 cast_environment_->PostDelayedTask(
70 CastEnvironment::MAIN,
71 FROM_HERE,
72 base::Bind(&FrameSender::SendRtcpReport, weak_factory_.GetWeakPtr(),
73 true),
74 time_to_next);
75 }
76
SendRtcpReport(bool schedule_future_reports)77 void FrameSender::SendRtcpReport(bool schedule_future_reports) {
78 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
79
80 // Sanity-check: We should have sent at least the first frame by this point.
81 DCHECK(!last_send_time_.is_null());
82
83 // Create lip-sync info for the sender report. The last sent frame's
84 // reference time and RTP timestamp are used to estimate an RTP timestamp in
85 // terms of "now." Note that |now| is never likely to be precise to an exact
86 // frame boundary; and so the computation here will result in a
87 // |now_as_rtp_timestamp| value that is rarely equal to any one emitted by the
88 // encoder.
89 const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
90 const base::TimeDelta time_delta =
91 now - GetRecordedReferenceTime(last_sent_frame_id_);
92 const int64 rtp_delta = TimeDeltaToRtpDelta(time_delta, rtp_timebase_);
93 const uint32 now_as_rtp_timestamp =
94 GetRecordedRtpTimestamp(last_sent_frame_id_) +
95 static_cast<uint32>(rtp_delta);
96 transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp);
97
98 if (schedule_future_reports)
99 ScheduleNextRtcpReport();
100 }
101
OnMeasuredRoundTripTime(base::TimeDelta rtt)102 void FrameSender::OnMeasuredRoundTripTime(base::TimeDelta rtt) {
103 DCHECK(rtt > base::TimeDelta());
104 current_round_trip_time_ = rtt;
105 }
106
SetTargetPlayoutDelay(base::TimeDelta new_target_playout_delay)107 void FrameSender::SetTargetPlayoutDelay(
108 base::TimeDelta new_target_playout_delay) {
109 new_target_playout_delay = std::max(new_target_playout_delay,
110 min_playout_delay_);
111 new_target_playout_delay = std::min(new_target_playout_delay,
112 max_playout_delay_);
113 target_playout_delay_ = new_target_playout_delay;
114 max_unacked_frames_ =
115 std::min(kMaxUnackedFrames,
116 1 + static_cast<int>(target_playout_delay_ *
117 max_frame_rate_ /
118 base::TimeDelta::FromSeconds(1)));
119 send_target_playout_delay_ = true;
120 }
121
ResendCheck()122 void FrameSender::ResendCheck() {
123 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
124 DCHECK(!last_send_time_.is_null());
125 const base::TimeDelta time_since_last_send =
126 cast_environment_->Clock()->NowTicks() - last_send_time_;
127 if (time_since_last_send > target_playout_delay_) {
128 if (latest_acked_frame_id_ == last_sent_frame_id_) {
129 // Last frame acked, no point in doing anything
130 } else {
131 VLOG(1) << SENDER_SSRC << "ACK timeout; last acked frame: "
132 << latest_acked_frame_id_;
133 ResendForKickstart();
134 }
135 }
136 ScheduleNextResendCheck();
137 }
138
ScheduleNextResendCheck()139 void FrameSender::ScheduleNextResendCheck() {
140 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
141 DCHECK(!last_send_time_.is_null());
142 base::TimeDelta time_to_next =
143 last_send_time_ - cast_environment_->Clock()->NowTicks() +
144 target_playout_delay_;
145 time_to_next = std::max(
146 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
147 cast_environment_->PostDelayedTask(
148 CastEnvironment::MAIN,
149 FROM_HERE,
150 base::Bind(&FrameSender::ResendCheck, weak_factory_.GetWeakPtr()),
151 time_to_next);
152 }
153
ResendForKickstart()154 void FrameSender::ResendForKickstart() {
155 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
156 DCHECK(!last_send_time_.is_null());
157 VLOG(1) << SENDER_SSRC << "Resending last packet of frame "
158 << last_sent_frame_id_ << " to kick-start.";
159 last_send_time_ = cast_environment_->Clock()->NowTicks();
160 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_);
161 }
162
RecordLatestFrameTimestamps(uint32 frame_id,base::TimeTicks reference_time,RtpTimestamp rtp_timestamp)163 void FrameSender::RecordLatestFrameTimestamps(uint32 frame_id,
164 base::TimeTicks reference_time,
165 RtpTimestamp rtp_timestamp) {
166 DCHECK(!reference_time.is_null());
167 frame_reference_times_[frame_id % arraysize(frame_reference_times_)] =
168 reference_time;
169 frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)] =
170 rtp_timestamp;
171 }
172
GetRecordedReferenceTime(uint32 frame_id) const173 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32 frame_id) const {
174 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)];
175 }
176
GetRecordedRtpTimestamp(uint32 frame_id) const177 RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32 frame_id) const {
178 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)];
179 }
180
GetUnacknowledgedFrameCount() const181 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
GetAllowedInFlightMediaDuration() const188 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
SendEncodedFrame(int requested_bitrate_before_encode,scoped_ptr<EncodedFrame> encoded_frame)196 void FrameSender::SendEncodedFrame(
197 int requested_bitrate_before_encode,
198 scoped_ptr<EncodedFrame> encoded_frame) {
199 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
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
204 const uint32 frame_id = encoded_frame->frame_id;
205
206 const bool is_first_frame_to_be_sent = last_send_time_.is_null();
207 last_send_time_ = cast_environment_->Clock()->NowTicks();
208 last_sent_frame_id_ = frame_id;
209 // 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.
211 // Also, schedule the periodic frame re-send checks.
212 if (is_first_frame_to_be_sent) {
213 latest_acked_frame_id_ = frame_id - 1;
214 ScheduleNextResendCheck();
215 }
216
217 VLOG_IF(1, !is_audio_ && encoded_frame->dependency == EncodedFrame::KEY)
218 << SENDER_SSRC << "Sending encoded key frame, id=" << frame_id;
219
220 cast_environment_->Logging()->InsertEncodedFrameEvent(
221 last_send_time_, FRAME_ENCODED,
222 is_audio_ ? AUDIO_EVENT : VIDEO_EVENT,
223 encoded_frame->rtp_timestamp,
224 frame_id, static_cast<int>(encoded_frame->data.size()),
225 encoded_frame->dependency == EncodedFrame::KEY,
226 requested_bitrate_before_encode);
227
228 RecordLatestFrameTimestamps(frame_id,
229 encoded_frame->reference_time,
230 encoded_frame->rtp_timestamp);
231
232 if (!is_audio_) {
233 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
234 TRACE_EVENT_INSTANT1(
235 "cast_perf_test", "VideoFrameEncoded",
236 TRACE_EVENT_SCOPE_THREAD,
237 "rtp_timestamp", encoded_frame->rtp_timestamp);
238 }
239
240 // At the start of the session, it's important to send reports before each
241 // frame so that the receiver can properly compute playout times. The reason
242 // more than one report is sent is because transmission is not guaranteed,
243 // only best effort, so send enough that one should almost certainly get
244 // through.
245 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
246 // SendRtcpReport() will schedule future reports to be made if this is the
247 // last "aggressive report."
248 ++num_aggressive_rtcp_reports_sent_;
249 const bool is_last_aggressive_report =
250 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart);
251 VLOG_IF(1, is_last_aggressive_report)
252 << SENDER_SSRC << "Sending last aggressive report.";
253 SendRtcpReport(is_last_aggressive_report);
254 }
255
256 congestion_control_->SendFrameToTransport(
257 frame_id, encoded_frame->data.size() * 8, last_send_time_);
258
259 if (send_target_playout_delay_) {
260 encoded_frame->new_playout_delay_ms =
261 target_playout_delay_.InMilliseconds();
262 }
263 transport_sender_->InsertFrame(ssrc_, *encoded_frame);
264 }
265
OnReceivedCastFeedback(const RtcpCastMessage & cast_feedback)266 void FrameSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
267 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
268
269 const bool have_valid_rtt = current_round_trip_time_ > base::TimeDelta();
270 if (have_valid_rtt) {
271 congestion_control_->UpdateRtt(current_round_trip_time_);
272
273 // Having the RTT value implies the receiver sent back a receiver report
274 // based on it having received a report from here. Therefore, ensure this
275 // sender stops aggressively sending reports.
276 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
277 VLOG(1) << SENDER_SSRC
278 << "No longer a need to send reports aggressively (sent "
279 << num_aggressive_rtcp_reports_sent_ << ").";
280 num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart;
281 ScheduleNextRtcpReport();
282 }
283 }
284
285 if (last_send_time_.is_null())
286 return; // Cannot get an ACK without having first sent a frame.
287
288 if (cast_feedback.missing_frames_and_packets.empty()) {
289 OnAck(cast_feedback.ack_frame_id);
290
291 // We only count duplicate ACKs when we have sent newer frames.
292 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id &&
293 latest_acked_frame_id_ != last_sent_frame_id_) {
294 duplicate_ack_counter_++;
295 } else {
296 duplicate_ack_counter_ = 0;
297 }
298 // TODO(miu): The values "2" and "3" should be derived from configuration.
299 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) {
300 VLOG(1) << SENDER_SSRC << "Received duplicate ACK for frame "
301 << latest_acked_frame_id_;
302 ResendForKickstart();
303 }
304 } else {
305 // Only count duplicated ACKs if there is no NACK request in between.
306 // This is to avoid aggresive resend.
307 duplicate_ack_counter_ = 0;
308 }
309
310 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
311 congestion_control_->AckFrame(cast_feedback.ack_frame_id, now);
312
313 cast_environment_->Logging()->InsertFrameEvent(
314 now,
315 FRAME_ACK_RECEIVED,
316 is_audio_ ? AUDIO_EVENT : VIDEO_EVENT,
317 GetRecordedRtpTimestamp(cast_feedback.ack_frame_id),
318 cast_feedback.ack_frame_id);
319
320 const bool is_acked_out_of_order =
321 static_cast<int32>(cast_feedback.ack_frame_id -
322 latest_acked_frame_id_) < 0;
323 VLOG(2) << SENDER_SSRC
324 << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "")
325 << " for frame " << cast_feedback.ack_frame_id;
326 if (!is_acked_out_of_order) {
327 // Cancel resends of acked frames.
328 std::vector<uint32> cancel_sending_frames;
329 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) {
330 latest_acked_frame_id_++;
331 cancel_sending_frames.push_back(latest_acked_frame_id_);
332 }
333 transport_sender_->CancelSendingFrames(ssrc_, cancel_sending_frames);
334 latest_acked_frame_id_ = cast_feedback.ack_frame_id;
335 }
336 }
337
ShouldDropNextFrame(base::TimeDelta frame_duration) const338 bool FrameSender::ShouldDropNextFrame(base::TimeDelta frame_duration) const {
339 // Check that accepting the next frame won't cause more frames to become
340 // in-flight than the system's design limit.
341 const int count_frames_in_flight =
342 GetUnacknowledgedFrameCount() + GetNumberOfFramesInEncoder();
343 if (count_frames_in_flight >= kMaxUnackedFrames) {
344 VLOG(1) << SENDER_SSRC << "Dropping: Too many frames would be in-flight.";
345 return true;
346 }
347
348 // Check that accepting the next frame won't exceed the configured maximum
349 // frame rate, allowing for short-term bursts.
350 base::TimeDelta duration_in_flight = GetInFlightMediaDuration();
351 const double max_frames_in_flight =
352 max_frame_rate_ * duration_in_flight.InSecondsF();
353 if (count_frames_in_flight >= max_frames_in_flight + kMaxFrameBurst) {
354 VLOG(1) << SENDER_SSRC << "Dropping: Burst threshold would be exceeded.";
355 return true;
356 }
357
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;
379 }
380
381 } // namespace cast
382 } // namespace media
383