LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/congestion_controller - delay_based_bwe.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 204 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include "webrtc/modules/congestion_controller/delay_based_bwe.h"
      12             : 
      13             : #include <algorithm>
      14             : #include <cmath>
      15             : #include <string>
      16             : 
      17             : #include "webrtc/base/checks.h"
      18             : #include "webrtc/base/constructormagic.h"
      19             : #include "webrtc/base/logging.h"
      20             : #include "webrtc/base/thread_annotations.h"
      21             : #include "webrtc/modules/congestion_controller/include/congestion_controller.h"
      22             : #include "webrtc/modules/pacing/paced_sender.h"
      23             : #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
      24             : #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
      25             : #include "webrtc/system_wrappers/include/field_trial.h"
      26             : #include "webrtc/system_wrappers/include/metrics.h"
      27             : #include "webrtc/typedefs.h"
      28             : 
      29             : namespace {
      30             : constexpr int kTimestampGroupLengthMs = 5;
      31             : constexpr int kAbsSendTimeFraction = 18;
      32             : constexpr int kAbsSendTimeInterArrivalUpshift = 8;
      33             : constexpr int kInterArrivalShift =
      34             :     kAbsSendTimeFraction + kAbsSendTimeInterArrivalUpshift;
      35             : constexpr double kTimestampToMs =
      36             :     1000.0 / static_cast<double>(1 << kInterArrivalShift);
      37             : // This ssrc is used to fulfill the current API but will be removed
      38             : // after the API has been changed.
      39             : constexpr uint32_t kFixedSsrc = 0;
      40             : constexpr int kInitialRateWindowMs = 500;
      41             : constexpr int kRateWindowMs = 150;
      42             : 
      43             : // Parameters for linear least squares fit of regression line to noisy data.
      44             : constexpr size_t kDefaultTrendlineWindowSize = 15;
      45             : constexpr double kDefaultTrendlineSmoothingCoeff = 0.9;
      46             : constexpr double kDefaultTrendlineThresholdGain = 4.0;
      47             : 
      48             : // Parameters for Theil-Sen robust fitting of line to noisy data.
      49             : constexpr size_t kDefaultMedianSlopeWindowSize = 20;
      50             : constexpr double kDefaultMedianSlopeThresholdGain = 4.0;
      51             : 
      52             : const char kBitrateEstimateExperiment[] = "WebRTC-ImprovedBitrateEstimate";
      53             : const char kBweTrendlineFilterExperiment[] = "WebRTC-BweTrendlineFilter";
      54             : const char kBweMedianSlopeFilterExperiment[] = "WebRTC-BweMedianSlopeFilter";
      55             : 
      56           0 : bool BitrateEstimateExperimentIsEnabled() {
      57           0 :   return webrtc::field_trial::FindFullName(kBitrateEstimateExperiment) ==
      58           0 :          "Enabled";
      59             : }
      60             : 
      61           0 : bool TrendlineFilterExperimentIsEnabled() {
      62             :   std::string experiment_string =
      63           0 :       webrtc::field_trial::FindFullName(kBweTrendlineFilterExperiment);
      64             :   // The experiment is enabled iff the field trial string begins with "Enabled".
      65           0 :   return experiment_string.find("Enabled") == 0;
      66             : }
      67             : 
      68           0 : bool MedianSlopeFilterExperimentIsEnabled() {
      69             :   std::string experiment_string =
      70           0 :       webrtc::field_trial::FindFullName(kBweMedianSlopeFilterExperiment);
      71             :   // The experiment is enabled iff the field trial string begins with "Enabled".
      72           0 :   return experiment_string.find("Enabled") == 0;
      73             : }
      74             : 
      75           0 : bool ReadTrendlineFilterExperimentParameters(size_t* window_size,
      76             :                                              double* smoothing_coef,
      77             :                                              double* threshold_gain) {
      78           0 :   RTC_DCHECK(TrendlineFilterExperimentIsEnabled());
      79           0 :   RTC_DCHECK(!MedianSlopeFilterExperimentIsEnabled());
      80           0 :   RTC_DCHECK(window_size != nullptr);
      81           0 :   RTC_DCHECK(smoothing_coef != nullptr);
      82           0 :   RTC_DCHECK(threshold_gain != nullptr);
      83             :   std::string experiment_string =
      84           0 :       webrtc::field_trial::FindFullName(kBweTrendlineFilterExperiment);
      85           0 :   int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%zu,%lf,%lf",
      86           0 :                              window_size, smoothing_coef, threshold_gain);
      87           0 :   if (parsed_values == 3) {
      88           0 :     RTC_CHECK_GT(*window_size, 1) << "Need at least 2 points to fit a line.";
      89           0 :     RTC_CHECK(0 <= *smoothing_coef && *smoothing_coef <= 1)
      90           0 :         << "Coefficient needs to be between 0 and 1 for weighted average.";
      91           0 :     RTC_CHECK_GT(*threshold_gain, 0) << "Threshold gain needs to be positive.";
      92           0 :     return true;
      93             :   }
      94           0 :   LOG(LS_WARNING) << "Failed to parse parameters for BweTrendlineFilter "
      95           0 :                      "experiment from field trial string. Using default.";
      96           0 :   *window_size = kDefaultTrendlineWindowSize;
      97           0 :   *smoothing_coef = kDefaultTrendlineSmoothingCoeff;
      98           0 :   *threshold_gain = kDefaultTrendlineThresholdGain;
      99           0 :   return false;
     100             : }
     101             : 
     102           0 : bool ReadMedianSlopeFilterExperimentParameters(size_t* window_size,
     103             :                                                double* threshold_gain) {
     104           0 :   RTC_DCHECK(!TrendlineFilterExperimentIsEnabled());
     105           0 :   RTC_DCHECK(MedianSlopeFilterExperimentIsEnabled());
     106           0 :   RTC_DCHECK(window_size != nullptr);
     107           0 :   RTC_DCHECK(threshold_gain != nullptr);
     108             :   std::string experiment_string =
     109           0 :       webrtc::field_trial::FindFullName(kBweMedianSlopeFilterExperiment);
     110           0 :   int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%zu,%lf",
     111           0 :                              window_size, threshold_gain);
     112           0 :   if (parsed_values == 2) {
     113           0 :     RTC_CHECK_GT(*window_size, 1) << "Need at least 2 points to fit a line.";
     114           0 :     RTC_CHECK_GT(*threshold_gain, 0) << "Threshold gain needs to be positive.";
     115           0 :     return true;
     116             :   }
     117           0 :   LOG(LS_WARNING) << "Failed to parse parameters for BweMedianSlopeFilter "
     118           0 :                      "experiment from field trial string. Using default.";
     119           0 :   *window_size = kDefaultMedianSlopeWindowSize;
     120           0 :   *threshold_gain = kDefaultMedianSlopeThresholdGain;
     121           0 :   return false;
     122             : }
     123             : }  // namespace
     124             : 
     125             : namespace webrtc {
     126             : 
     127           0 : DelayBasedBwe::BitrateEstimator::BitrateEstimator()
     128             :     : sum_(0),
     129             :       current_win_ms_(0),
     130             :       prev_time_ms_(-1),
     131             :       bitrate_estimate_(-1.0f),
     132             :       bitrate_estimate_var_(50.0f),
     133             :       old_estimator_(kBitrateWindowMs, 8000),
     134           0 :       in_experiment_(BitrateEstimateExperimentIsEnabled()) {}
     135             : 
     136           0 : void DelayBasedBwe::BitrateEstimator::Update(int64_t now_ms, int bytes) {
     137           0 :   if (!in_experiment_) {
     138           0 :     old_estimator_.Update(bytes, now_ms);
     139           0 :     rtc::Optional<uint32_t> rate = old_estimator_.Rate(now_ms);
     140           0 :     bitrate_estimate_ = -1.0f;
     141           0 :     if (rate)
     142           0 :       bitrate_estimate_ = *rate / 1000.0f;
     143           0 :     return;
     144             :   }
     145           0 :   int rate_window_ms = kRateWindowMs;
     146             :   // We use a larger window at the beginning to get a more stable sample that
     147             :   // we can use to initialize the estimate.
     148           0 :   if (bitrate_estimate_ < 0.f)
     149           0 :     rate_window_ms = kInitialRateWindowMs;
     150           0 :   float bitrate_sample = UpdateWindow(now_ms, bytes, rate_window_ms);
     151           0 :   if (bitrate_sample < 0.0f)
     152           0 :     return;
     153           0 :   if (bitrate_estimate_ < 0.0f) {
     154             :     // This is the very first sample we get. Use it to initialize the estimate.
     155           0 :     bitrate_estimate_ = bitrate_sample;
     156           0 :     return;
     157             :   }
     158             :   // Define the sample uncertainty as a function of how far away it is from the
     159             :   // current estimate.
     160             :   float sample_uncertainty =
     161           0 :       10.0f * std::abs(bitrate_estimate_ - bitrate_sample) / bitrate_estimate_;
     162           0 :   float sample_var = sample_uncertainty * sample_uncertainty;
     163             :   // Update a bayesian estimate of the rate, weighting it lower if the sample
     164             :   // uncertainty is large.
     165             :   // The bitrate estimate uncertainty is increased with each update to model
     166             :   // that the bitrate changes over time.
     167           0 :   float pred_bitrate_estimate_var = bitrate_estimate_var_ + 5.f;
     168           0 :   bitrate_estimate_ = (sample_var * bitrate_estimate_ +
     169           0 :                        pred_bitrate_estimate_var * bitrate_sample) /
     170           0 :                       (sample_var + pred_bitrate_estimate_var);
     171           0 :   bitrate_estimate_var_ = sample_var * pred_bitrate_estimate_var /
     172           0 :                           (sample_var + pred_bitrate_estimate_var);
     173             : }
     174             : 
     175           0 : float DelayBasedBwe::BitrateEstimator::UpdateWindow(int64_t now_ms,
     176             :                                                     int bytes,
     177             :                                                     int rate_window_ms) {
     178             :   // Reset if time moves backwards.
     179           0 :   if (now_ms < prev_time_ms_) {
     180           0 :     prev_time_ms_ = -1;
     181           0 :     sum_ = 0;
     182           0 :     current_win_ms_ = 0;
     183             :   }
     184           0 :   if (prev_time_ms_ >= 0) {
     185           0 :     current_win_ms_ += now_ms - prev_time_ms_;
     186             :     // Reset if nothing has been received for more than a full window.
     187           0 :     if (now_ms - prev_time_ms_ > rate_window_ms) {
     188           0 :       sum_ = 0;
     189           0 :       current_win_ms_ %= rate_window_ms;
     190             :     }
     191             :   }
     192           0 :   prev_time_ms_ = now_ms;
     193           0 :   float bitrate_sample = -1.0f;
     194           0 :   if (current_win_ms_ >= rate_window_ms) {
     195           0 :     bitrate_sample = 8.0f * sum_ / static_cast<float>(rate_window_ms);
     196           0 :     current_win_ms_ -= rate_window_ms;
     197           0 :     sum_ = 0;
     198             :   }
     199           0 :   sum_ += bytes;
     200           0 :   return bitrate_sample;
     201             : }
     202             : 
     203           0 : rtc::Optional<uint32_t> DelayBasedBwe::BitrateEstimator::bitrate_bps() const {
     204           0 :   if (bitrate_estimate_ < 0.f)
     205           0 :     return rtc::Optional<uint32_t>();
     206           0 :   return rtc::Optional<uint32_t>(bitrate_estimate_ * 1000);
     207             : }
     208             : 
     209           0 : DelayBasedBwe::DelayBasedBwe(Clock* clock)
     210           0 :     : in_trendline_experiment_(TrendlineFilterExperimentIsEnabled()),
     211           0 :       in_median_slope_experiment_(MedianSlopeFilterExperimentIsEnabled()),
     212             :       clock_(clock),
     213             :       inter_arrival_(),
     214             :       kalman_estimator_(),
     215             :       trendline_estimator_(),
     216             :       detector_(),
     217             :       receiver_incoming_bitrate_(),
     218             :       last_update_ms_(-1),
     219             :       last_seen_packet_ms_(-1),
     220             :       uma_recorded_(false),
     221             :       trendline_window_size_(kDefaultTrendlineWindowSize),
     222             :       trendline_smoothing_coeff_(kDefaultTrendlineSmoothingCoeff),
     223             :       trendline_threshold_gain_(kDefaultTrendlineThresholdGain),
     224           0 :       probing_interval_estimator_(&rate_control_),
     225             :       median_slope_window_size_(kDefaultMedianSlopeWindowSize),
     226           0 :       median_slope_threshold_gain_(kDefaultMedianSlopeThresholdGain) {
     227           0 :   if (in_trendline_experiment_) {
     228           0 :     ReadTrendlineFilterExperimentParameters(&trendline_window_size_,
     229             :                                             &trendline_smoothing_coeff_,
     230           0 :                                             &trendline_threshold_gain_);
     231             :   }
     232           0 :   if (in_median_slope_experiment_) {
     233           0 :     ReadMedianSlopeFilterExperimentParameters(&median_slope_window_size_,
     234           0 :                                               &median_slope_threshold_gain_);
     235             :   }
     236             : 
     237           0 :   network_thread_.DetachFromThread();
     238           0 : }
     239             : 
     240           0 : DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
     241             :     const std::vector<PacketInfo>& packet_feedback_vector) {
     242           0 :   RTC_DCHECK(network_thread_.CalledOnValidThread());
     243           0 :   if (!uma_recorded_) {
     244           0 :     RTC_HISTOGRAM_ENUMERATION(kBweTypeHistogram,
     245             :                               BweNames::kSendSideTransportSeqNum,
     246             :                               BweNames::kBweNamesMax);
     247           0 :     uma_recorded_ = true;
     248             :   }
     249           0 :   Result aggregated_result;
     250           0 :   for (const auto& packet_info : packet_feedback_vector) {
     251           0 :     Result result = IncomingPacketInfo(packet_info);
     252           0 :     if (result.updated)
     253           0 :       aggregated_result = result;
     254             :   }
     255           0 :   return aggregated_result;
     256             : }
     257             : 
     258           0 : DelayBasedBwe::Result DelayBasedBwe::IncomingPacketInfo(
     259             :     const PacketInfo& info) {
     260           0 :   int64_t now_ms = clock_->TimeInMilliseconds();
     261             : 
     262           0 :   receiver_incoming_bitrate_.Update(info.arrival_time_ms, info.payload_size);
     263           0 :   Result result;
     264             :   // Reset if the stream has timed out.
     265           0 :   if (last_seen_packet_ms_ == -1 ||
     266           0 :       now_ms - last_seen_packet_ms_ > kStreamTimeOutMs) {
     267           0 :     inter_arrival_.reset(
     268             :         new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000,
     269           0 :                          kTimestampToMs, true));
     270           0 :     kalman_estimator_.reset(new OveruseEstimator(OverUseDetectorOptions()));
     271           0 :     trendline_estimator_.reset(new TrendlineEstimator(
     272             :         trendline_window_size_, trendline_smoothing_coeff_,
     273           0 :         trendline_threshold_gain_));
     274           0 :     median_slope_estimator_.reset(new MedianSlopeEstimator(
     275           0 :         median_slope_window_size_, median_slope_threshold_gain_));
     276             :   }
     277           0 :   last_seen_packet_ms_ = now_ms;
     278             : 
     279             :   uint32_t send_time_24bits =
     280             :       static_cast<uint32_t>(
     281           0 :           ((static_cast<uint64_t>(info.send_time_ms) << kAbsSendTimeFraction) +
     282           0 :            500) /
     283           0 :           1000) &
     284           0 :       0x00FFFFFF;
     285             :   // Shift up send time to use the full 32 bits that inter_arrival works with,
     286             :   // so wrapping works properly.
     287           0 :   uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
     288             : 
     289           0 :   uint32_t ts_delta = 0;
     290           0 :   int64_t t_delta = 0;
     291           0 :   int size_delta = 0;
     292           0 :   if (inter_arrival_->ComputeDeltas(timestamp, info.arrival_time_ms, now_ms,
     293           0 :                                     info.payload_size, &ts_delta, &t_delta,
     294             :                                     &size_delta)) {
     295           0 :     double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
     296           0 :     if (in_trendline_experiment_) {
     297           0 :       trendline_estimator_->Update(t_delta, ts_delta_ms, info.arrival_time_ms);
     298           0 :       detector_.Detect(trendline_estimator_->trendline_slope(), ts_delta_ms,
     299           0 :                        trendline_estimator_->num_of_deltas(),
     300           0 :                        info.arrival_time_ms);
     301           0 :     } else if (in_median_slope_experiment_) {
     302           0 :       median_slope_estimator_->Update(t_delta, ts_delta_ms,
     303           0 :                                       info.arrival_time_ms);
     304           0 :       detector_.Detect(median_slope_estimator_->trendline_slope(), ts_delta_ms,
     305           0 :                        median_slope_estimator_->num_of_deltas(),
     306           0 :                        info.arrival_time_ms);
     307             :     } else {
     308           0 :       kalman_estimator_->Update(t_delta, ts_delta_ms, size_delta,
     309           0 :                                 detector_.State(), info.arrival_time_ms);
     310           0 :       detector_.Detect(kalman_estimator_->offset(), ts_delta_ms,
     311           0 :                        kalman_estimator_->num_of_deltas(),
     312           0 :                        info.arrival_time_ms);
     313             :     }
     314             :   }
     315             : 
     316           0 :   int probing_bps = 0;
     317           0 :   if (info.probe_cluster_id != PacketInfo::kNotAProbe) {
     318           0 :     probing_bps = probe_bitrate_estimator_.HandleProbeAndEstimateBitrate(info);
     319             :   }
     320             :   rtc::Optional<uint32_t> acked_bitrate_bps =
     321           0 :       receiver_incoming_bitrate_.bitrate_bps();
     322             :   // Currently overusing the bandwidth.
     323           0 :   if (detector_.State() == kBwOverusing) {
     324           0 :     if (acked_bitrate_bps &&
     325           0 :         rate_control_.TimeToReduceFurther(now_ms, *acked_bitrate_bps)) {
     326           0 :       result.updated =
     327           0 :           UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps,
     328             :                          &result.target_bitrate_bps);
     329             :     }
     330           0 :   } else if (probing_bps > 0) {
     331             :     // No overuse, but probing measured a bitrate.
     332           0 :     rate_control_.SetEstimate(probing_bps, info.arrival_time_ms);
     333           0 :     result.probe = true;
     334           0 :     result.updated =
     335           0 :         UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps,
     336             :                        &result.target_bitrate_bps);
     337             :   }
     338           0 :   if (!result.updated &&
     339           0 :       (last_update_ms_ == -1 ||
     340           0 :        now_ms - last_update_ms_ > rate_control_.GetFeedbackInterval())) {
     341           0 :     result.updated =
     342           0 :         UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps,
     343             :                        &result.target_bitrate_bps);
     344             :   }
     345           0 :   if (result.updated) {
     346           0 :     last_update_ms_ = now_ms;
     347             :     BWE_TEST_LOGGING_PLOT(1, "target_bitrate_bps", now_ms,
     348             :                           result.target_bitrate_bps);
     349             :   }
     350             : 
     351           0 :   return result;
     352             : }
     353             : 
     354           0 : bool DelayBasedBwe::UpdateEstimate(int64_t arrival_time_ms,
     355             :                                    int64_t now_ms,
     356             :                                    rtc::Optional<uint32_t> acked_bitrate_bps,
     357             :                                    uint32_t* target_bitrate_bps) {
     358             :   // TODO(terelius): RateControlInput::noise_var is deprecated and will be
     359             :   // removed. In the meantime, we set it to zero.
     360           0 :   const RateControlInput input(detector_.State(), acked_bitrate_bps, 0);
     361           0 :   rate_control_.Update(&input, now_ms);
     362           0 :   *target_bitrate_bps = rate_control_.UpdateBandwidthEstimate(now_ms);
     363           0 :   return rate_control_.ValidEstimate();
     364             : }
     365             : 
     366           0 : void DelayBasedBwe::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
     367           0 :   rate_control_.SetRtt(avg_rtt_ms);
     368           0 : }
     369             : 
     370           0 : bool DelayBasedBwe::LatestEstimate(std::vector<uint32_t>* ssrcs,
     371             :                                    uint32_t* bitrate_bps) const {
     372             :   // Currently accessed from both the process thread (see
     373             :   // ModuleRtpRtcpImpl::Process()) and the configuration thread (see
     374             :   // Call::GetStats()). Should in the future only be accessed from a single
     375             :   // thread.
     376           0 :   RTC_DCHECK(ssrcs);
     377           0 :   RTC_DCHECK(bitrate_bps);
     378           0 :   if (!rate_control_.ValidEstimate())
     379           0 :     return false;
     380             : 
     381           0 :   *ssrcs = {kFixedSsrc};
     382           0 :   *bitrate_bps = rate_control_.LatestEstimate();
     383           0 :   return true;
     384             : }
     385             : 
     386           0 : void DelayBasedBwe::SetMinBitrate(int min_bitrate_bps) {
     387             :   // Called from both the configuration thread and the network thread. Shouldn't
     388             :   // be called from the network thread in the future.
     389           0 :   rate_control_.SetMinBitrate(min_bitrate_bps);
     390           0 : }
     391             : 
     392           0 : int64_t DelayBasedBwe::GetProbingIntervalMs() const {
     393           0 :   return probing_interval_estimator_.GetIntervalMs();
     394             : }
     395             : }  // namespace webrtc

Generated by: LCOV version 1.13