Enable configuring probes via field trial.

This CL adds a field trial that lets us control the size of the initial probes, how we grow the following probes and how big and frequent our ALR probes are.

Bug: webrtc:10394
Change-Id: I6c7783dfada9aaf55cd836dd8991bb7b8ca4993b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/126880
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Commit-Queue: Jonas Olsson <jonasolsson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27077}
diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn
index 326571e..5a2d512 100644
--- a/modules/congestion_controller/goog_cc/BUILD.gn
+++ b/modules/congestion_controller/goog_cc/BUILD.gn
@@ -179,6 +179,7 @@
     "../../../rtc_base:logging",
     "../../../rtc_base:macromagic",
     "../../../rtc_base:safe_conversions",
+    "../../../rtc_base/experiments:field_trial_parser",
     "../../../rtc_base/system:unused",
     "../../../system_wrappers:metrics",
     "//third_party/abseil-cpp/absl/memory:memory",
diff --git a/modules/congestion_controller/goog_cc/probe_controller.cc b/modules/congestion_controller/goog_cc/probe_controller.cc
index 9128fe7..dfcb7f6 100644
--- a/modules/congestion_controller/goog_cc/probe_controller.cc
+++ b/modules/congestion_controller/goog_cc/probe_controller.cc
@@ -45,15 +45,6 @@
 // specify max bitrate.
 constexpr int64_t kDefaultMaxProbingBitrateBps = 5000000;
 
-// Interval between probes when ALR periodic probing is enabled.
-constexpr int64_t kAlrPeriodicProbingIntervalMs = 5000;
-
-// Minimum probe bitrate percentage to probe further for repeated probes,
-// relative to the previous probe. For example, if 1Mbps probe results in
-// 80kbps, then we'll probe again at 1.6Mbps. In that case second probe won't be
-// sent if we get 600kbps from the first one.
-constexpr int kRepeatedProbeMinPercentage = 70;
-
 // If the bitrate drops to a factor |kBitrateDropThreshold| or lower
 // and we recover within |kBitrateDropTimeoutMs|, then we'll send
 // a probe at a fraction |kProbeFractionAfterDrop| of the original bitrate.
@@ -82,6 +73,9 @@
 // Never probe higher than configured by OnMaxTotalAllocatedBitrate().
 constexpr char kCappedProbingFieldTrialName[] = "WebRTC-BweCappedProbing";
 
+constexpr char kConfigurableProbingFieldTrialName[] =
+    "WebRTC-Bwe-ConfigurableProbing";
+
 void MaybeLogProbeClusterCreated(RtcEventLog* event_log,
                                  const ProbeClusterConfig& probe) {
   RTC_DCHECK(event_log);
@@ -98,6 +92,25 @@
 
 }  // namespace
 
+ProbeControllerConfig::ProbeControllerConfig(
+    const WebRtcKeyValueConfig* key_value_config)
+    : first_exponential_probe_scale_("p1", 3.0),
+      second_exponential_probe_scale_("p2", 6.0),
+      further_exponential_probe_scale_("step_size", 2),
+      further_probe_threshold("further_probe_threshold", 0.7),
+      alr_probing_interval_("alr_interval", TimeDelta::seconds(5)),
+      alr_probe_scale_("alr_scale", 2) {
+  ParseFieldTrial(
+      {&first_exponential_probe_scale_, &second_exponential_probe_scale_,
+       &further_exponential_probe_scale_, &further_probe_threshold,
+       &alr_probing_interval_, &alr_probe_scale_},
+      key_value_config->Lookup(kConfigurableProbingFieldTrialName));
+}
+
+ProbeControllerConfig::ProbeControllerConfig(const ProbeControllerConfig&) =
+    default;
+ProbeControllerConfig::~ProbeControllerConfig() = default;
+
 ProbeController::ProbeController(const WebRtcKeyValueConfig* key_value_config,
                                  RtcEventLog* event_log)
     : enable_periodic_alr_probing_(false),
