Tweaks for LossBasedBweV2.
Caches the TCP fairness limit to avoid redundant calculation. Adds option to append the delay based estimate as a candidate. Makes the appending of acknowledged bitrate as a candidate optional. Adds a log-bandwidth bias term.
(submit on behalf of crodbro)
Bug: webrtc:12707
Change-Id: Ic4b0f58e6f0bc3b117fe78a2321a07db65afd9dd
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228163
Commit-Queue: Ying Wang <yinwa@webrtc.org>
Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34687}
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 ae52b2d..63202d8 100644
--- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc
+++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc
@@ -178,7 +178,8 @@
}
void LossBasedBweV2::UpdateBandwidthEstimate(
- rtc::ArrayView<const PacketResult> packet_results) {
+ rtc::ArrayView<const PacketResult> packet_results,
+ DataRate delay_based_estimate) {
if (!IsEnabled()) {
RTC_LOG(LS_WARNING)
<< "The estimator must be enabled before it can be used.";
@@ -202,7 +203,7 @@
ChannelParameters best_candidate = current_estimate_;
double objective_max = std::numeric_limits<double>::lowest();
- for (ChannelParameters candidate : GetCandidates()) {
+ for (ChannelParameters candidate : GetCandidates(delay_based_estimate)) {
NewtonsMethodUpdate(candidate);
const double candidate_objective = GetObjective(candidate);
@@ -226,6 +227,8 @@
{1.05, 1.0, 0.95});
FieldTrialParameter<double> higher_bandwidth_bias_factor("HigherBwBiasFactor",
0.00001);
+ FieldTrialParameter<double> higher_log_bandwidth_bias_factor(
+ "HigherLogBwBiasFactor", 0.001);
FieldTrialParameter<double> inherent_loss_lower_bound(
"InherentLossLowerBound", 1.0e-3);
FieldTrialParameter<DataRate> inherent_loss_upper_bound_bandwidth_balance(
@@ -236,6 +239,10 @@
"InitialInherentLossEstimate", 0.01);
FieldTrialParameter<int> newton_iterations("NewtonIterations", 1);
FieldTrialParameter<double> newton_step_size("NewtonStepSize", 0.5);
+ FieldTrialParameter<bool> append_acknowledged_rate_candidate(
+ "AckedRateCandidate", true);
+ FieldTrialParameter<bool> append_delay_based_estimate_candidate(
+ "DelayBasedCandidate", false);
FieldTrialParameter<TimeDelta> observation_duration_lower_bound(
"ObservationDurationLowerBound", TimeDelta::Seconds(1));
FieldTrialParameter<int> observation_window_size("ObservationWindowSize", 20);
@@ -251,17 +258,27 @@
0.99);
if (key_value_config) {
- ParseFieldTrial(
- {&enabled, &bandwidth_rampup_upper_bound_factor, &candidate_factors,
- &higher_bandwidth_bias_factor, &inherent_loss_lower_bound,
- &inherent_loss_upper_bound_bandwidth_balance,
- &inherent_loss_upper_bound_offset, &initial_inherent_loss_estimate,
- &newton_iterations, &newton_step_size,
- &observation_duration_lower_bound, &observation_window_size,
- &sending_rate_smoothing_factor, &tcp_fairness_temporal_weight_factor,
- &tcp_fairness_upper_bound_bandwidth_balance,
- &tcp_fairness_upper_bound_loss_offset, &temporal_weight_factor},
- key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2"));
+ ParseFieldTrial({&enabled,
+ &bandwidth_rampup_upper_bound_factor,
+ &candidate_factors,
+ &higher_bandwidth_bias_factor,
+ &higher_log_bandwidth_bias_factor,
+ &inherent_loss_lower_bound,
+ &inherent_loss_upper_bound_bandwidth_balance,
+ &inherent_loss_upper_bound_offset,
+ &initial_inherent_loss_estimate,
+ &newton_iterations,
+ &newton_step_size,
+ &append_acknowledged_rate_candidate,
+ &append_delay_based_estimate_candidate,
+ &observation_duration_lower_bound,
+ &observation_window_size,
+ &sending_rate_smoothing_factor,
+ &tcp_fairness_temporal_weight_factor,
+ &tcp_fairness_upper_bound_bandwidth_balance,
+ &tcp_fairness_upper_bound_loss_offset,
+ &temporal_weight_factor},
+ key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2"));
}
absl::optional<Config> config;
@@ -273,6 +290,8 @@
bandwidth_rampup_upper_bound_factor.Get();
config->candidate_factors = candidate_factors.Get();
config->higher_bandwidth_bias_factor = higher_bandwidth_bias_factor.Get();
+ config->higher_log_bandwidth_bias_factor =
+ higher_log_bandwidth_bias_factor.Get();
config->inherent_loss_lower_bound = inherent_loss_lower_bound.Get();
config->inherent_loss_upper_bound_bandwidth_balance =
inherent_loss_upper_bound_bandwidth_balance.Get();
@@ -281,6 +300,10 @@
config->initial_inherent_loss_estimate = initial_inherent_loss_estimate.Get();
config->newton_iterations = newton_iterations.Get();
config->newton_step_size = newton_step_size.Get();
+ config->append_acknowledged_rate_candidate =
+ append_acknowledged_rate_candidate.Get();
+ config->append_delay_based_estimate_candidate =
+ append_delay_based_estimate_candidate.Get();
config->observation_duration_lower_bound =
observation_duration_lower_bound.Get();
config->observation_window_size = observation_window_size.Get();
@@ -427,19 +450,23 @@
return static_cast<double>(num_lost_packets) / num_packets;
}
-std::vector<LossBasedBweV2::ChannelParameters> LossBasedBweV2::GetCandidates()
- const {
+std::vector<LossBasedBweV2::ChannelParameters> LossBasedBweV2::GetCandidates(
+ DataRate delay_based_estimate) const {
std::vector<DataRate> bandwidths;
for (double candidate_factor : config_->candidate_factors) {
- bandwidths.emplace_back(candidate_factor *
- current_estimate_.loss_limited_bandwidth);
+ bandwidths.push_back(candidate_factor *
+ current_estimate_.loss_limited_bandwidth);
}
- if (acknowledged_bitrate_.has_value()) {
- bandwidths.emplace_back(*acknowledged_bitrate_);
+ if (acknowledged_bitrate_.has_value() &&
+ config_->append_acknowledged_rate_candidate) {
+ bandwidths.push_back(*acknowledged_bitrate_);
}
- // TODO(crodbro): Consider adding the delay based estimate as a candidate.
+ if (IsValid(delay_based_estimate) &&
+ config_->append_delay_based_estimate_candidate) {
+ bandwidths.push_back(delay_based_estimate);
+ }
const DataRate candidate_bandwidth_upper_bound =
acknowledged_bitrate_.has_value()
@@ -516,10 +543,22 @@
return std::min(inherent_loss_upper_bound, 1.0);
}
+double LossBasedBweV2::GetHighBandwidthBias(DataRate bandwidth) const {
+ if (IsValid(bandwidth)) {
+ return config_->higher_bandwidth_bias_factor * bandwidth.kbps() +
+ config_->higher_log_bandwidth_bias_factor *
+ std::log(1.0 + bandwidth.kbps());
+ }
+ return 0.0;
+}
+
double LossBasedBweV2::GetObjective(
const ChannelParameters& channel_parameters) const {
double objective = 0.0;
+ const double high_bandwidth_bias =
+ GetHighBandwidthBias(channel_parameters.loss_limited_bandwidth);
+
for (const Observation& observation : observations_) {
if (!observation.IsInitialized()) {
continue;
@@ -537,9 +576,7 @@
((observation.num_lost_packets * std::log(loss_probability)) +
(observation.num_received_packets * std::log(1.0 - loss_probability)));
objective +=
- temporal_weight * (config_->higher_bandwidth_bias_factor *
- channel_parameters.loss_limited_bandwidth.kbps() *
- observation.num_packets);
+ temporal_weight * high_bandwidth_bias * observation.num_packets;
}
return objective;
@@ -565,18 +602,19 @@
}
DataRate LossBasedBweV2::GetTcpFairnessBandwidthUpperBound() const {
- if (num_observations_ <= 0) {
- return DataRate::PlusInfinity();
- }
+ return cached_tcp_fairness_limit_.value_or(DataRate::PlusInfinity());
+}
+void LossBasedBweV2::CalculateTcpFairnessBandwidthUpperBound() {
+ DataRate tcp_fairness_limit = DataRate::PlusInfinity();
const double average_reported_loss_ratio = GetAverageReportedLossRatio();
- if (average_reported_loss_ratio <=
+ if (average_reported_loss_ratio >
config_->tcp_fairness_upper_bound_loss_offset) {
- return DataRate::PlusInfinity();
+ tcp_fairness_limit = config_->tcp_fairness_upper_bound_bandwidth_balance /
+ (average_reported_loss_ratio -
+ config_->tcp_fairness_upper_bound_loss_offset);
}
- return config_->tcp_fairness_upper_bound_bandwidth_balance /
- (average_reported_loss_ratio -
- config_->tcp_fairness_upper_bound_loss_offset);
+ cached_tcp_fairness_limit_ = tcp_fairness_limit;
}
void LossBasedBweV2::CalculateTemporalWeights() {
@@ -646,6 +684,7 @@
partial_observation_ = PartialObservation();
+ CalculateTcpFairnessBandwidthUpperBound();
return true;
}
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 83d6f33..10fb33f 100644
--- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h
+++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h
@@ -48,7 +48,8 @@
void SetBandwidthEstimate(DataRate bandwidth_estimate);
void UpdateBandwidthEstimate(
- rtc::ArrayView<const PacketResult> packet_results);
+ rtc::ArrayView<const PacketResult> packet_results,
+ DataRate delay_based_estimate);
private:
struct ChannelParameters {
@@ -60,6 +61,7 @@
double bandwidth_rampup_upper_bound_factor = 0.0;
std::vector<double> candidate_factors;
double higher_bandwidth_bias_factor = 0.0;
+ double higher_log_bandwidth_bias_factor = 0.0;
double inherent_loss_lower_bound = 0.0;
DataRate inherent_loss_upper_bound_bandwidth_balance =
DataRate::MinusInfinity();
@@ -67,6 +69,8 @@
double initial_inherent_loss_estimate = 0.0;
int newton_iterations = 0;
double newton_step_size = 0.0;
+ bool append_acknowledged_rate_candidate = true;
+ bool append_delay_based_estimate_candidate = false;
TimeDelta observation_duration_lower_bound = TimeDelta::Zero();
int observation_window_size = 0;
double sending_rate_smoothing_factor = 0.0;
@@ -104,14 +108,17 @@
// Returns `0.0` if not enough loss statistics have been received.
double GetAverageReportedLossRatio() const;
- std::vector<ChannelParameters> GetCandidates() const;
+ std::vector<ChannelParameters> GetCandidates(
+ DataRate delay_based_estimate) const;
Derivatives GetDerivatives(const ChannelParameters& channel_parameters) const;
double GetFeasibleInherentLoss(
const ChannelParameters& channel_parameters) const;
double GetInherentLossUpperBound(DataRate bandwidth) const;
+ double GetHighBandwidthBias(DataRate bandwidth) const;
double GetObjective(const ChannelParameters& channel_parameters) const;
DataRate GetSendingRate(DataRate instantaneous_sending_rate) const;
DataRate GetTcpFairnessBandwidthUpperBound() const;
+ void CalculateTcpFairnessBandwidthUpperBound();
void CalculateTemporalWeights();
void NewtonsMethodUpdate(ChannelParameters& channel_parameters) const;
@@ -126,6 +133,7 @@
std::vector<Observation> observations_;
PartialObservation partial_observation_;
Timestamp last_send_time_most_recent_observation_ = Timestamp::PlusInfinity();
+ absl::optional<DataRate> cached_tcp_fairness_limit_;
std::vector<double> tcp_fairness_temporal_weights_;
std::vector<double> temporal_weights_;
};
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 87ac31d..bb71668 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
@@ -105,7 +105,8 @@
loss_based_bandwidth_estimator.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
- loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback, DataRate::PlusInfinity());
EXPECT_TRUE(loss_based_bandwidth_estimator.IsReady());
EXPECT_TRUE(loss_based_bandwidth_estimator.GetBandwidthEstimate().IsFinite());
@@ -127,7 +128,8 @@
Config(/*enabled=*/true, /*valid=*/true));
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
- loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback, DataRate::PlusInfinity());
EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
EXPECT_TRUE(
@@ -159,7 +161,8 @@
EXPECT_TRUE(
loss_based_bandwidth_estimator.GetBandwidthEstimate().IsPlusInfinity());
- loss_based_bandwidth_estimator.UpdateBandwidthEstimate(not_enough_feedback);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ not_enough_feedback, DataRate::PlusInfinity());
EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
EXPECT_TRUE(
@@ -196,7 +199,8 @@
loss_based_bandwidth_estimator.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
- loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_1);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_1, DataRate::PlusInfinity());
EXPECT_NE(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
DataRate::KilobitsPerSec(600));
@@ -207,7 +211,8 @@
EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
DataRate::KilobitsPerSec(600));
- loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_2);
+ loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
+ enough_feedback_2, DataRate::PlusInfinity());
EXPECT_NE(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
DataRate::KilobitsPerSec(600));
@@ -246,8 +251,10 @@
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator_2.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
- loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(enough_feedback_1);
- loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(enough_feedback_1);
+ loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
+ enough_feedback_1, DataRate::PlusInfinity());
+ loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(
+ enough_feedback_1, DataRate::PlusInfinity());
EXPECT_EQ(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(),
DataRate::KilobitsPerSec(660));
@@ -258,8 +265,10 @@
EXPECT_EQ(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(),
DataRate::KilobitsPerSec(660));
- loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(enough_feedback_2);
- loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(enough_feedback_2);
+ loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
+ enough_feedback_2, DataRate::PlusInfinity());
+ loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(
+ enough_feedback_2, DataRate::PlusInfinity());
EXPECT_NE(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(),
loss_based_bandwidth_estimator_2.GetBandwidthEstimate());
@@ -288,7 +297,7 @@
loss_based_bandwidth_estimator.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
- enough_feedback_no_received_packets);
+ enough_feedback_no_received_packets, DataRate::PlusInfinity());
EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
DataRate::KilobitsPerSec(100));
diff --git a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc
index 749b073..8fb3275 100644
--- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc
+++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc
@@ -364,7 +364,7 @@
}
if (LossBasedBandwidthEstimatorV2Enabled()) {
loss_based_bandwidth_estimator_v2_.UpdateBandwidthEstimate(
- report.packet_feedbacks);
+ report.packet_feedbacks, delay_based_limit_);
}
}