Tweaks for LossBasedBweV2.

Caches the TCP fairness limit to avoid redundant calculation. Adds option to append the delay based estimate as a candidate. Makes the appending of acknowledged bitrate as a candidate optional. Adds a log-bandwidth bias term.
(submit on behalf of crodbro)

Bug: webrtc:12707
Change-Id: Ic4b0f58e6f0bc3b117fe78a2321a07db65afd9dd
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228163
Commit-Queue: Ying Wang <yinwa@webrtc.org>
Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34687}
diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc
index ae52b2d..63202d8 100644
--- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc
+++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc
@@ -178,7 +178,8 @@
 }
 
 void LossBasedBweV2::UpdateBandwidthEstimate(
-    rtc::ArrayView<const PacketResult> packet_results) {
+    rtc::ArrayView<const PacketResult> packet_results,
+    DataRate delay_based_estimate) {
   if (!IsEnabled()) {
     RTC_LOG(LS_WARNING)
         << "The estimator must be enabled before it can be used.";
@@ -202,7 +203,7 @@
 
   ChannelParameters best_candidate = current_estimate_;
   double objective_max = std::numeric_limits<double>::lowest();
-  for (ChannelParameters candidate : GetCandidates()) {
+  for (ChannelParameters candidate : GetCandidates(delay_based_estimate)) {
     NewtonsMethodUpdate(candidate);
 
     const double candidate_objective = GetObjective(candidate);
@@ -226,6 +227,8 @@
                                            {1.05, 1.0, 0.95});
   FieldTrialParameter<double> higher_bandwidth_bias_factor("HigherBwBiasFactor",
                                                            0.00001);
+  FieldTrialParameter<double> higher_log_bandwidth_bias_factor(
+      "HigherLogBwBiasFactor", 0.001);
   FieldTrialParameter<double> inherent_loss_lower_bound(
       "InherentLossLowerBound", 1.0e-3);
   FieldTrialParameter<DataRate> inherent_loss_upper_bound_bandwidth_balance(
@@ -236,6 +239,10 @@
       "InitialInherentLossEstimate", 0.01);
   FieldTrialParameter<int> newton_iterations("NewtonIterations", 1);
   FieldTrialParameter<double> newton_step_size("NewtonStepSize", 0.5);
+  FieldTrialParameter<bool> append_acknowledged_rate_candidate(
+      "AckedRateCandidate", true);
+  FieldTrialParameter<bool> append_delay_based_estimate_candidate(
+      "DelayBasedCandidate", false);
   FieldTrialParameter<TimeDelta> observation_duration_lower_bound(
       "ObservationDurationLowerBound", TimeDelta::Seconds(1));
   FieldTrialParameter<int> observation_window_size("ObservationWindowSize", 20);
@@ -251,17 +258,27 @@
                                                      0.99);
 
   if (key_value_config) {
-    ParseFieldTrial(
-        {&enabled, &bandwidth_rampup_upper_bound_factor, &candidate_factors,
-         &higher_bandwidth_bias_factor, &inherent_loss_lower_bound,
-         &inherent_loss_upper_bound_bandwidth_balance,
-         &inherent_loss_upper_bound_offset, &initial_inherent_loss_estimate,
-         &newton_iterations, &newton_step_size,
-         &observation_duration_lower_bound, &observation_window_size,
-         &sending_rate_smoothing_factor, &tcp_fairness_temporal_weight_factor,
-         &tcp_fairness_upper_bound_bandwidth_balance,
-         &tcp_fairness_upper_bound_loss_offset, &temporal_weight_factor},
-        key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2"));
+    ParseFieldTrial({&enabled,
+                     &bandwidth_rampup_upper_bound_factor,
+                     &candidate_factors,
+                     &higher_bandwidth_bias_factor,
+                     &higher_log_bandwidth_bias_factor,
+                     &inherent_loss_lower_bound,
+                     &inherent_loss_upper_bound_bandwidth_balance,
+                     &inherent_loss_upper_bound_offset,
+                     &initial_inherent_loss_estimate,
+                     &newton_iterations,
+                     &newton_step_size,
+                     &append_acknowledged_rate_candidate,
+                     &append_delay_based_estimate_candidate,
+                     &observation_duration_lower_bound,
+                     &observation_window_size,
+                     &sending_rate_smoothing_factor,
+                     &tcp_fairness_temporal_weight_factor,
+                     &tcp_fairness_upper_bound_bandwidth_balance,
+                     &tcp_fairness_upper_bound_loss_offset,
+                     &temporal_weight_factor},
+                    key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2"));
   }
 
   absl::optional<Config> config;
@@ -273,6 +290,8 @@
       bandwidth_rampup_upper_bound_factor.Get();
   config->candidate_factors = candidate_factors.Get();
   config->higher_bandwidth_bias_factor = higher_bandwidth_bias_factor.Get();
+  config->higher_log_bandwidth_bias_factor =
+      higher_log_bandwidth_bias_factor.Get();
   config->inherent_loss_lower_bound = inherent_loss_lower_bound.Get();
   config->inherent_loss_upper_bound_bandwidth_balance =
       inherent_loss_upper_bound_bandwidth_balance.Get();
@@ -281,6 +300,10 @@
   config->initial_inherent_loss_estimate = initial_inherent_loss_estimate.Get();
   config->newton_iterations = newton_iterations.Get();
   config->newton_step_size = newton_step_size.Get();
+  config->append_acknowledged_rate_candidate =
+      append_acknowledged_rate_candidate.Get();
+  config->append_delay_based_estimate_candidate =
+      append_delay_based_estimate_candidate.Get();
   config->observation_duration_lower_bound =
       observation_duration_lower_bound.Get();
   config->observation_window_size = observation_window_size.Get();
@@ -427,19 +450,23 @@
   return static_cast<double>(num_lost_packets) / num_packets;
 }
 
-std::vector<LossBasedBweV2::ChannelParameters> LossBasedBweV2::GetCandidates()
-    const {
+std::vector<LossBasedBweV2::ChannelParameters> LossBasedBweV2::GetCandidates(
+    DataRate delay_based_estimate) const {
   std::vector<DataRate> bandwidths;
   for (double candidate_factor : config_->candidate_factors) {
-    bandwidths.emplace_back(candidate_factor *
-                            current_estimate_.loss_limited_bandwidth);
+    bandwidths.push_back(candidate_factor *
+                         current_estimate_.loss_limited_bandwidth);
   }
 
-  if (acknowledged_bitrate_.has_value()) {
-    bandwidths.emplace_back(*acknowledged_bitrate_);
+  if (acknowledged_bitrate_.has_value() &&
+      config_->append_acknowledged_rate_candidate) {
+    bandwidths.push_back(*acknowledged_bitrate_);
   }
 
-  // TODO(crodbro): Consider adding the delay based estimate as a candidate.
+  if (IsValid(delay_based_estimate) &&
+      config_->append_delay_based_estimate_candidate) {
+    bandwidths.push_back(delay_based_estimate);
+  }
 
   const DataRate candidate_bandwidth_upper_bound =
       acknowledged_bitrate_.has_value()
@@ -516,10 +543,22 @@
   return std::min(inherent_loss_upper_bound, 1.0);
 }
 
+double LossBasedBweV2::GetHighBandwidthBias(DataRate bandwidth) const {
+  if (IsValid(bandwidth)) {
+    return config_->higher_bandwidth_bias_factor * bandwidth.kbps() +
+           config_->higher_log_bandwidth_bias_factor *
+               std::log(1.0 + bandwidth.kbps());
+  }
+  return 0.0;
+}
+
 double LossBasedBweV2::GetObjective(
     const ChannelParameters& channel_parameters) const {
   double objective = 0.0;
 
+  const double high_bandwidth_bias =
+      GetHighBandwidthBias(channel_parameters.loss_limited_bandwidth);
+
   for (const Observation& observation : observations_) {
     if (!observation.IsInitialized()) {
       continue;
@@ -537,9 +576,7 @@
         ((observation.num_lost_packets * std::log(loss_probability)) +
          (observation.num_received_packets * std::log(1.0 - loss_probability)));
     objective +=
-        temporal_weight * (config_->higher_bandwidth_bias_factor *
-                           channel_parameters.loss_limited_bandwidth.kbps() *
-                           observation.num_packets);
+        temporal_weight * high_bandwidth_bias * observation.num_packets;
   }
 
   return objective;
@@ -565,18 +602,19 @@
 }
 
 DataRate LossBasedBweV2::GetTcpFairnessBandwidthUpperBound() const {
-  if (num_observations_ <= 0) {
-    return DataRate::PlusInfinity();
-  }
+  return cached_tcp_fairness_limit_.value_or(DataRate::PlusInfinity());
+}
 
+void LossBasedBweV2::CalculateTcpFairnessBandwidthUpperBound() {
+  DataRate tcp_fairness_limit = DataRate::PlusInfinity();
   const double average_reported_loss_ratio = GetAverageReportedLossRatio();
-  if (average_reported_loss_ratio <=
+  if (average_reported_loss_ratio >
       config_->tcp_fairness_upper_bound_loss_offset) {
-    return DataRate::PlusInfinity();
+    tcp_fairness_limit = config_->tcp_fairness_upper_bound_bandwidth_balance /
+                         (average_reported_loss_ratio -
+                          config_->tcp_fairness_upper_bound_loss_offset);
   }
-  return config_->tcp_fairness_upper_bound_bandwidth_balance /
-         (average_reported_loss_ratio -
-          config_->tcp_fairness_upper_bound_loss_offset);
+  cached_tcp_fairness_limit_ = tcp_fairness_limit;
 }
 
 void LossBasedBweV2::CalculateTemporalWeights() {
@@ -646,6 +684,7 @@
 
   partial_observation_ = PartialObservation();
 
+  CalculateTcpFairnessBandwidthUpperBound();
   return true;
 }
 
diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h
index 83d6f33..10fb33f 100644
--- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h
+++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h
@@ -48,7 +48,8 @@
   void SetBandwidthEstimate(DataRate bandwidth_estimate);
 
   void UpdateBandwidthEstimate(
-      rtc::ArrayView<const PacketResult> packet_results);
+      rtc::ArrayView<const PacketResult> packet_results,
+      DataRate delay_based_estimate);
 
  private:
   struct ChannelParameters {
@@ -60,6 +61,7 @@
     double bandwidth_rampup_upper_bound_factor = 0.0;
     std::vector<double> candidate_factors;
     double higher_bandwidth_bias_factor = 0.0;
+    double higher_log_bandwidth_bias_factor = 0.0;
     double inherent_loss_lower_bound = 0.0;
     DataRate inherent_loss_upper_bound_bandwidth_balance =
         DataRate::MinusInfinity();
@@ -67,6 +69,8 @@
     double initial_inherent_loss_estimate = 0.0;
     int newton_iterations = 0;
     double newton_step_size = 0.0;
+    bool append_acknowledged_rate_candidate = true;
+    bool append_delay_based_estimate_candidate = false;
     TimeDelta observation_duration_lower_bound = TimeDelta::Zero();
     int observation_window_size = 0;
     double sending_rate_smoothing_factor = 0.0;
@@ -104,14 +108,17 @@
 
   // Returns `0.0` if not enough loss statistics have been received.
   double GetAverageReportedLossRatio() const;
-  std::vector<ChannelParameters> GetCandidates() const;
+  std::vector<ChannelParameters> GetCandidates(
+      DataRate delay_based_estimate) const;
   Derivatives GetDerivatives(const ChannelParameters& channel_parameters) const;
   double GetFeasibleInherentLoss(
       const ChannelParameters& channel_parameters) const;
   double GetInherentLossUpperBound(DataRate bandwidth) const;
+  double GetHighBandwidthBias(DataRate bandwidth) const;
   double GetObjective(const ChannelParameters& channel_parameters) const;
   DataRate GetSendingRate(DataRate instantaneous_sending_rate) const;
   DataRate GetTcpFairnessBandwidthUpperBound() const;
+  void CalculateTcpFairnessBandwidthUpperBound();
 
   void CalculateTemporalWeights();
   void NewtonsMethodUpdate(ChannelParameters& channel_parameters) const;
@@ -126,6 +133,7 @@
   std::vector<Observation> observations_;
   PartialObservation partial_observation_;
   Timestamp last_send_time_most_recent_observation_ = Timestamp::PlusInfinity();
+  absl::optional<DataRate> cached_tcp_fairness_limit_;
   std::vector<double> tcp_fairness_temporal_weights_;
   std::vector<double> temporal_weights_;
 };
diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc b/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc
index 87ac31d..bb71668 100644
--- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc
+++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc
@@ -105,7 +105,8 @@
 
   loss_based_bandwidth_estimator.SetBandwidthEstimate(
       DataRate::KilobitsPerSec(600));
-  loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback);
+  loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+      enough_feedback, DataRate::PlusInfinity());
 
   EXPECT_TRUE(loss_based_bandwidth_estimator.IsReady());
   EXPECT_TRUE(loss_based_bandwidth_estimator.GetBandwidthEstimate().IsFinite());
@@ -127,7 +128,8 @@
       Config(/*enabled=*/true, /*valid=*/true));
   LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
 
-  loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback);
+  loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+      enough_feedback, DataRate::PlusInfinity());
 
   EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
   EXPECT_TRUE(
@@ -159,7 +161,8 @@
   EXPECT_TRUE(
       loss_based_bandwidth_estimator.GetBandwidthEstimate().IsPlusInfinity());
 
-  loss_based_bandwidth_estimator.UpdateBandwidthEstimate(not_enough_feedback);
+  loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+      not_enough_feedback, DataRate::PlusInfinity());
 
   EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
   EXPECT_TRUE(
@@ -196,7 +199,8 @@
 
   loss_based_bandwidth_estimator.SetBandwidthEstimate(
       DataRate::KilobitsPerSec(600));
-  loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_1);
+  loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+      enough_feedback_1, DataRate::PlusInfinity());
 
   EXPECT_NE(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
             DataRate::KilobitsPerSec(600));
