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