1 /*
2  *  Copyright (c) 2017 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 "modules/congestion_controller/goog_cc/bitrate_estimator.h"
12 
13 #include <stdio.h>
14 
15 #include <algorithm>
16 #include <cmath>
17 #include <string>
18 
19 #include "api/units/data_rate.h"
20 #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
21 #include "rtc_base/logging.h"
22 
23 namespace webrtc {
24 
25 namespace {
26 constexpr int kInitialRateWindowMs = 500;
27 constexpr int kRateWindowMs = 150;
28 constexpr int kMinRateWindowMs = 150;
29 constexpr int kMaxRateWindowMs = 1000;
30 
31 const char kBweThroughputWindowConfig[] = "WebRTC-BweThroughputWindowConfig";
32 
33 }  // namespace
34 
BitrateEstimator(const WebRtcKeyValueConfig * key_value_config)35 BitrateEstimator::BitrateEstimator(const WebRtcKeyValueConfig* key_value_config)
36     : sum_(0),
37       initial_window_ms_("initial_window_ms",
38                          kInitialRateWindowMs,
39                          kMinRateWindowMs,
40                          kMaxRateWindowMs),
41       noninitial_window_ms_("window_ms",
42                             kRateWindowMs,
43                             kMinRateWindowMs,
44                             kMaxRateWindowMs),
45       uncertainty_scale_("scale", 10.0),
46       uncertainty_scale_in_alr_("scale_alr", uncertainty_scale_),
47       small_sample_uncertainty_scale_("scale_small", uncertainty_scale_),
48       small_sample_threshold_("small_thresh", DataSize::Zero()),
49       uncertainty_symmetry_cap_("symmetry_cap", DataRate::Zero()),
50       estimate_floor_("floor", DataRate::Zero()),
51       current_window_ms_(0),
52       prev_time_ms_(-1),
53       bitrate_estimate_kbps_(-1.0f),
54       bitrate_estimate_var_(50.0f) {
55   // E.g WebRTC-BweThroughputWindowConfig/initial_window_ms:350,window_ms:250/
56   ParseFieldTrial(
57       {&initial_window_ms_, &noninitial_window_ms_, &uncertainty_scale_,
58        &uncertainty_scale_in_alr_, &small_sample_uncertainty_scale_,
59        &small_sample_threshold_, &uncertainty_symmetry_cap_, &estimate_floor_},
60       key_value_config->Lookup(kBweThroughputWindowConfig));
61 }
62 
63 BitrateEstimator::~BitrateEstimator() = default;
64 
Update(Timestamp at_time,DataSize amount,bool in_alr)65 void BitrateEstimator::Update(Timestamp at_time, DataSize amount, bool in_alr) {
66   int rate_window_ms = noninitial_window_ms_.Get();
67   // We use a larger window at the beginning to get a more stable sample that
68   // we can use to initialize the estimate.
69   if (bitrate_estimate_kbps_ < 0.f)
70     rate_window_ms = initial_window_ms_.Get();
71   bool is_small_sample = false;
72   float bitrate_sample_kbps = UpdateWindow(at_time.ms(), amount.bytes(),
73                                            rate_window_ms, &is_small_sample);
74   if (bitrate_sample_kbps < 0.0f)
75     return;
76   if (bitrate_estimate_kbps_ < 0.0f) {
77     // This is the very first sample we get. Use it to initialize the estimate.
78     bitrate_estimate_kbps_ = bitrate_sample_kbps;
79     return;
80   }
81   // Optionally use higher uncertainty for very small samples to avoid dropping
82   // estimate and for samples obtained in ALR.
83   float scale = uncertainty_scale_;
84   if (is_small_sample && bitrate_sample_kbps < bitrate_estimate_kbps_) {
85     scale = small_sample_uncertainty_scale_;
86   } else if (in_alr && bitrate_sample_kbps < bitrate_estimate_kbps_) {
87     // Optionally use higher uncertainty for samples obtained during ALR.
88     scale = uncertainty_scale_in_alr_;
89   }
90   // Define the sample uncertainty as a function of how far away it is from the
91   // current estimate. With low values of uncertainty_symmetry_cap_ we add more
92   // uncertainty to increases than to decreases. For higher values we approach
93   // symmetry.
94   float sample_uncertainty =
95       scale * std::abs(bitrate_estimate_kbps_ - bitrate_sample_kbps) /
96       (bitrate_estimate_kbps_ +
97        std::min(bitrate_sample_kbps,
98                 uncertainty_symmetry_cap_.Get().kbps<float>()));
99 
100   float sample_var = sample_uncertainty * sample_uncertainty;
101   // Update a bayesian estimate of the rate, weighting it lower if the sample
102   // uncertainty is large.
103   // The bitrate estimate uncertainty is increased with each update to model
104   // that the bitrate changes over time.
105   float pred_bitrate_estimate_var = bitrate_estimate_var_ + 5.f;
106   bitrate_estimate_kbps_ = (sample_var * bitrate_estimate_kbps_ +
107                             pred_bitrate_estimate_var * bitrate_sample_kbps) /
108                            (sample_var + pred_bitrate_estimate_var);
109   bitrate_estimate_kbps_ =
110       std::max(bitrate_estimate_kbps_, estimate_floor_.Get().kbps<float>());
111   bitrate_estimate_var_ = sample_var * pred_bitrate_estimate_var /
112                           (sample_var + pred_bitrate_estimate_var);
113   BWE_TEST_LOGGING_PLOT(1, "acknowledged_bitrate", at_time.ms(),
114                         bitrate_estimate_kbps_ * 1000);
115 }
116 
UpdateWindow(int64_t now_ms,int bytes,int rate_window_ms,bool * is_small_sample)117 float BitrateEstimator::UpdateWindow(int64_t now_ms,
118                                      int bytes,
119                                      int rate_window_ms,
120                                      bool* is_small_sample) {
121   RTC_DCHECK(is_small_sample != nullptr);
122   // Reset if time moves backwards.
123   if (now_ms < prev_time_ms_) {
124     prev_time_ms_ = -1;
125     sum_ = 0;
126     current_window_ms_ = 0;
127   }
128   if (prev_time_ms_ >= 0) {
129     current_window_ms_ += now_ms - prev_time_ms_;
130     // Reset if nothing has been received for more than a full window.
131     if (now_ms - prev_time_ms_ > rate_window_ms) {
132       sum_ = 0;
133       current_window_ms_ %= rate_window_ms;
134     }
135   }
136   prev_time_ms_ = now_ms;
137   float bitrate_sample = -1.0f;
138   if (current_window_ms_ >= rate_window_ms) {
139     *is_small_sample = sum_ < small_sample_threshold_->bytes();
140     bitrate_sample = 8.0f * sum_ / static_cast<float>(rate_window_ms);
141     current_window_ms_ -= rate_window_ms;
142     sum_ = 0;
143   }
144   sum_ += bytes;
145   return bitrate_sample;
146 }
147 
bitrate() const148 absl::optional<DataRate> BitrateEstimator::bitrate() const {
149   if (bitrate_estimate_kbps_ < 0.f)
150     return absl::nullopt;
151   return DataRate::KilobitsPerSec(bitrate_estimate_kbps_);
152 }
153 
PeekRate() const154 absl::optional<DataRate> BitrateEstimator::PeekRate() const {
155   if (current_window_ms_ > 0)
156     return DataSize::Bytes(sum_) / TimeDelta::Millis(current_window_ms_);
157   return absl::nullopt;
158 }
159 
ExpectFastRateChange()160 void BitrateEstimator::ExpectFastRateChange() {
161   // By setting the bitrate-estimate variance to a higher value we allow the
162   // bitrate to change fast for the next few samples.
163   bitrate_estimate_var_ += 200;
164 }
165 
166 }  // namespace webrtc
167