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 e26fcc6cb1..ab8fbc2b12 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 @@ void LossBasedBweV2::UpdateBandwidthEstimate( 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 347e2a86d1..771db63e12 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 @@ TEST_F(LossBasedBweV2Test, // 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 @@ TEST_F(LossBasedBweV2Test, 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 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,