From 66eaed03932170b8c36ad92a54dd4bacb0321dec Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Mon, 28 May 2018 13:32:36 +0200 Subject: [PATCH] Adding direct congestion window pushback to encoders. When CongestionWindowPushback experiment is enabled, the pacer is oblivious to the congestion window. The relation between outstanding data and the congestion window affects encoder allocations directly. Bug: None Change-Id: Iaacc1d460d44a4ff2d586934c4f9ceb067109337 Reviewed-on: https://webrtc-review.googlesource.com/74922 Commit-Queue: Ying Wang Reviewed-by: Sebastian Jansson Reviewed-by: Christoffer Rodbro Cr-Commit-Position: refs/heads/master@{#23411} --- .../goog_cc/goog_cc_network_control.cc | 8 ++- .../goog_cc/goog_cc_network_control.h | 2 + .../rtp/send_side_congestion_controller.cc | 64 +++++++++++++++++-- 3 files changed, 67 insertions(+), 7 deletions(-) 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 b0bf6f31f0..829faea381 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -348,7 +348,13 @@ rtc::Optional GoogCcNetworkController::MaybeUpdateCongestionWindow() { TimeDelta time_window = TimeDelta::ms(*min_feedback_rtt_ms_ + accepted_queue_ms_); DataSize data_window = last_bandwidth_ * time_window; - data_window = std::max(kMinCwnd, data_window); + if (current_data_window_) { + data_window = + std::max(kMinCwnd, (data_window + current_data_window_.value()) / 2); + } else { + data_window = std::max(kMinCwnd, data_window); + } + current_data_window_ = data_window; RTC_LOG(LS_INFO) << "Feedback rtt: " << *min_feedback_rtt_ms_ << " Bitrate: " << last_bandwidth_.bps(); return data_window; 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 f7039f0a17..3afd8d23a7 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.h +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.h @@ -89,6 +89,8 @@ class GoogCcNetworkController : public NetworkControllerInterface { int64_t accepted_queue_ms_; bool previously_in_alr = false; + rtc::Optional current_data_window_; + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(GoogCcNetworkController); }; diff --git a/modules/congestion_controller/rtp/send_side_congestion_controller.cc b/modules/congestion_controller/rtp/send_side_congestion_controller.cc index fa010e8234..4ee5b7c4f8 100644 --- a/modules/congestion_controller/rtp/send_side_congestion_controller.cc +++ b/modules/congestion_controller/rtp/send_side_congestion_controller.cc @@ -38,8 +38,16 @@ namespace webrtc_cc { namespace { using send_side_cc_internal::PeriodicTask; +// When CongestionWindowPushback is enabled, the pacer is oblivious to +// the congestion window. The relation between outstanding data and +// the congestion window affects encoder allocations directly. +const char kCongestionPushbackExperiment[] = "WebRTC-CongestionWindowPushback"; + +// When PacerPushbackExperiment is enabled, build-up in the pacer due to +// the congestion window and/or data spikes reduces encoder allocations. const char kPacerPushbackExperiment[] = "WebRTC-PacerPushbackExperiment"; const int64_t PacerQueueUpdateIntervalMs = 25; +const uint32_t MinPushbackTargetBitrateBps = 30000; bool IsPacerPushbackExperimentEnabled() { return webrtc::field_trial::IsEnabled(kPacerPushbackExperiment) || @@ -48,6 +56,10 @@ bool IsPacerPushbackExperimentEnabled() { webrtc::runtime_enabled_features::kDualStreamModeFeatureName)); } +bool IsCongestionWindowExperimentEnabled() { + return webrtc::field_trial::IsEnabled(kCongestionPushbackExperiment); +} + void SortPacketFeedbackVector(std::vector* input) { std::sort(input->begin(), input->end(), PacketFeedbackComparator()); } @@ -155,6 +167,7 @@ class ControlHandler { void PostUpdates(NetworkControlUpdate update); void OnNetworkAvailability(NetworkAvailability msg); + void OnOutstandingData(DataSize in_flight_data); void OnPacerQueueUpdate(TimeDelta expected_queue_time); rtc::Optional last_transfer_rate(); @@ -172,13 +185,16 @@ class ControlHandler { PacerController* pacer_controller_; rtc::Optional current_target_rate_msg_; + rtc::Optional congestion_window_; + DataSize outstanding_data_ = DataSize::Zero(); bool network_available_ = true; int64_t last_reported_target_bitrate_bps_ = 0; uint8_t last_reported_fraction_loss_ = 0; int64_t last_reported_rtt_ms_ = 0; const bool pacer_pushback_experiment_ = false; + const bool congestion_window_pushback_experiment_ = false; int64_t pacer_expected_queue_ms_ = 0; - float encoding_rate_ratio_ = 1.0; + double encoding_rate_ratio_ = 1.0; rtc::SequencedTaskChecker sequenced_checker_; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ControlHandler); @@ -189,14 +205,19 @@ ControlHandler::ControlHandler(NetworkChangedObserver* observer, const Clock* clock) : observer_(observer), pacer_controller_(pacer_controller), - pacer_pushback_experiment_(IsPacerPushbackExperimentEnabled()) { + pacer_pushback_experiment_(IsPacerPushbackExperimentEnabled()), + congestion_window_pushback_experiment_( + IsCongestionWindowExperimentEnabled()) { sequenced_checker_.Detach(); } void ControlHandler::PostUpdates(NetworkControlUpdate update) { RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); - if (update.congestion_window) { - pacer_controller_->OnCongestionWindow(*update.congestion_window); + if (congestion_window_pushback_experiment_) { + if (update.congestion_window) { + congestion_window_ = update.congestion_window; + pacer_controller_->OnCongestionWindow(*update.congestion_window); + } } if (update.pacer_config) { pacer_controller_->OnPacerConfig(*update.pacer_config); @@ -216,6 +237,12 @@ void ControlHandler::OnNetworkAvailability(NetworkAvailability msg) { OnNetworkInvalidation(); } +void ControlHandler::OnOutstandingData(DataSize in_flight_data) { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); + outstanding_data_ = in_flight_data; + OnNetworkInvalidation(); +} + void ControlHandler::OnPacerQueueUpdate(TimeDelta expected_queue_time) { RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); pacer_expected_queue_ms_ = expected_queue_time.ms(); @@ -241,6 +268,29 @@ void ControlHandler::OnNetworkInvalidation() { if (!network_available_) { target_bitrate_bps = 0; + } else if (congestion_window_pushback_experiment_ && congestion_window_) { + double fill_ratio = outstanding_data_.bytes() / + static_cast(congestion_window_->bytes()); + if (fill_ratio > 1.5) { + encoding_rate_ratio_ *= 0.9; + } else if (fill_ratio > 1) { + encoding_rate_ratio_ *= 0.95; + } else if (fill_ratio < 0.1) { + encoding_rate_ratio_ = 1.0; + } else { + encoding_rate_ratio_ *= 1.05; + encoding_rate_ratio_ = std::min(encoding_rate_ratio_, 1.0); + } + + uint32_t adjusted_target_bitrate_bps = + static_cast(target_bitrate_bps * encoding_rate_ratio_); + + // If adjusted target bitrate is lower than minimum target bitrate, + // does not reduce target bitrate lower than minimum target bitrate. + target_bitrate_bps = + adjusted_target_bitrate_bps < MinPushbackTargetBitrateBps + ? std::min(target_bitrate_bps, MinPushbackTargetBitrateBps) + : adjusted_target_bitrate_bps; } else if (!pacer_pushback_experiment_) { target_bitrate_bps = IsSendQueueFull() ? 0 : target_bitrate_bps; } else { @@ -249,9 +299,9 @@ void ControlHandler::OnNetworkInvalidation() { if (queue_length_ms == 0) { encoding_rate_ratio_ = 1.0; } else if (queue_length_ms > 50) { - float encoding_ratio = 1.0 - queue_length_ms / 1000.0; + double encoding_ratio = 1.0 - queue_length_ms / 1000.0; encoding_rate_ratio_ = std::min(encoding_rate_ratio_, encoding_ratio); - encoding_rate_ratio_ = std::max(encoding_rate_ratio_, 0.0f); + encoding_rate_ratio_ = std::max(encoding_rate_ratio_, 0.0); } target_bitrate_bps *= encoding_rate_ratio_; @@ -667,6 +717,8 @@ void SendSideCongestionController::MaybeUpdateOutstandingData() { task_queue_->PostTask([this, in_flight_data]() { RTC_DCHECK_RUN_ON(task_queue_); pacer_controller_->OnOutstandingData(in_flight_data); + if (control_handler_) + control_handler_->OnOutstandingData(in_flight_data); }); }