Move congestion window field trial parsing to new class.

This cl is part of work to move several experiments into a joint
experiment group. Most of them vill be ralted to video, hence the name.

Bug: webrtc:10223
Change-Id: I8767c43abb6aa910ab51710eeb908e0f9df1e296
Reviewed-on: https://webrtc-review.googlesource.com/c/118361
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26346}
diff --git a/modules/congestion_controller/BUILD.gn b/modules/congestion_controller/BUILD.gn
index 06b8669..7bd049e 100644
--- a/modules/congestion_controller/BUILD.gn
+++ b/modules/congestion_controller/BUILD.gn
@@ -46,6 +46,7 @@
     "../../rtc_base:deprecation",
     "../../rtc_base:ptr_util",
     "../../rtc_base:rate_limiter",
+    "../../rtc_base/experiments:rate_control_settings",
     "../../rtc_base/network:sent_packet",
     "../../system_wrappers",
     "../../system_wrappers:field_trial",
diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn
index 9de1815..9326f86 100644
--- a/modules/congestion_controller/goog_cc/BUILD.gn
+++ b/modules/congestion_controller/goog_cc/BUILD.gn
@@ -45,6 +45,7 @@
     "../../../rtc_base:rtc_base_approved",
     "../../../rtc_base/experiments:alr_experiment",
     "../../../rtc_base/experiments:field_trial_parser",
+    "../../../rtc_base/experiments:rate_control_settings",
     "../../../system_wrappers",
     "../../bitrate_controller",
     "../../remote_bitrate_estimator",
@@ -77,6 +78,7 @@
     "../../../api/units:data_size",
     "../../../rtc_base:checks",
     "../../../rtc_base:rtc_base_approved",
+    "../../../rtc_base/experiments:rate_control_settings",
     "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
diff --git a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc
index 7d83b8c..4e6bed6 100644
--- a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc
+++ b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc
@@ -15,46 +15,18 @@
 
 #include "modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h"
 #include "rtc_base/checks.h"
