diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.cc index 57f4afa146..6871afae0e 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe.cc @@ -61,7 +61,7 @@ DelayBasedBwe::DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config, network_state_predictor_(network_state_predictor), inter_arrival_(), delay_detector_( - new TrendlineEstimator(key_value_config_, network_state_predictor_)), + new TrendlineEstimator(network_state_predictor_)), last_seen_packet_(Timestamp::MinusInfinity()), uma_recorded_(false), rate_control_(key_value_config, /*send_side=*/true), @@ -127,7 +127,7 @@ void DelayBasedBwe::IncomingPacketFeedback(const PacketResult& packet_feedback, new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000, kTimestampToMs, true)); delay_detector_.reset( - new TrendlineEstimator(key_value_config_, network_state_predictor_)); + new TrendlineEstimator(network_state_predictor_)); } last_seen_packet_ = at_time; diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.cc b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.cc index 885c6776cb..dedb33d3f9 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.cc +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.cc @@ -13,96 +13,92 @@ #include "modules/congestion_controller/goog_cc/trendline_estimator.h" -#include "modules/remote_bitrate_estimator/include/bwe_defines.h" -#include "rtc_base/numerics/safe_minmax.h" - -#include "Logger.hpp" - -#include #include + #include #include +#include "absl/strings/match.h" +#include "absl/types/optional.h" +#include "api/network_state_predictor.h" +#include "rtc_base/numerics/safe_minmax.h" +#include "api/transport/webrtc_key_value_config.h" + +#include "Logger.hpp" + namespace webrtc { namespace { // Parameters for linear least squares fit of regression line to noisy data. -constexpr size_t kDefaultTrendlineWindowSize = 20; -constexpr double kDefaultTrendlineSmoothingCoeff = 0.6; +constexpr double kDefaultTrendlineSmoothingCoeff = 0.9; constexpr double kDefaultTrendlineThresholdGain = 4.0; -const char kBweWindowSizeInPacketsExperiment[] = - "WebRTC-BweWindowSizeInPackets"; - -size_t ReadTrendlineFilterWindowSize( - const WebRtcKeyValueConfig* key_value_config) { - std::string experiment_string = - key_value_config->Lookup(kBweWindowSizeInPacketsExperiment); - size_t window_size; - int parsed_values = - sscanf(experiment_string.c_str(), "Enabled-%zu", &window_size); - if (parsed_values == 1) { - if (window_size > 1) - return window_size; - MS_WARN_DEV("window size must be greater than 1"); - } - MS_WARN_DEV( - "failed to parse parameters for BweWindowSizeInPackets" - " experiment from field trial string, using default"); - return kDefaultTrendlineWindowSize; -} absl::optional LinearFitSlope( - const std::deque>& points) { - //RTC_DCHECK(points.size() >= 2); + const std::deque& packets) { + // RTC_DCHECK(packets.size() >= 2); // Compute the "center of mass". double sum_x = 0; double sum_y = 0; - for (const auto& point : points) { - sum_x += point.first; - sum_y += point.second; + for (const auto& packet : packets) { + sum_x += packet.arrival_time_ms; + sum_y += packet.smoothed_delay_ms; } - double x_avg = sum_x / points.size(); - double y_avg = sum_y / points.size(); + double x_avg = sum_x / packets.size(); + double y_avg = sum_y / packets.size(); // Compute the slope k = \sum (x_i-x_avg)(y_i-y_avg) / \sum (x_i-x_avg)^2 double numerator = 0; double denominator = 0; - for (const auto& point : points) { - numerator += (point.first - x_avg) * (point.second - y_avg); - denominator += (point.first - x_avg) * (point.first - x_avg); + for (const auto& packet : packets) { + double x = packet.arrival_time_ms; + double y = packet.smoothed_delay_ms; + numerator += (x - x_avg) * (y - y_avg); + denominator += (x - x_avg) * (x - x_avg); } if (denominator == 0) return absl::nullopt; return numerator / denominator; } +absl::optional ComputeSlopeCap( + const std::deque& packets, + const TrendlineEstimatorSettings& settings) { + // RTC_DCHECK(1 <= settings.beginning_packets && + // settings.beginning_packets < packets.size()); + // RTC_DCHECK(1 <= settings.end_packets && + // settings.end_packets < packets.size()); + // RTC_DCHECK(settings.beginning_packets + settings.end_packets <= + // packets.size()); + TrendlineEstimator::PacketTiming early = packets[0]; + for (size_t i = 1; i < settings.beginning_packets; ++i) { + if (packets[i].raw_delay_ms < early.raw_delay_ms) + early = packets[i]; + } + size_t late_start = packets.size() - settings.end_packets; + TrendlineEstimator::PacketTiming late = packets[late_start]; + for (size_t i = late_start + 1; i < packets.size(); ++i) { + if (packets[i].raw_delay_ms < late.raw_delay_ms) + late = packets[i]; + } + if (late.arrival_time_ms - early.arrival_time_ms < 1) { + return absl::nullopt; + } + return (late.raw_delay_ms - early.raw_delay_ms) / + (late.arrival_time_ms - early.arrival_time_ms) + + settings.cap_uncertainty; +} + constexpr double kMaxAdaptOffsetMs = 15.0; -constexpr double kOverUsingTimeThreshold = 30; +constexpr double kOverUsingTimeThreshold = 10; constexpr int kMinNumDeltas = 60; constexpr int kDeltaCounterMax = 1000; } // namespace TrendlineEstimator::TrendlineEstimator( - const WebRtcKeyValueConfig* key_value_config, NetworkStatePredictor* network_state_predictor) - : TrendlineEstimator( - key_value_config->Lookup(kBweWindowSizeInPacketsExperiment) - .find("Enabled") == 0 - ? ReadTrendlineFilterWindowSize(key_value_config) - : kDefaultTrendlineWindowSize, - kDefaultTrendlineSmoothingCoeff, - kDefaultTrendlineThresholdGain, - network_state_predictor) {} - -TrendlineEstimator::TrendlineEstimator( - size_t window_size, - double smoothing_coef, - double threshold_gain, - NetworkStatePredictor* network_state_predictor) - : window_size_(window_size), - smoothing_coef_(smoothing_coef), - threshold_gain_(threshold_gain), + : smoothing_coef_(kDefaultTrendlineSmoothingCoeff), + threshold_gain_(kDefaultTrendlineThresholdGain), num_of_deltas_(0), first_arrival_time_ms_(-1), accumulated_delay_(0), @@ -120,63 +116,75 @@ TrendlineEstimator::TrendlineEstimator( hypothesis_(BandwidthUsage::kBwNormal), hypothesis_predicted_(BandwidthUsage::kBwNormal), network_state_predictor_(network_state_predictor) { - MS_DEBUG_DEV( - "using Trendline filter for delay change estimation with window size: %zu", - window_size_); } TrendlineEstimator::~TrendlineEstimator() {} +void TrendlineEstimator::UpdateTrendline(double recv_delta_ms, + double send_delta_ms, + int64_t send_time_ms, + int64_t arrival_time_ms) { + const double delta_ms = recv_delta_ms - send_delta_ms; + ++num_of_deltas_; + num_of_deltas_ = std::min(num_of_deltas_, kDeltaCounterMax); + if (first_arrival_time_ms_ == -1) + first_arrival_time_ms_ = arrival_time_ms; + + // Exponential backoff filter. + accumulated_delay_ += delta_ms; + // BWE_TEST_LOGGING_PLOT(1, "accumulated_delay_ms", arrival_time_ms, + // accumulated_delay_); + smoothed_delay_ = smoothing_coef_ * smoothed_delay_ + + (1 - smoothing_coef_) * accumulated_delay_; + // BWE_TEST_LOGGING_PLOT(1, "smoothed_delay_ms", arrival_time_ms, + // smoothed_delay_); + + // Maintain packet window + delay_hist_.emplace_back( + static_cast(arrival_time_ms - first_arrival_time_ms_), + smoothed_delay_, accumulated_delay_); + if (settings_.enable_sort) { + for (size_t i = delay_hist_.size() - 1; + i > 0 && + delay_hist_[i].arrival_time_ms < delay_hist_[i - 1].arrival_time_ms; + --i) { + std::swap(delay_hist_[i], delay_hist_[i - 1]); + } + } + if (delay_hist_.size() > settings_.window_size) + delay_hist_.pop_front(); + + // Simple linear regression. + double trend = prev_trend_; + if (delay_hist_.size() == settings_.window_size) { + // Update trend_ if it is possible to fit a line to the data. The delay + // trend can be seen as an estimate of (send_rate - capacity)/capacity. + // 0 < trend < 1 -> the delay increases, queues are filling up + // trend == 0 -> the delay does not change + // trend < 0 -> the delay decreases, queues are being emptied + trend = LinearFitSlope(delay_hist_).value_or(trend); + if (settings_.enable_cap) { + absl::optional cap = ComputeSlopeCap(delay_hist_, settings_); + // We only use the cap to filter out overuse detections, not + // to detect additional underuses. + if (trend >= 0 && cap.has_value() && trend > cap.value()) { + trend = cap.value(); + } + } + } + // BWE_TEST_LOGGING_PLOT(1, "trendline_slope", arrival_time_ms, trend); + + Detect(trend, send_delta_ms, arrival_time_ms); +} + void TrendlineEstimator::Update(double recv_delta_ms, double send_delta_ms, int64_t send_time_ms, int64_t arrival_time_ms, bool calculated_deltas) { if (calculated_deltas) { - const double delta_ms = recv_delta_ms - send_delta_ms; - ++num_of_deltas_; - num_of_deltas_ = std::min(num_of_deltas_, kDeltaCounterMax); - if (first_arrival_time_ms_ == -1) - first_arrival_time_ms_ = arrival_time_ms; - - // Exponential backoff filter. - accumulated_delay_ += delta_ms; - // BWE_TEST_LOGGING_PLOT(1, "accumulated_delay_ms", arrival_time_ms, - // accumulated_delay_); - // smoothed_delay_ = smoothing_coef_ * smoothed_delay_ + - // (1 - smoothing_coef_) * accumulated_delay_; - // MS_NOTE: Apply WEMA to the current delta_ms. Don't consider the - // accumulated delay. Tests show it behaves more robustly upon delta peaks. - smoothed_delay_ = smoothing_coef_ * delta_ms + - (1 - smoothing_coef_) * smoothed_delay_; - // BWE_TEST_LOGGING_PLOT(1, "smoothed_delay_ms", arrival_time_ms, - // smoothed_delay_); - - // Simple linear regression. - delay_hist_.push_back(std::make_pair( - static_cast(arrival_time_ms - first_arrival_time_ms_), - smoothed_delay_)); - if (delay_hist_.size() > window_size_) - delay_hist_.pop_front(); - double trend = prev_trend_; - if (delay_hist_.size() == window_size_) { - // Update trend_ if it is possible to fit a line to the data. The delay - // trend can be seen as an estimate of (send_rate - capacity)/capacity. - // 0 < trend < 1 -> the delay increases, queues are filling up - // trend == 0 -> the delay does not change - // trend < 0 -> the delay decreases, queues are being emptied - trend = LinearFitSlope(delay_hist_).value_or(trend); - } - - // BWE_TEST_LOGGING_PLOT(1, "trendline_slope", arrival_time_ms, trend); - - MS_DEBUG_DEV("trend:%f, send_delta_ms:%f, recv_delta_ms:%f, delta_ms:%f arrival_time_ms:%" PRIi64 ", accumulated_delay_:%f, smoothed_delay_:%f", trend, send_delta_ms, recv_delta_ms, delta_ms, arrival_time_ms, accumulated_delay_, smoothed_delay_); - Detect(trend, send_delta_ms, arrival_time_ms); - } - else { - MS_DEBUG_DEV("no calculated deltas"); + UpdateTrendline(recv_delta_ms, send_delta_ms, send_time_ms, arrival_time_ms); } - if (network_state_predictor_) { hypothesis_predicted_ = network_state_predictor_->Update( send_time_ms, arrival_time_ms, hypothesis_); @@ -212,6 +220,7 @@ void TrendlineEstimator::Detect(double trend, double ts_delta, int64_t now_ms) { if (trend >= prev_trend_) { time_over_using_ = 0; overuse_counter_ = 0; + hypothesis_ = BandwidthUsage::kBwOverusing; MS_DEBUG_DEV("hypothesis_: BandwidthUsage::kBwOverusing"); #if MS_LOG_DEV_LEVEL == 3 @@ -219,8 +228,6 @@ void TrendlineEstimator::Detect(double trend, double ts_delta, int64_t now_ms) { MS_DEBUG_DEV("arrival_time_ms - first_arrival_time_ms_:%f, smoothed_delay_:%f", kv.first, kv.second); } #endif - - hypothesis_ = BandwidthUsage::kBwOverusing; } } } else if (modified_trend < -threshold_) { @@ -231,8 +238,8 @@ void TrendlineEstimator::Detect(double trend, double ts_delta, int64_t now_ms) { } else { time_over_using_ = -1; overuse_counter_ = 0; - MS_DEBUG_DEV("---- BandwidthUsage::kBwNormal ---"); hypothesis_ = BandwidthUsage::kBwNormal; + MS_DEBUG_DEV("---- BandwidthUsage::kBwNormal ---"); } prev_trend_ = trend; UpdateThreshold(modified_trend, now_ms); diff --git a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.h b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.h index f4c23d706d..7eeb101d02 100644 --- a/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.h +++ b/worker/deps/libwebrtc/libwebrtc/modules/congestion_controller/goog_cc/trendline_estimator.h @@ -10,37 +10,48 @@ #ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_TRENDLINE_ESTIMATOR_H_ #define MODULES_CONGESTION_CONTROLLER_GOOG_CC_TRENDLINE_ESTIMATOR_H_ +#include +#include + +#include +#include +#include + #include "api/network_state_predictor.h" #include "api/transport/webrtc_key_value_config.h" #include "modules/congestion_controller/goog_cc/delay_increase_detector_interface.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "rtc_base/constructor_magic.h" -#include -#include -#include -#include - namespace webrtc { +struct TrendlineEstimatorSettings { + static constexpr unsigned kDefaultTrendlineWindowSize = 20; + + // Sort the packets in the window. Should be redundant, + // but then almost no cost. + bool enable_sort = false; + + // Cap the trendline slope based on the minimum delay seen + // in the beginning_packets and end_packets respectively. + bool enable_cap = false; + unsigned beginning_packets = 7; + unsigned end_packets = 7; + double cap_uncertainty = 0.0; + + // Size (in packets) of the window. + unsigned window_size = kDefaultTrendlineWindowSize; +}; + class TrendlineEstimator : public DelayIncreaseDetectorInterface { public: - TrendlineEstimator(const WebRtcKeyValueConfig* key_value_config, - NetworkStatePredictor* network_state_predictor); - // |window_size| is the number of points required to compute a trend line. - // |smoothing_coef| controls how much we smooth out the delay before fitting - // the trend line. |threshold_gain| is used to scale the trendline slope for - // comparison to the old threshold. Once the old estimator has been removed - // (or the thresholds been merged into the estimators), we can just set the - // threshold instead of setting a gain.|network_state_predictor| is used to - // bettter predict network state. - TrendlineEstimator(size_t window_size, - double smoothing_coef, - double threshold_gain, - NetworkStatePredictor* network_state_predictor); + TrendlineEstimator(NetworkStatePredictor* network_state_predictor); ~TrendlineEstimator() override; + TrendlineEstimator(const TrendlineEstimator&) = delete; + TrendlineEstimator& operator=(const TrendlineEstimator&) = delete; + // Update the estimator with a new sample. The deltas should represent deltas // between timestamp groups as defined by the InterArrival class. void Update(double recv_delta_ms, @@ -49,21 +60,33 @@ class TrendlineEstimator : public DelayIncreaseDetectorInterface { int64_t arrival_time_ms, bool calculated_deltas) override; + void UpdateTrendline(double recv_delta_ms, + double send_delta_ms, + int64_t send_time_ms, + int64_t arrival_time_ms); + BandwidthUsage State() const override; - protected: - // Used in unit tests. - double modified_trend() const { return prev_trend_ * threshold_gain_; } + struct PacketTiming { + PacketTiming(double arrival_time_ms, + double smoothed_delay_ms, + double raw_delay_ms) + : arrival_time_ms(arrival_time_ms), + smoothed_delay_ms(smoothed_delay_ms), + raw_delay_ms(raw_delay_ms) {} + double arrival_time_ms; + double smoothed_delay_ms; + double raw_delay_ms; + }; private: friend class GoogCcStatePrinter; - void Detect(double trend, double ts_delta, int64_t now_ms); void UpdateThreshold(double modified_offset, int64_t now_ms); // Parameters. - const size_t window_size_; + TrendlineEstimatorSettings settings_; const double smoothing_coef_; const double threshold_gain_; // Used by the existing threshold. @@ -74,7 +97,7 @@ class TrendlineEstimator : public DelayIncreaseDetectorInterface { double accumulated_delay_; double smoothed_delay_; // Linear least squares regression. - std::deque> delay_hist_; + std::deque delay_hist_; const double k_up_; const double k_down_; @@ -88,8 +111,6 @@ class TrendlineEstimator : public DelayIncreaseDetectorInterface { BandwidthUsage hypothesis_; BandwidthUsage hypothesis_predicted_; NetworkStatePredictor* network_state_predictor_; - - RTC_DISALLOW_COPY_AND_ASSIGN(TrendlineEstimator); }; } // namespace webrtc