diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn index cbfcf77877..394844411b 100644 --- a/modules/congestion_controller/goog_cc/BUILD.gn +++ b/modules/congestion_controller/goog_cc/BUILD.gn @@ -21,6 +21,8 @@ rtc_static_library("goog_cc") { sources = [ "goog_cc_network_control.cc", "goog_cc_network_control.h", + "overuse_predictor.cc", + "overuse_predictor.h", ] deps = [ diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe.cc b/modules/congestion_controller/goog_cc/delay_based_bwe.cc index 35574db0f3..0f60002764 100644 --- a/modules/congestion_controller/goog_cc/delay_based_bwe.cc +++ b/modules/congestion_controller/goog_cc/delay_based_bwe.cc @@ -167,6 +167,12 @@ void DelayBasedBwe::IncomingPacketFeedback( packet_feedback.arrival_time_ms, calculated_deltas); } +DataRate DelayBasedBwe::TriggerOveruse(Timestamp at_time, + absl::optional link_capacity) { + RateControlInput input(BandwidthUsage::kBwOverusing, link_capacity); + return rate_control_.Update(&input, at_time); +} + DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate( absl::optional acked_bitrate, absl::optional probe_bitrate, diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe.h b/modules/congestion_controller/goog_cc/delay_based_bwe.h index 53b1242bad..4841dde8de 100644 --- a/modules/congestion_controller/goog_cc/delay_based_bwe.h +++ b/modules/congestion_controller/goog_cc/delay_based_bwe.h @@ -64,6 +64,9 @@ class DelayBasedBwe { TimeDelta GetExpectedBwePeriod() const; void SetAlrLimitedBackoffExperiment(bool enabled); + DataRate TriggerOveruse(Timestamp at_time, + absl::optional link_capacity); + private: friend class GoogCcStatePrinter; void IncomingPacketFeedback(const PacketFeedback& packet_feedback, diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc index 549272d538..540c01a9a0 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -114,6 +114,7 @@ GoogCcNetworkController::GoogCcNetworkController(NetworkControllerConfig config, network_state_predictor_.get())), acknowledged_bitrate_estimator_( absl::make_unique(key_value_config_)), + overuse_predictor_(key_value_config_), initial_config_(config), last_raw_target_rate_(*config.constraints.starting_rate), last_pushback_target_rate_(last_raw_target_rate_), @@ -260,9 +261,24 @@ NetworkControlUpdate GoogCcNetworkController::OnSentPacket( TimeDelta::Zero()); } bandwidth_estimation_->OnSentPacket(sent_packet); + bool network_changed = false; + if (network_estimator_ && overuse_predictor_.Enabled()) { + overuse_predictor_.OnSentPacket(sent_packet); + auto estimate = network_estimator_->GetCurrentEstimate(); + if (estimate && overuse_predictor_.PredictOveruse(*estimate)) { + DataRate new_target = delay_based_bwe_->TriggerOveruse( + sent_packet.send_time, acknowledged_bitrate_estimator_->bitrate()); + bandwidth_estimation_->UpdateDelayBasedEstimate(sent_packet.send_time, + new_target); + network_changed = true; + } + } if (congestion_window_pushback_controller_) { congestion_window_pushback_controller_->UpdateOutstandingData( sent_packet.data_in_flight.bytes()); + network_changed = true; + } + if (network_changed) { NetworkControlUpdate update; MaybeTriggerOnNetworkChanged(&update, sent_packet.send_time); return update; diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.h b/modules/congestion_controller/goog_cc/goog_cc_network_control.h index de1ea4f220..7411c1e399 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.h +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.h @@ -31,6 +31,7 @@ #include "modules/congestion_controller/goog_cc/alr_detector.h" #include "modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h" #include "modules/congestion_controller/goog_cc/delay_based_bwe.h" +#include "modules/congestion_controller/goog_cc/overuse_predictor.h" #include "modules/congestion_controller/goog_cc/probe_controller.h" #include "rtc_base/constructor_magic.h" #include "rtc_base/experiments/field_trial_parser.h" @@ -96,6 +97,7 @@ class GoogCcNetworkController : public NetworkControllerInterface { std::unique_ptr network_state_predictor_; std::unique_ptr delay_based_bwe_; std::unique_ptr acknowledged_bitrate_estimator_; + OverusePredictor overuse_predictor_; absl::optional initial_config_; diff --git a/modules/congestion_controller/goog_cc/overuse_predictor.cc b/modules/congestion_controller/goog_cc/overuse_predictor.cc new file mode 100644 index 0000000000..a47c47a2fc --- /dev/null +++ b/modules/congestion_controller/goog_cc/overuse_predictor.cc @@ -0,0 +1,72 @@ +/* + * Copyright 2019 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/congestion_controller/goog_cc/overuse_predictor.h" + +#include + +namespace webrtc { +namespace { +constexpr int kMaxPendingPackets = 100; + +DataRate GetAvailableCapacity(const NetworkStateEstimate& est, + double deviation) { + double capacity_bps = est.link_capacity.bps(); + double min_capacity_bps = est.link_capacity_min.bps(); + double deviation_bps = est.link_capacity_std_dev.bps(); + return DataRate::bps( + std::max(capacity_bps + deviation_bps * deviation, min_capacity_bps)); +} +} // namespace + +OverusePredictorConfig::OverusePredictorConfig(const std::string& config) { + ParseFieldTrial({&enabled, &capacity_dev_ratio_threshold, &capacity_deviation, + &delay_threshold}, + config); +} + +OverusePredictor::OverusePredictor(const WebRtcKeyValueConfig* config) + : conf_(config->Lookup("WebRTC-Bwe-OverusePredictor")) {} + +bool OverusePredictor::Enabled() const { + return conf_.enabled; +} + +void OverusePredictor::OnSentPacket(SentPacket sent_packet) { + pending_.push_back(SentPacketInfo{sent_packet.send_time, sent_packet.size}); + if (pending_.size() > kMaxPendingPackets) + pending_.pop_front(); +} + +bool OverusePredictor::PredictOveruse(const NetworkStateEstimate& est) { + while (!pending_.empty() && pending_.front().send_time < est.last_send_time) { + pending_.pop_front(); + } + double deviation_ratio = est.link_capacity_std_dev / est.link_capacity; + if (deviation_ratio > conf_.capacity_dev_ratio_threshold) + return false; + TimeDelta buffer_delay = PredictDelay(est) - est.propagation_delay; + return buffer_delay > conf_.delay_threshold; +} + +TimeDelta OverusePredictor::PredictDelay(const NetworkStateEstimate& est) { + auto safe_capacity = GetAvailableCapacity(est, conf_.capacity_deviation); + Timestamp last_send_time = est.last_send_time; + TimeDelta link_delay = est.pre_link_buffer_delay; + for (const auto& packet : pending_) { + auto delta = packet.send_time - last_send_time; + last_send_time = packet.send_time; + link_delay = std::max(link_delay - delta, est.propagation_delay); + link_delay += packet.size / safe_capacity; + } + return link_delay; +} + +} // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/overuse_predictor.h b/modules/congestion_controller/goog_cc/overuse_predictor.h new file mode 100644 index 0000000000..c4170db115 --- /dev/null +++ b/modules/congestion_controller/goog_cc/overuse_predictor.h @@ -0,0 +1,49 @@ +/* + * Copyright 2019 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. + */ +#ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_OVERUSE_PREDICTOR_H_ +#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_OVERUSE_PREDICTOR_H_ + +#include +#include + +#include "api/transport/network_types.h" +#include "api/transport/webrtc_key_value_config.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/experiments/field_trial_units.h" + +namespace webrtc { + +struct OverusePredictorConfig { + FieldTrialFlag enabled{"Enabled"}; + FieldTrialParameter capacity_dev_ratio_threshold{"dev_thr", 0.2}; + FieldTrialParameter capacity_deviation{"cap_dev", -1}; + FieldTrialParameter delay_threshold{"del_thr", TimeDelta::ms(100)}; + explicit OverusePredictorConfig(const std::string& config); +}; + +class OverusePredictor { + public: + explicit OverusePredictor(const WebRtcKeyValueConfig* config); + void OnSentPacket(SentPacket sent_packet); + bool Enabled() const; + bool PredictOveruse(const NetworkStateEstimate& est); + + private: + struct SentPacketInfo { + Timestamp send_time; + DataSize size; + }; + TimeDelta PredictDelay(const NetworkStateEstimate& est); + const OverusePredictorConfig conf_; + std::deque pending_; +}; +} // namespace webrtc + +#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_OVERUSE_PREDICTOR_H_