@@ -107,7 +120,8 @@
       limit_probes_with_allocateable_rate_(
           key_value_config->Lookup(kCappedProbingFieldTrialName)
               .find("Disabled") != 0),
-      event_log_(event_log) {
+      event_log_(event_log),
+      config_(ProbeControllerConfig(key_value_config)) {
   Reset(0);
 }
 
@@ -204,8 +218,13 @@
 
   // When probing at 1.8 Mbps ( 6x 300), this represents a threshold of
   // 1.2 Mbps to continue probing.
-  return InitiateProbing(
-      at_time_ms, {3 * start_bitrate_bps_, 6 * start_bitrate_bps_}, true);
+  std::vector<int64_t> probes = {static_cast<int64_t>(
+      config_.first_exponential_probe_scale_ * start_bitrate_bps_)};
+  if (config_.second_exponential_probe_scale_) {
+    probes.push_back(config_.second_exponential_probe_scale_.Value() *
+                     start_bitrate_bps_);
+  }
+  return InitiateProbing(at_time_ms, probes, true);
 }
 
 std::vector<ProbeClusterConfig> ProbeController::SetEstimatedBitrate(
@@ -229,8 +248,11 @@
 
     if (min_bitrate_to_probe_further_bps_ != kExponentialProbingDisabled &&
         bitrate_bps > min_bitrate_to_probe_further_bps_) {
-      // Double the probing bitrate.
-      pending_probes = InitiateProbing(at_time_ms, {2 * bitrate_bps}, true);
+      pending_probes = InitiateProbing(
+          at_time_ms,
+          {static_cast<int64_t>(config_.further_exponential_probe_scale_ *
+                                bitrate_bps)},
+          true);
     }
   }
 
@@ -291,16 +313,6 @@
   return std::vector<ProbeClusterConfig>();
 }
 
-std::vector<ProbeClusterConfig> ProbeController::InitiateCapacityProbing(
-    int64_t bitrate_bps,
-    int64_t at_time_ms) {
-  if (state_ != State::kWaitingForProbingResult) {
-    RTC_DCHECK(network_available_);
-    return InitiateProbing(at_time_ms, {2 * bitrate_bps}, true);
-  }
-  return std::vector<ProbeClusterConfig>();
-}
-
 void ProbeController::SetMaxBitrate(int64_t max_bitrate_bps) {
   max_bitrate_bps_ = max_bitrate_bps;
 }
@@ -339,9 +351,12 @@
     if (alr_start_time_ms_ && estimated_bitrate_bps_ > 0) {
       int64_t next_probe_time_ms =
           std::max(*alr_start_time_ms_, time_last_probing_initiated_ms_) +
-          kAlrPeriodicProbingIntervalMs;
+          config_.alr_probing_interval_->ms();
       if (at_time_ms >= next_probe_time_ms) {
-        return InitiateProbing(at_time_ms, {estimated_bitrate_bps_ * 2}, true);
+        return InitiateProbing(at_time_ms,
+                               {static_cast<int64_t>(estimated_bitrate_bps_ *
+                                                     config_.alr_probe_scale_)},
+                               true);
       }
     }
   }
