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 <algorithm>
8 #include <limits>
9 #include <memory>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/bind.h"
14 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/numerics/safe_conversions.h"
17 #include "base/trace_event/trace_event.h"
18 #include "media/cast/constants.h"
19 #include "media/cast/sender/sender_encoded_frame.h"
20 
21 namespace media {
22 namespace cast {
23 namespace {
24 
25 constexpr int kNumAggressiveReportsSentAtStart = 100;
26 constexpr base::TimeDelta kMinSchedulingDelay =
27     base::TimeDelta::FromMilliseconds(1);
28 constexpr base::TimeDelta kReceiverProcessTime =
29     base::TimeDelta::FromMilliseconds(250);
30 
31 // The additional number of frames that can be in-flight when input exceeds the
32 // maximum frame rate.
33 constexpr int kMaxFrameBurst = 5;
34 
35 }  // namespace
36 
37 // Convenience macro used in logging statements throughout this file.
38 #define SENDER_SSRC (is_audio_ ? "AUDIO[" : "VIDEO[") << ssrc_ << "] "
39 
RtcpClient(base::WeakPtr<FrameSender> frame_sender)40 FrameSender::RtcpClient::RtcpClient(base::WeakPtr<FrameSender> frame_sender)
41     : frame_sender_(frame_sender) {}
42 
43 FrameSender::RtcpClient::~RtcpClient() = default;
44 
OnReceivedCastMessage(const RtcpCastMessage & cast_message)45 void FrameSender::RtcpClient::OnReceivedCastMessage(
46     const RtcpCastMessage& cast_message) {
47   if (frame_sender_)
48     frame_sender_->OnReceivedCastFeedback(cast_message);
49 }
50 
OnReceivedRtt(base::TimeDelta round_trip_time)51 void FrameSender::RtcpClient::OnReceivedRtt(base::TimeDelta round_trip_time) {
52   if (frame_sender_)
53     frame_sender_->OnMeasuredRoundTripTime(round_trip_time);
54 }
55 
OnReceivedPli()56 void FrameSender::RtcpClient::OnReceivedPli() {
57   if (frame_sender_)
58     frame_sender_->OnReceivedPli();
59 }
60 
FrameSender(scoped_refptr<CastEnvironment> cast_environment,CastTransport * const transport_sender,const FrameSenderConfig & config,CongestionControl * congestion_control)61 FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment,
62                          CastTransport* const transport_sender,
63                          const FrameSenderConfig& config,
64                          CongestionControl* congestion_control)
65     : cast_environment_(cast_environment),
66       transport_sender_(transport_sender),
67       ssrc_(config.sender_ssrc),
68       min_playout_delay_(config.min_playout_delay.is_zero()
69                              ? config.max_playout_delay
70                              : config.min_playout_delay),
71       max_playout_delay_(config.max_playout_delay),
72       animated_playout_delay_(config.animated_playout_delay.is_zero()
73                                   ? config.max_playout_delay
74                                   : config.animated_playout_delay),
75       send_target_playout_delay_(false),
76       max_frame_rate_(config.max_frame_rate),
77       num_aggressive_rtcp_reports_sent_(0),
78       duplicate_ack_counter_(0),
79       congestion_control_(congestion_control),
80       picture_lost_at_receiver_(false),
81       rtp_timebase_(config.rtp_timebase),
82       is_audio_(config.rtp_payload_type <= RtpPayloadType::AUDIO_LAST),
83       max_ack_delay_(config.max_playout_delay) {
84   DCHECK(transport_sender_);
85   DCHECK_GT(rtp_timebase_, 0);
86   DCHECK(congestion_control_);
87   // We assume animated content to begin with since that is the common use
88   // case today.
89   VLOG(1) << SENDER_SSRC << "min latency "
90           << min_playout_delay_.InMilliseconds() << "max latency "
91           << max_playout_delay_.InMilliseconds() << "animated latency "
92           << animated_playout_delay_.InMilliseconds();
93   SetTargetPlayoutDelay(animated_playout_delay_);
94 
95   CastTransportRtpConfig transport_config;
96   transport_config.ssrc = config.sender_ssrc;
97   transport_config.feedback_ssrc = config.receiver_ssrc;
98   transport_config.rtp_payload_type = config.rtp_payload_type;
99   transport_config.aes_key = config.aes_key;
100   transport_config.aes_iv_mask = config.aes_iv_mask;
101 
102   transport_sender->InitializeStream(
103       transport_config,
104       std::make_unique<FrameSender::RtcpClient>(weak_factory_.GetWeakPtr()));
105 }
106 
107 FrameSender::~FrameSender() = default;
108 
ScheduleNextRtcpReport()109 void FrameSender::ScheduleNextRtcpReport() {
110   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
111 
112   cast_environment_->PostDelayedTask(
113       CastEnvironment::MAIN, FROM_HERE,
114       base::BindOnce(&FrameSender::SendRtcpReport, weak_factory_.GetWeakPtr(),
115                      true),
116       base::TimeDelta::FromMilliseconds(kRtcpReportIntervalMs));
117 }
118 
SendRtcpReport(bool schedule_future_reports)119 void FrameSender::SendRtcpReport(bool schedule_future_reports) {
120   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
121 
122   // Sanity-check: We should have sent at least the first frame by this point.
123   DCHECK(!last_send_time_.is_null());
124 
125   // Create lip-sync info for the sender report.  The last sent frame's
126   // reference time and RTP timestamp are used to estimate an RTP timestamp in
127   // terms of "now."  Note that |now| is never likely to be precise to an exact
128   // frame boundary; and so the computation here will result in a
129   // |now_as_rtp_timestamp| value that is rarely equal to any one emitted by the
130   // encoder.
131   const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
132   const base::TimeDelta time_delta =
133       now - GetRecordedReferenceTime(last_sent_frame_id_);
134   const RtpTimeDelta rtp_delta =
135       RtpTimeDelta::FromTimeDelta(time_delta, rtp_timebase_);
136   const RtpTimeTicks now_as_rtp_timestamp =
137       GetRecordedRtpTimestamp(last_sent_frame_id_) + rtp_delta;
138   transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp);
139 
140   if (schedule_future_reports)
141     ScheduleNextRtcpReport();
142 }
143 
OnMeasuredRoundTripTime(base::TimeDelta round_trip_time)144 void FrameSender::OnMeasuredRoundTripTime(base::TimeDelta round_trip_time) {
145   DCHECK_GT(round_trip_time, base::TimeDelta());
146   current_round_trip_time_ = round_trip_time;
147   max_ack_delay_ = 2 * std::max(current_round_trip_time_, base::TimeDelta()) +
148                    kReceiverProcessTime;
149   max_ack_delay_ = std::min(max_ack_delay_, target_playout_delay_);
150 }
151 
SetTargetPlayoutDelay(base::TimeDelta new_target_playout_delay)152 void FrameSender::SetTargetPlayoutDelay(
153     base::TimeDelta new_target_playout_delay) {
154   if (send_target_playout_delay_ &&
155       target_playout_delay_ == new_target_playout_delay) {
156     return;
157   }
158   new_target_playout_delay = std::max(new_target_playout_delay,
159                                       min_playout_delay_);
160   new_target_playout_delay = std::min(new_target_playout_delay,
161                                       max_playout_delay_);
162   VLOG(2) << SENDER_SSRC << "Target playout delay changing from "
163           << target_playout_delay_.InMilliseconds() << " ms to "
164           << new_target_playout_delay.InMilliseconds() << " ms.";
165   target_playout_delay_ = new_target_playout_delay;
166   max_ack_delay_ = std::min(max_ack_delay_, target_playout_delay_);
167   send_target_playout_delay_ = true;
168   congestion_control_->UpdateTargetPlayoutDelay(target_playout_delay_);
169 }
170 
ResendCheck()171 void FrameSender::ResendCheck() {
172   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
173   DCHECK(!last_send_time_.is_null());
174   const base::TimeDelta time_since_last_send =
175       cast_environment_->Clock()->NowTicks() - last_send_time_;
176   if (time_since_last_send > max_ack_delay_) {
177     if (latest_acked_frame_id_ == last_sent_frame_id_) {
178       // Last frame acked, no point in doing anything
179     } else {
180       VLOG(1) << SENDER_SSRC << "ACK timeout; last acked frame: "
181               << latest_acked_frame_id_;
182       ResendForKickstart();
183     }
184   }
185   ScheduleNextResendCheck();
186 }
187 
ScheduleNextResendCheck()188 void FrameSender::ScheduleNextResendCheck() {
189   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
190   DCHECK(!last_send_time_.is_null());
191   base::TimeDelta time_to_next =
192       last_send_time_ - cast_environment_->Clock()->NowTicks() + max_ack_delay_;
193   time_to_next = std::max(time_to_next, kMinSchedulingDelay);
194   cast_environment_->PostDelayedTask(
195       CastEnvironment::MAIN, FROM_HERE,
196       base::BindOnce(&FrameSender::ResendCheck, weak_factory_.GetWeakPtr()),
197       time_to_next);
198 }
199 
ResendForKickstart()200 void FrameSender::ResendForKickstart() {
201   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
202   DCHECK(!last_send_time_.is_null());
203   VLOG(1) << SENDER_SSRC << "Resending last packet of frame "
204           << last_sent_frame_id_ << " to kick-start.";
205   last_send_time_ = cast_environment_->Clock()->NowTicks();
206   transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_);
207 }
208 
RecordLatestFrameTimestamps(FrameId frame_id,base::TimeTicks reference_time,RtpTimeTicks rtp_timestamp)209 void FrameSender::RecordLatestFrameTimestamps(FrameId frame_id,
210                                               base::TimeTicks reference_time,
211                                               RtpTimeTicks rtp_timestamp) {
212   DCHECK(!reference_time.is_null());
213   frame_reference_times_[frame_id.lower_8_bits()] = reference_time;
214   frame_rtp_timestamps_[frame_id.lower_8_bits()] = rtp_timestamp;
215 }
216 
GetRecordedReferenceTime(FrameId frame_id) const217 base::TimeTicks FrameSender::GetRecordedReferenceTime(FrameId frame_id) const {
218   return frame_reference_times_[frame_id.lower_8_bits()];
219 }
220 
GetRecordedRtpTimestamp(FrameId frame_id) const221 RtpTimeTicks FrameSender::GetRecordedRtpTimestamp(FrameId frame_id) const {
222   return frame_rtp_timestamps_[frame_id.lower_8_bits()];
223 }
224 
GetUnacknowledgedFrameCount() const225 int FrameSender::GetUnacknowledgedFrameCount() const {
226   if (last_send_time_.is_null())
227     return 0;
228   const int count = last_sent_frame_id_ - latest_acked_frame_id_;
229   DCHECK_GE(count, 0);
230   return count;
231 }
232 
GetAllowedInFlightMediaDuration() const233 base::TimeDelta FrameSender::GetAllowedInFlightMediaDuration() const {
234   // The total amount allowed in-flight media should equal the amount that fits
235   // within the entire playout delay window, plus the amount of time it takes to
236   // receive an ACK from the receiver.
237   // TODO(miu): Research is needed, but there is likely a better formula.
238   return target_playout_delay_ + (current_round_trip_time_ / 2);
239 }
240 
SendEncodedFrame(int requested_bitrate_before_encode,std::unique_ptr<SenderEncodedFrame> encoded_frame)241 void FrameSender::SendEncodedFrame(
242     int requested_bitrate_before_encode,
243     std::unique_ptr<SenderEncodedFrame> encoded_frame) {
244   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
245 
246   VLOG(2) << SENDER_SSRC << "About to send another frame: last_sent="
247           << last_sent_frame_id_ << ", latest_acked=" << latest_acked_frame_id_;
248 
249   const FrameId frame_id = encoded_frame->frame_id;
250   const bool is_first_frame_to_be_sent = last_send_time_.is_null();
251 
252   if (picture_lost_at_receiver_ &&
253       (encoded_frame->dependency == EncodedFrame::KEY)) {
254     picture_lost_at_receiver_ = false;
255     DCHECK(frame_id > latest_acked_frame_id_);
256     // Cancel sending remaining frames.
257     std::vector<FrameId> cancel_sending_frames;
258     for (FrameId id = latest_acked_frame_id_ + 1; id < frame_id; ++id) {
259       cancel_sending_frames.push_back(id);
260     }
261     transport_sender_->CancelSendingFrames(ssrc_, cancel_sending_frames);
262     OnCancelSendingFrames();
263   }
264 
265   last_send_time_ = cast_environment_->Clock()->NowTicks();
266   last_sent_frame_id_ = frame_id;
267   // If this is the first frame about to be sent, fake the value of
268   // |latest_acked_frame_id_| to indicate the receiver starts out all caught up.
269   // Also, schedule the periodic frame re-send checks.
270   if (is_first_frame_to_be_sent) {
271     latest_acked_frame_id_ = frame_id - 1;
272     ScheduleNextResendCheck();
273   }
274 
275   VLOG_IF(1, !is_audio_ && encoded_frame->dependency == EncodedFrame::KEY)
276       << SENDER_SSRC << "Sending encoded key frame, id=" << frame_id;
277 
278   std::unique_ptr<FrameEvent> encode_event(new FrameEvent());
279   encode_event->timestamp = encoded_frame->encode_completion_time;
280   encode_event->type = FRAME_ENCODED;
281   encode_event->media_type = is_audio_ ? AUDIO_EVENT : VIDEO_EVENT;
282   encode_event->rtp_timestamp = encoded_frame->rtp_timestamp;
283   encode_event->frame_id = frame_id;
284   encode_event->size = base::checked_cast<uint32_t>(encoded_frame->data.size());
285   encode_event->key_frame = encoded_frame->dependency == EncodedFrame::KEY;
286   encode_event->target_bitrate = requested_bitrate_before_encode;
287   encode_event->encoder_cpu_utilization = encoded_frame->encoder_utilization;
288   encode_event->idealized_bitrate_utilization =
289       encoded_frame->lossy_utilization;
290   cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event));
291 
292   RecordLatestFrameTimestamps(frame_id,
293                               encoded_frame->reference_time,
294                               encoded_frame->rtp_timestamp);
295 
296   if (!is_audio_) {
297     // Used by chrome/browser/media/cast_mirroring_performance_browsertest.cc
298     TRACE_EVENT_INSTANT1(
299         "cast_perf_test", "VideoFrameEncoded",
300         TRACE_EVENT_SCOPE_THREAD,
301         "rtp_timestamp", encoded_frame->rtp_timestamp.lower_32_bits());
302   }
303 
304   // At the start of the session, it's important to send reports before each
305   // frame so that the receiver can properly compute playout times.  The reason
306   // more than one report is sent is because transmission is not guaranteed,
307   // only best effort, so send enough that one should almost certainly get
308   // through.
309   if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
310     // SendRtcpReport() will schedule future reports to be made if this is the
311     // last "aggressive report."
312     ++num_aggressive_rtcp_reports_sent_;
313     const bool is_last_aggressive_report =
314         (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart);
315     VLOG_IF(1, is_last_aggressive_report)
316         << SENDER_SSRC << "Sending last aggressive report.";
317     SendRtcpReport(is_last_aggressive_report);
318   }
319 
320   congestion_control_->SendFrameToTransport(
321       frame_id, encoded_frame->data.size() * 8, last_send_time_);
322 
323   if (send_target_playout_delay_) {
324     encoded_frame->new_playout_delay_ms =
325         target_playout_delay_.InMilliseconds();
326   }
327 
328   TRACE_EVENT_ASYNC_BEGIN1("cast.stream",
329                            is_audio_ ? "Audio Transport" : "Video Transport",
330                            frame_id.lower_32_bits(), "rtp_timestamp",
331                            encoded_frame->rtp_timestamp.lower_32_bits());
332   transport_sender_->InsertFrame(ssrc_, *encoded_frame);
333 }
334 
OnCancelSendingFrames()335 void FrameSender::OnCancelSendingFrames() {}
336 
OnReceivedCastFeedback(const RtcpCastMessage & cast_feedback)337 void FrameSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
338   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
339 
340   const bool have_valid_rtt = current_round_trip_time_ > base::TimeDelta();
341   if (have_valid_rtt) {
342     congestion_control_->UpdateRtt(current_round_trip_time_);
343 
344     // Having the RTT value implies the receiver sent back a receiver report
345     // based on it having received a report from here.  Therefore, ensure this
346     // sender stops aggressively sending reports.
347     if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
348       VLOG(1) << SENDER_SSRC
349               << "No longer a need to send reports aggressively (sent "
350               << num_aggressive_rtcp_reports_sent_ << ").";
351       num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart;
352       ScheduleNextRtcpReport();
353     }
354   }
355 
356   if (last_send_time_.is_null())
357     return;  // Cannot get an ACK without having first sent a frame.
358 
359   if (cast_feedback.missing_frames_and_packets.empty() &&
360       cast_feedback.received_later_frames.empty()) {
361     if (latest_acked_frame_id_ == cast_feedback.ack_frame_id) {
362       VLOG(1) << SENDER_SSRC << "Received duplicate ACK for frame "
363               << latest_acked_frame_id_;
364       TRACE_EVENT_INSTANT2(
365           "cast.stream", "Duplicate ACK", TRACE_EVENT_SCOPE_THREAD,
366           "ack_frame_id", cast_feedback.ack_frame_id.lower_32_bits(),
367           "last_sent_frame_id", last_sent_frame_id_.lower_32_bits());
368     }
369     // We only count duplicate ACKs when we have sent newer frames.
370     if (latest_acked_frame_id_ == cast_feedback.ack_frame_id &&
371         latest_acked_frame_id_ != last_sent_frame_id_) {
372       duplicate_ack_counter_++;
373     } else {
374       duplicate_ack_counter_ = 0;
375     }
376     // TODO(miu): The values "2" and "3" should be derived from configuration.
377     if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) {
378       ResendForKickstart();
379     }
380   } else {
381     // Only count duplicated ACKs if there is no NACK request in between.
382     // This is to avoid aggresive resend.
383     duplicate_ack_counter_ = 0;
384   }
385 
386   base::TimeTicks now = cast_environment_->Clock()->NowTicks();
387   congestion_control_->AckFrame(cast_feedback.ack_frame_id, now);
388   if (!cast_feedback.received_later_frames.empty()) {
389     // Ack the received frames.
390     congestion_control_->AckLaterFrames(cast_feedback.received_later_frames,
391                                         now);
392   }
393 
394   std::unique_ptr<FrameEvent> ack_event(new FrameEvent());
395   ack_event->timestamp = now;
396   ack_event->type = FRAME_ACK_RECEIVED;
397   ack_event->media_type = is_audio_ ? AUDIO_EVENT : VIDEO_EVENT;
398   ack_event->rtp_timestamp =
399       GetRecordedRtpTimestamp(cast_feedback.ack_frame_id);
400   ack_event->frame_id = cast_feedback.ack_frame_id;
401   cast_environment_->logger()->DispatchFrameEvent(std::move(ack_event));
402 
403   const bool is_acked_out_of_order =
404       cast_feedback.ack_frame_id < latest_acked_frame_id_;
405   VLOG(2) << SENDER_SSRC
406           << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "")
407           << " for frame " << cast_feedback.ack_frame_id;
408   if (is_acked_out_of_order) {
409     TRACE_EVENT_INSTANT2(
410         "cast.stream", "ACK out of order", TRACE_EVENT_SCOPE_THREAD,
411         "ack_frame_id", cast_feedback.ack_frame_id.lower_32_bits(),
412         "latest_acked_frame_id", latest_acked_frame_id_.lower_32_bits());
413   } else if (latest_acked_frame_id_ < cast_feedback.ack_frame_id) {
414     // Cancel resends of acked frames.
415     std::vector<FrameId> frames_to_cancel;
416     frames_to_cancel.reserve(cast_feedback.ack_frame_id -
417                              latest_acked_frame_id_);
418     do {
419       ++latest_acked_frame_id_;
420       frames_to_cancel.push_back(latest_acked_frame_id_);
421       // This is a good place to match the trace for frame ids
422       // since this ensures we not only track frame ids that are
423       // implicitly ACKed, but also handles duplicate ACKs
424       TRACE_EVENT_ASYNC_END1(
425           "cast.stream", is_audio_ ? "Audio Transport" : "Video Transport",
426           latest_acked_frame_id_.lower_32_bits(), "RTT_usecs",
427           current_round_trip_time_.InMicroseconds());
428     } while (latest_acked_frame_id_ < cast_feedback.ack_frame_id);
429     transport_sender_->CancelSendingFrames(ssrc_, frames_to_cancel);
430     OnCancelSendingFrames();
431   }
432 }
433 
OnReceivedPli()434 void FrameSender::OnReceivedPli() {
435   picture_lost_at_receiver_ = true;
436 }
437 
ShouldDropNextFrame(base::TimeDelta frame_duration) const438 bool FrameSender::ShouldDropNextFrame(base::TimeDelta frame_duration) const {
439   // Check that accepting the next frame won't cause more frames to become
440   // in-flight than the system's design limit.
441   const int count_frames_in_flight =
442       GetUnacknowledgedFrameCount() + GetNumberOfFramesInEncoder();
443   if (count_frames_in_flight >= kMaxUnackedFrames) {
444     VLOG(1) << SENDER_SSRC << "Dropping: Too many frames would be in-flight.";
445     return true;
446   }
447 
448   // Check that accepting the next frame won't exceed the configured maximum
449   // frame rate, allowing for short-term bursts.
450   base::TimeDelta duration_in_flight = GetInFlightMediaDuration();
451   const double max_frames_in_flight =
452       max_frame_rate_ * duration_in_flight.InSecondsF();
453   if (count_frames_in_flight >= max_frames_in_flight + kMaxFrameBurst) {
454     VLOG(1) << SENDER_SSRC << "Dropping: Burst threshold would be exceeded.";
455     return true;
456   }
457 
458   // Check that accepting the next frame won't exceed the allowed in-flight
459   // media duration.
460   const base::TimeDelta duration_would_be_in_flight =
461       duration_in_flight + frame_duration;
462   const base::TimeDelta allowed_in_flight = GetAllowedInFlightMediaDuration();
463   if (VLOG_IS_ON(1)) {
464     const int64_t percent =
465         allowed_in_flight > base::TimeDelta()
466             ? base::ClampRound<int64_t>(duration_would_be_in_flight /
467                                         allowed_in_flight * 100)
468             : std::numeric_limits<int64_t>::max();
469     VLOG_IF(1, percent > 50)
470         << SENDER_SSRC
471         << duration_in_flight.InMicroseconds() << " usec in-flight + "
472         << frame_duration.InMicroseconds() << " usec for next frame --> "
473         << percent << "% of allowed in-flight.";
474   }
475   if (duration_would_be_in_flight > allowed_in_flight) {
476     VLOG(1) << SENDER_SSRC << "Dropping: In-flight duration would be too high.";
477     return true;
478   }
479 
480   // Next frame is accepted.
481   return false;
482 }
483 
484 }  // namespace cast
485 }  // namespace media
486