Home | History | Annotate | Download | only in remote_bitrate_estimator
      1 /*
      2  *  Copyright (c) 2012 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/remote_bitrate_estimator/overuse_detector.h"
     12 
     13 #include <math.h>
     14 #include <stdlib.h>
     15 
     16 #include <algorithm>
     17 #include <sstream>
     18 #include <string>
     19 
     20 #include "webrtc/base/checks.h"
     21 #include "webrtc/base/common.h"
     22 #include "webrtc/modules/remote_bitrate_estimator/include/bwe_defines.h"
     23 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
     24 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
     25 #include "webrtc/system_wrappers/include/field_trial.h"
     26 #include "webrtc/system_wrappers/include/trace.h"
     27 
     28 namespace webrtc {
     29 
     30 const char kAdaptiveThresholdExperiment[] = "WebRTC-AdaptiveBweThreshold";
     31 const char kEnabledPrefix[] = "Enabled";
     32 const size_t kEnabledPrefixLength = sizeof(kEnabledPrefix) - 1;
     33 const size_t kMinExperimentLength = kEnabledPrefixLength + 3;
     34 
     35 const double kMaxAdaptOffsetMs = 15.0;
     36 const double kOverUsingTimeThreshold = 10;
     37 
     38 bool AdaptiveThresholdExperimentIsEnabled() {
     39   std::string experiment_string =
     40       webrtc::field_trial::FindFullName(kAdaptiveThresholdExperiment);
     41   if (experiment_string.length() < kMinExperimentLength)
     42     return false;
     43   return experiment_string.substr(0, kEnabledPrefixLength) == kEnabledPrefix;
     44 }
     45 
     46 // Gets thresholds from the experiment name following the format
     47 // "WebRTC-AdaptiveBweThreshold/Enabled-0.5,0.002/".
     48 bool ReadExperimentConstants(double* k_up, double* k_down) {
     49   std::string experiment_string =
     50       webrtc::field_trial::FindFullName(kAdaptiveThresholdExperiment);
     51   return sscanf(experiment_string.substr(kEnabledPrefixLength + 1).c_str(),
     52                 "%lf,%lf", k_up, k_down) == 2;
     53 }
     54 
     55 OveruseDetector::OveruseDetector(const OverUseDetectorOptions& options)
     56     : in_experiment_(AdaptiveThresholdExperimentIsEnabled()),
     57       k_up_(0.01),
     58       k_down_(0.00018),
     59       overusing_time_threshold_(100),
     60       options_(options),
     61       threshold_(12.5),
     62       last_update_ms_(-1),
     63       prev_offset_(0.0),
     64       time_over_using_(-1),
     65       overuse_counter_(0),
     66       hypothesis_(kBwNormal) {
     67   if (in_experiment_)
     68     InitializeExperiment();
     69 }
     70 
     71 OveruseDetector::~OveruseDetector() {}
     72 
     73 BandwidthUsage OveruseDetector::State() const {
     74   return hypothesis_;
     75 }
     76 
     77 BandwidthUsage OveruseDetector::Detect(double offset,
     78                                        double ts_delta,
     79                                        int num_of_deltas,
     80                                        int64_t now_ms) {
     81   if (num_of_deltas < 2) {
     82     return kBwNormal;
     83   }
     84   const double prev_offset = prev_offset_;
     85   prev_offset_ = offset;
     86   const double T = std::min(num_of_deltas, 60) * offset;
     87   BWE_TEST_LOGGING_PLOT(1, "offset", now_ms, T);
     88   BWE_TEST_LOGGING_PLOT(1, "threshold", now_ms, threshold_);
     89   if (T > threshold_) {
     90     if (time_over_using_ == -1) {
     91       // Initialize the timer. Assume that we've been
     92       // over-using half of the time since the previous
     93       // sample.
     94       time_over_using_ = ts_delta / 2;
     95     } else {
     96       // Increment timer
     97       time_over_using_ += ts_delta;
     98     }
     99     overuse_counter_++;
    100     if (time_over_using_ > overusing_time_threshold_ && overuse_counter_ > 1) {
    101       if (offset >= prev_offset) {
    102         time_over_using_ = 0;
    103         overuse_counter_ = 0;
    104         hypothesis_ = kBwOverusing;
    105       }
    106     }
    107   } else if (T < -threshold_) {
    108     time_over_using_ = -1;
    109     overuse_counter_ = 0;
    110     hypothesis_ = kBwUnderusing;
    111   } else {
    112     time_over_using_ = -1;
    113     overuse_counter_ = 0;
    114     hypothesis_ = kBwNormal;
    115   }
    116 
    117   UpdateThreshold(T, now_ms);
    118 
    119   return hypothesis_;
    120 }
    121 
    122 void OveruseDetector::UpdateThreshold(double modified_offset, int64_t now_ms) {
    123   if (!in_experiment_)
    124     return;
    125 
    126   if (last_update_ms_ == -1)
    127     last_update_ms_ = now_ms;
    128 
    129   if (fabs(modified_offset) > threshold_ + kMaxAdaptOffsetMs) {
    130     // Avoid adapting the threshold to big latency spikes, caused e.g.,
    131     // by a sudden capacity drop.
    132     last_update_ms_ = now_ms;
    133     return;
    134   }
    135 
    136   const double k = fabs(modified_offset) < threshold_ ? k_down_ : k_up_;
    137   threshold_ +=
    138       k * (fabs(modified_offset) - threshold_) * (now_ms - last_update_ms_);
    139 
    140   const double kMinThreshold = 6;
    141   const double kMaxThreshold = 600;
    142   threshold_ = std::min(std::max(threshold_, kMinThreshold), kMaxThreshold);
    143 
    144   last_update_ms_ = now_ms;
    145 }
    146 
    147 void OveruseDetector::InitializeExperiment() {
    148   RTC_DCHECK(in_experiment_);
    149   double k_up = 0.0;
    150   double k_down = 0.0;
    151   overusing_time_threshold_ = kOverUsingTimeThreshold;
    152   if (ReadExperimentConstants(&k_up, &k_down)) {
    153     k_up_ = k_up;
    154     k_down_ = k_down;
    155   }
    156 }
    157 }  // namespace webrtc
    158