@@ -207,7 +211,8 @@
   EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
             DataRate::KilobitsPerSec(600));
 
-  loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_2);
+  loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+      enough_feedback_2, DataRate::PlusInfinity());
 
   EXPECT_NE(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
             DataRate::KilobitsPerSec(600));
@@ -246,8 +251,10 @@
       DataRate::KilobitsPerSec(600));
   loss_based_bandwidth_estimator_2.SetBandwidthEstimate(
       DataRate::KilobitsPerSec(600));
-  loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(enough_feedback_1);
-  loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(enough_feedback_1);
+  loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
+      enough_feedback_1, DataRate::PlusInfinity());
+  loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(
+      enough_feedback_1, DataRate::PlusInfinity());
 
   EXPECT_EQ(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(),
             DataRate::KilobitsPerSec(660));
@@ -258,8 +265,10 @@
   EXPECT_EQ(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(),
             DataRate::KilobitsPerSec(660));
 
-  loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(enough_feedback_2);
-  loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(enough_feedback_2);
+  loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
+      enough_feedback_2, DataRate::PlusInfinity());
+  loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(
+      enough_feedback_2, DataRate::PlusInfinity());
 
   EXPECT_NE(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(),
             loss_based_bandwidth_estimator_2.GetBandwidthEstimate());
@@ -288,7 +297,7 @@
   loss_based_bandwidth_estimator.SetBandwidthEstimate(
       DataRate::KilobitsPerSec(600));
   loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
-      enough_feedback_no_received_packets);
+      enough_feedback_no_received_packets, DataRate::PlusInfinity());
 
   EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
             DataRate::KilobitsPerSec(100));
diff --git a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc
index 749b073..8fb3275 100644
--- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc
+++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc
@@ -364,7 +364,7 @@
   }
   if (LossBasedBandwidthEstimatorV2Enabled()) {
     loss_based_bandwidth_estimator_v2_.UpdateBandwidthEstimate(
-        report.packet_feedbacks);
+        report.packet_feedbacks, delay_based_limit_);
   }
 }