Integrate trendline estimator into loss based bwe v2.

Bug: webrtc:12707
Change-Id: I510d3799c14599344d1714178e42b29e7c0c06d7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/254380
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Commit-Queue: Diep Bui <diepbp@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36236}
This commit is contained in:
Diep Bui
2022-03-17 11:59:47 +00:00
committed by WebRTC LUCI CQ
parent 2c9bba7741
commit 4ceea65848
10 changed files with 410 additions and 78 deletions

View File

@ -153,6 +153,7 @@ rtc_library("loss_based_bwe_v2") {
]
deps = [
"../../../api:array_view",
"../../../api:network_state_predictor_api",
"../../../api/transport:network_control",
"../../../api/transport:webrtc_key_value_config",
"../../../api/units:data_rate",
@ -195,6 +196,7 @@ rtc_library("send_side_bwe") {
deps = [
":loss_based_bwe_v1",
":loss_based_bwe_v2",
"../../../api:network_state_predictor_api",
"../../../api/rtc_event_log",
"../../../api/transport:network_control",
"../../../api/transport:webrtc_key_value_config",
@ -325,6 +327,7 @@ if (rtc_include_tests) {
":probe_controller",
":pushback_controller",
":send_side_bwe",
"../../../api:network_state_predictor_api",
"../../../api/rtc_event_log",
"../../../api/test/network_emulation",
"../../../api/test/network_emulation:create_cross_traffic",

View File

@ -193,11 +193,10 @@ void DelayBasedBwe::IncomingPacketFeedback(const PacketResult& packet_feedback,
packet_feedback.sent_packet.send_time, packet_feedback.receive_time,
at_time, packet_size.bytes(), &send_delta, &recv_delta, &size_delta);
delay_detector_for_packet->Update(
recv_delta.ms(), send_delta.ms(),
delay_detector_for_packet->Update(recv_delta.ms(), send_delta.ms(),
packet_feedback.sent_packet.send_time.ms(),
packet_feedback.receive_time.ms(), packet_size.bytes(),
calculated_deltas);
packet_feedback.receive_time.ms(),
packet_size.bytes(), calculated_deltas);
}
DataRate DelayBasedBwe::TriggerOveruse(Timestamp at_time,
@ -266,6 +265,8 @@ DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
prev_bitrate_ = bitrate;
prev_state_ = detector_state;
}
result.delay_detector_state = detector_state;
return result;
}

View File

@ -56,6 +56,7 @@ class DelayBasedBwe {
DataRate target_bitrate = DataRate::Zero();
bool recovered_from_overuse;
bool backoff_in_alr;
BandwidthUsage delay_detector_state;
};
explicit DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config,

View File

@ -495,7 +495,6 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(
auto acknowledged_bitrate = acknowledged_bitrate_estimator_->bitrate();
bandwidth_estimation_->SetAcknowledgedRate(acknowledged_bitrate,
report.feedback_time);
bandwidth_estimation_->IncomingPacketFeedbackVector(report);
for (const auto& feedback : report.SortedByReceiveTime()) {
if (feedback.sent_packet.pacing_info.probe_cluster_id !=
PacedPacketInfo::kNotAProbe) {
@ -553,11 +552,13 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(
}
// Since SetSendBitrate now resets the delay-based estimate, we have to
// call UpdateDelayBasedEstimate after SetSendBitrate.
bandwidth_estimation_->UpdateDelayBasedEstimate(report.feedback_time,
result.target_bitrate);
bandwidth_estimation_->UpdateDelayBasedEstimate(
report.feedback_time, result.target_bitrate,
result.delay_detector_state);
// Update the estimate in the ProbeController, in case we want to probe.
MaybeTriggerOnNetworkChanged(&update, report.feedback_time);
}
bandwidth_estimation_->UpdateLossBasedEstimatorFromFeedbackVector(report);
recovered_from_overuse = result.recovered_from_overuse;
backoff_in_alr = result.backoff_in_alr;

View File

@ -21,6 +21,7 @@
#include "absl/algorithm/container.h"
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "api/network_state_predictor.h"
#include "api/transport/network_types.h"
#include "api/transport/webrtc_key_value_config.h"
#include "api/units/data_rate.h"
@ -89,18 +90,11 @@ double GetLossProbability(double inherent_loss,
<< ToString(loss_limited_bandwidth);
}
// We approximate the loss model
// loss_probability = inherent_loss + (1 - inherent_loss) *
// max(0, sending_rate - bandwidth) / sending_rate
// by
// loss_probability = inherent_loss +
// max(0, sending_rate - bandwidth) / sending_rate
// as it allows for simpler calculations and makes little difference in
// practice.
double loss_probability = inherent_loss;
if (IsValid(sending_rate) && IsValid(loss_limited_bandwidth) &&
(sending_rate > loss_limited_bandwidth)) {
loss_probability += (sending_rate - loss_limited_bandwidth) / sending_rate;
loss_probability += (1 - inherent_loss) *
(sending_rate - loss_limited_bandwidth) / sending_rate;
}
return std::min(std::max(loss_probability, 1.0e-6), 1.0 - 1.0e-6);
}
@ -138,7 +132,8 @@ bool LossBasedBweV2::IsReady() const {
num_observations_ > 0;
}
DataRate LossBasedBweV2::GetBandwidthEstimate() const {
DataRate LossBasedBweV2::GetBandwidthEstimate(
DataRate delay_based_limit) const {
if (!IsReady()) {
if (!IsEnabled()) {
RTC_LOG(LS_WARNING)
@ -156,8 +151,14 @@ DataRate LossBasedBweV2::GetBandwidthEstimate() const {
return DataRate::PlusInfinity();
}
if (delay_based_limit.IsFinite()) {
return std::min({current_estimate_.loss_limited_bandwidth,
GetInstantUpperBound(),
delay_based_limit * config_->delay_based_limit_factor});
} else {
return std::min(current_estimate_.loss_limited_bandwidth,
GetInstantUpperBound());
}
}
void LossBasedBweV2::SetAcknowledgedBitrate(DataRate acknowledged_bitrate) {
@ -180,7 +181,8 @@ void LossBasedBweV2::SetBandwidthEstimate(DataRate bandwidth_estimate) {
void LossBasedBweV2::UpdateBandwidthEstimate(
rtc::ArrayView<const PacketResult> packet_results,
DataRate delay_based_estimate) {
DataRate delay_based_estimate,
BandwidthUsage delay_detector_state) {
if (!IsEnabled()) {
RTC_LOG(LS_WARNING)
<< "The estimator must be enabled before it can be used.";
@ -192,7 +194,7 @@ void LossBasedBweV2::UpdateBandwidthEstimate(
return;
}
if (!PushBackObservation(packet_results)) {
if (!PushBackObservation(packet_results, delay_detector_state)) {
return;
}
@ -264,6 +266,15 @@ absl::optional<LossBasedBweV2::Config> LossBasedBweV2::CreateConfig(
"InstantUpperBoundLossOffset", 0.05);
FieldTrialParameter<double> temporal_weight_factor("TemporalWeightFactor",
0.99);
FieldTrialParameter<double> bandwidth_backoff_lower_bound_factor(
"BwBackoffLowerBoundFactor", 0.85);
FieldTrialParameter<bool> trendline_integration_enabled(
"TrendlineIntegrationEnabled", false);
FieldTrialParameter<double> delay_based_limit_factor("DelayBasedLimitFactor",
1.0);
FieldTrialParameter<int> trendline_window_size("TrendlineWindowSize", 20);
FieldTrialParameter<bool> backoff_when_overusing("BackoffWhenOverusing",
false);
if (key_value_config) {
ParseFieldTrial({&enabled,
@ -287,7 +298,12 @@ absl::optional<LossBasedBweV2::Config> LossBasedBweV2::CreateConfig(
&instant_upper_bound_temporal_weight_factor,
&instant_upper_bound_bandwidth_balance,
&instant_upper_bound_loss_offset,
&temporal_weight_factor},
&temporal_weight_factor,
&bandwidth_backoff_lower_bound_factor,
&trendline_integration_enabled,
&delay_based_limit_factor,
&trendline_window_size,
&backoff_when_overusing},
key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2"));
}
@ -328,6 +344,12 @@ absl::optional<LossBasedBweV2::Config> LossBasedBweV2::CreateConfig(
config->instant_upper_bound_loss_offset =
instant_upper_bound_loss_offset.Get();
config->temporal_weight_factor = temporal_weight_factor.Get();
config->bandwidth_backoff_lower_bound_factor =
bandwidth_backoff_lower_bound_factor.Get();
config->trendline_integration_enabled = trendline_integration_enabled.Get();
config->delay_based_limit_factor = delay_based_limit_factor.Get();
config->trendline_window_size = trendline_window_size.Get();
config->backoff_when_overusing = backoff_when_overusing.Get();
return config;
}
@ -470,7 +492,24 @@ bool LossBasedBweV2::IsConfigValid() const {
<< config_->temporal_weight_factor;
valid = false;
}
if (config_->bandwidth_backoff_lower_bound_factor > 1.0) {
RTC_LOG(LS_WARNING)
<< "The bandwidth backoff lower bound factor must not be greater than "
"1: "
<< config_->bandwidth_backoff_lower_bound_factor;
valid = false;
}
if (config_->delay_based_limit_factor < 1.0) {
RTC_LOG(LS_WARNING)
<< "The delay based limit factor must not be less than 1: "
<< config_->delay_based_limit_factor;
valid = false;
}
if (config_->trendline_window_size < 2) {
RTC_LOG(LS_WARNING) << "The trendline window size must be at least 2: "
<< config_->trendline_window_size;
valid = false;
}
return valid;
}
@ -521,20 +560,36 @@ DataRate LossBasedBweV2::GetCandidateBandwidthUpperBound() const {
std::vector<LossBasedBweV2::ChannelParameters> LossBasedBweV2::GetCandidates(
DataRate delay_based_estimate) const {
std::vector<DataRate> bandwidths;
bool can_increase_bitrate = TrendlineEsimateAllowBitrateIncrease();
bool can_decrease_bitrate = TrendlineEsimateAllowBitrateDecrease();
for (double candidate_factor : config_->candidate_factors) {
if (!can_increase_bitrate && candidate_factor >= 1.0) {
// When the network is overusing, the estimate is forced to decrease
// even if there is no loss yet.
if (candidate_factor > 1 || config_->backoff_when_overusing) {
continue;
}
}
if (!can_decrease_bitrate && candidate_factor < 1.0) {
continue;
}
bandwidths.push_back(candidate_factor *
current_estimate_.loss_limited_bandwidth);
}
if (acknowledged_bitrate_.has_value() &&
config_->append_acknowledged_rate_candidate) {
bandwidths.push_back(*acknowledged_bitrate_);
config_->append_acknowledged_rate_candidate && can_decrease_bitrate) {
bandwidths.push_back(*acknowledged_bitrate_ *
config_->bandwidth_backoff_lower_bound_factor);
}
if (IsValid(delay_based_estimate) &&
config_->append_delay_based_estimate_candidate) {
if (can_increase_bitrate &&
delay_based_estimate > current_estimate_.loss_limited_bandwidth) {
bandwidths.push_back(delay_based_estimate);
}
}
const DataRate candidate_bandwidth_upper_bound =
GetCandidateBandwidthUpperBound();
@ -704,8 +759,47 @@ void LossBasedBweV2::NewtonsMethodUpdate(
}
}
bool LossBasedBweV2::TrendlineEsimateAllowBitrateDecrease() const {
if (!config_->trendline_integration_enabled) {
return true;
}
for (const auto& detector_state : delay_detector_states_) {
if (detector_state == BandwidthUsage::kBwOverusing) {
return true;
}
}
for (const auto& detector_state : delay_detector_states_) {
if (detector_state == BandwidthUsage::kBwUnderusing) {
return false;
}
}
return true;
}
bool LossBasedBweV2::TrendlineEsimateAllowBitrateIncrease() const {
if (!config_->trendline_integration_enabled) {
return true;
}
for (const auto& detector_state : delay_detector_states_) {
if (detector_state == BandwidthUsage::kBwOverusing) {
return false;
}
}
return true;
}
bool LossBasedBweV2::PushBackObservation(
rtc::ArrayView<const PacketResult> packet_results) {
rtc::ArrayView<const PacketResult> packet_results,
BandwidthUsage delay_detector_state) {
delay_detector_states_.push_front(delay_detector_state);
if (static_cast<int>(delay_detector_states_.size()) >
config_->trendline_window_size) {
delay_detector_states_.pop_back();
}
if (packet_results.empty()) {
return false;
}
@ -729,7 +823,9 @@ bool LossBasedBweV2::PushBackObservation(
last_send_time - last_send_time_most_recent_observation_;
// Too small to be meaningful.
if (observation_duration < config_->observation_duration_lower_bound) {
if (observation_duration < config_->observation_duration_lower_bound &&
(delay_detector_state == BandwidthUsage::kBwNormal ||
!config_->trendline_integration_enabled)) {
return false;
}

View File

@ -12,10 +12,12 @@
#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_LOSS_BASED_BWE_V2_H_
#include <cstddef>
#include <deque>
#include <vector>
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "api/network_state_predictor.h"
#include "api/transport/network_types.h"
#include "api/transport/webrtc_key_value_config.h"
#include "api/units/data_rate.h"
@ -42,14 +44,15 @@ class LossBasedBweV2 {
bool IsReady() const;
// Returns `DataRate::PlusInfinity` if no BWE can be calculated.
DataRate GetBandwidthEstimate() const;
DataRate GetBandwidthEstimate(DataRate delay_based_limit) const;
void SetAcknowledgedBitrate(DataRate acknowledged_bitrate);
void SetBandwidthEstimate(DataRate bandwidth_estimate);
void UpdateBandwidthEstimate(
rtc::ArrayView<const PacketResult> packet_results,
DataRate delay_based_estimate);
DataRate delay_based_estimate,
BandwidthUsage delay_detector_state);
private:
struct ChannelParameters {
@ -80,6 +83,11 @@ class LossBasedBweV2 {
DataRate instant_upper_bound_bandwidth_balance = DataRate::MinusInfinity();
double instant_upper_bound_loss_offset = 0.0;
double temporal_weight_factor = 0.0;
double bandwidth_backoff_lower_bound_factor = 0.0;
bool trendline_integration_enabled = false;
double delay_based_limit_factor = 1.0;
int trendline_window_size = 0;
bool backoff_when_overusing = false;
};
struct Derivatives {
@ -124,9 +132,21 @@ class LossBasedBweV2 {
void CalculateTemporalWeights();
void NewtonsMethodUpdate(ChannelParameters& channel_parameters) const;
// Returns true if either
// 1. At least one of states in the window is kBwOverusing, or
// 2. There are no kBwUnderusing states in the window.
bool TrendlineEsimateAllowBitrateDecrease() const;
// Returns false if there exists an overusing state in the window.
bool TrendlineEsimateAllowBitrateIncrease() const;
// Returns false if no observation was created.
bool PushBackObservation(rtc::ArrayView<const PacketResult> packet_results);
bool PushBackObservation(rtc::ArrayView<const PacketResult> packet_results,
BandwidthUsage delay_detector_state);
void UpdateTrendlineEstimator(
const std::vector<PacketResult>& packet_feedbacks,
Timestamp at_time);
void UpdateDelayDetector(BandwidthUsage delay_detector_state);
absl::optional<DataRate> acknowledged_bitrate_;
absl::optional<Config> config_;
@ -139,6 +159,7 @@ class LossBasedBweV2 {
absl::optional<DataRate> cached_instant_upper_bound_;
std::vector<double> instant_upper_bound_temporal_weights_;
std::vector<double> temporal_weights_;
std::deque<BandwidthUsage> delay_detector_states_;
};
} // namespace webrtc

View File

@ -12,6 +12,7 @@
#include <string>
#include "api/network_state_predictor.h"
#include "api/transport/network_types.h"
#include "api/units/data_rate.h"
#include "api/units/data_size.h"
@ -48,14 +49,16 @@ std::string Config(bool enabled, bool valid) {
}
config_string
<< ",CandidateFactors:0.9|1.1,HigherBwBiasFactor:0.01,"
<< ",CandidateFactors:1.1|1.0|0.95,HigherBwBiasFactor:0.01,"
"DelayBasedCandidate:true,"
"InherentLossLowerBound:0.001,InherentLossUpperBoundBwBalance:14kbps,"
"InherentLossUpperBoundOffset:0.9,InitialInherentLossEstimate:0.01,"
"NewtonIterations:2,NewtonStepSize:0.4,ObservationWindowSize:15,"
"SendingRateSmoothingFactor:0.01,"
"InstantUpperBoundTemporalWeightFactor:0.97,"
"InstantUpperBoundBwBalance:90kbps,"
"InstantUpperBoundLossOffset:0.1,TemporalWeightFactor:0.98";
"InstantUpperBoundLossOffset:0.1,TemporalWeightFactor:0.98,"
"BackoffWhenOverusing:true";
config_string.AppendFormat(
",ObservationDurationLowerBound:%dms",
@ -133,10 +136,13 @@ TEST(LossBasedBweV2Test, BandwidthEstimateGivenInitializationAndThenFeedback) {
loss_based_bandwidth_estimator.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback, DataRate::PlusInfinity());
enough_feedback, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_TRUE(loss_based_bandwidth_estimator.IsReady());
EXPECT_TRUE(loss_based_bandwidth_estimator.GetBandwidthEstimate().IsFinite());
EXPECT_TRUE(
loss_based_bandwidth_estimator
.GetBandwidthEstimate(/*delay_based_limit=*/DataRate::PlusInfinity())
.IsFinite());
}
TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) {
@ -156,11 +162,13 @@ TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) {
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback, DataRate::PlusInfinity());
enough_feedback, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
EXPECT_TRUE(
loss_based_bandwidth_estimator.GetBandwidthEstimate().IsPlusInfinity());
loss_based_bandwidth_estimator
.GetBandwidthEstimate(/*delay_based_limit=*/DataRate::PlusInfinity())
.IsPlusInfinity());
}
TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) {
@ -186,14 +194,18 @@ TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) {
EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
EXPECT_TRUE(
loss_based_bandwidth_estimator.GetBandwidthEstimate().IsPlusInfinity());
loss_based_bandwidth_estimator
.GetBandwidthEstimate(/*delay_based_limit=*/DataRate::PlusInfinity())
.IsPlusInfinity());
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
not_enough_feedback, DataRate::PlusInfinity());
not_enough_feedback, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
EXPECT_TRUE(
loss_based_bandwidth_estimator.GetBandwidthEstimate().IsPlusInfinity());
loss_based_bandwidth_estimator
.GetBandwidthEstimate(/*delay_based_limit=*/DataRate::PlusInfinity())
.IsPlusInfinity());
}
TEST(LossBasedBweV2Test,
@ -227,21 +239,24 @@ TEST(LossBasedBweV2Test,
loss_based_bandwidth_estimator.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_1, DataRate::PlusInfinity());
enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_NE(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
EXPECT_NE(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_2, DataRate::PlusInfinity());
enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_NE(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
EXPECT_NE(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
DataRate::KilobitsPerSec(600));
}
@ -279,26 +294,30 @@ TEST(LossBasedBweV2Test,
loss_based_bandwidth_estimator_2.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
enough_feedback_1, DataRate::PlusInfinity());
enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(
enough_feedback_1, DataRate::PlusInfinity());
enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_EQ(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(),
EXPECT_EQ(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
DataRate::KilobitsPerSec(660));
loss_based_bandwidth_estimator_1.SetAcknowledgedBitrate(
DataRate::KilobitsPerSec(600));
EXPECT_EQ(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(),
EXPECT_EQ(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
DataRate::KilobitsPerSec(660));
loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
enough_feedback_2, DataRate::PlusInfinity());
enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(
enough_feedback_2, DataRate::PlusInfinity());
enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_NE(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(),
loss_based_bandwidth_estimator_2.GetBandwidthEstimate());
EXPECT_NE(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
loss_based_bandwidth_estimator_2.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()));
}
TEST(LossBasedBweV2Test,
@ -324,12 +343,187 @@ TEST(LossBasedBweV2Test,
loss_based_bandwidth_estimator.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_no_received_packets, DataRate::PlusInfinity());
enough_feedback_no_received_packets, DataRate::PlusInfinity(),
BandwidthUsage::kBwNormal);
EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate(),
EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
DataRate::KilobitsPerSec(100));
}
// When network is overusing and flag `BackoffWhenOverusing` is true,
// the bandwidth estimate is forced to decrease even if there is no loss yet.
TEST(LossBasedBweV2Test, BandwidthEstimateDecreasesWhenOverusing) {
PacketResult enough_feedback_1[2];
PacketResult enough_feedback_2[2];
enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero();
enough_feedback_1[1].sent_packet.send_time =
Timestamp::Zero() + kObservationDurationLowerBound;
enough_feedback_2[0].sent_packet.send_time =
Timestamp::Zero() + 2 * kObservationDurationLowerBound;
enough_feedback_2[1].sent_packet.send_time =
Timestamp::Zero() + 3 * kObservationDurationLowerBound;
enough_feedback_1[0].receive_time = Timestamp::PlusInfinity();
enough_feedback_1[1].receive_time =
Timestamp::Zero() + 2 * kObservationDurationLowerBound;
enough_feedback_2[0].receive_time = Timestamp::PlusInfinity();
enough_feedback_2[1].receive_time =
Timestamp::Zero() + 4 * kObservationDurationLowerBound;
ExplicitKeyValueConfig key_value_config(
Config(/*enabled=*/true, /*valid=*/true));
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
loss_based_bandwidth_estimator.SetAcknowledgedBitrate(
DataRate::KilobitsPerSec(300));
loss_based_bandwidth_estimator.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_1, DataRate::PlusInfinity(),
BandwidthUsage::kBwOverusing);
EXPECT_LE(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_LE(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
DataRate::KilobitsPerSec(600));
}
TEST(LossBasedBweV2Test, BandwidthEstimateIncreasesWhenUnderusing) {
PacketResult enough_feedback_1[2];
PacketResult enough_feedback_2[2];
enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero();
enough_feedback_1[1].sent_packet.send_time =
Timestamp::Zero() + kObservationDurationLowerBound;
enough_feedback_2[0].sent_packet.send_time =
Timestamp::Zero() + 2 * kObservationDurationLowerBound;
enough_feedback_2[1].sent_packet.send_time =
Timestamp::Zero() + 3 * kObservationDurationLowerBound;
enough_feedback_1[0].receive_time =
Timestamp::Zero() + kObservationDurationLowerBound;
enough_feedback_1[1].receive_time =
Timestamp::Zero() + 2 * kObservationDurationLowerBound;
enough_feedback_2[0].receive_time =
Timestamp::Zero() + 3 * kObservationDurationLowerBound;
enough_feedback_2[1].receive_time =
Timestamp::Zero() + 4 * kObservationDurationLowerBound;
ExplicitKeyValueConfig key_value_config(
Config(/*enabled=*/true, /*valid=*/true));
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
loss_based_bandwidth_estimator.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_1, DataRate::PlusInfinity(),
BandwidthUsage::kBwUnderusing);
EXPECT_GT(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_GT(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
DataRate::KilobitsPerSec(600));
}
TEST(LossBasedBweV2Test,
BandwidthEstimateCappedByDelayBasedEstimateWhenUnderusing) {
PacketResult enough_feedback_1[2];
PacketResult enough_feedback_2[2];
enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero();
enough_feedback_1[1].sent_packet.send_time =
Timestamp::Zero() + kObservationDurationLowerBound;
enough_feedback_2[0].sent_packet.send_time =
Timestamp::Zero() + 2 * kObservationDurationLowerBound;
enough_feedback_2[1].sent_packet.send_time =
Timestamp::Zero() + 3 * kObservationDurationLowerBound;
enough_feedback_1[0].receive_time =
Timestamp::Zero() + kObservationDurationLowerBound;
enough_feedback_1[1].receive_time =
Timestamp::Zero() + 2 * kObservationDurationLowerBound;
enough_feedback_2[0].receive_time =
Timestamp::Zero() + 3 * kObservationDurationLowerBound;
enough_feedback_2[1].receive_time =
Timestamp::Zero() + 4 * kObservationDurationLowerBound;
ExplicitKeyValueConfig key_value_config(
Config(/*enabled=*/true, /*valid=*/true));
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
loss_based_bandwidth_estimator.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_1, DataRate::PlusInfinity(),
BandwidthUsage::kBwUnderusing);
EXPECT_GT(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
DataRate::KilobitsPerSec(600));
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::KilobitsPerSec(500)),
DataRate::KilobitsPerSec(500));
}
TEST(LossBasedBweV2Test, NotUseAckedBitrateInNormalState) {
PacketResult enough_feedback_1[2];
PacketResult enough_feedback_2[2];
enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000);
enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero();
enough_feedback_1[1].sent_packet.send_time =
Timestamp::Zero() + kObservationDurationLowerBound;
enough_feedback_2[0].sent_packet.send_time =
Timestamp::Zero() + 2 * kObservationDurationLowerBound;
enough_feedback_2[1].sent_packet.send_time =
Timestamp::Zero() + 3 * kObservationDurationLowerBound;
enough_feedback_1[0].receive_time =
Timestamp::Zero() + kObservationDurationLowerBound;
enough_feedback_1[1].receive_time =
Timestamp::Zero() + 2 * kObservationDurationLowerBound;
enough_feedback_2[0].receive_time =
Timestamp::Zero() + 3 * kObservationDurationLowerBound;
enough_feedback_2[1].receive_time =
Timestamp::Zero() + 4 * kObservationDurationLowerBound;
ExplicitKeyValueConfig key_value_config(
Config(/*enabled=*/true, /*valid=*/true));
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
loss_based_bandwidth_estimator.SetBandwidthEstimate(
DataRate::KilobitsPerSec(600));
DataRate acked_bitrate = DataRate::KilobitsPerSec(300);
loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_bitrate);
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_GT(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
acked_bitrate);
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
EXPECT_GT(loss_based_bandwidth_estimator.GetBandwidthEstimate(
/*delay_based_limit=*/DataRate::PlusInfinity()),
acked_bitrate);
}
} // namespace
} // namespace webrtc

View File

@ -17,6 +17,7 @@
#include <string>
#include "absl/strings/match.h"
#include "api/network_state_predictor.h"
#include "api/rtc_event_log/rtc_event.h"
#include "api/rtc_event_log/rtc_event_log.h"
#include "api/transport/webrtc_key_value_config.h"
@ -229,7 +230,8 @@ SendSideBandwidthEstimation::SendSideBandwidthEstimation(
bitrate_threshold_(kDefaultBitrateThreshold),
loss_based_bandwidth_estimator_v1_(key_value_config),
loss_based_bandwidth_estimator_v2_(key_value_config),
disable_receiver_limit_caps_only_("Disabled") {
disable_receiver_limit_caps_only_("Disabled"),
delay_detector_state_(BandwidthUsage::kBwNormal) {
RTC_DCHECK(event_log);
if (BweLossExperimentIsEnabled()) {
uint32_t bitrate_threshold_kbps;
@ -271,6 +273,7 @@ void SendSideBandwidthEstimation::OnRouteChange() {
uma_update_state_ = kNoUpdate;
uma_rtt_state_ = kNoUpdate;
last_rtc_event_log_ = Timestamp::MinusInfinity();
delay_detector_state_ = BandwidthUsage::kBwNormal;
}
void SendSideBandwidthEstimation::SetBitrates(
@ -330,9 +333,12 @@ void SendSideBandwidthEstimation::UpdateReceiverEstimate(Timestamp at_time,
ApplyTargetLimits(at_time);
}
void SendSideBandwidthEstimation::UpdateDelayBasedEstimate(Timestamp at_time,
DataRate bitrate) {
void SendSideBandwidthEstimation::UpdateDelayBasedEstimate(
Timestamp at_time,
DataRate bitrate,
BandwidthUsage delay_detector_state) {
link_capacity_.UpdateDelayBasedEstimate(at_time, bitrate);
delay_detector_state_ = delay_detector_state;
// TODO(srte): Ensure caller passes PlusInfinity, not zero, to represent no
// limitation.
delay_based_limit_ = bitrate.IsZero() ? DataRate::PlusInfinity() : bitrate;
@ -356,7 +362,7 @@ void SendSideBandwidthEstimation::SetAcknowledgedRate(
}
}
void SendSideBandwidthEstimation::IncomingPacketFeedbackVector(
void SendSideBandwidthEstimation::UpdateLossBasedEstimatorFromFeedbackVector(
const TransportPacketsFeedback& report) {
if (LossBasedBandwidthEstimatorV1Enabled()) {
loss_based_bandwidth_estimator_v1_.UpdateLossStatistics(
@ -364,7 +370,7 @@ void SendSideBandwidthEstimation::IncomingPacketFeedbackVector(
}
if (LossBasedBandwidthEstimatorV2Enabled()) {
loss_based_bandwidth_estimator_v2_.UpdateBandwidthEstimate(
report.packet_feedbacks, delay_based_limit_);
report.packet_feedbacks, delay_based_limit_, delay_detector_state_);
}
}
@ -509,8 +515,8 @@ void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) {
if (LossBasedBandwidthEstimatorV2ReadyForUse()) {
DataRate new_bitrate =
loss_based_bandwidth_estimator_v2_.GetBandwidthEstimate();
new_bitrate = std::min(new_bitrate, delay_based_limit_);
loss_based_bandwidth_estimator_v2_.GetBandwidthEstimate(
delay_based_limit_);
UpdateTargetBitrate(new_bitrate, at_time);
return;
}

View File

@ -20,6 +20,7 @@
#include <vector>
#include "absl/types/optional.h"
#include "api/network_state_predictor.h"
#include "api/transport/network_types.h"
#include "api/transport/webrtc_key_value_config.h"
#include "api/units/data_rate.h"
@ -97,7 +98,9 @@ class SendSideBandwidthEstimation {
void UpdateReceiverEstimate(Timestamp at_time, DataRate bandwidth);
// Call when a new delay-based estimate is available.
void UpdateDelayBasedEstimate(Timestamp at_time, DataRate bitrate);
void UpdateDelayBasedEstimate(Timestamp at_time,
DataRate bitrate,
BandwidthUsage delay_detector_state);
// Call when we receive a RTCP message with a ReceiveBlock.
void UpdatePacketsLost(int64_t packets_lost,
@ -116,7 +119,8 @@ class SendSideBandwidthEstimation {
int GetMinBitrate() const;
void SetAcknowledgedRate(absl::optional<DataRate> acknowledged_rate,
Timestamp at_time);
void IncomingPacketFeedbackVector(const TransportPacketsFeedback& report);
void UpdateLossBasedEstimatorFromFeedbackVector(
const TransportPacketsFeedback& report);
private:
friend class GoogCcStatePrinter;
@ -199,6 +203,7 @@ class SendSideBandwidthEstimation {
LossBasedBandwidthEstimation loss_based_bandwidth_estimator_v1_;
LossBasedBweV2 loss_based_bandwidth_estimator_v2_;
FieldTrialFlag disable_receiver_limit_caps_only_;
BandwidthUsage delay_detector_state_;
};
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_SEND_SIDE_BANDWIDTH_ESTIMATION_H_

View File

@ -10,6 +10,7 @@
#include "modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h"
#include "api/network_state_predictor.h"
#include "api/rtc_event_log/rtc_event.h"
#include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h"
#include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
@ -54,7 +55,8 @@ void TestProbing(bool use_delay_based) {
// Initial REMB applies immediately.
if (use_delay_based) {
bwe.UpdateDelayBasedEstimate(Timestamp::Millis(now_ms),
DataRate::BitsPerSec(kRembBps));
DataRate::BitsPerSec(kRembBps),
BandwidthUsage::kBwNormal);
} else {
bwe.UpdateReceiverEstimate(Timestamp::Millis(now_ms),
DataRate::BitsPerSec(kRembBps));
@ -66,7 +68,8 @@ void TestProbing(bool use_delay_based) {
now_ms += 2001;
if (use_delay_based) {
bwe.UpdateDelayBasedEstimate(Timestamp::Millis(now_ms),
DataRate::BitsPerSec(kSecondRembBps));
DataRate::BitsPerSec(kSecondRembBps),
BandwidthUsage::kBwNormal);
} else {
bwe.UpdateReceiverEstimate(Timestamp::Millis(now_ms),
DataRate::BitsPerSec(kSecondRembBps));
@ -157,7 +160,8 @@ TEST(SendSideBweTest, SettingSendBitrateOverridesDelayBasedEstimate) {
Timestamp::Millis(now_ms));
bwe.UpdateDelayBasedEstimate(Timestamp::Millis(now_ms),
DataRate::BitsPerSec(kDelayBasedBitrateBps));
DataRate::BitsPerSec(kDelayBasedBitrateBps),
BandwidthUsage::kBwNormal);
bwe.UpdateEstimate(Timestamp::Millis(now_ms));
EXPECT_GE(bwe.target_rate().bps(), kInitialBitrateBps);
EXPECT_LE(bwe.target_rate().bps(), kDelayBasedBitrateBps);