Update loss based bwe - probe integration.
Instead of use probe_bitrate as the bandwidth estimate, the change uses probe bitrate as the bandwidth limit.
The experiment is not started, so it does not affect production.
Bug: webrtc:12707
Change-Id: Iefd8cdfe87983057489e551816bf5d4cb38f7c9f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/296040
Commit-Queue: Diep Bui <diepbp@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39603}
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 223a928..4c0f5fc 100644
--- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc
+++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc
@@ -209,9 +209,8 @@
void LossBasedBweV2::SetProbeBitrate(absl::optional<DataRate> probe_bitrate) {
if (probe_bitrate.has_value() && IsValid(probe_bitrate.value())) {
- if (!IsValid(probe_bitrate_) || probe_bitrate_ > probe_bitrate.value()) {
- probe_bitrate_ = probe_bitrate.value();
- }
+ probe_bitrate_ = probe_bitrate.value();
+ last_probe_timestamp_ = last_send_time_most_recent_observation_;
}
}
@@ -229,7 +228,7 @@
<< "The estimator must be enabled before it can be used.";
return;
}
- SetProbeBitrate(probe_bitrate);
+
if (packet_results.empty()) {
RTC_LOG(LS_VERBOSE)
<< "The estimate cannot be updated without any loss statistics.";
@@ -240,6 +239,8 @@
return;
}
+ SetProbeBitrate(probe_bitrate);
+
if (!IsValid(current_estimate_.loss_limited_bandwidth)) {
RTC_LOG(LS_VERBOSE)
<< "The estimator must be initialized before it can be used.";
@@ -300,24 +301,27 @@
: config_->bandwidth_rampup_upper_bound_factor *
(*acknowledged_bitrate_);
}
-
- // Use probe bitrate as the estimate as probe bitrate is trusted to be
- // correct. After being used, the probe bitrate is reset.
- if (config_->probe_integration_enabled && IsValid(probe_bitrate_)) {
- best_candidate.loss_limited_bandwidth =
- std::min(probe_bitrate_, best_candidate.loss_limited_bandwidth);
- probe_bitrate_ = DataRate::MinusInfinity();
- }
}
if (IsEstimateIncreasingWhenLossLimited(best_candidate) &&
- best_candidate.loss_limited_bandwidth < delay_based_estimate) {
+ best_candidate.loss_limited_bandwidth < delay_based_estimate_) {
current_state_ = LossBasedState::kIncreasing;
} else if (best_candidate.loss_limited_bandwidth < delay_based_estimate_) {
current_state_ = LossBasedState::kDecreasing;
} else if (best_candidate.loss_limited_bandwidth >= delay_based_estimate_) {
current_state_ = LossBasedState::kDelayBasedEstimate;
}
+
+ // Use probe bitrate as the estimate limit when probes are requested.
+ if (config_->probe_integration_enabled && IsValid(probe_bitrate_) &&
+ IsRequestingProbe()) {
+ if (last_probe_timestamp_ + config_->probe_expiration >=
+ last_send_time_most_recent_observation_) {
+ best_candidate.loss_limited_bandwidth =
+ std::min(probe_bitrate_, best_candidate.loss_limited_bandwidth);
+ }
+ }
+
current_estimate_ = best_candidate;
if (IsBandwidthLimitedDueToLoss() &&
@@ -412,6 +416,8 @@
"SlopeOfBweHighLossFunc", 1000);
FieldTrialParameter<bool> probe_integration_enabled("ProbeIntegrationEnabled",
false);
+ FieldTrialParameter<TimeDelta> probe_expiration("ProbeExpiration",
+ TimeDelta::Seconds(10));
FieldTrialParameter<bool> bound_by_upper_link_capacity_when_loss_limited(
"BoundByUpperLinkCapacityWhenLossLimited", true);
FieldTrialParameter<bool> not_use_acked_rate_in_alr("NotUseAckedRateInAlr",
@@ -449,6 +455,7 @@
&use_acked_bitrate_only_when_overusing,
¬_increase_if_inherent_loss_less_than_average_loss,
&probe_integration_enabled,
+ &probe_expiration,
&high_loss_rate_threshold,
&bandwidth_cap_at_high_loss_rate,
&slope_of_bwe_high_loss_func,
@@ -514,6 +521,7 @@
bandwidth_cap_at_high_loss_rate.Get();
config->slope_of_bwe_high_loss_func = slope_of_bwe_high_loss_func.Get();
config->probe_integration_enabled = probe_integration_enabled.Get();
+ config->probe_expiration = probe_expiration.Get();
config->bound_by_upper_link_capacity_when_loss_limited =
bound_by_upper_link_capacity_when_loss_limited.Get();
config->not_use_acked_rate_in_alr = not_use_acked_rate_in_alr.Get();
@@ -1084,4 +1092,8 @@
return current_state_ != LossBasedState::kDelayBasedEstimate;
}
+bool LossBasedBweV2::IsRequestingProbe() const {
+ return current_state_ == LossBasedState::kIncreasing;
+}
+
} // namespace webrtc
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 84f2378..f5a6396 100644
--- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h
+++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h
@@ -40,6 +40,8 @@
struct Result {
~Result() = default;
DataRate bandwidth_estimate = DataRate::Zero();
+ // State is used by goog_cc, which later sends probe requests to probe
+ // controller if state is kIncreasing.
LossBasedState state = LossBasedState::kDelayBasedEstimate;
};
// Creates a disabled `LossBasedBweV2` if the
@@ -112,6 +114,7 @@
DataRate bandwidth_cap_at_high_loss_rate = DataRate::MinusInfinity();
double slope_of_bwe_high_loss_func = 1000.0;
bool probe_integration_enabled = false;
+ TimeDelta probe_expiration = TimeDelta::Zero();
bool bound_by_upper_link_capacity_when_loss_limited = false;
bool not_use_acked_rate_in_alr = false;
};
@@ -177,6 +180,7 @@
const ChannelParameters& best_candidate);
bool IsBandwidthLimitedDueToLoss() const;
void SetProbeBitrate(absl::optional<DataRate> probe_bitrate);
+ bool IsRequestingProbe() const;
absl::optional<DataRate> acknowledged_bitrate_;
absl::optional<Config> config_;
@@ -198,6 +202,7 @@
DataRate probe_bitrate_ = DataRate::PlusInfinity();
DataRate delay_based_estimate_ = DataRate::PlusInfinity();
DataRate upper_link_capacity_ = DataRate::PlusInfinity();
+ Timestamp last_probe_timestamp_ = Timestamp::MinusInfinity();
};
} // namespace webrtc
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 6771420..d745f37 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
@@ -1148,13 +1148,13 @@
DataRate::KilobitsPerSec(600));
}
-TEST_P(LossBasedBweV2Test, UseProbeResultWhenRecoveringFromLoss) {
+TEST_P(LossBasedBweV2Test, LimitByProbeResultWhenRecoveringFromLoss) {
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,"
+ "InstantUpperBoundBwBalance:10000kbps,DelayedIncreaseWindow:100s,"
+ "DelayBasedCandidate:true,MaxIncreaseFactor:1.3,"
"BwRampupUpperBoundFactor:2.0,ProbeIntegrationEnabled:true/");
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000);
@@ -1172,7 +1172,7 @@
/*probe_estimate=*/absl::nullopt,
/*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false);
- // Network recovers after loss.
+ // Network recovers after loss
DataRate probe_estimate = DataRate::KilobitsPerSec(300);
std::vector<PacketResult> enough_feedback_2 =
CreatePacketResultsWithReceivedPackets(
@@ -1183,9 +1183,82 @@
probe_estimate, /*upper_link_capacity=*/DataRate::PlusInfinity(),
/*in_alr=*/false);
+ for (int i = 2; i < 5; ++i) {
+ enough_feedback_2 = CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound * i);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity(),
+ /*in_alr=*/false);
+ LossBasedBweV2::Result result_after_recovery =
+ loss_based_bandwidth_estimator.GetLossBasedResult();
+ EXPECT_LE(result_after_recovery.bandwidth_estimate, probe_estimate);
+ }
+}
+
+TEST_P(LossBasedBweV2Test, NotLimitByProbeResultWhenProbeResultIsExpired) {
+ ExplicitKeyValueConfig key_value_config(
+ "WebRTC-Bwe-LossBasedBweV2/"
+ "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true,"
+ "ObservationWindowSize:2,ObservationDurationLowerBound:200ms,"
+ "InstantUpperBoundBwBalance:10000kbps,DelayedIncreaseWindow:100s,"
+ "DelayBasedCandidate:true,MaxIncreaseFactor:1.3,"
+ "BwRampupUpperBoundFactor:2.0,ProbeIntegrationEnabled:true,"
+ "ProbeExpiration:10s/");
+ 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(), /*in_alr=*/false);
+
+ // 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(),
+ /*in_alr=*/false);
+
+ for (int i = 2; i < 5; ++i) {
+ enough_feedback_2 = CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound * i);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity(),
+ /*in_alr=*/false);
+ }
+
+ std::vector<PacketResult> enough_feedback_3 =
+ CreatePacketResultsWithReceivedPackets(
+ /*first_packet_timestamp=*/Timestamp::Zero() +
+ kObservationDurationLowerBound + TimeDelta::Seconds(11));
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal,
+ /*probe_estimate=*/absl::nullopt,
+ /*upper_link_capacity=*/DataRate::PlusInfinity(),
+ /*in_alr=*/false);
+
+ // Probe result is expired after 10s.
LossBasedBweV2::Result result_after_recovery =
loss_based_bandwidth_estimator.GetLossBasedResult();
- EXPECT_EQ(result_after_recovery.bandwidth_estimate, probe_estimate);
+ EXPECT_GT(result_after_recovery.bandwidth_estimate, probe_estimate);
}
// If BoundByUpperLinkCapacityWhenLossLimited is enabled, the estimate is