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 ae52b2d852..63202d879a 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::SetBandwidthEstimate(DataRate bandwidth_estimate) { } void LossBasedBweV2::UpdateBandwidthEstimate( - rtc::ArrayView packet_results) { + rtc::ArrayView 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 @@ void LossBasedBweV2::UpdateBandwidthEstimate( ChannelParameters best_candidate = current_estimate_; double objective_max = std::numeric_limits::lowest(); - for (ChannelParameters candidate : GetCandidates()) { + for (ChannelParameters candidate : GetCandidates(delay_based_estimate)) { NewtonsMethodUpdate(candidate); const double candidate_objective = GetObjective(candidate); @@ -226,6 +227,8 @@ absl::optional LossBasedBweV2::CreateConfig( {1.05, 1.0, 0.95}); FieldTrialParameter higher_bandwidth_bias_factor("HigherBwBiasFactor", 0.00001); + FieldTrialParameter higher_log_bandwidth_bias_factor( + "HigherLogBwBiasFactor", 0.001); FieldTrialParameter inherent_loss_lower_bound( "InherentLossLowerBound", 1.0e-3); FieldTrialParameter inherent_loss_upper_bound_bandwidth_balance( @@ -236,6 +239,10 @@ absl::optional LossBasedBweV2::CreateConfig( "InitialInherentLossEstimate", 0.01); FieldTrialParameter newton_iterations("NewtonIterations", 1); FieldTrialParameter newton_step_size("NewtonStepSize", 0.5); + FieldTrialParameter append_acknowledged_rate_candidate( + "AckedRateCandidate", true); + FieldTrialParameter append_delay_based_estimate_candidate( + "DelayBasedCandidate", false); FieldTrialParameter observation_duration_lower_bound( "ObservationDurationLowerBound", TimeDelta::Seconds(1)); FieldTrialParameter observation_window_size("ObservationWindowSize", 20); @@ -251,17 +258,27 @@ absl::optional LossBasedBweV2::CreateConfig( 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; @@ -273,6 +290,8 @@ absl::optional LossBasedBweV2::CreateConfig( 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 @@ absl::optional LossBasedBweV2::CreateConfig( 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 @@ double LossBasedBweV2::GetAverageReportedLossRatio() const { return static_cast(num_lost_packets) / num_packets; } -std::vector LossBasedBweV2::GetCandidates() - const { +std::vector LossBasedBweV2::GetCandidates( + DataRate delay_based_estimate) const { std::vector 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 @@ double LossBasedBweV2::GetInherentLossUpperBound(DataRate bandwidth) const { 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 @@ double LossBasedBweV2::GetObjective( ((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::GetSendingRate( } 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 @@ bool LossBasedBweV2::PushBackObservation( 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 83d6f33598..10fb33f537 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 @@ class LossBasedBweV2 { void SetBandwidthEstimate(DataRate bandwidth_estimate); void UpdateBandwidthEstimate( - rtc::ArrayView packet_results); + rtc::ArrayView packet_results, + DataRate delay_based_estimate); private: struct ChannelParameters { @@ -60,6 +61,7 @@ class LossBasedBweV2 { double bandwidth_rampup_upper_bound_factor = 0.0; std::vector 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 @@ class LossBasedBweV2 { 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 @@ class LossBasedBweV2 { // Returns `0.0` if not enough loss statistics have been received. double GetAverageReportedLossRatio() const; - std::vector GetCandidates() const; + std::vector 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 @@ class LossBasedBweV2 { std::vector observations_; PartialObservation partial_observation_; Timestamp last_send_time_most_recent_observation_ = Timestamp::PlusInfinity(); + absl::optional cached_tcp_fairness_limit_; std::vector tcp_fairness_temporal_weights_; std::vector 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 87ac31dfdc..bb71668d8b 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 @@ TEST(LossBasedBweV2Test, BandwidthEstimateGivenInitializationAndThenFeedback) { 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 @@ TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) { 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 @@ TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) { 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 @@ TEST(LossBasedBweV2Test, 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 @@ TEST(LossBasedBweV2Test, 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 @@ TEST(LossBasedBweV2Test, 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 @@ TEST(LossBasedBweV2Test, 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 @@ TEST(LossBasedBweV2Test, 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 749b073cd5..8fb3275cc9 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 @@ void SendSideBandwidthEstimation::IncomingPacketFeedbackVector( } if (LossBasedBandwidthEstimatorV2Enabled()) { loss_based_bandwidth_estimator_v2_.UpdateBandwidthEstimate( - report.packet_feedbacks); + report.packet_feedbacks, delay_based_limit_); } }