+#include "rtc_base/experiments/rate_control_settings.h"
 
 namespace webrtc {
 
-namespace {
-
-// 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.
-// This experiment is build on top of congestion window experiment.
-const char kCongestionPushbackExperiment[] = "WebRTC-CongestionWindowPushback";
-const uint32_t kDefaultMinPushbackTargetBitrateBps = 30000;
-
-bool ReadCongestionWindowPushbackExperimentParameter(
-    const WebRtcKeyValueConfig* key_value_config,
-    uint32_t* min_pushback_target_bitrate_bps) {
-  RTC_DCHECK(min_pushback_target_bitrate_bps);
-  std::string experiment_string =
-      key_value_config->Lookup(kCongestionPushbackExperiment);
-  int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%" PRIu32,
-                             min_pushback_target_bitrate_bps);
-  if (parsed_values == 1) {
-    RTC_CHECK_GE(*min_pushback_target_bitrate_bps, 0)
-        << "Min pushback target bitrate must be greater than or equal to 0.";
-    return true;
-  }
-  return false;
-}
-
-}  // namespace
-
 CongestionWindowPushbackController::CongestionWindowPushbackController(
     const WebRtcKeyValueConfig* key_value_config)
     : add_pacing_(
           key_value_config->Lookup("WebRTC-AddPacingToCongestionWindowPushback")
-              .find("Enabled") == 0) {
-  if (!ReadCongestionWindowPushbackExperimentParameter(
-          key_value_config, &min_pushback_target_bitrate_bps_)) {
-    min_pushback_target_bitrate_bps_ = kDefaultMinPushbackTargetBitrateBps;
-  }
-}
+              .find("Enabled") == 0),
+      min_pushback_target_bitrate_bps_(
+          RateControlSettings::ParseFromKeyValueConfig(key_value_config)
+              .CongestionWindowMinPushbackTargetBitrateBps()) {}
 
 CongestionWindowPushbackController::CongestionWindowPushbackController(
     const WebRtcKeyValueConfig* key_value_config,
diff --git a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h
index 9b64093..edf8bcb 100644
--- a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h
+++ b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h
@@ -43,7 +43,7 @@
   int64_t outstanding_bytes_ = 0;
   int64_t pacing_bytes_ = 0;
   const bool add_pacing_;
-  uint32_t min_pushback_target_bitrate_bps_;
+  const uint32_t min_pushback_target_bitrate_bps_;
   double encoding_rate_ratio_ = 1.0;
 };
 
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 6fd621f..d7b0565 100644
--- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc
+++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc
@@ -32,15 +32,6 @@
 
 namespace webrtc {
 namespace {
-
-const char kCwndExperiment[] = "WebRTC-CwndExperiment";
-// 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";
-
-const int64_t kDefaultAcceptedQueueMs = 250;
-
 // From RTCPSender video report interval.
 constexpr TimeDelta kLossUpdateInterval = TimeDelta::Millis<1000>();
 
@@ -51,37 +42,6 @@
 // overshoots from the encoder.
 const float kDefaultPaceMultiplier = 2.5f;
 
-std::unique_ptr<CongestionWindowPushbackController>
-MaybeCreateCongestionWindowPushbackController(
-    const WebRtcKeyValueConfig* const key_value_config) {
-  if (key_value_config->Lookup(kCongestionPushbackExperiment).find("Enabled") ==
-          0 &&
-      key_value_config->Lookup(kCwndExperiment).find("Enabled") == 0)
-    return absl::make_unique<CongestionWindowPushbackController>(
-        key_value_config);
-  return nullptr;
-}
-
-bool CwndExperimentEnabled(const WebRtcKeyValueConfig* const key_value_config) {
-  std::string experiment_string = key_value_config->Lookup(kCwndExperiment);
-  // The experiment is enabled iff the field trial string begins with "Enabled".
-  return experiment_string.find("Enabled") == 0;
-}
-bool ReadCwndExperimentParameter(
-    const WebRtcKeyValueConfig* const key_value_config,
-    int64_t* accepted_queue_ms) {
-  RTC_DCHECK(accepted_queue_ms);
-  std::string experiment_string = key_value_config->Lookup(kCwndExperiment);
-  int parsed_values =
-      sscanf(experiment_string.c_str(), "Enabled-%" PRId64, accepted_queue_ms);
-  if (parsed_values == 1) {
-    RTC_CHECK_GE(*accepted_queue_ms, 0)
-        << "Accepted must be greater than or equal to 0.";
-    return true;
-  }
-  return false;
-}
-
 // Makes sure that the bitrate and the min, max values are in valid range.
 static void ClampBitrates(int64_t* bitrate_bps,
                           int64_t* min_bitrate_bps,
@@ -140,9 +100,14 @@
       fall_back_to_probe_rate_(
           key_value_config_->Lookup("WebRTC-Bwe-ProbeRateFallback")
               .find("Enabled") == 0),
+      rate_control_experiments_(
+          RateControlSettings::ParseFromKeyValueConfig(key_value_config_)),
       probe_controller_(new ProbeController(key_value_config_)),
       congestion_window_pushback_controller_(
-          MaybeCreateCongestionWindowPushbackController(key_value_config_)),
+          rate_control_experiments_.UseCongestionWindowPushback()
+              ? absl::make_unique<CongestionWindowPushbackController>(
+                    key_value_config_)
+              : nullptr),
       bandwidth_estimation_(
           absl::make_unique<SendSideBandwidthEstimation>(event_log_)),
       alr_detector_(absl::make_unique<AlrDetector>()),
@@ -170,21 +135,13 @@
           DataRate::Zero())),
       max_padding_rate_(config.stream_based_config.max_padding_rate.value_or(
           DataRate::Zero())),
