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