mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-19 00:27:51 +01:00
Introduce hold duration in loss based BWE.
The initial hold duration is 300ms. Whenever it enters kDecreasing state, it will double the current hold duration. The hold duration will be reset as soon as the delay based estimate works, e.g. the state is kDelayBased to avoid getting stuck at low bitrate. Bug: webrtc:12707 Change-Id: I3906ff80b071ba3eb6274b012fb31922f4cbc7b6 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/324304 Commit-Queue: Diep Bui <diepbp@webrtc.org> Reviewed-by: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/main@{#40991}
This commit is contained in:
parent
5b186e98bc
commit
75a131f39c
3 changed files with 174 additions and 1 deletions
|
@ -35,6 +35,8 @@ namespace webrtc {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr TimeDelta kInitHoldDuration = TimeDelta::Millis(300);
|
||||||
|
|
||||||
bool IsValid(DataRate datarate) {
|
bool IsValid(DataRate datarate) {
|
||||||
return datarate.IsFinite();
|
return datarate.IsFinite();
|
||||||
}
|
}
|
||||||
|
@ -125,6 +127,7 @@ LossBasedBweV2::LossBasedBweV2(const FieldTrialsView* key_value_config)
|
||||||
instant_upper_bound_temporal_weights_.resize(
|
instant_upper_bound_temporal_weights_.resize(
|
||||||
config_->observation_window_size);
|
config_->observation_window_size);
|
||||||
CalculateTemporalWeights();
|
CalculateTemporalWeights();
|
||||||
|
hold_duration_ = kInitHoldDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LossBasedBweV2::IsEnabled() const {
|
bool LossBasedBweV2::IsEnabled() const {
|
||||||
|
@ -318,6 +321,16 @@ void LossBasedBweV2::UpdateResult() {
|
||||||
GetInstantUpperBound()));
|
GetInstantUpperBound()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loss_based_result_.state == LossBasedState::kDecreasing &&
|
||||||
|
last_hold_timestamp_ > last_send_time_most_recent_observation_ &&
|
||||||
|
bounded_bandwidth_estimate < delay_based_estimate_) {
|
||||||
|
// BWE is not allowed to increase during the HOLD duration. The purpose of
|
||||||
|
// HOLD is to not immediately ramp up BWE to a rate that may cause loss.
|
||||||
|
loss_based_result_.bandwidth_estimate = std::min(
|
||||||
|
loss_based_result_.bandwidth_estimate, bounded_bandwidth_estimate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsEstimateIncreasingWhenLossLimited(
|
if (IsEstimateIncreasingWhenLossLimited(
|
||||||
/*old_estimate=*/loss_based_result_.bandwidth_estimate,
|
/*old_estimate=*/loss_based_result_.bandwidth_estimate,
|
||||||
/*new_estimate=*/bounded_bandwidth_estimate) &&
|
/*new_estimate=*/bounded_bandwidth_estimate) &&
|
||||||
|
@ -328,8 +341,21 @@ void LossBasedBweV2::UpdateResult() {
|
||||||
: LossBasedState::kIncreasing;
|
: LossBasedState::kIncreasing;
|
||||||
} else if (bounded_bandwidth_estimate < delay_based_estimate_ &&
|
} else if (bounded_bandwidth_estimate < delay_based_estimate_ &&
|
||||||
bounded_bandwidth_estimate < max_bitrate_) {
|
bounded_bandwidth_estimate < max_bitrate_) {
|
||||||
|
if (loss_based_result_.state != LossBasedState::kDecreasing &&
|
||||||
|
config_->hold_duration_factor > 0) {
|
||||||
|
RTC_LOG(LS_INFO) << this << " "
|
||||||
|
<< "Switch to HOLD. Bounded BWE: "
|
||||||
|
<< bounded_bandwidth_estimate.kbps()
|
||||||
|
<< ", duration: " << hold_duration_.seconds();
|
||||||
|
last_hold_timestamp_ =
|
||||||
|
last_send_time_most_recent_observation_ + hold_duration_;
|
||||||
|
hold_duration_ = hold_duration_ * config_->hold_duration_factor;
|
||||||
|
}
|
||||||
loss_based_result_.state = LossBasedState::kDecreasing;
|
loss_based_result_.state = LossBasedState::kDecreasing;
|
||||||
} else {
|
} else {
|
||||||
|
// Reset the HOLD duration if delay based estimate works to avoid getting
|
||||||
|
// stuck in low bitrate.
|
||||||
|
hold_duration_ = kInitHoldDuration;
|
||||||
loss_based_result_.state = LossBasedState::kDelayBasedEstimate;
|
loss_based_result_.state = LossBasedState::kDelayBasedEstimate;
|
||||||
}
|
}
|
||||||
loss_based_result_.bandwidth_estimate = bounded_bandwidth_estimate;
|
loss_based_result_.bandwidth_estimate = bounded_bandwidth_estimate;
|
||||||
|
@ -417,6 +443,7 @@ absl::optional<LossBasedBweV2::Config> LossBasedBweV2::CreateConfig(
|
||||||
"LowerBoundByAckedRateFactor", 0.0);
|
"LowerBoundByAckedRateFactor", 0.0);
|
||||||
FieldTrialParameter<bool> use_padding_for_increase("UsePadding", false);
|
FieldTrialParameter<bool> use_padding_for_increase("UsePadding", false);
|
||||||
|
|
||||||
|
FieldTrialParameter<double> hold_duration_factor("HoldDurationFactor", 0.0);
|
||||||
if (key_value_config) {
|
if (key_value_config) {
|
||||||
ParseFieldTrial({&enabled,
|
ParseFieldTrial({&enabled,
|
||||||
&bandwidth_rampup_upper_bound_factor,
|
&bandwidth_rampup_upper_bound_factor,
|
||||||
|
@ -454,7 +481,8 @@ absl::optional<LossBasedBweV2::Config> LossBasedBweV2::CreateConfig(
|
||||||
&use_in_start_phase,
|
&use_in_start_phase,
|
||||||
&min_num_observations,
|
&min_num_observations,
|
||||||
&lower_bound_by_acked_rate_factor,
|
&lower_bound_by_acked_rate_factor,
|
||||||
&use_padding_for_increase},
|
&use_padding_for_increase,
|
||||||
|
&hold_duration_factor},
|
||||||
key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2"));
|
key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,6 +545,7 @@ absl::optional<LossBasedBweV2::Config> LossBasedBweV2::CreateConfig(
|
||||||
config->lower_bound_by_acked_rate_factor =
|
config->lower_bound_by_acked_rate_factor =
|
||||||
lower_bound_by_acked_rate_factor.Get();
|
lower_bound_by_acked_rate_factor.Get();
|
||||||
config->use_padding_for_increase = use_padding_for_increase.Get();
|
config->use_padding_for_increase = use_padding_for_increase.Get();
|
||||||
|
config->hold_duration_factor = hold_duration_factor.Get();
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,7 @@ class LossBasedBweV2 {
|
||||||
int min_num_observations = 0;
|
int min_num_observations = 0;
|
||||||
double lower_bound_by_acked_rate_factor = 0.0;
|
double lower_bound_by_acked_rate_factor = 0.0;
|
||||||
bool use_padding_for_increase = false;
|
bool use_padding_for_increase = false;
|
||||||
|
double hold_duration_factor = 0.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Derivatives {
|
struct Derivatives {
|
||||||
|
@ -191,6 +192,8 @@ class LossBasedBweV2 {
|
||||||
DataRate max_bitrate_ = DataRate::PlusInfinity();
|
DataRate max_bitrate_ = DataRate::PlusInfinity();
|
||||||
DataRate delay_based_estimate_ = DataRate::PlusInfinity();
|
DataRate delay_based_estimate_ = DataRate::PlusInfinity();
|
||||||
LossBasedBweV2::Result loss_based_result_ = LossBasedBweV2::Result();
|
LossBasedBweV2::Result loss_based_result_ = LossBasedBweV2::Result();
|
||||||
|
Timestamp last_hold_timestamp_ = Timestamp::MinusInfinity();
|
||||||
|
TimeDelta hold_duration_ = TimeDelta::Zero();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
|
@ -1491,5 +1491,146 @@ TEST_F(LossBasedBweV2Test, IncreaseUsingPaddingStateIfFieldTrial) {
|
||||||
LossBasedState::kIncreaseUsingPadding);
|
LossBasedState::kIncreaseUsingPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(LossBasedBweV2Test, IncreaseEstimateIfNotHold) {
|
||||||
|
ExplicitKeyValueConfig key_value_config(
|
||||||
|
ShortObservationConfig("HoldDurationFactor:0"));
|
||||||
|
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
|
||||||
|
loss_based_bandwidth_estimator.SetBandwidthEstimate(
|
||||||
|
DataRate::KilobitsPerSec(2500));
|
||||||
|
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
||||||
|
CreatePacketResultsWith50pLossRate(
|
||||||
|
/*first_packet_timestamp=*/Timestamp::Zero()),
|
||||||
|
/*delay_based_estimate=*/DataRate::PlusInfinity(),
|
||||||
|
/*in_alr=*/false);
|
||||||
|
ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
|
||||||
|
LossBasedState::kDecreasing);
|
||||||
|
DataRate estimate =
|
||||||
|
loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
|
||||||
|
|
||||||
|
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
||||||
|
CreatePacketResultsWithReceivedPackets(
|
||||||
|
/*first_packet_timestamp=*/Timestamp::Zero() +
|
||||||
|
kObservationDurationLowerBound),
|
||||||
|
/*delay_based_estimate=*/DataRate::PlusInfinity(),
|
||||||
|
/*in_alr=*/false);
|
||||||
|
EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
|
||||||
|
LossBasedState::kIncreasing);
|
||||||
|
EXPECT_GT(
|
||||||
|
loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
|
||||||
|
estimate);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LossBasedBweV2Test, IncreaseEstimateAfterHoldDuration) {
|
||||||
|
ExplicitKeyValueConfig key_value_config(
|
||||||
|
ShortObservationConfig("HoldDurationFactor:3"));
|
||||||
|
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
|
||||||
|
loss_based_bandwidth_estimator.SetBandwidthEstimate(
|
||||||
|
DataRate::KilobitsPerSec(2500));
|
||||||
|
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
||||||
|
CreatePacketResultsWith50pLossRate(
|
||||||
|
/*first_packet_timestamp=*/Timestamp::Zero()),
|
||||||
|
/*delay_based_estimate=*/DataRate::PlusInfinity(),
|
||||||
|
/*in_alr=*/false);
|
||||||
|
ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
|
||||||
|
LossBasedState::kDecreasing);
|
||||||
|
DataRate estimate =
|
||||||
|
loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
|
||||||
|
|
||||||
|
// During the hold duration, e.g. first 300ms, the estimate cannot increase.
|
||||||
|
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
||||||
|
CreatePacketResultsWithReceivedPackets(
|
||||||
|
/*first_packet_timestamp=*/Timestamp::Zero() +
|
||||||
|
kObservationDurationLowerBound),
|
||||||
|
/*delay_based_estimate=*/DataRate::PlusInfinity(),
|
||||||
|
/*in_alr=*/false);
|
||||||
|
EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
|
||||||
|
LossBasedState::kDecreasing);
|
||||||
|
EXPECT_EQ(
|
||||||
|
loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
|
||||||
|
estimate);
|
||||||
|
|
||||||
|
// After the hold duration, the estimate can increase.
|
||||||
|
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
||||||
|
CreatePacketResultsWithReceivedPackets(
|
||||||
|
/*first_packet_timestamp=*/Timestamp::Zero() +
|
||||||
|
kObservationDurationLowerBound * 2),
|
||||||
|
/*delay_based_estimate=*/DataRate::PlusInfinity(),
|
||||||
|
/*in_alr=*/false);
|
||||||
|
EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
|
||||||
|
LossBasedState::kIncreasing);
|
||||||
|
EXPECT_GE(
|
||||||
|
loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
|
||||||
|
estimate);
|
||||||
|
|
||||||
|
// Get another 50p packet loss.
|
||||||
|
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
||||||
|
CreatePacketResultsWith50pLossRate(
|
||||||
|
/*first_packet_timestamp=*/Timestamp::Zero() +
|
||||||
|
kObservationDurationLowerBound * 3),
|
||||||
|
/*delay_based_estimate=*/DataRate::PlusInfinity(),
|
||||||
|
/*in_alr=*/false);
|
||||||
|
EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
|
||||||
|
LossBasedState::kDecreasing);
|
||||||
|
estimate =
|
||||||
|
loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
|
||||||
|
|
||||||
|
// During the hold duration, e.g. next 900ms, the estimate cannot increase.
|
||||||
|
for (int i = 4; i <= 6; ++i) {
|
||||||
|
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
||||||
|
CreatePacketResultsWithReceivedPackets(
|
||||||
|
/*first_packet_timestamp=*/Timestamp::Zero() +
|
||||||
|
kObservationDurationLowerBound * i),
|
||||||
|
/*delay_based_estimate=*/DataRate::PlusInfinity(),
|
||||||
|
/*in_alr=*/false);
|
||||||
|
EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
|
||||||
|
LossBasedState::kDecreasing);
|
||||||
|
EXPECT_EQ(
|
||||||
|
loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
|
||||||
|
estimate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// After the hold duration, the estimate can increase again.
|
||||||
|
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
||||||
|
CreatePacketResultsWithReceivedPackets(
|
||||||
|
/*first_packet_timestamp=*/Timestamp::Zero() +
|
||||||
|
kObservationDurationLowerBound * 7),
|
||||||
|
/*delay_based_estimate=*/DataRate::PlusInfinity(),
|
||||||
|
/*in_alr=*/false);
|
||||||
|
EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
|
||||||
|
LossBasedState::kIncreasing);
|
||||||
|
EXPECT_GE(
|
||||||
|
loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
|
||||||
|
estimate);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LossBasedBweV2Test, EndHoldDurationIfDelayBasedEstimateWorks) {
|
||||||
|
ExplicitKeyValueConfig key_value_config(
|
||||||
|
ShortObservationConfig("HoldDurationFactor:3"));
|
||||||
|
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
|
||||||
|
loss_based_bandwidth_estimator.SetBandwidthEstimate(
|
||||||
|
DataRate::KilobitsPerSec(2500));
|
||||||
|
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
||||||
|
CreatePacketResultsWith50pLossRate(
|
||||||
|
/*first_packet_timestamp=*/Timestamp::Zero()),
|
||||||
|
/*delay_based_estimate=*/DataRate::PlusInfinity(),
|
||||||
|
/*in_alr=*/false);
|
||||||
|
ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
|
||||||
|
LossBasedState::kDecreasing);
|
||||||
|
DataRate estimate =
|
||||||
|
loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate;
|
||||||
|
|
||||||
|
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
||||||
|
CreatePacketResultsWithReceivedPackets(
|
||||||
|
/*first_packet_timestamp=*/Timestamp::Zero() +
|
||||||
|
kObservationDurationLowerBound),
|
||||||
|
/*delay_based_estimate=*/estimate + DataRate::KilobitsPerSec(10),
|
||||||
|
/*in_alr=*/false);
|
||||||
|
EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state,
|
||||||
|
LossBasedState::kDelayBasedEstimate);
|
||||||
|
EXPECT_EQ(
|
||||||
|
loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate,
|
||||||
|
estimate + DataRate::KilobitsPerSec(10));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
Loading…
Reference in a new issue