-      max_total_allocated_bitrate_(DataRate::Zero()),
-      in_cwnd_experiment_(CwndExperimentEnabled(key_value_config_)),
-      accepted_queue_ms_(kDefaultAcceptedQueueMs) {
+      max_total_allocated_bitrate_(DataRate::Zero()) {
   RTC_DCHECK(config.constraints.at_time.IsFinite());
   ParseFieldTrial(
       {&safe_reset_on_route_change_, &safe_reset_acknowledged_rate_},
       key_value_config_->Lookup("WebRTC-Bwe-SafeResetOnRouteChange"));
   if (delay_based_bwe_)
     delay_based_bwe_->SetMinBitrate(congestion_controller::GetMinBitrate());
-  if (in_cwnd_experiment_ &&
-      !ReadCwndExperimentParameter(key_value_config_, &accepted_queue_ms_)) {
-    RTC_LOG(LS_WARNING) << "Failed to parse parameters for CwndExperiment "
-                           "from field trial string. Experiment disabled.";
-    in_cwnd_experiment_ = false;
-  }
 }
 
 GoogCcNetworkController::~GoogCcNetworkController() {}
@@ -589,13 +546,15 @@
 
   // No valid RTT could be because send-side BWE isn't used, in which case
   // we don't try to limit the outstanding packets.
-  if (in_cwnd_experiment_ && max_feedback_rtt.IsFinite()) {
+  if (rate_control_experiments_.UseCongestionWindow() &&
+      max_feedback_rtt.IsFinite()) {
     int64_t min_feedback_max_rtt_ms =
         *std::min_element(feedback_max_rtts_.begin(), feedback_max_rtts_.end());
 
     const DataSize kMinCwnd = DataSize::bytes(2 * 1500);
-    TimeDelta time_window =
-        TimeDelta::ms(min_feedback_max_rtt_ms + accepted_queue_ms_);
+    TimeDelta time_window = TimeDelta::ms(
+        min_feedback_max_rtt_ms +
+        rate_control_experiments_.GetCongestionWindowAdditionalTimeMs());
     DataSize data_window = last_raw_target_rate_ * time_window;
     if (current_data_window_) {
       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 7d65689..f60d31d 100644
--- a/modules/congestion_controller/goog_cc/goog_cc_network_control.h
+++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.h
@@ -34,6 +34,7 @@
 #include "modules/congestion_controller/goog_cc/probe_controller.h"
 #include "rtc_base/constructor_magic.h"
 #include "rtc_base/experiments/field_trial_parser.h"
+#include "rtc_base/experiments/rate_control_settings.h"
 
 namespace webrtc {
 
@@ -78,6 +79,7 @@
   FieldTrialFlag safe_reset_acknowledged_rate_;
   const bool use_stable_bandwidth_estimate_;
   const bool fall_back_to_probe_rate_;
+  const RateControlSettings rate_control_experiments_;
 
   const std::unique_ptr<ProbeController> probe_controller_;
   const std::unique_ptr<CongestionWindowPushbackController>
@@ -113,8 +115,6 @@
   DataRate max_padding_rate_;
   DataRate max_total_allocated_bitrate_;
 
-  bool in_cwnd_experiment_;
-  int64_t accepted_queue_ms_;
   bool previously_in_alr = false;
 
   absl::optional<DataSize> current_data_window_;
diff --git a/modules/congestion_controller/include/send_side_congestion_controller.h b/modules/congestion_controller/include/send_side_congestion_controller.h
index b428eed..545be0e 100644
--- a/modules/congestion_controller/include/send_side_congestion_controller.h
+++ b/modules/congestion_controller/include/send_side_congestion_controller.h
@@ -168,8 +168,7 @@
   std::unique_ptr<ProbeBitrateEstimator> probe_bitrate_estimator_
       RTC_GUARDED_BY(bwe_lock_);
   std::unique_ptr<DelayBasedBwe> delay_based_bwe_ RTC_GUARDED_BY(bwe_lock_);
-  bool in_cwnd_experiment_;
-  int64_t accepted_queue_ms_;
+  absl::optional<int64_t> cwnd_experiment_parameter_;
   bool was_in_alr_;
   const bool send_side_bwe_with_overhead_;
   size_t transport_overhead_bytes_per_packet_ RTC_GUARDED_BY(bwe_lock_);
diff --git a/modules/congestion_controller/send_side_congestion_controller.cc b/modules/congestion_controller/send_side_congestion_controller.cc
index 8b6d223..ef1e2a1 100644
--- a/modules/congestion_controller/send_side_congestion_controller.cc
+++ b/modules/congestion_controller/send_side_congestion_controller.cc
@@ -28,6 +28,7 @@
 #include "modules/congestion_controller/goog_cc/probe_controller.h"
 #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
 #include "rtc_base/checks.h"
+#include "rtc_base/experiments/rate_control_settings.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/network/sent_packet.h"
 #include "rtc_base/rate_limiter.h"
@@ -36,48 +37,7 @@
 namespace webrtc {
 namespace {
 
-const char kCwndExperiment[] = "WebRTC-CwndExperiment";
 const char kPacerPushbackExperiment[] = "WebRTC-PacerPushbackExperiment";
-
-// 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";
-
-const int64_t kDefaultAcceptedQueueMs = 250;
-
-bool CwndExperimentEnabled(const WebRtcKeyValueConfig* const key_value_config) {
-  std::string experiment_string = key_value_config->Lookup(kCwndExperiment);
-  // The experiment is enabled iff the field trial string begins with "Enabled".
-  return experiment_string.find("Enabled") == 0;
-}
-
-bool ReadCwndExperimentParameter(
-    const WebRtcKeyValueConfig* const key_value_config,
-    int64_t* accepted_queue_ms) {
-  RTC_DCHECK(accepted_queue_ms);
-  std::string experiment_string = key_value_config->Lookup(kCwndExperiment);
-  int parsed_values =
-      sscanf(experiment_string.c_str(), "Enabled-%" PRId64, accepted_queue_ms);
-  if (parsed_values == 1) {
-    RTC_CHECK_GE(*accepted_queue_ms, 0)
-        << "Accepted must be greater than or equal to 0.";
-    return true;
-  }
-  return false;
-}
-
-std::unique_ptr<CongestionWindowPushbackController>
-MaybeCreateCongestionWindowPushbackController(
-    const WebRtcKeyValueConfig* const key_value_config) {
-  if (key_value_config->Lookup(kCongestionPushbackExperiment).find("Enabled") ==
-          0 &&
-      key_value_config->Lookup(kCwndExperiment).find("Enabled") == 0)
-    return absl::make_unique<CongestionWindowPushbackController>(
-        key_value_config);
-  return nullptr;
-}
-
 static const int64_t kRetransmitWindowSizeMs = 500;
 
 // Makes sure that the bitrate and the min, max values are in valid range.
@@ -152,24 +112,25 @@
       min_bitrate_bps_(congestion_controller::GetMinBitrateBps()),
       probe_bitrate_estimator_(new ProbeBitrateEstimator(event_log_)),
       delay_based_bwe_(new DelayBasedBwe(key_value_config_, event_log_)),
-      in_cwnd_experiment_(CwndExperimentEnabled(key_value_config_)),
-      accepted_queue_ms_(kDefaultAcceptedQueueMs),
       was_in_alr_(false),
       send_side_bwe_with_overhead_(
           key_value_config_->Lookup("WebRTC-SendSideBwe-WithOverhead")
               .find("Enabled") == 0),
       transport_overhead_bytes_per_packet_(0),
       pacer_pushback_experiment_(
-          IsPacerPushbackExperimentEnabled(key_value_config_)),
-      congestion_window_pushback_controller_(
-          MaybeCreateCongestionWindowPushbackController(key_value_config_)) {
-  delay_based_bwe_->SetMinBitrate(DataRate::bps(min_bitrate_bps_));
-  if (in_cwnd_experiment_ &&
-      !ReadCwndExperimentParameter(key_value_config_, &accepted_queue_ms_)) {
-    RTC_LOG(LS_WARNING) << "Failed to parse parameters for CwndExperiment "
-                           "from field trial string. Experiment disabled.";
-    in_cwnd_experiment_ = false;
+          IsPacerPushbackExperimentEnabled(key_value_config_)) {
+  RateControlSettings experiment_params =
+      RateControlSettings::ParseFromKeyValueConfig(key_value_config);
+  if (experiment_params.UseCongestionWindow()) {
+    cwnd_experiment_parameter_ =
+        experiment_params.GetCongestionWindowAdditionalTimeMs();
   }
+  if (experiment_params.UseCongestionWindowPushback()) {
+    congestion_window_pushback_controller_ =
+        absl::make_unique<CongestionWindowPushbackController>(
+            key_value_config_);
+  }
+  delay_based_bwe_->SetMinBitrate(DataRate::bps(min_bitrate_bps_));
 }
 
 DEPRECATED_SendSideCongestionController::
@@ -185,8 +146,7 @@
   RTC_CHECK_GE(min_pushback_target_bitrate_bps, 0)
       << "Min pushback target bitrate must be greater than or equal to 0.";
 
-  in_cwnd_experiment_ = true;
-  accepted_queue_ms_ = accepted_queue_ms;
+  cwnd_experiment_parameter_ = accepted_queue_ms;
   congestion_window_pushback_controller_ =
       absl::make_unique<CongestionWindowPushbackController>(
           key_value_config_, min_pushback_target_bitrate_bps);
@@ -364,7 +324,7 @@
     return;
   transport_feedback_adapter_.OnSentPacket(sent_packet.packet_id,
                                            sent_packet.send_time_ms);
-  if (in_cwnd_experiment_)
+  if (cwnd_experiment_parameter_)
     LimitOutstandingBytes(transport_feedback_adapter_.GetOutstandingBytes());
 }
 
@@ -472,14 +432,14 @@
     rtc::CritScope cs(&probe_lock_);
     SendProbes(probe_controller_->RequestProbe(clock_->TimeInMilliseconds()));
   }
-  if (in_cwnd_experiment_) {
+  if (cwnd_experiment_parameter_) {
     LimitOutstandingBytes(transport_feedback_adapter_.GetOutstandingBytes());
   }
 }
 
 void DEPRECATED_SendSideCongestionController::LimitOutstandingBytes(
     size_t num_outstanding_bytes) {
-  RTC_DCHECK(in_cwnd_experiment_);
+  RTC_DCHECK(cwnd_experiment_parameter_);
   rtc::CritScope lock(&network_state_lock_);
   absl::optional<int64_t> min_rtt_ms =
       transport_feedback_adapter_.GetMinFeedbackLoopRtt();
@@ -489,7 +449,7 @@
     return;
   const size_t kMinCwndBytes = 2 * 1500;
   size_t max_outstanding_bytes =
-      std::max<size_t>((*min_rtt_ms + accepted_queue_ms_) *
+      std::max<size_t>((*min_rtt_ms + *cwnd_experiment_parameter_) *
                            last_reported_bitrate_bps_ / 1000 / 8,
                        kMinCwndBytes);
   if (congestion_window_pushback_controller_) {
diff --git a/rtc_base/experiments/BUILD.gn b/rtc_base/experiments/BUILD.gn
index 4b3f2a9..5c0fee2 100644
--- a/rtc_base/experiments/BUILD.gn
+++ b/rtc_base/experiments/BUILD.gn
@@ -97,6 +97,22 @@
   ]
 }
 
+rtc_static_library("rate_control_settings") {
+  sources = [
+    "rate_control_settings.cc",
+    "rate_control_settings.h",
+  ]
+  deps = [
+    ":field_trial_parser",
+    "../:rtc_base_approved",
+    "../../api/transport:field_trial_based_config",
+    "../../api/transport:webrtc_key_value_config",
+    "../../system_wrappers:field_trial",
+    "//third_party/abseil-cpp/absl/memory:memory",
+    "//third_party/abseil-cpp/absl/types:optional",
+  ]
+}
+
 if (rtc_include_tests) {
   rtc_source_set("experiments_unittests") {
     testonly = true
diff --git a/rtc_base/experiments/OWNERS b/rtc_base/experiments/OWNERS
index 9c55872..20d5d79 100644
--- a/rtc_base/experiments/OWNERS
+++ b/rtc_base/experiments/OWNERS
@@ -6,3 +6,5 @@
 per-file normalize_simulcast_size_experiment*=asapersson@webrtc.org
 per-file quality_scaling_experiment*=asapersson@webrtc.org
 per-file rtt_mult_experiment*=mhoro@webrtc.org
+per-file rate_control_settings*=sprang@webrtc.org
+per-file rate_control_settings*=srte@webrtc.org
diff --git a/rtc_base/experiments/rate_control_settings.cc b/rtc_base/experiments/rate_control_settings.cc
new file mode 100644
index 0000000..81089b8
--- /dev/null
+++ b/rtc_base/experiments/rate_control_settings.cc
@@ -0,0 +1,114 @@
+/*
+ *  Copyright (c) 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 "rtc_base/experiments/rate_control_settings.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "api/transport/field_trial_based_config.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+
+namespace {
+
+const char* kCongestionWindowFieldTrialName = "WebRTC-CwndExperiment";
+const int kDefaultAcceptedQueueMs = 250;
+
+const char* kCongestionWindowPushbackFieldTrialName =
+    "WebRTC-CongestionWindowPushback";
+const int kDefaultMinPushbackTargetBitrateBps = 30000;
+
+absl::optional<int> MaybeReadCwndExperimentParameter(
+    const WebRtcKeyValueConfig* const key_value_config) {
+  int64_t accepted_queue_ms;
+  std::string experiment_string =
+      key_value_config->Lookup(kCongestionWindowFieldTrialName);
+  int parsed_values =
+      sscanf(experiment_string.c_str(), "Enabled-%" PRId64, &accepted_queue_ms);
+  if (parsed_values == 1) {
+    RTC_CHECK_GE(accepted_queue_ms, 0)
+        << "Accepted must be greater than or equal to 0.";
+    return rtc::checked_cast<int>(accepted_queue_ms);
+  } else if (experiment_string.find("Enabled") == 0) {
+    return kDefaultAcceptedQueueMs;
+  }
+  return absl::nullopt;
+}
+
+absl::optional<int> MaybeReadCongestionWindowPushbackExperimentParameter(
+    const WebRtcKeyValueConfig* const key_value_config) {
+  uint32_t min_pushback_target_bitrate_bps;
+  std::string experiment_string =
+      key_value_config->Lookup(kCongestionWindowPushbackFieldTrialName);
+  int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%" PRIu32,
+                             &min_pushback_target_bitrate_bps);
+  if (parsed_values == 1) {
+    RTC_CHECK_GE(min_pushback_target_bitrate_bps, 0)
+        << "Min pushback target bitrate must be greater than or equal to 0.";
+    return rtc::checked_cast<int>(min_pushback_target_bitrate_bps);
+  } else if (experiment_string.find("Enabled") == 0) {
+    return kDefaultMinPushbackTargetBitrateBps;
+  }
+  return absl::nullopt;
+}
+
+}  // namespace
+
+RateControlSettings::RateControlSettings(
+    const WebRtcKeyValueConfig* const key_value_config)
+    : congestion_window_("cwnd",
+                         MaybeReadCwndExperimentParameter(key_value_config)),
+      congestion_window_pushback_(
+          "cwnd_pushback",
+          MaybeReadCongestionWindowPushbackExperimentParameter(
+              key_value_config)) {
+  ParseFieldTrial({&congestion_window_, &congestion_window_pushback_},
+                  key_value_config->Lookup("WebRTC-VideoRateControl"));
+}
+
+RateControlSettings::~RateControlSettings() = default;
+RateControlSettings::RateControlSettings(RateControlSettings&&) = default;
+
+RateControlSettings RateControlSettings::ParseFromFieldTrials() {
+  FieldTrialBasedConfig field_trial_config;
+  return RateControlSettings(&field_trial_config);
+}
+
+RateControlSettings RateControlSettings::ParseFromKeyValueConfig(
+    const WebRtcKeyValueConfig* const key_value_config) {
+  FieldTrialBasedConfig field_trial_config;
+  return RateControlSettings(key_value_config ? key_value_config
+                                              : &field_trial_config);
+}
+
+bool RateControlSettings::UseCongestionWindow() const {
+  return congestion_window_;
+}
+
+int64_t RateControlSettings::GetCongestionWindowAdditionalTimeMs() const {
+  return congestion_window_.GetOptional().value_or(kDefaultAcceptedQueueMs);
+}
+
+bool RateControlSettings::UseCongestionWindowPushback() const {
+  return congestion_window_ && congestion_window_pushback_;
+}
+
+uint32_t RateControlSettings::CongestionWindowMinPushbackTargetBitrateBps()
+    const {
+  return congestion_window_pushback_.GetOptional().value_or(
+      kDefaultMinPushbackTargetBitrateBps);
+}
+
+}  // namespace webrtc
diff --git a/rtc_base/experiments/rate_control_settings.h b/rtc_base/experiments/rate_control_settings.h
new file mode 100644
index 0000000..0afda87
--- /dev/null
+++ b/rtc_base/experiments/rate_control_settings.h
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 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 RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_
+#define RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_
+
+#include "absl/types/optional.h"
+#include "api/transport/webrtc_key_value_config.h"
+#include "rtc_base/experiments/field_trial_parser.h"
+
+namespace webrtc {
+
+class RateControlSettings final {
+ public:
+  ~RateControlSettings();
+  RateControlSettings(RateControlSettings&&);
+
+  static RateControlSettings ParseFromFieldTrials();
+  static RateControlSettings ParseFromKeyValueConfig(
+      const WebRtcKeyValueConfig* const key_value_config);
+
+  // 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.
+  bool UseCongestionWindow() const;
+  int64_t GetCongestionWindowAdditionalTimeMs() const;
+  bool UseCongestionWindowPushback() const;
+  uint32_t CongestionWindowMinPushbackTargetBitrateBps() const;
+
+ private:
+  explicit RateControlSettings(
+      const WebRtcKeyValueConfig* const key_value_config);
+
+  FieldTrialOptional<int> congestion_window_;
+  FieldTrialOptional<int> congestion_window_pushback_;
+};
+
+}  // namespace webrtc
+
+#endif  // RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_