summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/modules/remote_bitrate_estimator/overuse_estimator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/modules/remote_bitrate_estimator/overuse_estimator.cc')
-rw-r--r--third_party/libwebrtc/modules/remote_bitrate_estimator/overuse_estimator.cc149
1 files changed, 149 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/remote_bitrate_estimator/overuse_estimator.cc b/third_party/libwebrtc/modules/remote_bitrate_estimator/overuse_estimator.cc
new file mode 100644
index 0000000000..5ca21d9629
--- /dev/null
+++ b/third_party/libwebrtc/modules/remote_bitrate_estimator/overuse_estimator.cc
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/remote_bitrate_estimator/overuse_estimator.h"
+
+#include <math.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include "api/network_state_predictor.h"
+#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace {
+
+constexpr int kMinFramePeriodHistoryLength = 60;
+constexpr int kDeltaCounterMax = 1000;
+
+} // namespace
+
+OveruseEstimator::OveruseEstimator() = default;
+
+void OveruseEstimator::Update(int64_t t_delta,
+ double ts_delta,
+ int size_delta,
+ BandwidthUsage current_hypothesis,
+ int64_t now_ms) {
+ const double min_frame_period = UpdateMinFramePeriod(ts_delta);
+ const double t_ts_delta = t_delta - ts_delta;
+ BWE_TEST_LOGGING_PLOT(1, "dm_ms", now_ms, t_ts_delta);
+ double fs_delta = size_delta;
+
+ ++num_of_deltas_;
+ if (num_of_deltas_ > kDeltaCounterMax) {
+ num_of_deltas_ = kDeltaCounterMax;
+ }
+
+ // Update the Kalman filter.
+ E_[0][0] += process_noise_[0];
+ E_[1][1] += process_noise_[1];
+
+ if ((current_hypothesis == BandwidthUsage::kBwOverusing &&
+ offset_ < prev_offset_) ||
+ (current_hypothesis == BandwidthUsage::kBwUnderusing &&
+ offset_ > prev_offset_)) {
+ E_[1][1] += 10 * process_noise_[1];
+ }
+
+ const double h[2] = {fs_delta, 1.0};
+ const double Eh[2] = {E_[0][0] * h[0] + E_[0][1] * h[1],
+ E_[1][0] * h[0] + E_[1][1] * h[1]};
+
+ BWE_TEST_LOGGING_PLOT(1, "d_ms", now_ms, slope_ * h[0] - offset_);
+
+ const double residual = t_ts_delta - slope_ * h[0] - offset_;
+
+ const bool in_stable_state =
+ (current_hypothesis == BandwidthUsage::kBwNormal);
+ const double max_residual = 3.0 * sqrt(var_noise_);
+ // We try to filter out very late frames. For instance periodic key
+ // frames doesn't fit the Gaussian model well.
+ if (fabs(residual) < max_residual) {
+ UpdateNoiseEstimate(residual, min_frame_period, in_stable_state);
+ } else {
+ UpdateNoiseEstimate(residual < 0 ? -max_residual : max_residual,
+ min_frame_period, in_stable_state);
+ }
+
+ const double denom = var_noise_ + h[0] * Eh[0] + h[1] * Eh[1];
+
+ const double K[2] = {Eh[0] / denom, Eh[1] / denom};
+
+ const double IKh[2][2] = {{1.0 - K[0] * h[0], -K[0] * h[1]},
+ {-K[1] * h[0], 1.0 - K[1] * h[1]}};
+ const double e00 = E_[0][0];
+ const double e01 = E_[0][1];
+
+ // Update state.
+ E_[0][0] = e00 * IKh[0][0] + E_[1][0] * IKh[0][1];
+ E_[0][1] = e01 * IKh[0][0] + E_[1][1] * IKh[0][1];
+ E_[1][0] = e00 * IKh[1][0] + E_[1][0] * IKh[1][1];
+ E_[1][1] = e01 * IKh[1][0] + E_[1][1] * IKh[1][1];
+
+ // The covariance matrix must be positive semi-definite.
+ bool positive_semi_definite =
+ E_[0][0] + E_[1][1] >= 0 &&
+ E_[0][0] * E_[1][1] - E_[0][1] * E_[1][0] >= 0 && E_[0][0] >= 0;
+ RTC_DCHECK(positive_semi_definite);
+ if (!positive_semi_definite) {
+ RTC_LOG(LS_ERROR)
+ << "The over-use estimator's covariance matrix is no longer "
+ "semi-definite.";
+ }
+
+ slope_ = slope_ + K[0] * residual;
+ prev_offset_ = offset_;
+ offset_ = offset_ + K[1] * residual;
+
+ BWE_TEST_LOGGING_PLOT(1, "kc", now_ms, K[0]);
+ BWE_TEST_LOGGING_PLOT(1, "km", now_ms, K[1]);
+ BWE_TEST_LOGGING_PLOT(1, "slope_1/bps", now_ms, slope_);
+ BWE_TEST_LOGGING_PLOT(1, "var_noise", now_ms, var_noise_);
+}
+
+double OveruseEstimator::UpdateMinFramePeriod(double ts_delta) {
+ double min_frame_period = ts_delta;
+ if (ts_delta_hist_.size() >= kMinFramePeriodHistoryLength) {
+ ts_delta_hist_.pop_front();
+ }
+ for (const double old_ts_delta : ts_delta_hist_) {
+ min_frame_period = std::min(old_ts_delta, min_frame_period);
+ }
+ ts_delta_hist_.push_back(ts_delta);
+ return min_frame_period;
+}
+
+void OveruseEstimator::UpdateNoiseEstimate(double residual,
+ double ts_delta,
+ bool stable_state) {
+ if (!stable_state) {
+ return;
+ }
+ // Faster filter during startup to faster adapt to the jitter level
+ // of the network. `alpha` is tuned for 30 frames per second, but is scaled
+ // according to `ts_delta`.
+ double alpha = 0.01;
+ if (num_of_deltas_ > 10 * 30) {
+ alpha = 0.002;
+ }
+ // Only update the noise estimate if we're not over-using. `beta` is a
+ // function of alpha and the time delta since the previous update.
+ const double beta = pow(1 - alpha, ts_delta * 30.0 / 1000.0);
+ avg_noise_ = beta * avg_noise_ + (1 - beta) * residual;
+ var_noise_ = beta * var_noise_ +
+ (1 - beta) * (avg_noise_ - residual) * (avg_noise_ - residual);
+ if (var_noise_ < 1) {
+ var_noise_ = 1;
+ }
+}
+} // namespace webrtc