Ensure that loss based BWE can switch to kIncreasing state when it wants to increase.

Increasing BWE by 1kbps should be safe/no-op in practice, and it ensures that padding in kIncreasing state will be triggered.

Bug: webrtc:12707
Change-Id: I82493d07a80abd60c93d9cff74baf0a55e77f2b7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/325286
Commit-Queue: Diep Bui <diepbp@webrtc.org>
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41046}
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 e26fcc6..ab8fbc2 100644
--- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc
+++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc
@@ -294,6 +294,15 @@
                    std::min(best_candidate.loss_limited_bandwidth,
                             config_->bandwidth_rampup_upper_bound_factor *
                                 (*acknowledged_bitrate_)));
+      // Increase current estimate by at least 1kbps to make sure that the state
+      // will be switched to kIncreasing, thus padding is triggered.
+      if (loss_based_result_.state == LossBasedState::kDecreasing &&
+          best_candidate.loss_limited_bandwidth ==
+              current_best_estimate_.loss_limited_bandwidth) {
+        best_candidate.loss_limited_bandwidth =
+            current_best_estimate_.loss_limited_bandwidth +
+            DataRate::KilobitsPerSec(1);
+      }
     }
   }
 
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 347e2a8..771db63 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
@@ -795,7 +795,7 @@
   // The estimate is capped by acked_bitrate * BwRampupUpperBoundFactor.
   EXPECT_EQ(result.bandwidth_estimate, estimate_1 * 0.9 * 1.2);
 
-  // But if acked bitrate decrease, BWE does not decrease when there is no
+  // But if acked bitrate decreases, BWE does not decrease when there is no
   // loss.
   loss_based_bandwidth_estimator.SetAcknowledgedBitrate(estimate_1 * 0.9);
   loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
@@ -809,6 +809,54 @@
       result.bandwidth_estimate);
 }
 
+// Ensure that the state can switch to kIncrease even when the bandwidth is
+// bounded by acked bitrate.
+TEST_F(LossBasedBweV2Test, EnsureIncreaseEvenIfAckedBitrateBound) {
+  ExplicitKeyValueConfig key_value_config(ShortObservationConfig(
+      "LossThresholdOfHighBandwidthPreference:0.99,"
+      "BwRampupUpperBoundFactor:1.2,"
+      // Set InstantUpperBoundBwBalance high to disable InstantUpperBound cap.
+      "InstantUpperBoundBwBalance:10000kbps,"));
+  std::vector<PacketResult> enough_feedback_1 =
+      CreatePacketResultsWith100pLossRate(
+          /*first_packet_timestamp=*/Timestamp::Zero());
+  LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+  DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+
+  loss_based_bandwidth_estimator.SetBandwidthEstimate(
+      DataRate::KilobitsPerSec(600));
+  loss_based_bandwidth_estimator.SetAcknowledgedBitrate(
+      DataRate::KilobitsPerSec(300));
+  loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_1,
+                                                         delay_based_estimate,
+                                                         /*in_alr=*/false);
+  ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
+            LossBasedState::kDecreasing);
+  LossBasedBweV2::Result result =
+      loss_based_bandwidth_estimator.GetLossBasedResult();
+  DataRate estimate_1 = result.bandwidth_estimate;
+  ASSERT_LT(estimate_1.kbps(), 600);
+
+  // Set a low acked bitrate.
+  loss_based_bandwidth_estimator.SetAcknowledgedBitrate(estimate_1 / 2);
+
+  int feedback_count = 1;
+  while (feedback_count < 5 && result.state != LossBasedState::kIncreasing) {
+    loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+        CreatePacketResultsWithReceivedPackets(
+            /*first_packet_timestamp=*/Timestamp::Zero() +
+            feedback_count++ * kObservationDurationLowerBound),
+        delay_based_estimate,
+        /*in_alr=*/false);
+    result = loss_based_bandwidth_estimator.GetLossBasedResult();
+  }
+
+  ASSERT_EQ(result.state, LossBasedState::kIncreasing);
+  // The estimate increases by 1kbps.
+  EXPECT_EQ(result.bandwidth_estimate,
+            estimate_1 + DataRate::KilobitsPerSec(1));
+}
+
 // After loss based bwe backs off, the estimate is bounded during the delayed
 // window.
 TEST_F(LossBasedBweV2Test,