Use acked bitrate as lower bound of loss based BWE.
This cl/ makes sure that the estimate cannot go lower than a factor of acked bitrate. The current flag LowerBoundByAckedRateFactor is set to 0, means we dont use it.
Bug: webrtc:12707
Change-Id: I75d5881f0b85a374af3f7039b82c71aee97fb7b0
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/323881
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Commit-Queue: Diep Bui <diepbp@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40958}
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 a938e93..46a2d4e 100644
--- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc
+++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc
@@ -164,11 +164,14 @@
if (IsValid(delay_based_estimate_)) {
result.bandwidth_estimate =
- std::min({current_estimate_.loss_limited_bandwidth,
- GetInstantUpperBound(), delay_based_estimate_});
+ std::max(GetInstantLowerBound(),
+ std::min({current_estimate_.loss_limited_bandwidth,
+ GetInstantUpperBound(), delay_based_estimate_}));
} else {
- result.bandwidth_estimate = std::min(
- current_estimate_.loss_limited_bandwidth, GetInstantUpperBound());
+ result.bandwidth_estimate =
+ std::max(GetInstantLowerBound(),
+ std::min(current_estimate_.loss_limited_bandwidth,
+ GetInstantUpperBound()));
}
return result;
}
@@ -176,6 +179,7 @@
void LossBasedBweV2::SetAcknowledgedBitrate(DataRate acknowledged_bitrate) {
if (IsValid(acknowledged_bitrate)) {
acknowledged_bitrate_ = acknowledged_bitrate;
+ CalculateInstantLowerBound();
} else {
RTC_LOG(LS_WARNING) << "The acknowledged bitrate must be finite: "
<< ToString(acknowledged_bitrate);
@@ -195,6 +199,7 @@
DataRate max_bitrate) {
if (IsValid(min_bitrate)) {
min_bitrate_ = min_bitrate;
+ CalculateInstantLowerBound();
} else {
RTC_LOG(LS_WARNING) << "The min bitrate must be finite: "
<< ToString(min_bitrate);
@@ -393,6 +398,8 @@
true);
FieldTrialParameter<bool> use_in_start_phase("UseInStartPhase", false);
FieldTrialParameter<int> min_num_observations("MinNumObservations", 3);
+ FieldTrialParameter<double> lower_bound_by_acked_rate_factor(
+ "LowerBoundByAckedRateFactor", 0.0);
if (key_value_config) {
ParseFieldTrial({&enabled,
&bandwidth_rampup_upper_bound_factor,
@@ -428,7 +435,8 @@
&slope_of_bwe_high_loss_func,
¬_use_acked_rate_in_alr,
&use_in_start_phase,
- &min_num_observations},
+ &min_num_observations,
+ &lower_bound_by_acked_rate_factor},
key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2"));
}
@@ -488,6 +496,8 @@
config->not_use_acked_rate_in_alr = not_use_acked_rate_in_alr.Get();
config->use_in_start_phase = use_in_start_phase.Get();
config->min_num_observations = min_num_observations.Get();
+ config->lower_bound_by_acked_rate_factor =
+ lower_bound_by_acked_rate_factor.Get();
return config;
}
@@ -673,6 +683,13 @@
<< config_->min_num_observations;
valid = false;
}
+ if (config_->lower_bound_by_acked_rate_factor < 0.0) {
+ RTC_LOG(LS_WARNING)
+ << "The estimate lower bound by acknowledged rate factor must be "
+ "non-negative: "
+ << config_->lower_bound_by_acked_rate_factor;
+ valid = false;
+ }
return valid;
}
@@ -913,6 +930,24 @@
cached_instant_upper_bound_ = instant_limit;
}
+DataRate LossBasedBweV2::GetInstantLowerBound() const {
+ return cached_instant_lower_bound_.value_or(DataRate::Zero());
+}
+
+void LossBasedBweV2::CalculateInstantLowerBound() {
+ DataRate instance_lower_bound = DataRate::Zero();
+ if (IsValid(acknowledged_bitrate_) &&
+ config_->lower_bound_by_acked_rate_factor > 0.0) {
+ instance_lower_bound = config_->lower_bound_by_acked_rate_factor *
+ acknowledged_bitrate_.value();
+ }
+
+ if (IsValid(min_bitrate_)) {
+ instance_lower_bound = std::max(instance_lower_bound, min_bitrate_);
+ }
+ cached_instant_lower_bound_ = instance_lower_bound;
+}
+
void LossBasedBweV2::CalculateTemporalWeights() {
for (int i = 0; i < config_->observation_window_size; ++i) {
temporal_weights_[i] = std::pow(config_->temporal_weight_factor, i);
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 09d4d87..81c2f90 100644
--- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h
+++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h
@@ -113,6 +113,7 @@
bool not_use_acked_rate_in_alr = false;
bool use_in_start_phase = false;
int min_num_observations = 0;
+ double lower_bound_by_acked_rate_factor = 0.0;
};
struct Derivatives {
@@ -154,6 +155,8 @@
DataRate GetSendingRate(DataRate instantaneous_sending_rate) const;
DataRate GetInstantUpperBound() const;
void CalculateInstantUpperBound();
+ DataRate GetInstantLowerBound() const;
+ void CalculateInstantLowerBound();
void CalculateTemporalWeights();
void NewtonsMethodUpdate(ChannelParameters& channel_parameters) const;
@@ -173,6 +176,7 @@
Timestamp last_send_time_most_recent_observation_ = Timestamp::PlusInfinity();
Timestamp last_time_estimate_reduced_ = Timestamp::MinusInfinity();
absl::optional<DataRate> cached_instant_upper_bound_;
+ absl::optional<DataRate> cached_instant_lower_bound_;
std::vector<double> instant_upper_bound_temporal_weights_;
std::vector<double> temporal_weights_;
Timestamp recovering_after_loss_timestamp_ = Timestamp::MinusInfinity();
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 d1d5fad..cc2b2c0 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
@@ -1185,7 +1185,6 @@
/*first_packet_timestamp=*/Timestamp::Zero());
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_100p_loss_1, delay_based_estimate,
-
/*in_alr=*/true);
// Make sure that the estimate decreases but higher than acked rate.
@@ -1248,5 +1247,55 @@
EXPECT_TRUE(loss_based_bandwidth_estimator.ReadyToUseInStartPhase());
}
+TEST_F(LossBasedBweV2Test, BoundEstimateByAckedRate) {
+ ExplicitKeyValueConfig key_value_config(
+ ShortObservationConfig("LowerBoundByAckedRateFactor:1.0"));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ loss_based_bandwidth_estimator.SetMinMaxBitrate(
+ /*min_bitrate=*/DataRate::KilobitsPerSec(10),
+ /*max_bitrate=*/DataRate::KilobitsPerSec(1000000));
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(
+ DataRate::KilobitsPerSec(500));
+
+ 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=*/DataRate::PlusInfinity(),
+ /*in_alr=*/false);
+
+ EXPECT_EQ(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(500));
+}
+
+TEST_F(LossBasedBweV2Test, NotBoundEstimateByAckedRate) {
+ ExplicitKeyValueConfig key_value_config(
+ ShortObservationConfig("LowerBoundByAckedRateFactor:0.0"));
+ LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
+ loss_based_bandwidth_estimator.SetMinMaxBitrate(
+ /*min_bitrate=*/DataRate::KilobitsPerSec(10),
+ /*max_bitrate=*/DataRate::KilobitsPerSec(1000000));
+ loss_based_bandwidth_estimator.SetBandwidthEstimate(
+ DataRate::KilobitsPerSec(600));
+ loss_based_bandwidth_estimator.SetAcknowledgedBitrate(
+ DataRate::KilobitsPerSec(500));
+
+ 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=*/DataRate::PlusInfinity(),
+ /*in_alr=*/false);
+
+ EXPECT_LT(
+ loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
+ DataRate::KilobitsPerSec(500));
+}
+
} // namespace
} // namespace webrtc