@@ -350,7 +365,7 @@
 
 std::vector<ProbeClusterConfig> ProbeController::InitiateProbing(
     int64_t now_ms,
-    std::initializer_list<int64_t> bitrates_to_probe,
+    std::vector<int64_t> bitrates_to_probe,
     bool probe_further) {
   int64_t max_probe_bitrate_bps =
       max_bitrate_bps_ > 0 ? max_bitrate_bps_ : kDefaultMaxProbingBitrateBps;
@@ -389,7 +404,7 @@
   if (probe_further) {
     state_ = State::kWaitingForProbingResult;
     min_bitrate_to_probe_further_bps_ =
-        (*(bitrates_to_probe.end() - 1)) * kRepeatedProbeMinPercentage / 100;
+        (*(bitrates_to_probe.end() - 1)) * config_.further_probe_threshold;
   } else {
     state_ = State::kProbingComplete;
     min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled;
diff --git a/modules/congestion_controller/goog_cc/probe_controller.h b/modules/congestion_controller/goog_cc/probe_controller.h
index f937987..d0efb27 100644
--- a/modules/congestion_controller/goog_cc/probe_controller.h
+++ b/modules/congestion_controller/goog_cc/probe_controller.h
@@ -21,12 +21,34 @@
 #include "api/transport/webrtc_key_value_config.h"
 #include "logging/rtc_event_log/rtc_event_log.h"
 #include "rtc_base/constructor_magic.h"
+#include "rtc_base/experiments/field_trial_parser.h"
 #include "rtc_base/system/unused.h"
 
 namespace webrtc {
 
 class Clock;
 
+struct ProbeControllerConfig {
+  explicit ProbeControllerConfig(const WebRtcKeyValueConfig* key_value_config);
+  ProbeControllerConfig(const ProbeControllerConfig&);
+  ProbeControllerConfig& operator=(const ProbeControllerConfig&) = default;
+  ~ProbeControllerConfig();
+
+  // These parameters configure the initial probes. First we send one or two
+  // probes of sizes p1 * start_bitrate_bps_ and p2 * start_bitrate_bps_.
+  // Then whenever we get a bitrate estimate of at least further_probe_threshold
+  // times the size of the last sent probe we'll send another one of size
+  // step_size times the new estimate.
+  FieldTrialParameter<double> first_exponential_probe_scale_;
+  FieldTrialOptional<double> second_exponential_probe_scale_;
+  FieldTrialParameter<double> further_exponential_probe_scale_;
+  FieldTrialParameter<double> further_probe_threshold;
+
+  // Configures how often we send ALR probes and how big they are.
+  FieldTrialParameter<TimeDelta> alr_probing_interval_;
+  FieldTrialParameter<double> alr_probe_scale_;
+};
+
 // This class controls initiation of probing to estimate initial channel
 // capacity. There is also support for probing during a session when max
 // bitrate is adjusted by an application.
@@ -63,9 +85,6 @@
   RTC_WARN_UNUSED_RESULT std::vector<ProbeClusterConfig> RequestProbe(
       int64_t at_time_ms);
 
-  RTC_WARN_UNUSED_RESULT std::vector<ProbeClusterConfig>
-  InitiateCapacityProbing(int64_t bitrate_bps, int64_t at_time_ms);
-
   // Sets a new maximum probing bitrate, without generating a new probe cluster.
   void SetMaxBitrate(int64_t max_bitrate_bps);
 
@@ -90,7 +109,7 @@
   InitiateExponentialProbing(int64_t at_time_ms);
   RTC_WARN_UNUSED_RESULT std::vector<ProbeClusterConfig> InitiateProbing(
       int64_t now_ms,
-      std::initializer_list<int64_t> bitrates_to_probe,
+      std::vector<int64_t> bitrates_to_probe,
       bool probe_further);
 
   bool network_available_;
@@ -118,6 +137,8 @@
 
   int32_t next_probe_cluster_id_ = 1;
 
+  ProbeControllerConfig config_;
+
   RTC_DISALLOW_COPY_AND_ASSIGN(ProbeController);
 };
 
diff --git a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc
index 112fe64..2fa1e22 100644
--- a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc
+++ b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc
@@ -15,7 +15,9 @@
 #include "api/units/timestamp.h"
 #include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
 #include "modules/congestion_controller/goog_cc/probe_controller.h"
+#include "rtc_base/logging.h"
 #include "system_wrappers/include/clock.h"
+#include "test/field_trial.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
 
@@ -61,7 +63,7 @@
 
   FieldTrialBasedConfig field_trial_config_;
   SimulatedClock clock_;
-  MockRtcEventLog mock_rtc_event_log;
+  NiceMock<MockRtcEventLog> mock_rtc_event_log;
   std::unique_ptr<ProbeController> probe_controller_;
 };
 
@@ -89,6 +91,7 @@
   probes = probe_controller_->Process(NowMs());
   probes = probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
                                           kMaxBitrateBps + 100, NowMs());
