summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc')
-rw-r--r--third_party/libwebrtc/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc1526
1 files changed, 1526 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc b/third_party/libwebrtc/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc
new file mode 100644
index 0000000000..c303c29d68
--- /dev/null
+++ b/third_party/libwebrtc/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc
@@ -0,0 +1,1526 @@
+/*
+ * Copyright 2021 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 "modules/congestion_controller/goog_cc/loss_based_bwe_v2.h"
+
+#include <string>
+#include <vector>
+
+#include "api/network_state_predictor.h"
+#include "api/transport/network_types.h"
+#include "api/units/data_rate.h"
+#include "api/units/data_size.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/strings/string_builder.h"
+#include "test/explicit_key_value_config.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+using ::webrtc::test::ExplicitKeyValueConfig;
+
+constexpr TimeDelta kObservationDurationLowerBound = TimeDelta::Millis(200);
+constexpr TimeDelta kDelayedIncreaseWindow = TimeDelta::Millis(300);
+constexpr double kMaxIncreaseFactor = 1.5;
+
+class LossBasedBweV2Test : public ::testing::TestWithParam<bool> {
+ protected:
+ std::string Config(bool enabled,
+ bool valid,
+ bool trendline_integration_enabled) {
+ char buffer[1024];
+ rtc::SimpleStringBuilder config_string(buffer);
+
+ config_string << "WebRTC-Bwe-LossBasedBweV2/";
+
+ if (enabled) {
+ config_string << "Enabled:true";
+ } else {
+ config_string << "Enabled:false";
+ }
+
+ if (valid) {
+ config_string << ",BwRampupUpperBoundFactor:1.2";
+ } else {
+ config_string << ",BwRampupUpperBoundFactor:0.0";
+ }
+
+ if (trendline_integration_enabled) {
+ config_string << ",TrendlineIntegrationEnabled:true";
+ } else {
+ config_string << ",TrendlineIntegrationEnabled:false";
+ }
+
+ config_string
+ << ",CandidateFactors:1.1|1.0|0.95,HigherBwBiasFactor:0.01,"
+ "DelayBasedCandidate:true,"
+ "InherentLossLowerBound:0.001,InherentLossUpperBoundBwBalance:"
+ "14kbps,"
+ "InherentLossUpperBoundOffset:0.9,InitialInherentLossEstimate:0.01,"
+ "NewtonIterations:2,NewtonStepSize:0.4,ObservationWindowSize:15,"
+ "SendingRateSmoothingFactor:0.01,"
+ "InstantUpperBoundTemporalWeightFactor:0.97,"
+ "InstantUpperBoundBwBalance:90kbps,"
+ "InstantUpperBoundLossOffset:0.1,TemporalWeightFactor:0.98";
+
+ config_string.AppendFormat(
+ ",ObservationDurationLowerBound:%dms",
+ static_cast<int>(kObservationDurationLowerBound.ms()));
+ config_string.AppendFormat(",MaxIncreaseFactor:%f", kMaxIncreaseFactor);
+ config_string.AppendFormat(",DelayedIncreaseWindow:%dms",
+ static_cast<int>(kDelayedIncreaseWindow.ms()));
+
+ config_string << "/";
+
+ return config_string.str();
+ }
+
+ std::vector<PacketResult> CreatePacketResultsWithReceivedPackets(
+ Timestamp first_packet_timestamp) {
+ std::vector<PacketResult> enough_feedback(2);
+ enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000);
+ enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000);
+ enough_feedback[0].sent_packet.send_time = first_packet_timestamp;
+ enough_feedback[1].sent_packet.send_time =
+ first_packet_timestamp + kObservationDurationLowerBound;
+ enough_feedback[0].receive_time =
+ first_packet_timestamp + kObservationDurationLowerBound;
+ enough_feedback[1].receive_time =
+ first_packet_timestamp + 2 * kObservationDurationLowerBound;
+ return enough_feedback;
+ }
+
+ std::vector<PacketResult> CreatePacketResultsWith10pLossRate(
+ Timestamp first_packet_timestamp) {
+ std::vector<PacketResult> enough_feedback(10);
+ enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000);
+ for (unsigned i = 0; i < enough_feedback.size(); ++i) {
+ enough_feedback[i].sent_packet.size = DataSize::Bytes(15'000);
+ enough_feedback[i].sent_packet.send_time =
+ first_packet_timestamp +
+ static_cast<int>(i) * kObservationDurationLowerBound;
+ enough_feedback[i].receive_time =
+ first_packet_timestamp +
+ static_cast<int>(i + 1) * kObservationDurationLowerBound;
+ }
+ enough_feedback[9].receive_time = Timestamp::PlusInfinity();
+ return enough_feedback;
+ }
+
+ std::vector<PacketResult> CreatePacketResultsWith50pLossRate(
+ Timestamp first_packet_timestamp) {
+ std::vector<PacketResult> enough_feedback(2);
+ enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000);
+ enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000);
+ enough_feedback[0].sent_packet.send_time = first_packet_timestamp;
+ enough_feedback[1].sent_packet.send_time =
+ first_packet_timestamp + kObservationDurationLowerBound;
+ enough_feedback[0].receive_time =
+ first_packet_timestamp + kObservationDurationLowerBound;
+ enough_feedback[1].receive_time = Timestamp::PlusInfinity();
+ return enough_feedback;
+ }
+
+ std::vector<PacketResult> CreatePacketResultsWith100pLossRate(
+ Timestamp first_packet_timestamp) {
+ std::vector<PacketResult> enough_feedback(2);
+ enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000);
+ enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000);
+ enough_feedback[0].sent_packet.send_time = first_packet_timestamp;
+ enough_feedback[1].sent_packet.send_time =
+ first_packet_timestamp + kObservationDurationLowerBound;
+ enough_feedback[0].receive_time = Timestamp::PlusInfinity();
+ enough_feedback[1].receive_time = Timestamp::PlusInfinity();
+ return enough_feedback;
+ }
+};
+
+TEST_P(LossBasedBweV2Test, EnabledWhenGivenValidConfigurationValues) {
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ EXPECT_TRUE(loss_based_bandwidth_estimator.IsEnabled());
+}
+
+TEST_P(LossBasedBweV2Test, DisabledWhenGivenDisabledConfiguration) {
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/false, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ EXPECT_FALSE(loss_based_bandwidth_estimator.IsEnabled());
+}
+
+TEST_P(LossBasedBweV2Test, DisabledWhenGivenNonValidConfigurationValues) {
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/false,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ EXPECT_FALSE(loss_based_bandwidth_estimator.IsEnabled());
+}
+
+TEST_P(LossBasedBweV2Test, DisabledWhenGivenNonPositiveCandidateFactor) {
+ ExplicitKeyValueConfig key_value_config_negative_candidate_factor(
+ "WebRTC-Bwe-LossBasedBweV2/Enabled:true,CandidateFactors:-1.3|1.1/");
+ LossBasedBweV2 loss_based_bandwidth_estimator_1(
+ &key_value_config_negative_candidate_factor);
+ EXPECT_FALSE(loss_based_bandwidth_estimator_1.IsEnabled());
+
+ ExplicitKeyValueConfig key_value_config_zero_candidate_factor(
+ "WebRTC-Bwe-LossBasedBweV2/Enabled:true,CandidateFactors:0.0|1.1/");
+ LossBasedBweV2 loss_based_bandwidth_estimator_2(
+ &key_value_config_zero_candidate_factor);
+ EXPECT_FALSE(loss_based_bandwidth_estimator_2.IsEnabled());
+}
+
+TEST_P(LossBasedBweV2Test,
+ DisabledWhenGivenConfigurationThatDoesNotAllowGeneratingCandidates) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.0,AckedRateCandidate:false,"
+ "DelayBasedCandidate:false/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ EXPECT_FALSE(loss_based_bandwidth_estimator.IsEnabled());
+}
+
+TEST_P(LossBasedBweV2Test, ReturnsDelayBasedEstimateWhenDisabled) {
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/false, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ /*packet_results=*/{},
+ /*delay_based_estimate=*/DataRate::KilobitsPerSec(100),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(100));
+}
+
+TEST_P(LossBasedBweV2Test,
+ ReturnsDelayBasedEstimateWhenWhenGivenNonValidConfigurationValues) {
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/false,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ /*packet_results=*/{},
+ /*delay_based_estimate=*/DataRate::KilobitsPerSec(100),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(100));
+}
+
+TEST_P(LossBasedBweV2Test,
+ BandwidthEstimateGivenInitializationAndThenFeedback) {
+ std::vector<PacketResult> enough_feedback =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ EXPECT_TRUE(loss_based_bandwidth_estimator.IsReady());
+ EXPECT_TRUE(loss_based_bandwidth_estimator.GetLossBasedResult()
+ .bandwidth_estimate.IsFinite());
+}
+
+TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) {
+ std::vector<PacketResult> enough_feedback =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
+ EXPECT_TRUE(loss_based_bandwidth_estimator.GetLossBasedResult()
+ .bandwidth_estimate.IsPlusInfinity());
+}
+
+TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) {
+ // Create packet results where the observation duration is less than the lower
+ // bound.
+ PacketResult not_enough_feedback[2];
+ not_enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000);
+ not_enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000);
+ not_enough_feedback[0].sent_packet.send_time = Timestamp::Zero();
+ not_enough_feedback[1].sent_packet.send_time =
+ Timestamp::Zero() + kObservationDurationLowerBound / 2;
+ not_enough_feedback[0].receive_time =
+ Timestamp::Zero() + kObservationDurationLowerBound / 2;
+ not_enough_feedback[1].receive_time =
+ Timestamp::Zero() + kObservationDurationLowerBound;
+
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+
+ EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
+ EXPECT_TRUE(loss_based_bandwidth_estimator.GetLossBasedResult()
+ .bandwidth_estimate.IsPlusInfinity());
+
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ not_enough_feedback, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
+ EXPECT_TRUE(loss_based_bandwidth_estimator.GetLossBasedResult()
+ .bandwidth_estimate.IsPlusInfinity());
+}
+
+TEST_P(LossBasedBweV2Test,
+ SetValueIsTheEstimateUntilAdditionalFeedbackHasBeenReceived) {
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ 2 * kObservationDurationLowerBound);
+
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ EXPECT_NE(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(600));
+
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(600));
+
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ EXPECT_NE(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(600));
+}
+
+TEST_P(LossBasedBweV2Test,
+ SetAcknowledgedBitrateOnlyAffectsTheBweWhenAdditionalFeedbackIsGiven) {
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ 2 * kObservationDurationLowerBound);
+
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator_1(&key_value_config);
+ LossBasedBweV2 loss_based_bandwidth_estimator_2(&key_value_config);
+
+ loss_based_bandwidth_estimator_1.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator_2.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
+ enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(
+ enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator_1.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(660));
+
+ loss_based_bandwidth_estimator_1.SetAcknowledgedBitrate(
+ DataRate::KilobitsPerSec(900));
+
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator_1.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(660));
+
+ loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
+ enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(
+ enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ EXPECT_NE(
+ loss_based_bandwidth_estimator_1.GetLossBasedResult().bandwidth_estimate,
+ loss_based_bandwidth_estimator_2.GetLossBasedResult().bandwidth_estimate);
+}
+
+TEST_P(LossBasedBweV2Test,
+ BandwidthEstimateIsCappedToBeTcpFairGivenTooHighLossRate) {
+ std::vector<PacketResult> enough_feedback_no_received_packets =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_no_received_packets,
+ /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(100));
+}
+
+TEST_P(LossBasedBweV2Test, BandwidthEstimateNotIncreaseWhenNetworkUnderusing) {
+ if (!GetParam()) {
+ GTEST_SKIP() << "This test should run only if "
+ "trendline_integration_enabled is enabled";
+ }
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ 2 * kObservationDurationLowerBound);
+
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwUnderusing, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ EXPECT_LE(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ EXPECT_LE(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(600));
+}
+
+// When network is normal, estimate can increase but never be higher than
+// the delay based estimate.
+TEST_P(LossBasedBweV2Test,
+ BandwidthEstimateCappedByDelayBasedEstimateWhenNetworkNormal) {
+ // Create two packet results, network is in normal state, 100% packets are
+ // received, and no delay increase.
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ 2 * kObservationDurationLowerBound);
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ // If the delay based estimate is infinity, then loss based estimate increases
+ // and not bounded by delay based estimate.
+ EXPECT_GT(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, /*delay_based_estimate=*/DataRate::KilobitsPerSec(500),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ // If the delay based estimate is not infinity, then loss based estimate is
+ // bounded by delay based estimate.
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(500));
+}
+
+// When loss based bwe receives a strong signal of overusing and an increase in
+// loss rate, it should acked bitrate for emegency backoff.
+TEST_P(LossBasedBweV2Test, UseAckedBitrateForEmegencyBackOff) {
+ // Create two packet results, first packet has 50% loss rate, second packet
+ // has 100% loss rate.
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWith50pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ 2 * kObservationDurationLowerBound);
+
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ DataRate acked_bitrate = DataRate::KilobitsPerSec(300);
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_bitrate);
+ // Update estimate when network is overusing, and 50% loss rate.
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwOverusing,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ // Update estimate again when network is continuously overusing, and 100%
+ // loss rate.
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwOverusing,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ // The estimate bitrate now is backed off based on acked bitrate.
+ EXPECT_LE(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ acked_bitrate);
+}
+
+// When receiving the same packet feedback, loss based bwe ignores the feedback
+// and returns the current estimate.
+TEST_P(LossBasedBweV2Test, NoBweChangeIfObservationDurationUnchanged) {
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ 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=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ DataRate estimate_1 =
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
+
+ // Use the same feedback and check if the estimate is unchanged.
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ DataRate estimate_2 =
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
+ EXPECT_EQ(estimate_2, estimate_1);
+}
+
+// When receiving feedback of packets that were sent within an observation
+// duration, and network is in the normal state, loss based bwe returns the
+// current estimate.
+TEST_P(LossBasedBweV2Test,
+ NoBweChangeIfObservationDurationIsSmallAndNetworkNormal) {
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound - TimeDelta::Millis(1));
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ DataRate estimate_1 =
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
+
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ DataRate estimate_2 =
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
+ EXPECT_EQ(estimate_2, estimate_1);
+}
+
+// When receiving feedback of packets that were sent within an observation
+// duration, and network is in the underusing state, loss based bwe returns the
+// current estimate.
+TEST_P(LossBasedBweV2Test,
+ NoBweIncreaseIfObservationDurationIsSmallAndNetworkUnderusing) {
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound - TimeDelta::Millis(1));
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ DataRate estimate_1 =
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
+
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwUnderusing, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ DataRate estimate_2 =
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
+ EXPECT_LE(estimate_2, estimate_1);
+}
+
+// When receiving feedback of packets that were sent within an observation
+// duration, network is overusing, and trendline integration is enabled, loss
+// based bwe updates its estimate.
+TEST_P(LossBasedBweV2Test,
+ UpdateEstimateIfObservationDurationIsSmallAndNetworkOverusing) {
+ if (!GetParam()) {
+ GTEST_SKIP() << "This test should run only if "
+ "trendline_integration_enabled is enabled";
+ }
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWith50pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound - TimeDelta::Millis(1));
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+
+ 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=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ DataRate estimate_1 =
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
+
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwOverusing,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ DataRate estimate_2 =
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
+ EXPECT_LT(estimate_2, estimate_1);
+}
+
+TEST_P(LossBasedBweV2Test,
+ IncreaseToDelayBasedEstimateIfNoLossOrDelayIncrease) {
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ 2 * kObservationDurationLowerBound);
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ 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.UpdateBandwidthEstimate(
+ enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ delay_based_estimate);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ delay_based_estimate);
+}
+
+TEST_P(LossBasedBweV2Test,
+ IncreaseByMaxIncreaseFactorAfterLossBasedBweBacksOff) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true,"
+ "ObservationWindowSize:2,ObservationDurationLowerBound:200ms,"
+ "InstantUpperBoundBwBalance:10000kbps,"
+ "DelayBasedCandidate:true,MaxIncreaseFactor:1.5,BwRampupUpperBoundFactor:"
+ "2.0,NotIncreaseIfInherentLossLessThanAverageLoss:false/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+ DataRate acked_rate = DataRate::KilobitsPerSec(300);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate);
+
+ // Create some loss to create the loss limited scenario.
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ LossBasedBweV2::Result result_at_loss =
+ loss_based_bandwidth_estimator.GetLossBasedResult();
+
+ // Network recovers after loss.
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ LossBasedBweV2::Result result_after_recovery =
+ loss_based_bandwidth_estimator.GetLossBasedResult();
+ EXPECT_EQ(result_after_recovery.bandwidth_estimate,
+ result_at_loss.bandwidth_estimate * 1.5);
+}
+
+TEST_P(LossBasedBweV2Test,
+ LossBasedStateIsDelayBasedEstimateAfterNetworkRecovering) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:100|1|0.5,AckedRateCandidate:true,"
+ "ObservationWindowSize:2,ObservationDurationLowerBound:200ms,"
+ "InstantUpperBoundBwBalance:10000kbps,"
+ "DelayBasedCandidate:true,MaxIncreaseFactor:100,"
+ "BwRampupUpperBoundFactor:"
+ "2.0,NotIncreaseIfInherentLossLessThanAverageLoss:false/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(600);
+ DataRate acked_rate = DataRate::KilobitsPerSec(300);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate);
+
+ // Create some loss to create the loss limited scenario.
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
+ LossBasedState::kDecreasing);
+
+ // Network recovers after loss.
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
+ LossBasedState::kDelayBasedEstimate);
+
+ // Network recovers continuing.
+ std::vector<PacketResult> enough_feedback_3 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound * 2);
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
+ LossBasedState::kDelayBasedEstimate);
+}
+
+TEST_P(LossBasedBweV2Test,
+ LossBasedStateIsNotDelayBasedEstimateIfDelayBasedEsimtateInfinite) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:100|1|0.5,AckedRateCandidate:true,"
+ "ObservationWindowSize:2,ObservationDurationLowerBound:200ms,"
+ "InstantUpperBoundBwBalance:10000kbps,"
+ "DelayBasedCandidate:true,MaxIncreaseFactor:100,"
+ "BwRampupUpperBoundFactor:"
+ "2.0/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ DataRate delay_based_estimate = DataRate::PlusInfinity();
+ DataRate acked_rate = DataRate::KilobitsPerSec(300);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate);
+
+ // Create some loss to create the loss limited scenario.
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
+ LossBasedState::kDecreasing);
+
+ // Network recovers after loss.
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ EXPECT_NE(loss_based_bandwidth_estimator.GetLossBasedResult().state,
+ LossBasedState::kDelayBasedEstimate);
+}
+
+// After loss based bwe backs off, the next estimate is capped by
+// a factor of acked bitrate.
+TEST_P(LossBasedBweV2Test,
+ IncreaseByFactorOfAckedBitrateAfterLossBasedBweBacksOff) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,LossThresholdOfHighBandwidthPreference:0.99,"
+ "BwRampupUpperBoundFactor:1.2,"
+ "InherentLossUpperBoundOffset:0.9,ObservationDurationLowerBound:200ms/");
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWith10pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ 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, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // Change the acked bitrate to make sure that the estimate is bounded by a
+ // factor of acked bitrate.
+ DataRate acked_bitrate = DataRate::KilobitsPerSec(50);
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_bitrate);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // The estimate is capped by acked_bitrate * BwRampupUpperBoundFactor.
+ DataRate estimate_2 =
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
+ EXPECT_EQ(estimate_2, acked_bitrate * 1.2);
+}
+
+// After loss based bwe backs off, the estimate is bounded during the delayed
+// window.
+TEST_P(LossBasedBweV2Test,
+ EstimateBitrateIsBoundedDuringDelayedWindowAfterLossBasedBweBacksOff) {
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWith50pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kDelayedIncreaseWindow - TimeDelta::Millis(2));
+ std::vector<PacketResult> enough_feedback_3 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kDelayedIncreaseWindow - TimeDelta::Millis(1));
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ 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, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ // Increase the acknowledged bitrate to make sure that the estimate is not
+ // capped too low.
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(
+ DataRate::KilobitsPerSec(5000));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // The estimate is capped by current_estimate * kMaxIncreaseFactor because
+ // it recently backed off.
+ DataRate estimate_2 =
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
+
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ // The latest estimate is the same as the previous estimate since the sent
+ // packets were sent within the DelayedIncreaseWindow.
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ estimate_2);
+}
+
+// The estimate is not bounded after the delayed increase window.
+TEST_P(LossBasedBweV2Test, KeepIncreasingEstimateAfterDelayedIncreaseWindow) {
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kDelayedIncreaseWindow - TimeDelta::Millis(1));
+ std::vector<PacketResult> enough_feedback_3 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kDelayedIncreaseWindow + TimeDelta::Millis(1));
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ 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, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ // Increase the acknowledged bitrate to make sure that the estimate is not
+ // capped too low.
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(
+ DataRate::KilobitsPerSec(5000));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // The estimate is capped by current_estimate * kMaxIncreaseFactor because it
+ // recently backed off.
+ DataRate estimate_2 =
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
+
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+ // The estimate can continue increasing after the DelayedIncreaseWindow.
+ EXPECT_GE(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ estimate_2);
+}
+
+TEST_P(LossBasedBweV2Test, NotIncreaseIfInherentLossLessThanAverageLoss) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.2,AckedRateCandidate:false,"
+ "ObservationWindowSize:2,"
+ "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps,"
+ "ObservationDurationLowerBound:200ms,"
+ "NotIncreaseIfInherentLossLessThanAverageLoss:true/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+
+ std::vector<PacketResult> enough_feedback_10p_loss_1 =
+ CreatePacketResultsWith10pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_10p_loss_1, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ std::vector<PacketResult> enough_feedback_10p_loss_2 =
+ CreatePacketResultsWith10pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_10p_loss_2, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // Do not increase the bitrate because inherent loss is less than average loss
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(600));
+}
+
+TEST_P(LossBasedBweV2Test,
+ SelectHighBandwidthCandidateIfLossRateIsLessThanThreshold) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.2|0.8,AckedRateCandidate:false,"
+ "ObservationWindowSize:2,"
+ "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps,"
+ "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000,"
+ "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0."
+ "20,NotIncreaseIfInherentLossLessThanAverageLoss:false/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+
+ std::vector<PacketResult> enough_feedback_10p_loss_1 =
+ CreatePacketResultsWith10pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_10p_loss_1, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ std::vector<PacketResult> enough_feedback_10p_loss_2 =
+ CreatePacketResultsWith10pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_10p_loss_2, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // Because LossThresholdOfHighBandwidthPreference is 20%, the average loss is
+ // 10%, bandwidth estimate should increase.
+ EXPECT_GT(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(600));
+}
+
+TEST_P(LossBasedBweV2Test,
+ SelectLowBandwidthCandidateIfLossRateIsIsHigherThanThreshold) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.2|0.8,AckedRateCandidate:false,"
+ "ObservationWindowSize:2,"
+ "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps,"
+ "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000,"
+ "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0."
+ "05/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+
+ std::vector<PacketResult> enough_feedback_10p_loss_1 =
+ CreatePacketResultsWith10pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_10p_loss_1, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ std::vector<PacketResult> enough_feedback_10p_loss_2 =
+ CreatePacketResultsWith10pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_10p_loss_2, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // Because LossThresholdOfHighBandwidthPreference is 5%, the average loss is
+ // 10%, bandwidth estimate should decrease.
+ EXPECT_LT(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(600));
+}
+
+TEST_P(LossBasedBweV2Test, UseProbeResultWhenRecoveringFromLoss) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true,"
+ "ObservationWindowSize:2,ObservationDurationLowerBound:200ms,"
+ "InstantUpperBoundBwBalance:10000kbps,"
+ "DelayBasedCandidate:true,MaxIncreaseFactor:1000,"
+ "BwRampupUpperBoundFactor:2.0,ProbeIntegrationEnabled:true/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+ DataRate acked_rate = DataRate::KilobitsPerSec(300);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate);
+
+ // Create some loss to create the loss limited scenario.
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // Network recovers after loss.
+ DataRate probe_estimate = DataRate::KilobitsPerSec(300);
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ probe_estimate, /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ LossBasedBweV2::Result result_after_recovery =
+ loss_based_bandwidth_estimator.GetLossBasedResult();
+ EXPECT_EQ(result_after_recovery.bandwidth_estimate, probe_estimate);
+}
+
+// If BoundByUpperLinkCapacityWhenLossLimited is enabled, the estimate is
+// bounded by the upper link capacity when bandwidth is loss limited.
+TEST_P(LossBasedBweV2Test, BoundEstimateByUpperLinkCapacityWhenLossLimited) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true,"
+ "ObservationWindowSize:2,ObservationDurationLowerBound:200ms,"
+ "InstantUpperBoundBwBalance:10000kbps,"
+ "DelayBasedCandidate:true,MaxIncreaseFactor:1000,"
+ "BwRampupUpperBoundFactor:2.0,BoundByUpperLinkCapacityWhenLossLimited:"
+ "true/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+ DataRate acked_rate = DataRate::KilobitsPerSec(300);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate);
+
+ // Create some loss to create the loss limited scenario.
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // Network recovers after loss.
+ DataRate upper_link_capacity = DataRate::KilobitsPerSec(10);
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt, upper_link_capacity);
+
+ LossBasedBweV2::Result result_after_recovery =
+ loss_based_bandwidth_estimator.GetLossBasedResult();
+ EXPECT_EQ(result_after_recovery.bandwidth_estimate, upper_link_capacity);
+}
+
+// If BoundByUpperLinkCapacityWhenLossLimited is enabled, the estimate is not
+// bounded by the upper link capacity when bandwidth is not loss limited.
+TEST_P(LossBasedBweV2Test,
+ NotBoundEstimateByUpperLinkCapacityWhenNotLossLimited) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true,"
+ "ObservationWindowSize:2,ObservationDurationLowerBound:200ms,"
+ "InstantUpperBoundBwBalance:10000kbps,"
+ "DelayBasedCandidate:true,MaxIncreaseFactor:1000,"
+ "BwRampupUpperBoundFactor:2.0,BoundByUpperLinkCapacityWhenLossLimited:"
+ "true/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+ DataRate acked_rate = DataRate::KilobitsPerSec(300);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate);
+
+ // Create a normal network without loss
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ DataRate upper_link_capacity = DataRate::KilobitsPerSec(10);
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt, upper_link_capacity);
+
+ LossBasedBweV2::Result loss_based_result =
+ loss_based_bandwidth_estimator.GetLossBasedResult();
+ EXPECT_GT(loss_based_result.bandwidth_estimate, upper_link_capacity);
+}
+
+// If BoundByUpperLinkCapacityWhenLossLimited is disabled, the estimate is not
+// bounded by the upper link capacity.
+TEST_P(LossBasedBweV2Test, NotBoundEstimateByUpperLinkCapacity) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true,"
+ "ObservationWindowSize:2,ObservationDurationLowerBound:200ms,"
+ "InstantUpperBoundBwBalance:10000kbps,"
+ "DelayBasedCandidate:true,MaxIncreaseFactor:1000,"
+ "BwRampupUpperBoundFactor:2.0,BoundByUpperLinkCapacityWhenLossLimited:"
+ "false/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+ DataRate acked_rate = DataRate::KilobitsPerSec(300);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate);
+
+ // Create some loss to create the loss limited scenario.
+ std::vector<PacketResult> enough_feedback_1 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // Network recovers after loss.
+ DataRate upper_link_capacity = DataRate::KilobitsPerSec(10);
+ std::vector<PacketResult> enough_feedback_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt, upper_link_capacity);
+
+ LossBasedBweV2::Result result_after_recovery =
+ loss_based_bandwidth_estimator.GetLossBasedResult();
+ EXPECT_GT(result_after_recovery.bandwidth_estimate, upper_link_capacity);
+}
+
+TEST_P(LossBasedBweV2Test,
+ StricterBoundUsingHighLossRateThresholdAt10pLossRate) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.0,AckedRateCandidate:false,"
+ "ObservationWindowSize:2,"
+ "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps,"
+ "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000,"
+ "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0."
+ "05,HighLossRateThreshold:0.09/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ loss_based_bandwidth_estimator.SetMinMaxBitrate(
+ /*min_bitrate=*/DataRate::KilobitsPerSec(10),
+ /*max_bitrate=*/DataRate::KilobitsPerSec(1000000));
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+
+ std::vector<PacketResult> enough_feedback_10p_loss_1 =
+ CreatePacketResultsWith10pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_10p_loss_1, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ std::vector<PacketResult> enough_feedback_10p_loss_2 =
+ CreatePacketResultsWith10pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_10p_loss_2, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // At 10% loss rate and high loss rate threshold to be 10%, cap the estimate
+ // to be 500 * 1000-0.1 = 400kbps.
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(400));
+}
+
+TEST_P(LossBasedBweV2Test,
+ StricterBoundUsingHighLossRateThresholdAt50pLossRate) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.0,AckedRateCandidate:false,"
+ "ObservationWindowSize:2,"
+ "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps,"
+ "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000,"
+ "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0."
+ "05,HighLossRateThreshold:0.3/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ loss_based_bandwidth_estimator.SetMinMaxBitrate(
+ /*min_bitrate=*/DataRate::KilobitsPerSec(10),
+ /*max_bitrate=*/DataRate::KilobitsPerSec(1000000));
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+
+ std::vector<PacketResult> enough_feedback_50p_loss_1 =
+ CreatePacketResultsWith50pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_50p_loss_1, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ std::vector<PacketResult> enough_feedback_50p_loss_2 =
+ CreatePacketResultsWith50pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_50p_loss_2, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // At 50% loss rate and high loss rate threshold to be 30%, cap the estimate
+ // to be the min bitrate.
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(10));
+}
+
+TEST_P(LossBasedBweV2Test,
+ StricterBoundUsingHighLossRateThresholdAt100pLossRate) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.0,AckedRateCandidate:false,"
+ "ObservationWindowSize:2,"
+ "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps,"
+ "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000,"
+ "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0."
+ "05,HighLossRateThreshold:0.3/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ loss_based_bandwidth_estimator.SetMinMaxBitrate(
+ /*min_bitrate=*/DataRate::KilobitsPerSec(10),
+ /*max_bitrate=*/DataRate::KilobitsPerSec(1000000));
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+
+ std::vector<PacketResult> enough_feedback_100p_loss_1 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_100p_loss_1, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ std::vector<PacketResult> enough_feedback_100p_loss_2 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_100p_loss_2, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // At 100% loss rate and high loss rate threshold to be 30%, cap the estimate
+ // to be the min bitrate.
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(10));
+}
+
+TEST_P(LossBasedBweV2Test, EstimateRecoversAfterHighLoss) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.1|1.0|0.9,AckedRateCandidate:false,"
+ "ObservationWindowSize:2,"
+ "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps,"
+ "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000,"
+ "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0."
+ "05,HighLossRateThreshold:0.3/");
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ loss_based_bandwidth_estimator.SetMinMaxBitrate(
+ /*min_bitrate=*/DataRate::KilobitsPerSec(10),
+ /*max_bitrate=*/DataRate::KilobitsPerSec(1000000));
+ DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+
+ std::vector<PacketResult> enough_feedback_100p_loss_1 =
+ CreatePacketResultsWith100pLossRate(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_100p_loss_1, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // Make sure that the estimate is set to min bitrate because of 100% loss
+ // rate.
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(10));
+
+ // Create some feedbacks with 0 loss rate to simulate network recovering.
+ std::vector<PacketResult> enough_feedback_0p_loss_1 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_0p_loss_1, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ std::vector<PacketResult> enough_feedback_0p_loss_2 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound * 2);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_0p_loss_2, delay_based_estimate,
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ // The estimate increases as network recovers.
+ EXPECT_GT(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(10));
+}
+
+TEST_P(LossBasedBweV2Test, EstimateIsNotHigherThanMaxBitrate) {
+ ExplicitKeyValueConfig key_value_config(
+ Config(/*enabled=*/true, /*valid=*/true,
+ /*trendline_integration_enabled=*/GetParam()));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ loss_based_bandwidth_estimator.SetMinMaxBitrate(
+ /*min_bitrate=*/DataRate::KilobitsPerSec(10),
+ /*max_bitrate=*/DataRate::KilobitsPerSec(1000));
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(1000));
+ std::vector<PacketResult> enough_feedback =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero());
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback, /*delay_based_estimate=*/DataRate::PlusInfinity(),
+ BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity());
+
+ EXPECT_LE(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(1000));
+}
+
+INSTANTIATE_TEST_SUITE_P(LossBasedBweV2Tests,
+ LossBasedBweV2Test,
+ ::testing::Bool());
+
+} // namespace
+} // namespace webrtc