Home | History | Annotate | Download | only in sender
      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 
     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 
     59 FrameSender::~FrameSender() {
     60 }
     61 
     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 
     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 
    102 void FrameSender::OnMeasuredRoundTripTime(base::TimeDelta rtt) {
    103   DCHECK(rtt > base::TimeDelta());
    104   current_round_trip_time_ = rtt;
    105 }
    106 
    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 
    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 
    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 
    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 
    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 
    173 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32 frame_id) const {
    174   return frame_reference_times_[frame_id % arraysize(frame_reference_times_)];
    175 }
    176 
    177 RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32 frame_id) const {
    178   return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)];
    179 }
    180 
    181 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 
    188 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 
    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 
    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 
    338 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