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:
@ -153,6 +153,7 @@ rtc_library("loss_based_bwe_v2") {
|
|||||||
]
|
]
|
||||||
deps = [
|
deps = [
|
||||||
"../../../api:array_view",
|
"../../../api:array_view",
|
||||||
|
"../../../api:network_state_predictor_api",
|
||||||
"../../../api/transport:network_control",
|
"../../../api/transport:network_control",
|
||||||
"../../../api/transport:webrtc_key_value_config",
|
"../../../api/transport:webrtc_key_value_config",
|
||||||
"../../../api/units:data_rate",
|
"../../../api/units:data_rate",
|
||||||
@ -195,6 +196,7 @@ rtc_library("send_side_bwe") {
|
|||||||
deps = [
|
deps = [
|
||||||
":loss_based_bwe_v1",
|
":loss_based_bwe_v1",
|
||||||
":loss_based_bwe_v2",
|
":loss_based_bwe_v2",
|
||||||
|
"../../../api:network_state_predictor_api",
|
||||||
"../../../api/rtc_event_log",
|
"../../../api/rtc_event_log",
|
||||||
"../../../api/transport:network_control",
|
"../../../api/transport:network_control",
|
||||||
"../../../api/transport:webrtc_key_value_config",
|
"../../../api/transport:webrtc_key_value_config",
|
||||||
@ -325,6 +327,7 @@ if (rtc_include_tests) {
|
|||||||
":probe_controller",
|
":probe_controller",
|
||||||
":pushback_controller",
|
":pushback_controller",
|
||||||
":send_side_bwe",
|
":send_side_bwe",
|
||||||
|
"../../../api:network_state_predictor_api",
|
||||||
"../../../api/rtc_event_log",
|
"../../../api/rtc_event_log",
|
||||||
"../../../api/test/network_emulation",
|
"../../../api/test/network_emulation",
|
||||||
"../../../api/test/network_emulation:create_cross_traffic",
|
"../../../api/test/network_emulation:create_cross_traffic",
|
||||||
|
@ -193,11 +193,10 @@ void DelayBasedBwe::IncomingPacketFeedback(const PacketResult& packet_feedback,
|
|||||||
packet_feedback.sent_packet.send_time, packet_feedback.receive_time,
|
packet_feedback.sent_packet.send_time, packet_feedback.receive_time,
|
||||||
at_time, packet_size.bytes(), &send_delta, &recv_delta, &size_delta);
|
at_time, packet_size.bytes(), &send_delta, &recv_delta, &size_delta);
|
||||||
|
|
||||||
delay_detector_for_packet->Update(
|
delay_detector_for_packet->Update(recv_delta.ms(), send_delta.ms(),
|
||||||
recv_delta.ms(), send_delta.ms(),
|
|
||||||
packet_feedback.sent_packet.send_time.ms(),
|
packet_feedback.sent_packet.send_time.ms(),
|
||||||
packet_feedback.receive_time.ms(), packet_size.bytes(),
|
packet_feedback.receive_time.ms(),
|
||||||
calculated_deltas);
|
packet_size.bytes(), calculated_deltas);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataRate DelayBasedBwe::TriggerOveruse(Timestamp at_time,
|
DataRate DelayBasedBwe::TriggerOveruse(Timestamp at_time,
|
||||||
@ -266,6 +265,8 @@ DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
|
|||||||
prev_bitrate_ = bitrate;
|
prev_bitrate_ = bitrate;
|
||||||
prev_state_ = detector_state;
|
prev_state_ = detector_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.delay_detector_state = detector_state;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ class DelayBasedBwe {
|
|||||||
DataRate target_bitrate = DataRate::Zero();
|
DataRate target_bitrate = DataRate::Zero();
|
||||||
bool recovered_from_overuse;
|
bool recovered_from_overuse;
|
||||||
bool backoff_in_alr;
|
bool backoff_in_alr;
|
||||||
|
BandwidthUsage delay_detector_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config,
|
explicit DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config,
|
||||||
|
@ -495,7 +495,6 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(
|
|||||||
auto acknowledged_bitrate = acknowledged_bitrate_estimator_->bitrate();
|
auto acknowledged_bitrate = acknowledged_bitrate_estimator_->bitrate();
|
||||||
bandwidth_estimation_->SetAcknowledgedRate(acknowledged_bitrate,
|
bandwidth_estimation_->SetAcknowledgedRate(acknowledged_bitrate,
|
||||||
report.feedback_time);
|
report.feedback_time);
|
||||||
bandwidth_estimation_->IncomingPacketFeedbackVector(report);
|
|
||||||
for (const auto& feedback : report.SortedByReceiveTime()) {
|
for (const auto& feedback : report.SortedByReceiveTime()) {
|
||||||
if (feedback.sent_packet.pacing_info.probe_cluster_id !=
|
if (feedback.sent_packet.pacing_info.probe_cluster_id !=
|
||||||
PacedPacketInfo::kNotAProbe) {
|
PacedPacketInfo::kNotAProbe) {
|
||||||
@ -553,11 +552,13 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(
|
|||||||
}
|
}
|
||||||
// Since SetSendBitrate now resets the delay-based estimate, we have to
|
// Since SetSendBitrate now resets the delay-based estimate, we have to
|
||||||
// call UpdateDelayBasedEstimate after SetSendBitrate.
|
// call UpdateDelayBasedEstimate after SetSendBitrate.
|
||||||
bandwidth_estimation_->UpdateDelayBasedEstimate(report.feedback_time,
|
bandwidth_estimation_->UpdateDelayBasedEstimate(
|
||||||
result.target_bitrate);
|
report.feedback_time, result.target_bitrate,
|
||||||
|
result.delay_detector_state);
|
||||||
// Update the estimate in the ProbeController, in case we want to probe.
|
// Update the estimate in the ProbeController, in case we want to probe.
|
||||||
MaybeTriggerOnNetworkChanged(&update, report.feedback_time);
|
MaybeTriggerOnNetworkChanged(&update, report.feedback_time);
|
||||||
}
|
}
|
||||||
|
bandwidth_estimation_->UpdateLossBasedEstimatorFromFeedbackVector(report);
|
||||||
recovered_from_overuse = result.recovered_from_overuse;
|
recovered_from_overuse = result.recovered_from_overuse;
|
||||||
backoff_in_alr = result.backoff_in_alr;
|
backoff_in_alr = result.backoff_in_alr;
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "absl/algorithm/container.h"
|
#include "absl/algorithm/container.h"
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
|
#include "api/network_state_predictor.h"
|
||||||
#include "api/transport/network_types.h"
|
#include "api/transport/network_types.h"
|
||||||
#include "api/transport/webrtc_key_value_config.h"
|
#include "api/transport/webrtc_key_value_config.h"
|
||||||
#include "api/units/data_rate.h"
|
#include "api/units/data_rate.h"
|
||||||
@ -89,18 +90,11 @@ double GetLossProbability(double inherent_loss,
|
|||||||
<< ToString(loss_limited_bandwidth);
|
<< 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;
|
double loss_probability = inherent_loss;
|
||||||
if (IsValid(sending_rate) && IsValid(loss_limited_bandwidth) &&
|
if (IsValid(sending_rate) && IsValid(loss_limited_bandwidth) &&
|
||||||
(sending_rate > 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);
|
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;
|
num_observations_ > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataRate LossBasedBweV2::GetBandwidthEstimate() const {
|
DataRate LossBasedBweV2::GetBandwidthEstimate(
|
||||||
|
DataRate delay_based_limit) const {
|
||||||
if (!IsReady()) {
|
if (!IsReady()) {
|
||||||
if (!IsEnabled()) {
|
if (!IsEnabled()) {
|
||||||
RTC_LOG(LS_WARNING)
|
RTC_LOG(LS_WARNING)
|
||||||
@ -156,8 +151,14 @@ DataRate LossBasedBweV2::GetBandwidthEstimate() const {
|
|||||||
return DataRate::PlusInfinity();
|
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,
|
return std::min(current_estimate_.loss_limited_bandwidth,
|
||||||
GetInstantUpperBound());
|
GetInstantUpperBound());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LossBasedBweV2::SetAcknowledgedBitrate(DataRate acknowledged_bitrate) {
|
void LossBasedBweV2::SetAcknowledgedBitrate(DataRate acknowledged_bitrate) {
|
||||||
@ -180,7 +181,8 @@ void LossBasedBweV2::SetBandwidthEstimate(DataRate bandwidth_estimate) {
|
|||||||
|
|
||||||
void LossBasedBweV2::UpdateBandwidthEstimate(
|
void LossBasedBweV2::UpdateBandwidthEstimate(
|
||||||
rtc::ArrayView<const PacketResult> packet_results,
|
rtc::ArrayView<const PacketResult> packet_results,
|
||||||
DataRate delay_based_estimate) {
|
DataRate delay_based_estimate,
|
||||||
|
BandwidthUsage delay_detector_state) {
|
||||||
if (!IsEnabled()) {
|
if (!IsEnabled()) {
|
||||||
RTC_LOG(LS_WARNING)
|
RTC_LOG(LS_WARNING)
|
||||||
<< "The estimator must be enabled before it can be used.";
|
<< "The estimator must be enabled before it can be used.";
|
||||||
@ -192,7 +194,7 @@ void LossBasedBweV2::UpdateBandwidthEstimate(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PushBackObservation(packet_results)) {
|
if (!PushBackObservation(packet_results, delay_detector_state)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,6 +266,15 @@ absl::optional<LossBasedBweV2::Config> LossBasedBweV2::CreateConfig(
|
|||||||
"InstantUpperBoundLossOffset", 0.05);
|
"InstantUpperBoundLossOffset", 0.05);
|
||||||
FieldTrialParameter<double> temporal_weight_factor("TemporalWeightFactor",
|
FieldTrialParameter<double> temporal_weight_factor("TemporalWeightFactor",
|
||||||
0.99);
|
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) {
|
if (key_value_config) {
|
||||||
ParseFieldTrial({&enabled,
|
ParseFieldTrial({&enabled,
|
||||||
@ -287,7 +298,12 @@ absl::optional<LossBasedBweV2::Config> LossBasedBweV2::CreateConfig(
|
|||||||
&instant_upper_bound_temporal_weight_factor,
|
&instant_upper_bound_temporal_weight_factor,
|
||||||
&instant_upper_bound_bandwidth_balance,
|
&instant_upper_bound_bandwidth_balance,
|
||||||
&instant_upper_bound_loss_offset,
|
&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"));
|
key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,6 +344,12 @@ absl::optional<LossBasedBweV2::Config> LossBasedBweV2::CreateConfig(
|
|||||||
config->instant_upper_bound_loss_offset =
|
config->instant_upper_bound_loss_offset =
|
||||||
instant_upper_bound_loss_offset.Get();
|
instant_upper_bound_loss_offset.Get();
|
||||||
config->temporal_weight_factor = temporal_weight_factor.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;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,7 +492,24 @@ bool LossBasedBweV2::IsConfigValid() const {
|
|||||||
<< config_->temporal_weight_factor;
|
<< config_->temporal_weight_factor;
|
||||||
valid = false;
|
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;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,20 +560,36 @@ DataRate LossBasedBweV2::GetCandidateBandwidthUpperBound() const {
|
|||||||
std::vector<LossBasedBweV2::ChannelParameters> LossBasedBweV2::GetCandidates(
|
std::vector<LossBasedBweV2::ChannelParameters> LossBasedBweV2::GetCandidates(
|
||||||
DataRate delay_based_estimate) const {
|
DataRate delay_based_estimate) const {
|
||||||
std::vector<DataRate> bandwidths;
|
std::vector<DataRate> bandwidths;
|
||||||
|
bool can_increase_bitrate = TrendlineEsimateAllowBitrateIncrease();
|
||||||
|
bool can_decrease_bitrate = TrendlineEsimateAllowBitrateDecrease();
|
||||||
for (double candidate_factor : config_->candidate_factors) {
|
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 *
|
bandwidths.push_back(candidate_factor *
|
||||||
current_estimate_.loss_limited_bandwidth);
|
current_estimate_.loss_limited_bandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acknowledged_bitrate_.has_value() &&
|
if (acknowledged_bitrate_.has_value() &&
|
||||||
config_->append_acknowledged_rate_candidate) {
|
config_->append_acknowledged_rate_candidate && can_decrease_bitrate) {
|
||||||
bandwidths.push_back(*acknowledged_bitrate_);
|
bandwidths.push_back(*acknowledged_bitrate_ *
|
||||||
|
config_->bandwidth_backoff_lower_bound_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsValid(delay_based_estimate) &&
|
if (IsValid(delay_based_estimate) &&
|
||||||
config_->append_delay_based_estimate_candidate) {
|
config_->append_delay_based_estimate_candidate) {
|
||||||
|
if (can_increase_bitrate &&
|
||||||
|
delay_based_estimate > current_estimate_.loss_limited_bandwidth) {
|
||||||
bandwidths.push_back(delay_based_estimate);
|
bandwidths.push_back(delay_based_estimate);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const DataRate candidate_bandwidth_upper_bound =
|
const DataRate candidate_bandwidth_upper_bound =
|
||||||
GetCandidateBandwidthUpperBound();
|
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(
|
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()) {
|
if (packet_results.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -729,7 +823,9 @@ bool LossBasedBweV2::PushBackObservation(
|
|||||||
last_send_time - last_send_time_most_recent_observation_;
|
last_send_time - last_send_time_most_recent_observation_;
|
||||||
|
|
||||||
// Too small to be meaningful.
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,10 +12,12 @@
|
|||||||
#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_LOSS_BASED_BWE_V2_H_
|
#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_LOSS_BASED_BWE_V2_H_
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <deque>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
|
#include "api/network_state_predictor.h"
|
||||||
#include "api/transport/network_types.h"
|
#include "api/transport/network_types.h"
|
||||||
#include "api/transport/webrtc_key_value_config.h"
|
#include "api/transport/webrtc_key_value_config.h"
|
||||||
#include "api/units/data_rate.h"
|
#include "api/units/data_rate.h"
|
||||||
@ -42,14 +44,15 @@ class LossBasedBweV2 {
|
|||||||
bool IsReady() const;
|
bool IsReady() const;
|
||||||
|
|
||||||
// Returns `DataRate::PlusInfinity` if no BWE can be calculated.
|
// 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 SetAcknowledgedBitrate(DataRate acknowledged_bitrate);
|
||||||
void SetBandwidthEstimate(DataRate bandwidth_estimate);
|
void SetBandwidthEstimate(DataRate bandwidth_estimate);
|
||||||
|
|
||||||
void UpdateBandwidthEstimate(
|
void UpdateBandwidthEstimate(
|
||||||
rtc::ArrayView<const PacketResult> packet_results,
|
rtc::ArrayView<const PacketResult> packet_results,
|
||||||
DataRate delay_based_estimate);
|
DataRate delay_based_estimate,
|
||||||
|
BandwidthUsage delay_detector_state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct ChannelParameters {
|
struct ChannelParameters {
|
||||||
@ -80,6 +83,11 @@ class LossBasedBweV2 {
|
|||||||
DataRate instant_upper_bound_bandwidth_balance = DataRate::MinusInfinity();
|
DataRate instant_upper_bound_bandwidth_balance = DataRate::MinusInfinity();
|
||||||
double instant_upper_bound_loss_offset = 0.0;
|
double instant_upper_bound_loss_offset = 0.0;
|
||||||
double temporal_weight_factor = 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 {
|
struct Derivatives {
|
||||||
@ -124,9 +132,21 @@ class LossBasedBweV2 {
|
|||||||
|
|
||||||
void CalculateTemporalWeights();
|
void CalculateTemporalWeights();
|
||||||
void NewtonsMethodUpdate(ChannelParameters& channel_parameters) const;
|
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.
|
// 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<DataRate> acknowledged_bitrate_;
|
||||||
absl::optional<Config> config_;
|
absl::optional<Config> config_;
|
||||||
@ -139,6 +159,7 @@ class LossBasedBweV2 {
|
|||||||
absl::optional<DataRate> cached_instant_upper_bound_;
|
absl::optional<DataRate> cached_instant_upper_bound_;
|
||||||
std::vector<double> instant_upper_bound_temporal_weights_;
|
std::vector<double> instant_upper_bound_temporal_weights_;
|
||||||
std::vector<double> temporal_weights_;
|
std::vector<double> temporal_weights_;
|
||||||
|
std::deque<BandwidthUsage> delay_detector_states_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "api/network_state_predictor.h"
|
||||||
#include "api/transport/network_types.h"
|
#include "api/transport/network_types.h"
|
||||||
#include "api/units/data_rate.h"
|
#include "api/units/data_rate.h"
|
||||||
#include "api/units/data_size.h"
|
#include "api/units/data_size.h"
|
||||||
@ -48,14 +49,16 @@ std::string Config(bool enabled, bool valid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
config_string
|
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,"
|
"InherentLossLowerBound:0.001,InherentLossUpperBoundBwBalance:14kbps,"
|
||||||
"InherentLossUpperBoundOffset:0.9,InitialInherentLossEstimate:0.01,"
|
"InherentLossUpperBoundOffset:0.9,InitialInherentLossEstimate:0.01,"
|
||||||
"NewtonIterations:2,NewtonStepSize:0.4,ObservationWindowSize:15,"
|
"NewtonIterations:2,NewtonStepSize:0.4,ObservationWindowSize:15,"
|
||||||
"SendingRateSmoothingFactor:0.01,"
|
"SendingRateSmoothingFactor:0.01,"
|
||||||
"InstantUpperBoundTemporalWeightFactor:0.97,"
|
"InstantUpperBoundTemporalWeightFactor:0.97,"
|
||||||
"InstantUpperBoundBwBalance:90kbps,"
|
"InstantUpperBoundBwBalance:90kbps,"
|
||||||
"InstantUpperBoundLossOffset:0.1,TemporalWeightFactor:0.98";
|
"InstantUpperBoundLossOffset:0.1,TemporalWeightFactor:0.98,"
|
||||||
|
"BackoffWhenOverusing:true";
|
||||||
|
|
||||||
config_string.AppendFormat(
|
config_string.AppendFormat(
|
||||||
",ObservationDurationLowerBound:%dms",
|
",ObservationDurationLowerBound:%dms",
|
||||||
@ -133,10 +136,13 @@ TEST(LossBasedBweV2Test, BandwidthEstimateGivenInitializationAndThenFeedback) {
|
|||||||
loss_based_bandwidth_estimator.SetBandwidthEstimate(
|
loss_based_bandwidth_estimator.SetBandwidthEstimate(
|
||||||
DataRate::KilobitsPerSec(600));
|
DataRate::KilobitsPerSec(600));
|
||||||
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
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.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) {
|
TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) {
|
||||||
@ -156,11 +162,13 @@ TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) {
|
|||||||
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
|
LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config);
|
||||||
|
|
||||||
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
||||||
enough_feedback, DataRate::PlusInfinity());
|
enough_feedback, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
|
||||||
|
|
||||||
EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
|
EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
loss_based_bandwidth_estimator.GetBandwidthEstimate().IsPlusInfinity());
|
loss_based_bandwidth_estimator
|
||||||
|
.GetBandwidthEstimate(/*delay_based_limit=*/DataRate::PlusInfinity())
|
||||||
|
.IsPlusInfinity());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) {
|
TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) {
|
||||||
@ -186,14 +194,18 @@ TEST(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) {
|
|||||||
|
|
||||||
EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
|
EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady());
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
loss_based_bandwidth_estimator.GetBandwidthEstimate().IsPlusInfinity());
|
loss_based_bandwidth_estimator
|
||||||
|
.GetBandwidthEstimate(/*delay_based_limit=*/DataRate::PlusInfinity())
|
||||||
|
.IsPlusInfinity());
|
||||||
|
|
||||||
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
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_FALSE(loss_based_bandwidth_estimator.IsReady());
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
loss_based_bandwidth_estimator.GetBandwidthEstimate().IsPlusInfinity());
|
loss_based_bandwidth_estimator
|
||||||
|
.GetBandwidthEstimate(/*delay_based_limit=*/DataRate::PlusInfinity())
|
||||||
|
.IsPlusInfinity());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(LossBasedBweV2Test,
|
TEST(LossBasedBweV2Test,
|
||||||
@ -227,21 +239,24 @@ TEST(LossBasedBweV2Test,
|
|||||||
loss_based_bandwidth_estimator.SetBandwidthEstimate(
|
loss_based_bandwidth_estimator.SetBandwidthEstimate(
|
||||||
DataRate::KilobitsPerSec(600));
|
DataRate::KilobitsPerSec(600));
|
||||||
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
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));
|
DataRate::KilobitsPerSec(600));
|
||||||
|
|
||||||
loss_based_bandwidth_estimator.SetBandwidthEstimate(
|
loss_based_bandwidth_estimator.SetBandwidthEstimate(
|
||||||
DataRate::KilobitsPerSec(600));
|
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));
|
DataRate::KilobitsPerSec(600));
|
||||||
|
|
||||||
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
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));
|
DataRate::KilobitsPerSec(600));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,26 +294,30 @@ TEST(LossBasedBweV2Test,
|
|||||||
loss_based_bandwidth_estimator_2.SetBandwidthEstimate(
|
loss_based_bandwidth_estimator_2.SetBandwidthEstimate(
|
||||||
DataRate::KilobitsPerSec(600));
|
DataRate::KilobitsPerSec(600));
|
||||||
loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
|
loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
|
||||||
enough_feedback_1, DataRate::PlusInfinity());
|
enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
|
||||||
loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(
|
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));
|
DataRate::KilobitsPerSec(660));
|
||||||
|
|
||||||
loss_based_bandwidth_estimator_1.SetAcknowledgedBitrate(
|
loss_based_bandwidth_estimator_1.SetAcknowledgedBitrate(
|
||||||
DataRate::KilobitsPerSec(600));
|
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));
|
DataRate::KilobitsPerSec(660));
|
||||||
|
|
||||||
loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
|
loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate(
|
||||||
enough_feedback_2, DataRate::PlusInfinity());
|
enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal);
|
||||||
loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate(
|
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(),
|
EXPECT_NE(loss_based_bandwidth_estimator_1.GetBandwidthEstimate(
|
||||||
loss_based_bandwidth_estimator_2.GetBandwidthEstimate());
|
/*delay_based_limit=*/DataRate::PlusInfinity()),
|
||||||
|
loss_based_bandwidth_estimator_2.GetBandwidthEstimate(
|
||||||
|
/*delay_based_limit=*/DataRate::PlusInfinity()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(LossBasedBweV2Test,
|
TEST(LossBasedBweV2Test,
|
||||||
@ -324,12 +343,187 @@ TEST(LossBasedBweV2Test,
|
|||||||
loss_based_bandwidth_estimator.SetBandwidthEstimate(
|
loss_based_bandwidth_estimator.SetBandwidthEstimate(
|
||||||
DataRate::KilobitsPerSec(600));
|
DataRate::KilobitsPerSec(600));
|
||||||
loss_based_bandwidth_estimator.UpdateBandwidthEstimate(
|
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));
|
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
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "absl/strings/match.h"
|
#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.h"
|
||||||
#include "api/rtc_event_log/rtc_event_log.h"
|
#include "api/rtc_event_log/rtc_event_log.h"
|
||||||
#include "api/transport/webrtc_key_value_config.h"
|
#include "api/transport/webrtc_key_value_config.h"
|
||||||
@ -229,7 +230,8 @@ SendSideBandwidthEstimation::SendSideBandwidthEstimation(
|
|||||||
bitrate_threshold_(kDefaultBitrateThreshold),
|
bitrate_threshold_(kDefaultBitrateThreshold),
|
||||||
loss_based_bandwidth_estimator_v1_(key_value_config),
|
loss_based_bandwidth_estimator_v1_(key_value_config),
|
||||||
loss_based_bandwidth_estimator_v2_(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);
|
RTC_DCHECK(event_log);
|
||||||
if (BweLossExperimentIsEnabled()) {
|
if (BweLossExperimentIsEnabled()) {
|
||||||
uint32_t bitrate_threshold_kbps;
|
uint32_t bitrate_threshold_kbps;
|
||||||
@ -271,6 +273,7 @@ void SendSideBandwidthEstimation::OnRouteChange() {
|
|||||||
uma_update_state_ = kNoUpdate;
|
uma_update_state_ = kNoUpdate;
|
||||||
uma_rtt_state_ = kNoUpdate;
|
uma_rtt_state_ = kNoUpdate;
|
||||||
last_rtc_event_log_ = Timestamp::MinusInfinity();
|
last_rtc_event_log_ = Timestamp::MinusInfinity();
|
||||||
|
delay_detector_state_ = BandwidthUsage::kBwNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendSideBandwidthEstimation::SetBitrates(
|
void SendSideBandwidthEstimation::SetBitrates(
|
||||||
@ -330,9 +333,12 @@ void SendSideBandwidthEstimation::UpdateReceiverEstimate(Timestamp at_time,
|
|||||||
ApplyTargetLimits(at_time);
|
ApplyTargetLimits(at_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendSideBandwidthEstimation::UpdateDelayBasedEstimate(Timestamp at_time,
|
void SendSideBandwidthEstimation::UpdateDelayBasedEstimate(
|
||||||
DataRate bitrate) {
|
Timestamp at_time,
|
||||||
|
DataRate bitrate,
|
||||||
|
BandwidthUsage delay_detector_state) {
|
||||||
link_capacity_.UpdateDelayBasedEstimate(at_time, bitrate);
|
link_capacity_.UpdateDelayBasedEstimate(at_time, bitrate);
|
||||||
|
delay_detector_state_ = delay_detector_state;
|
||||||
// TODO(srte): Ensure caller passes PlusInfinity, not zero, to represent no
|
// TODO(srte): Ensure caller passes PlusInfinity, not zero, to represent no
|
||||||
// limitation.
|
// limitation.
|
||||||
delay_based_limit_ = bitrate.IsZero() ? DataRate::PlusInfinity() : bitrate;
|
delay_based_limit_ = bitrate.IsZero() ? DataRate::PlusInfinity() : bitrate;
|
||||||
@ -356,7 +362,7 @@ void SendSideBandwidthEstimation::SetAcknowledgedRate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendSideBandwidthEstimation::IncomingPacketFeedbackVector(
|
void SendSideBandwidthEstimation::UpdateLossBasedEstimatorFromFeedbackVector(
|
||||||
const TransportPacketsFeedback& report) {
|
const TransportPacketsFeedback& report) {
|
||||||
if (LossBasedBandwidthEstimatorV1Enabled()) {
|
if (LossBasedBandwidthEstimatorV1Enabled()) {
|
||||||
loss_based_bandwidth_estimator_v1_.UpdateLossStatistics(
|
loss_based_bandwidth_estimator_v1_.UpdateLossStatistics(
|
||||||
@ -364,7 +370,7 @@ void SendSideBandwidthEstimation::IncomingPacketFeedbackVector(
|
|||||||
}
|
}
|
||||||
if (LossBasedBandwidthEstimatorV2Enabled()) {
|
if (LossBasedBandwidthEstimatorV2Enabled()) {
|
||||||
loss_based_bandwidth_estimator_v2_.UpdateBandwidthEstimate(
|
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()) {
|
if (LossBasedBandwidthEstimatorV2ReadyForUse()) {
|
||||||
DataRate new_bitrate =
|
DataRate new_bitrate =
|
||||||
loss_based_bandwidth_estimator_v2_.GetBandwidthEstimate();
|
loss_based_bandwidth_estimator_v2_.GetBandwidthEstimate(
|
||||||
new_bitrate = std::min(new_bitrate, delay_based_limit_);
|
delay_based_limit_);
|
||||||
UpdateTargetBitrate(new_bitrate, at_time);
|
UpdateTargetBitrate(new_bitrate, at_time);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
|
#include "api/network_state_predictor.h"
|
||||||
#include "api/transport/network_types.h"
|
#include "api/transport/network_types.h"
|
||||||
#include "api/transport/webrtc_key_value_config.h"
|
#include "api/transport/webrtc_key_value_config.h"
|
||||||
#include "api/units/data_rate.h"
|
#include "api/units/data_rate.h"
|
||||||
@ -97,7 +98,9 @@ class SendSideBandwidthEstimation {
|
|||||||
void UpdateReceiverEstimate(Timestamp at_time, DataRate bandwidth);
|
void UpdateReceiverEstimate(Timestamp at_time, DataRate bandwidth);
|
||||||
|
|
||||||
// Call when a new delay-based estimate is available.
|
// 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.
|
// Call when we receive a RTCP message with a ReceiveBlock.
|
||||||
void UpdatePacketsLost(int64_t packets_lost,
|
void UpdatePacketsLost(int64_t packets_lost,
|
||||||
@ -116,7 +119,8 @@ class SendSideBandwidthEstimation {
|
|||||||
int GetMinBitrate() const;
|
int GetMinBitrate() const;
|
||||||
void SetAcknowledgedRate(absl::optional<DataRate> acknowledged_rate,
|
void SetAcknowledgedRate(absl::optional<DataRate> acknowledged_rate,
|
||||||
Timestamp at_time);
|
Timestamp at_time);
|
||||||
void IncomingPacketFeedbackVector(const TransportPacketsFeedback& report);
|
void UpdateLossBasedEstimatorFromFeedbackVector(
|
||||||
|
const TransportPacketsFeedback& report);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class GoogCcStatePrinter;
|
friend class GoogCcStatePrinter;
|
||||||
@ -199,6 +203,7 @@ class SendSideBandwidthEstimation {
|
|||||||
LossBasedBandwidthEstimation loss_based_bandwidth_estimator_v1_;
|
LossBasedBandwidthEstimation loss_based_bandwidth_estimator_v1_;
|
||||||
LossBasedBweV2 loss_based_bandwidth_estimator_v2_;
|
LossBasedBweV2 loss_based_bandwidth_estimator_v2_;
|
||||||
FieldTrialFlag disable_receiver_limit_caps_only_;
|
FieldTrialFlag disable_receiver_limit_caps_only_;
|
||||||
|
BandwidthUsage delay_detector_state_;
|
||||||
};
|
};
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_SEND_SIDE_BANDWIDTH_ESTIMATION_H_
|
#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_SEND_SIDE_BANDWIDTH_ESTIMATION_H_
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h"
|
#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 "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/events/rtc_event_bwe_update_loss_based.h"
|
||||||
#include "logging/rtc_event_log/mock/mock_rtc_event_log.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.
|
// Initial REMB applies immediately.
|
||||||
if (use_delay_based) {
|
if (use_delay_based) {
|
||||||
bwe.UpdateDelayBasedEstimate(Timestamp::Millis(now_ms),
|
bwe.UpdateDelayBasedEstimate(Timestamp::Millis(now_ms),
|
||||||
DataRate::BitsPerSec(kRembBps));
|
DataRate::BitsPerSec(kRembBps),
|
||||||
|
BandwidthUsage::kBwNormal);
|
||||||
} else {
|
} else {
|
||||||
bwe.UpdateReceiverEstimate(Timestamp::Millis(now_ms),
|
bwe.UpdateReceiverEstimate(Timestamp::Millis(now_ms),
|
||||||
DataRate::BitsPerSec(kRembBps));
|
DataRate::BitsPerSec(kRembBps));
|
||||||
@ -66,7 +68,8 @@ void TestProbing(bool use_delay_based) {
|
|||||||
now_ms += 2001;
|
now_ms += 2001;
|
||||||
if (use_delay_based) {
|
if (use_delay_based) {
|
||||||
bwe.UpdateDelayBasedEstimate(Timestamp::Millis(now_ms),
|
bwe.UpdateDelayBasedEstimate(Timestamp::Millis(now_ms),
|
||||||
DataRate::BitsPerSec(kSecondRembBps));
|
DataRate::BitsPerSec(kSecondRembBps),
|
||||||
|
BandwidthUsage::kBwNormal);
|
||||||
} else {
|
} else {
|
||||||
bwe.UpdateReceiverEstimate(Timestamp::Millis(now_ms),
|
bwe.UpdateReceiverEstimate(Timestamp::Millis(now_ms),
|
||||||
DataRate::BitsPerSec(kSecondRembBps));
|
DataRate::BitsPerSec(kSecondRembBps));
|
||||||
@ -157,7 +160,8 @@ TEST(SendSideBweTest, SettingSendBitrateOverridesDelayBasedEstimate) {
|
|||||||
Timestamp::Millis(now_ms));
|
Timestamp::Millis(now_ms));
|
||||||
|
|
||||||
bwe.UpdateDelayBasedEstimate(Timestamp::Millis(now_ms),
|
bwe.UpdateDelayBasedEstimate(Timestamp::Millis(now_ms),
|
||||||
DataRate::BitsPerSec(kDelayBasedBitrateBps));
|
DataRate::BitsPerSec(kDelayBasedBitrateBps),
|
||||||
|
BandwidthUsage::kBwNormal);
|
||||||
bwe.UpdateEstimate(Timestamp::Millis(now_ms));
|
bwe.UpdateEstimate(Timestamp::Millis(now_ms));
|
||||||
EXPECT_GE(bwe.target_rate().bps(), kInitialBitrateBps);
|
EXPECT_GE(bwe.target_rate().bps(), kInitialBitrateBps);
|
||||||
EXPECT_LE(bwe.target_rate().bps(), kDelayBasedBitrateBps);
|
EXPECT_LE(bwe.target_rate().bps(), kDelayBasedBitrateBps);
|
||||||
|
Reference in New Issue
Block a user