+  EXPECT_EQ(probes.size(), 1u);
   EXPECT_EQ(probes[0].target_data_rate.bps(), kMaxBitrateBps + 100);
 }
 
@@ -102,6 +105,7 @@
   probes = probe_controller_->SetEstimatedBitrate(kMaxBitrateBps, NowMs());
   probes = probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
                                           kMaxBitrateBps + 100, NowMs());
+  EXPECT_EQ(probes.size(), 1u);
   EXPECT_EQ(probes[0].target_data_rate.bps(), kMaxBitrateBps + 100);
 }
 
@@ -115,6 +119,7 @@
   EXPECT_EQ(probes.size(), 0u);
 
   probes = probe_controller_->SetEstimatedBitrate(1800, NowMs());
+  EXPECT_EQ(probes.size(), 1u);
   EXPECT_EQ(probes[0].target_data_rate.bps(), 2 * 1800);
 }
 
@@ -252,6 +257,7 @@
   // until SetEstimatedBitrate is called with an updated estimate.
   clock_.AdvanceTimeMilliseconds(10000);
   probes = probe_controller_->Process(NowMs());
+  EXPECT_EQ(probes.size(), 1u);
   EXPECT_EQ(probes[0].target_data_rate.bps(), kStartBitrateBps * 2);
 }
 
@@ -262,6 +268,7 @@
   // Verify that probe bitrate is capped at the specified max bitrate.
   probes =
       probe_controller_->SetEstimatedBitrate(60 * kMbpsMultiplier, NowMs());
+  EXPECT_EQ(probes.size(), 1u);
   EXPECT_EQ(probes[0].target_data_rate.bps(), 100 * kMbpsMultiplier);
   // Verify that repeated probes aren't sent.
   probes =
@@ -293,6 +300,7 @@
   // Probes such as ALR capped at 2x the max allocation limit.
   clock_.AdvanceTimeMilliseconds(5000);
   probes = probe_controller_->Process(NowMs());
+  EXPECT_EQ(probes.size(), 1u);
   EXPECT_EQ(probes[0].target_data_rate.bps(), 2 * max_allocated_bps);
 
   // Remove allocation limit.
@@ -300,8 +308,31 @@
       probe_controller_->OnMaxTotalAllocatedBitrate(0, NowMs()).empty());
   clock_.AdvanceTimeMilliseconds(5000);
   probes = probe_controller_->Process(NowMs());
+  EXPECT_EQ(probes.size(), 1u);
   EXPECT_EQ(probes[0].target_data_rate.bps(), estimated_bitrate_bps * 2);
 }
 
+TEST_F(ProbeControllerTest, ConfigurableProbingFieldTrial) {
+  auto trials = test::ScopedFieldTrials(
+      "WebRTC-Bwe-ConfigurableProbing/"
+      "p1:2,p2:5,step_size:3,further_probe_threshold:0.8/");
+  probe_controller_.reset(
+      new ProbeController(&field_trial_config_, &mock_rtc_event_log));
+  auto probes = probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                               kMaxBitrateBps, NowMs());
+  EXPECT_EQ(probes.size(), 2u);
+  EXPECT_EQ(probes[0].target_data_rate.bps(), 600);
+  EXPECT_EQ(probes[1].target_data_rate.bps(), 1500);
+
+  // Repeated probe should only be sent when estimated bitrate climbs above
+  // 0.8 * 5 * kStartBitrateBps = 1200.
+  probes = probe_controller_->SetEstimatedBitrate(1100, NowMs());
+  EXPECT_EQ(probes.size(), 0u);
+
+  probes = probe_controller_->SetEstimatedBitrate(1250, NowMs());
+  EXPECT_EQ(probes.size(), 1u);
+  EXPECT_EQ(probes[0].target_data_rate.bps(), 3 * 1250);
+}
+
 }  // namespace test
 }  // namespace webrtc