• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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