Replace int with Timestamp and DataRate in ProbeController
Replace most instances. SetAlrStartTime is set as is should be cleaned up together with the callsite. Bug: webrtc:14404 Change-Id: I8ec532828ef665afbf08f0943465a429ab40baa1 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/273300 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/main@{#37932}
This commit is contained in:
parent
590a965a9f
commit
d6e9749942
@ -262,6 +262,7 @@ rtc_library("probe_controller") {
|
||||
"../../../api/rtc_event_log",
|
||||
"../../../api/transport:network_control",
|
||||
"../../../api/units:data_rate",
|
||||
"../../../api/units:data_size",
|
||||
"../../../api/units:time_delta",
|
||||
"../../../api/units:timestamp",
|
||||
"../../../logging:rtc_event_bwe",
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "absl/strings/match.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_remote_estimate.h"
|
||||
#include "modules/congestion_controller/goog_cc/alr_detector.h"
|
||||
#include "modules/congestion_controller/goog_cc/probe_controller.h"
|
||||
@ -51,15 +52,6 @@ constexpr float kDefaultPaceMultiplier = 2.5f;
|
||||
// below the current throughput estimate to drain the network queues.
|
||||
constexpr double kProbeDropThroughputFraction = 0.85;
|
||||
|
||||
int64_t GetBpsOrDefault(const absl::optional<DataRate>& rate,
|
||||
int64_t fallback_bps) {
|
||||
if (rate && rate->IsFinite()) {
|
||||
return rate->bps();
|
||||
} else {
|
||||
return fallback_bps;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsEnabled(const FieldTrialsView* config, absl::string_view key) {
|
||||
return absl::StartsWith(config->Lookup(key), "Enabled");
|
||||
}
|
||||
@ -173,7 +165,7 @@ NetworkControlUpdate GoogCcNetworkController::OnNetworkRouteChange(
|
||||
delay_based_bwe_.reset(new DelayBasedBwe(key_value_config_, event_log_,
|
||||
network_state_predictor_.get()));
|
||||
bandwidth_estimation_->OnRouteChange();
|
||||
probe_controller_->Reset(msg.at_time.ms());
|
||||
probe_controller_->Reset(msg.at_time);
|
||||
NetworkControlUpdate update;
|
||||
update.probe_cluster_configs = ResetConstraints(msg.constraints);
|
||||
MaybeTriggerOnNetworkChanged(&update, msg.at_time);
|
||||
@ -196,7 +188,7 @@ NetworkControlUpdate GoogCcNetworkController::OnProcessInterval(
|
||||
initial_config_->stream_based_config.max_total_allocated_bitrate;
|
||||
if (total_bitrate) {
|
||||
auto probes = probe_controller_->OnMaxTotalAllocatedBitrate(
|
||||
total_bitrate->bps(), msg.at_time.ms());
|
||||
*total_bitrate, msg.at_time);
|
||||
update.probe_cluster_configs.insert(update.probe_cluster_configs.end(),
|
||||
probes.begin(), probes.end());
|
||||
|
||||
@ -213,7 +205,7 @@ NetworkControlUpdate GoogCcNetworkController::OnProcessInterval(
|
||||
alr_detector_->GetApplicationLimitedRegionStartTime();
|
||||
probe_controller_->SetAlrStartTimeMs(start_time_ms);
|
||||
|
||||
auto probes = probe_controller_->Process(msg.at_time.ms());
|
||||
auto probes = probe_controller_->Process(msg.at_time);
|
||||
update.probe_cluster_configs.insert(update.probe_cluster_configs.end(),
|
||||
probes.begin(), probes.end());
|
||||
|
||||
@ -299,9 +291,9 @@ NetworkControlUpdate GoogCcNetworkController::OnStreamsConfig(
|
||||
if (rate_control_settings_.TriggerProbeOnMaxAllocatedBitrateChange()) {
|
||||
update.probe_cluster_configs =
|
||||
probe_controller_->OnMaxTotalAllocatedBitrate(
|
||||
msg.max_total_allocated_bitrate->bps(), msg.at_time.ms());
|
||||
*msg.max_total_allocated_bitrate, msg.at_time);
|
||||
} else {
|
||||
probe_controller_->SetMaxBitrate(msg.max_total_allocated_bitrate->bps());
|
||||
probe_controller_->SetMaxBitrate(*msg.max_total_allocated_bitrate);
|
||||
}
|
||||
max_total_allocated_bitrate_ = *msg.max_total_allocated_bitrate;
|
||||
}
|
||||
@ -373,8 +365,8 @@ std::vector<ProbeClusterConfig> GoogCcNetworkController::ResetConstraints(
|
||||
delay_based_bwe_->SetMinBitrate(min_data_rate_);
|
||||
|
||||
return probe_controller_->SetBitrates(
|
||||
min_data_rate_.bps(), GetBpsOrDefault(starting_rate_, -1),
|
||||
max_data_rate_.bps_or(-1), new_constraints.at_time.ms());
|
||||
min_data_rate_, starting_rate_.value_or(DataRate::Zero()), max_data_rate_,
|
||||
new_constraints.at_time);
|
||||
}
|
||||
|
||||
NetworkControlUpdate GoogCcNetworkController::OnTransportLossReport(
|
||||
@ -564,7 +556,7 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(
|
||||
|
||||
if (recovered_from_overuse) {
|
||||
probe_controller_->SetAlrStartTimeMs(alr_start_time);
|
||||
auto probes = probe_controller_->RequestProbe(report.feedback_time.ms());
|
||||
auto probes = probe_controller_->RequestProbe(report.feedback_time);
|
||||
update.probe_cluster_configs.insert(update.probe_cluster_configs.end(),
|
||||
probes.begin(), probes.end());
|
||||
}
|
||||
@ -682,8 +674,7 @@ void GoogCcNetworkController::MaybeTriggerOnNetworkChanged(
|
||||
update->target_rate = target_rate_msg;
|
||||
|
||||
auto probes = probe_controller_->SetEstimatedBitrate(
|
||||
loss_based_target_rate.bps(), bwe_limited_due_to_packet_loss,
|
||||
at_time.ms());
|
||||
loss_based_target_rate, bwe_limited_due_to_packet_loss, at_time);
|
||||
update->probe_cluster_configs.insert(update->probe_cluster_configs.end(),
|
||||
probes.begin(), probes.end());
|
||||
update->pacer_config = GetPacingRates(at_time);
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h"
|
||||
@ -31,32 +32,28 @@ namespace webrtc {
|
||||
namespace {
|
||||
// Maximum waiting time from the time of initiating probing to getting
|
||||
// the measured results back.
|
||||
constexpr int64_t kMaxWaitingTimeForProbingResultMs = 1000;
|
||||
|
||||
// Value of `min_bitrate_to_probe_further_bps_` that indicates
|
||||
// further probing is disabled.
|
||||
constexpr int kExponentialProbingDisabled = 0;
|
||||
constexpr TimeDelta kMaxWaitingTimeForProbingResult = TimeDelta::Seconds(1);
|
||||
|
||||
// Default probing bitrate limit. Applied only when the application didn't
|
||||
// specify max bitrate.
|
||||
constexpr int64_t kDefaultMaxProbingBitrateBps = 5000000;
|
||||
constexpr DataRate kDefaultMaxProbingBitrate = DataRate::KilobitsPerSec(5000);
|
||||
|
||||
// If the bitrate drops to a factor `kBitrateDropThreshold` or lower
|
||||
// and we recover within `kBitrateDropTimeoutMs`, then we'll send
|
||||
// a probe at a fraction `kProbeFractionAfterDrop` of the original bitrate.
|
||||
constexpr double kBitrateDropThreshold = 0.66;
|
||||
constexpr int kBitrateDropTimeoutMs = 5000;
|
||||
constexpr TimeDelta kBitrateDropTimeout = TimeDelta::Seconds(5);
|
||||
constexpr double kProbeFractionAfterDrop = 0.85;
|
||||
|
||||
// Timeout for probing after leaving ALR. If the bitrate drops significantly,
|
||||
// (as determined by the delay based estimator) and we leave ALR, then we will
|
||||
// send a probe if we recover within `kLeftAlrTimeoutMs` ms.
|
||||
constexpr int kAlrEndedTimeoutMs = 3000;
|
||||
constexpr TimeDelta kAlrEndedTimeout = TimeDelta::Seconds(3);
|
||||
|
||||
// The expected uncertainty of probe result (as a fraction of the target probe
|
||||
// This is a limit on how often probing can be done when there is a BW
|
||||
// drop detected in ALR.
|
||||
constexpr int64_t kMinTimeBetweenAlrProbesMs = 5000;
|
||||
constexpr TimeDelta kMinTimeBetweenAlrProbes = TimeDelta::Seconds(5);
|
||||
|
||||
// bitrate). Used to avoid probing if the probe bitrate is close to our current
|
||||
// estimate.
|
||||
@ -73,11 +70,10 @@ void MaybeLogProbeClusterCreated(RtcEventLog* event_log,
|
||||
return;
|
||||
}
|
||||
|
||||
size_t min_bytes = static_cast<int32_t>(probe.target_data_rate.bps() *
|
||||
probe.target_duration.ms() / 8000);
|
||||
DataSize min_data_size = probe.target_data_rate * probe.target_duration;
|
||||
event_log->Log(std::make_unique<RtcEventProbeClusterCreated>(
|
||||
probe.id, probe.target_data_rate.bps(), probe.target_probe_count,
|
||||
min_bytes));
|
||||
min_data_size.bytes()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -138,32 +134,33 @@ ProbeController::ProbeController(const FieldTrialsView* key_value_config,
|
||||
"Enabled")),
|
||||
event_log_(event_log),
|
||||
config_(ProbeControllerConfig(key_value_config)) {
|
||||
Reset(0);
|
||||
Reset(Timestamp::Zero());
|
||||
}
|
||||
|
||||
ProbeController::~ProbeController() {}
|
||||
|
||||
std::vector<ProbeClusterConfig> ProbeController::SetBitrates(
|
||||
int64_t min_bitrate_bps,
|
||||
int64_t start_bitrate_bps,
|
||||
int64_t max_bitrate_bps,
|
||||
int64_t at_time_ms) {
|
||||
if (start_bitrate_bps > 0) {
|
||||
start_bitrate_bps_ = start_bitrate_bps;
|
||||
estimated_bitrate_bps_ = start_bitrate_bps;
|
||||
} else if (start_bitrate_bps_ == 0) {
|
||||
start_bitrate_bps_ = min_bitrate_bps;
|
||||
DataRate min_bitrate,
|
||||
DataRate start_bitrate,
|
||||
DataRate max_bitrate,
|
||||
Timestamp at_time) {
|
||||
if (start_bitrate > DataRate::Zero()) {
|
||||
start_bitrate_ = start_bitrate;
|
||||
estimated_bitrate_ = start_bitrate;
|
||||
} else if (start_bitrate_.IsZero()) {
|
||||
start_bitrate_ = min_bitrate;
|
||||
}
|
||||
|
||||
// The reason we use the variable `old_max_bitrate_pbs` is because we
|
||||
// need to set `max_bitrate_bps_` before we call InitiateProbing.
|
||||
int64_t old_max_bitrate_bps = max_bitrate_bps_;
|
||||
max_bitrate_bps_ = max_bitrate_bps;
|
||||
// need to set `max_bitrate_` before we call InitiateProbing.
|
||||
DataRate old_max_bitrate = max_bitrate_;
|
||||
max_bitrate_ =
|
||||
max_bitrate.IsFinite() ? max_bitrate : kDefaultMaxProbingBitrate;
|
||||
|
||||
switch (state_) {
|
||||
case State::kInit:
|
||||
if (network_available_)
|
||||
return InitiateExponentialProbing(at_time_ms);
|
||||
return InitiateExponentialProbing(at_time);
|
||||
break;
|
||||
|
||||
case State::kWaitingForProbingResult:
|
||||
@ -172,21 +169,20 @@ std::vector<ProbeClusterConfig> ProbeController::SetBitrates(
|
||||
case State::kProbingComplete:
|
||||
// If the new max bitrate is higher than both the old max bitrate and the
|
||||
// estimate then initiate probing.
|
||||
if (estimated_bitrate_bps_ != 0 &&
|
||||
old_max_bitrate_bps < max_bitrate_bps_ &&
|
||||
estimated_bitrate_bps_ < max_bitrate_bps_) {
|
||||
if (!estimated_bitrate_.IsZero() && old_max_bitrate < max_bitrate_ &&
|
||||
estimated_bitrate_ < max_bitrate_) {
|
||||
// The assumption is that if we jump more than 20% in the bandwidth
|
||||
// estimate or if the bandwidth estimate is within 90% of the new
|
||||
// max bitrate then the probing attempt was successful.
|
||||
mid_call_probing_succcess_threshold_ =
|
||||
std::min(estimated_bitrate_bps_ * 1.2, max_bitrate_bps_ * 0.9);
|
||||
std::min(estimated_bitrate_ * 1.2, max_bitrate_ * 0.9);
|
||||
mid_call_probing_waiting_for_result_ = true;
|
||||
mid_call_probing_bitrate_bps_ = max_bitrate_bps_;
|
||||
mid_call_probing_bitrate_ = max_bitrate_;
|
||||
|
||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Initiated",
|
||||
max_bitrate_bps_ / 1000);
|
||||
max_bitrate_.kbps());
|
||||
|
||||
return InitiateProbing(at_time_ms, {max_bitrate_bps_}, false);
|
||||
return InitiateProbing(at_time, {max_bitrate_}, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -194,37 +190,35 @@ std::vector<ProbeClusterConfig> ProbeController::SetBitrates(
|
||||
}
|
||||
|
||||
std::vector<ProbeClusterConfig> ProbeController::OnMaxTotalAllocatedBitrate(
|
||||
int64_t max_total_allocated_bitrate,
|
||||
int64_t at_time_ms) {
|
||||
const bool in_alr = alr_start_time_ms_.has_value();
|
||||
DataRate max_total_allocated_bitrate,
|
||||
Timestamp at_time) {
|
||||
const bool in_alr = alr_start_time_.has_value();
|
||||
const bool allow_allocation_probe = in_alr;
|
||||
|
||||
if (state_ == State::kProbingComplete &&
|
||||
max_total_allocated_bitrate != max_total_allocated_bitrate_ &&
|
||||
estimated_bitrate_bps_ != 0 &&
|
||||
(max_bitrate_bps_ <= 0 || estimated_bitrate_bps_ < max_bitrate_bps_) &&
|
||||
estimated_bitrate_bps_ < max_total_allocated_bitrate &&
|
||||
estimated_bitrate_ < max_bitrate_ &&
|
||||
estimated_bitrate_ < max_total_allocated_bitrate &&
|
||||
allow_allocation_probe) {
|
||||
max_total_allocated_bitrate_ = max_total_allocated_bitrate;
|
||||
|
||||
if (!config_.first_allocation_probe_scale)
|
||||
return std::vector<ProbeClusterConfig>();
|
||||
|
||||
DataRate first_probe_rate =
|
||||
DataRate::BitsPerSec(max_total_allocated_bitrate) *
|
||||
config_.first_allocation_probe_scale.Value();
|
||||
DataRate first_probe_rate = max_total_allocated_bitrate *
|
||||
config_.first_allocation_probe_scale.Value();
|
||||
DataRate probe_cap = config_.allocation_probe_max.Get();
|
||||
first_probe_rate = std::min(first_probe_rate, probe_cap);
|
||||
std::vector<int64_t> probes = {first_probe_rate.bps()};
|
||||
std::vector<DataRate> probes = {first_probe_rate};
|
||||
if (config_.second_allocation_probe_scale) {
|
||||
DataRate second_probe_rate =
|
||||
DataRate::BitsPerSec(max_total_allocated_bitrate) *
|
||||
max_total_allocated_bitrate *
|
||||
config_.second_allocation_probe_scale.Value();
|
||||
second_probe_rate = std::min(second_probe_rate, probe_cap);
|
||||
if (second_probe_rate > first_probe_rate)
|
||||
probes.push_back(second_probe_rate.bps());
|
||||
probes.push_back(second_probe_rate);
|
||||
}
|
||||
return InitiateProbing(at_time_ms, probes,
|
||||
return InitiateProbing(at_time, probes,
|
||||
config_.allocation_allow_further_probing.Get());
|
||||
}
|
||||
max_total_allocated_bitrate_ = max_total_allocated_bitrate;
|
||||
@ -237,65 +231,61 @@ std::vector<ProbeClusterConfig> ProbeController::OnNetworkAvailability(
|
||||
|
||||
if (!network_available_ && state_ == State::kWaitingForProbingResult) {
|
||||
state_ = State::kProbingComplete;
|
||||
min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled;
|
||||
min_bitrate_to_probe_further_ = DataRate::PlusInfinity();
|
||||
}
|
||||
|
||||
if (network_available_ && state_ == State::kInit && start_bitrate_bps_ > 0)
|
||||
return InitiateExponentialProbing(msg.at_time.ms());
|
||||
if (network_available_ && state_ == State::kInit && !start_bitrate_.IsZero())
|
||||
return InitiateExponentialProbing(msg.at_time);
|
||||
return std::vector<ProbeClusterConfig>();
|
||||
}
|
||||
|
||||
std::vector<ProbeClusterConfig> ProbeController::InitiateExponentialProbing(
|
||||
int64_t at_time_ms) {
|
||||
Timestamp at_time) {
|
||||
RTC_DCHECK(network_available_);
|
||||
RTC_DCHECK(state_ == State::kInit);
|
||||
RTC_DCHECK_GT(start_bitrate_bps_, 0);
|
||||
RTC_DCHECK_GT(start_bitrate_, DataRate::Zero());
|
||||
|
||||
// When probing at 1.8 Mbps ( 6x 300), this represents a threshold of
|
||||
// 1.2 Mbps to continue probing.
|
||||
std::vector<int64_t> probes = {static_cast<int64_t>(
|
||||
config_.first_exponential_probe_scale * start_bitrate_bps_)};
|
||||
std::vector<DataRate> probes = {config_.first_exponential_probe_scale *
|
||||
start_bitrate_};
|
||||
if (config_.second_exponential_probe_scale) {
|
||||
probes.push_back(config_.second_exponential_probe_scale.Value() *
|
||||
start_bitrate_bps_);
|
||||
start_bitrate_);
|
||||
}
|
||||
return InitiateProbing(at_time_ms, probes, true);
|
||||
return InitiateProbing(at_time, probes, true);
|
||||
}
|
||||
|
||||
std::vector<ProbeClusterConfig> ProbeController::SetEstimatedBitrate(
|
||||
int64_t bitrate_bps,
|
||||
DataRate bitrate,
|
||||
bool bwe_limited_due_to_packet_loss,
|
||||
int64_t at_time_ms) {
|
||||
Timestamp at_time) {
|
||||
bwe_limited_due_to_packet_loss_ = bwe_limited_due_to_packet_loss;
|
||||
if (bitrate_bps < kBitrateDropThreshold * estimated_bitrate_bps_) {
|
||||
time_of_last_large_drop_ms_ = at_time_ms;
|
||||
bitrate_before_last_large_drop_bps_ = estimated_bitrate_bps_;
|
||||
if (bitrate < kBitrateDropThreshold * estimated_bitrate_) {
|
||||
time_of_last_large_drop_ = at_time;
|
||||
bitrate_before_last_large_drop_ = estimated_bitrate_;
|
||||
}
|
||||
estimated_bitrate_bps_ = bitrate_bps;
|
||||
estimated_bitrate_ = bitrate;
|
||||
|
||||
if (mid_call_probing_waiting_for_result_ &&
|
||||
bitrate_bps >= mid_call_probing_succcess_threshold_) {
|
||||
bitrate >= mid_call_probing_succcess_threshold_) {
|
||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Success",
|
||||
mid_call_probing_bitrate_bps_ / 1000);
|
||||
mid_call_probing_bitrate_.kbps());
|
||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.ProbedKbps",
|
||||
bitrate_bps / 1000);
|
||||
bitrate.kbps());
|
||||
mid_call_probing_waiting_for_result_ = false;
|
||||
}
|
||||
std::vector<ProbeClusterConfig> pending_probes;
|
||||
if (state_ == State::kWaitingForProbingResult) {
|
||||
// Continue probing if probing results indicate channel has greater
|
||||
// capacity.
|
||||
RTC_LOG(LS_INFO) << "Measured bitrate: " << bitrate_bps
|
||||
RTC_LOG(LS_INFO) << "Measured bitrate: " << bitrate
|
||||
<< " Minimum to probe further: "
|
||||
<< min_bitrate_to_probe_further_bps_;
|
||||
<< min_bitrate_to_probe_further_;
|
||||
|
||||
if (min_bitrate_to_probe_further_bps_ != kExponentialProbingDisabled &&
|
||||
bitrate_bps > min_bitrate_to_probe_further_bps_) {
|
||||
if (bitrate > min_bitrate_to_probe_further_) {
|
||||
pending_probes = InitiateProbing(
|
||||
at_time_ms,
|
||||
{static_cast<int64_t>(config_.further_exponential_probe_scale *
|
||||
bitrate_bps)},
|
||||
true);
|
||||
at_time, {config_.further_exponential_probe_scale * bitrate}, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,50 +298,54 @@ void ProbeController::EnablePeriodicAlrProbing(bool enable) {
|
||||
|
||||
void ProbeController::SetAlrStartTimeMs(
|
||||
absl::optional<int64_t> alr_start_time_ms) {
|
||||
alr_start_time_ms_ = alr_start_time_ms;
|
||||
if (alr_start_time_ms) {
|
||||
alr_start_time_ = Timestamp::Millis(*alr_start_time_ms);
|
||||
} else {
|
||||
alr_start_time_ = absl::nullopt;
|
||||
}
|
||||
}
|
||||
void ProbeController::SetAlrEndedTimeMs(int64_t alr_end_time_ms) {
|
||||
alr_end_time_ms_.emplace(alr_end_time_ms);
|
||||
alr_end_time_.emplace(Timestamp::Millis(alr_end_time_ms));
|
||||
}
|
||||
|
||||
std::vector<ProbeClusterConfig> ProbeController::RequestProbe(
|
||||
int64_t at_time_ms) {
|
||||
Timestamp at_time) {
|
||||
// Called once we have returned to normal state after a large drop in
|
||||
// estimated bandwidth. The current response is to initiate a single probe
|
||||
// session (if not already probing) at the previous bitrate.
|
||||
//
|
||||
// If the probe session fails, the assumption is that this drop was a
|
||||
// real one from a competing flow or a network change.
|
||||
bool in_alr = alr_start_time_ms_.has_value();
|
||||
bool in_alr = alr_start_time_.has_value();
|
||||
bool alr_ended_recently =
|
||||
(alr_end_time_ms_.has_value() &&
|
||||
at_time_ms - alr_end_time_ms_.value() < kAlrEndedTimeoutMs);
|
||||
(alr_end_time_.has_value() &&
|
||||
at_time - alr_end_time_.value() < kAlrEndedTimeout);
|
||||
if (in_alr || alr_ended_recently || in_rapid_recovery_experiment_) {
|
||||
if (state_ == State::kProbingComplete) {
|
||||
uint32_t suggested_probe_bps =
|
||||
kProbeFractionAfterDrop * bitrate_before_last_large_drop_bps_;
|
||||
uint32_t min_expected_probe_result_bps =
|
||||
(1 - kProbeUncertainty) * suggested_probe_bps;
|
||||
int64_t time_since_drop_ms = at_time_ms - time_of_last_large_drop_ms_;
|
||||
int64_t time_since_probe_ms = at_time_ms - last_bwe_drop_probing_time_ms_;
|
||||
if (min_expected_probe_result_bps > estimated_bitrate_bps_ &&
|
||||
time_since_drop_ms < kBitrateDropTimeoutMs &&
|
||||
time_since_probe_ms > kMinTimeBetweenAlrProbesMs) {
|
||||
DataRate suggested_probe =
|
||||
kProbeFractionAfterDrop * bitrate_before_last_large_drop_;
|
||||
DataRate min_expected_probe_result =
|
||||
(1 - kProbeUncertainty) * suggested_probe;
|
||||
TimeDelta time_since_drop = at_time - time_of_last_large_drop_;
|
||||
TimeDelta time_since_probe = at_time - last_bwe_drop_probing_time_;
|
||||
if (min_expected_probe_result > estimated_bitrate_ &&
|
||||
time_since_drop < kBitrateDropTimeout &&
|
||||
time_since_probe > kMinTimeBetweenAlrProbes) {
|
||||
RTC_LOG(LS_INFO) << "Detected big bandwidth drop, start probing.";
|
||||
// Track how often we probe in response to bandwidth drop in ALR.
|
||||
RTC_HISTOGRAM_COUNTS_10000(
|
||||
"WebRTC.BWE.BweDropProbingIntervalInS",
|
||||
(at_time_ms - last_bwe_drop_probing_time_ms_) / 1000);
|
||||
last_bwe_drop_probing_time_ms_ = at_time_ms;
|
||||
return InitiateProbing(at_time_ms, {suggested_probe_bps}, false);
|
||||
(at_time - last_bwe_drop_probing_time_).seconds());
|
||||
last_bwe_drop_probing_time_ = at_time;
|
||||
return InitiateProbing(at_time, {suggested_probe}, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::vector<ProbeClusterConfig>();
|
||||
}
|
||||
|
||||
void ProbeController::SetMaxBitrate(int64_t max_bitrate_bps) {
|
||||
max_bitrate_bps_ = max_bitrate_bps;
|
||||
void ProbeController::SetMaxBitrate(DataRate max_bitrate) {
|
||||
max_bitrate_ = max_bitrate;
|
||||
}
|
||||
|
||||
void ProbeController::SetNetworkStateEstimate(
|
||||
@ -359,112 +353,106 @@ void ProbeController::SetNetworkStateEstimate(
|
||||
network_estimate_ = estimate;
|
||||
}
|
||||
|
||||
void ProbeController::Reset(int64_t at_time_ms) {
|
||||
void ProbeController::Reset(Timestamp at_time) {
|
||||
network_available_ = true;
|
||||
bwe_limited_due_to_packet_loss_ = false;
|
||||
state_ = State::kInit;
|
||||
min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled;
|
||||
time_last_probing_initiated_ms_ = 0;
|
||||
estimated_bitrate_bps_ = 0;
|
||||
min_bitrate_to_probe_further_ = DataRate::PlusInfinity();
|
||||
time_last_probing_initiated_ = Timestamp::Zero();
|
||||
estimated_bitrate_ = DataRate::Zero();
|
||||
network_estimate_ = absl::nullopt;
|
||||
start_bitrate_bps_ = 0;
|
||||
max_bitrate_bps_ = 0;
|
||||
int64_t now_ms = at_time_ms;
|
||||
last_bwe_drop_probing_time_ms_ = now_ms;
|
||||
alr_end_time_ms_.reset();
|
||||
start_bitrate_ = DataRate::Zero();
|
||||
max_bitrate_ = kDefaultMaxProbingBitrate;
|
||||
Timestamp now = at_time;
|
||||
last_bwe_drop_probing_time_ = now;
|
||||
alr_end_time_.reset();
|
||||
mid_call_probing_waiting_for_result_ = false;
|
||||
time_of_last_large_drop_ms_ = now_ms;
|
||||
bitrate_before_last_large_drop_bps_ = 0;
|
||||
max_total_allocated_bitrate_ = 0;
|
||||
time_of_last_large_drop_ = now;
|
||||
bitrate_before_last_large_drop_ = DataRate::Zero();
|
||||
max_total_allocated_bitrate_ = DataRate::Zero();
|
||||
}
|
||||
|
||||
bool ProbeController::TimeForAlrProbe(int64_t at_time_ms) const {
|
||||
if (enable_periodic_alr_probing_ && alr_start_time_ms_) {
|
||||
int64_t next_probe_time_ms =
|
||||
std::max(*alr_start_time_ms_, time_last_probing_initiated_ms_) +
|
||||
config_.alr_probing_interval->ms();
|
||||
return at_time_ms >= next_probe_time_ms;
|
||||
bool ProbeController::TimeForAlrProbe(Timestamp at_time) const {
|
||||
if (enable_periodic_alr_probing_ && alr_start_time_) {
|
||||
Timestamp next_probe_time =
|
||||
std::max(*alr_start_time_, time_last_probing_initiated_) +
|
||||
config_.alr_probing_interval;
|
||||
return at_time >= next_probe_time;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProbeController::TimeForNetworkStateProbe(int64_t at_time_ms) const {
|
||||
bool ProbeController::TimeForNetworkStateProbe(Timestamp at_time) const {
|
||||
if (config_.network_state_estimate_probing_interval->IsFinite() &&
|
||||
network_estimate_ && network_estimate_->link_capacity_upper.IsFinite() &&
|
||||
estimated_bitrate_bps_ < network_estimate_->link_capacity_upper.bps()) {
|
||||
int64_t next_probe_time_ms =
|
||||
time_last_probing_initiated_ms_ +
|
||||
config_.network_state_estimate_probing_interval->ms();
|
||||
return at_time_ms >= next_probe_time_ms;
|
||||
estimated_bitrate_ < network_estimate_->link_capacity_upper) {
|
||||
Timestamp next_probe_time = time_last_probing_initiated_ +
|
||||
config_.network_state_estimate_probing_interval;
|
||||
return at_time >= next_probe_time;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<ProbeClusterConfig> ProbeController::Process(int64_t at_time_ms) {
|
||||
if (at_time_ms - time_last_probing_initiated_ms_ >
|
||||
kMaxWaitingTimeForProbingResultMs) {
|
||||
std::vector<ProbeClusterConfig> ProbeController::Process(Timestamp at_time) {
|
||||
if (at_time - time_last_probing_initiated_ >
|
||||
kMaxWaitingTimeForProbingResult) {
|
||||
mid_call_probing_waiting_for_result_ = false;
|
||||
|
||||
if (state_ == State::kWaitingForProbingResult) {
|
||||
RTC_LOG(LS_INFO) << "kWaitingForProbingResult: timeout";
|
||||
state_ = State::kProbingComplete;
|
||||
min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled;
|
||||
min_bitrate_to_probe_further_ = DataRate::PlusInfinity();
|
||||
}
|
||||
}
|
||||
if (estimated_bitrate_bps_ <= 0 || state_ != State::kProbingComplete) {
|
||||
if (estimated_bitrate_.IsZero() || state_ != State::kProbingComplete) {
|
||||
return {};
|
||||
}
|
||||
if (TimeForAlrProbe(at_time_ms) || TimeForNetworkStateProbe(at_time_ms)) {
|
||||
return InitiateProbing(at_time_ms,
|
||||
{static_cast<int64_t>(estimated_bitrate_bps_ *
|
||||
config_.alr_probe_scale)},
|
||||
true);
|
||||
if (TimeForAlrProbe(at_time) || TimeForNetworkStateProbe(at_time)) {
|
||||
return InitiateProbing(
|
||||
at_time, {estimated_bitrate_ * config_.alr_probe_scale}, true);
|
||||
}
|
||||
return std::vector<ProbeClusterConfig>();
|
||||
}
|
||||
|
||||
std::vector<ProbeClusterConfig> ProbeController::InitiateProbing(
|
||||
int64_t now_ms,
|
||||
std::vector<int64_t> bitrates_to_probe,
|
||||
Timestamp now,
|
||||
std::vector<DataRate> bitrates_to_probe,
|
||||
bool probe_further) {
|
||||
if (bwe_limited_due_to_packet_loss_ &&
|
||||
!config_.probe_if_bwe_limited_due_to_loss) {
|
||||
return {};
|
||||
}
|
||||
int64_t max_probe_bitrate_bps =
|
||||
max_bitrate_bps_ > 0 ? max_bitrate_bps_ : kDefaultMaxProbingBitrateBps;
|
||||
DataRate max_probe_bitrate = max_bitrate_;
|
||||
if (config_.network_state_estimate_probing_interval->IsFinite() &&
|
||||
network_estimate_ &&
|
||||
network_estimate_->link_capacity_upper > DataRate::Zero()) {
|
||||
max_probe_bitrate_bps = std::min(
|
||||
max_probe_bitrate_bps,
|
||||
static_cast<int64_t>(network_estimate_->link_capacity_upper.bps() *
|
||||
config_.network_state_probe_scale));
|
||||
max_probe_bitrate =
|
||||
std::min(max_probe_bitrate, network_estimate_->link_capacity_upper *
|
||||
config_.network_state_probe_scale);
|
||||
}
|
||||
if (max_total_allocated_bitrate_ > 0) {
|
||||
if (max_total_allocated_bitrate_ > DataRate::Zero()) {
|
||||
// If a max allocated bitrate has been configured, allow probing up to 2x
|
||||
// that rate. This allows some overhead to account for bursty streams,
|
||||
// which otherwise would have to ramp up when the overshoot is already in
|
||||
// progress.
|
||||
// It also avoids minor quality reduction caused by probes often being
|
||||
// received at slightly less than the target probe bitrate.
|
||||
max_probe_bitrate_bps =
|
||||
std::min(max_probe_bitrate_bps, max_total_allocated_bitrate_ * 2);
|
||||
max_probe_bitrate =
|
||||
std::min(max_probe_bitrate, max_total_allocated_bitrate_ * 2);
|
||||
}
|
||||
|
||||
std::vector<ProbeClusterConfig> pending_probes;
|
||||
for (int64_t bitrate : bitrates_to_probe) {
|
||||
RTC_DCHECK_GT(bitrate, 0);
|
||||
for (DataRate bitrate : bitrates_to_probe) {
|
||||
RTC_DCHECK(!bitrate.IsZero());
|
||||
|
||||
if (bitrate > max_probe_bitrate_bps) {
|
||||
bitrate = max_probe_bitrate_bps;
|
||||
if (bitrate > max_probe_bitrate) {
|
||||
bitrate = max_probe_bitrate;
|
||||
probe_further = false;
|
||||
}
|
||||
|
||||
ProbeClusterConfig config;
|
||||
config.at_time = Timestamp::Millis(now_ms);
|
||||
config.target_data_rate =
|
||||
DataRate::BitsPerSec(rtc::dchecked_cast<int>(bitrate));
|
||||
config.at_time = now;
|
||||
config.target_data_rate = bitrate;
|
||||
config.target_duration = config_.min_probe_duration;
|
||||
config.target_probe_count = config_.min_probe_packets_sent;
|
||||
config.id = next_probe_cluster_id_;
|
||||
@ -472,14 +460,14 @@ std::vector<ProbeClusterConfig> ProbeController::InitiateProbing(
|
||||
MaybeLogProbeClusterCreated(event_log_, config);
|
||||
pending_probes.push_back(config);
|
||||
}
|
||||
time_last_probing_initiated_ms_ = now_ms;
|
||||
time_last_probing_initiated_ = now;
|
||||
if (probe_further) {
|
||||
state_ = State::kWaitingForProbingResult;
|
||||
min_bitrate_to_probe_further_bps_ =
|
||||
min_bitrate_to_probe_further_ =
|
||||
(*(bitrates_to_probe.end() - 1)) * config_.further_probe_threshold;
|
||||
} else {
|
||||
state_ = State::kProbingComplete;
|
||||
min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled;
|
||||
min_bitrate_to_probe_further_ = DataRate::PlusInfinity();
|
||||
}
|
||||
return pending_probes;
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "api/transport/network_control.h"
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -34,7 +35,7 @@ struct ProbeControllerConfig {
|
||||
~ProbeControllerConfig();
|
||||
|
||||
// These parameters configure the initial probes. First we send one or two
|
||||
// probes of sizes p1 * start_bitrate_bps_ and p2 * start_bitrate_bps_.
|
||||
// probes of sizes p1 * start_bitrate_ and p2 * start_bitrate_.
|
||||
// Then whenever we get a bitrate estimate of at least further_probe_threshold
|
||||
// times the size of the last sent probe we'll send another one of size
|
||||
// step_size times the new estimate.
|
||||
@ -78,24 +79,24 @@ class ProbeController {
|
||||
ProbeController& operator=(const ProbeController&) = delete;
|
||||
|
||||
ABSL_MUST_USE_RESULT std::vector<ProbeClusterConfig> SetBitrates(
|
||||
int64_t min_bitrate_bps,
|
||||
int64_t start_bitrate_bps,
|
||||
int64_t max_bitrate_bps,
|
||||
int64_t at_time_ms);
|
||||
DataRate min_bitrate,
|
||||
DataRate start_bitrate,
|
||||
DataRate max_bitrate,
|
||||
Timestamp at_time);
|
||||
|
||||
// The total bitrate, as opposed to the max bitrate, is the sum of the
|
||||
// configured bitrates for all active streams.
|
||||
ABSL_MUST_USE_RESULT std::vector<ProbeClusterConfig>
|
||||
OnMaxTotalAllocatedBitrate(int64_t max_total_allocated_bitrate,
|
||||
int64_t at_time_ms);
|
||||
OnMaxTotalAllocatedBitrate(DataRate max_total_allocated_bitrate,
|
||||
Timestamp at_time);
|
||||
|
||||
ABSL_MUST_USE_RESULT std::vector<ProbeClusterConfig> OnNetworkAvailability(
|
||||
NetworkAvailability msg);
|
||||
|
||||
ABSL_MUST_USE_RESULT std::vector<ProbeClusterConfig> SetEstimatedBitrate(
|
||||
int64_t target_bitrate_bps,
|
||||
DataRate bitrate,
|
||||
bool bwe_limited_due_to_packet_loss,
|
||||
int64_t at_time_ms);
|
||||
Timestamp at_time);
|
||||
|
||||
void EnablePeriodicAlrProbing(bool enable);
|
||||
|
||||
@ -103,18 +104,18 @@ class ProbeController {
|
||||
void SetAlrEndedTimeMs(int64_t alr_end_time);
|
||||
|
||||
ABSL_MUST_USE_RESULT std::vector<ProbeClusterConfig> RequestProbe(
|
||||
int64_t at_time_ms);
|
||||
Timestamp at_time);
|
||||
|
||||
// Sets a new maximum probing bitrate, without generating a new probe cluster.
|
||||
void SetMaxBitrate(int64_t max_bitrate_bps);
|
||||
void SetMaxBitrate(DataRate max_bitrate);
|
||||
void SetNetworkStateEstimate(webrtc::NetworkStateEstimate estimate);
|
||||
|
||||
// Resets the ProbeController to a state equivalent to as if it was just
|
||||
// created EXCEPT for `enable_periodic_alr_probing_`.
|
||||
void Reset(int64_t at_time_ms);
|
||||
void Reset(Timestamp at_time);
|
||||
|
||||
ABSL_MUST_USE_RESULT std::vector<ProbeClusterConfig> Process(
|
||||
int64_t at_time_ms);
|
||||
Timestamp at_time);
|
||||
|
||||
private:
|
||||
enum class State {
|
||||
@ -127,36 +128,36 @@ class ProbeController {
|
||||
};
|
||||
|
||||
ABSL_MUST_USE_RESULT std::vector<ProbeClusterConfig>
|
||||
InitiateExponentialProbing(int64_t at_time_ms);
|
||||
InitiateExponentialProbing(Timestamp at_time);
|
||||
ABSL_MUST_USE_RESULT std::vector<ProbeClusterConfig> InitiateProbing(
|
||||
int64_t now_ms,
|
||||
std::vector<int64_t> bitrates_to_probe,
|
||||
Timestamp now,
|
||||
std::vector<DataRate> bitrates_to_probe,
|
||||
bool probe_further);
|
||||
bool TimeForAlrProbe(int64_t at_time_ms) const;
|
||||
bool TimeForNetworkStateProbe(int64_t at_time_ms) const;
|
||||
bool TimeForAlrProbe(Timestamp at_time) const;
|
||||
bool TimeForNetworkStateProbe(Timestamp at_time) const;
|
||||
|
||||
bool network_available_;
|
||||
bool bwe_limited_due_to_packet_loss_;
|
||||
State state_;
|
||||
int64_t min_bitrate_to_probe_further_bps_;
|
||||
int64_t time_last_probing_initiated_ms_;
|
||||
int64_t estimated_bitrate_bps_;
|
||||
DataRate min_bitrate_to_probe_further_ = DataRate::PlusInfinity();
|
||||
Timestamp time_last_probing_initiated_ = Timestamp::MinusInfinity();
|
||||
DataRate estimated_bitrate_ = DataRate::Zero();
|
||||
absl::optional<webrtc::NetworkStateEstimate> network_estimate_;
|
||||
int64_t start_bitrate_bps_;
|
||||
int64_t max_bitrate_bps_;
|
||||
int64_t last_bwe_drop_probing_time_ms_;
|
||||
absl::optional<int64_t> alr_start_time_ms_;
|
||||
absl::optional<int64_t> alr_end_time_ms_;
|
||||
DataRate start_bitrate_ = DataRate::Zero();
|
||||
DataRate max_bitrate_ = DataRate::PlusInfinity();
|
||||
Timestamp last_bwe_drop_probing_time_ = Timestamp::Zero();
|
||||
absl::optional<Timestamp> alr_start_time_;
|
||||
absl::optional<Timestamp> alr_end_time_;
|
||||
bool enable_periodic_alr_probing_;
|
||||
int64_t time_of_last_large_drop_ms_;
|
||||
int64_t bitrate_before_last_large_drop_bps_;
|
||||
int64_t max_total_allocated_bitrate_;
|
||||
Timestamp time_of_last_large_drop_ = Timestamp::MinusInfinity();
|
||||
DataRate bitrate_before_last_large_drop_ = DataRate::Zero();
|
||||
DataRate max_total_allocated_bitrate_ = DataRate::Zero();
|
||||
|
||||
const bool in_rapid_recovery_experiment_;
|
||||
// For WebRTC.BWE.MidCallProbing.* metric.
|
||||
bool mid_call_probing_waiting_for_result_;
|
||||
int64_t mid_call_probing_bitrate_bps_;
|
||||
int64_t mid_call_probing_succcess_threshold_;
|
||||
DataRate mid_call_probing_bitrate_ = DataRate::Zero();
|
||||
DataRate mid_call_probing_succcess_threshold_ = DataRate::Zero();
|
||||
RtcEventLog* event_log_;
|
||||
|
||||
int32_t next_probe_cluster_id_ = 1;
|
||||
|
||||
@ -11,9 +11,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
|
||||
#include "rtc_base/logging.h"
|
||||
@ -22,27 +21,22 @@
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::AtLeast;
|
||||
using ::testing::Field;
|
||||
using ::testing::Matcher;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::Return;
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kMinBitrateBps = 100;
|
||||
constexpr int kStartBitrateBps = 300;
|
||||
constexpr int kMaxBitrateBps = 10000;
|
||||
constexpr DataRate kMinBitrate = DataRate::BitsPerSec(100);
|
||||
constexpr DataRate kStartBitrate = DataRate::BitsPerSec(300);
|
||||
constexpr DataRate kMaxBitrate = DataRate::BitsPerSec(10000);
|
||||
|
||||
constexpr int kExponentialProbingTimeoutMs = 5000;
|
||||
constexpr TimeDelta kExponentialProbingTimeout = TimeDelta::Seconds(5);
|
||||
|
||||
constexpr int kAlrProbeInterval = 5000;
|
||||
constexpr int kAlrEndedTimeoutMs = 3000;
|
||||
constexpr int kBitrateDropTimeoutMs = 5000;
|
||||
constexpr TimeDelta kAlrProbeInterval = TimeDelta::Seconds(5);
|
||||
constexpr TimeDelta kAlrEndedTimeout = TimeDelta::Seconds(3);
|
||||
constexpr TimeDelta kBitrateDropTimeout = TimeDelta::Seconds(5);
|
||||
} // namespace
|
||||
|
||||
class ProbeControllerFixture {
|
||||
@ -56,10 +50,7 @@ class ProbeControllerFixture {
|
||||
}
|
||||
|
||||
Timestamp CurrentTime() { return clock_.CurrentTime(); }
|
||||
int64_t NowMs() { return clock_.TimeInMilliseconds(); }
|
||||
void AdvanceTimeMilliseconds(int64_t delta_ms) {
|
||||
clock_.AdvanceTimeMilliseconds(delta_ms);
|
||||
}
|
||||
void AdvanceTime(TimeDelta delta) { clock_.AdvanceTime(delta); }
|
||||
|
||||
ExplicitKeyValueConfig field_trial_config_;
|
||||
SimulatedClock clock_;
|
||||
@ -71,8 +62,8 @@ TEST(ProbeControllerTest, InitiatesProbingAtStart) {
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
EXPECT_GE(probes.size(), 2u);
|
||||
}
|
||||
|
||||
@ -81,7 +72,7 @@ TEST(ProbeControllerTest, SetsDefaultTargetDurationAndTargetProbeCount) {
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
std::vector<ProbeClusterConfig> probes = probe_controller->SetBitrates(
|
||||
kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs());
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
ASSERT_GE(probes.size(), 2u);
|
||||
|
||||
EXPECT_EQ(probes[0].target_duration, TimeDelta::Millis(15));
|
||||
@ -96,7 +87,7 @@ TEST(ProbeControllerTest,
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
std::vector<ProbeClusterConfig> probes = probe_controller->SetBitrates(
|
||||
kMinBitrateBps, kStartBitrateBps, kMaxBitrateBps, fixture.NowMs());
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
ASSERT_GE(probes.size(), 2u);
|
||||
|
||||
EXPECT_EQ(probes[0].target_duration, TimeDelta::Millis(123));
|
||||
@ -109,8 +100,8 @@ TEST(ProbeControllerTest, ProbeOnlyWhenNetworkIsUp) {
|
||||
fixture.CreateController();
|
||||
auto probes = probe_controller->OnNetworkAvailability(
|
||||
{.at_time = fixture.CurrentTime(), .network_available = false});
|
||||
probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
probes = probe_controller->SetBitrates(kMinBitrate, kStartBitrate,
|
||||
kMaxBitrate, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 0u);
|
||||
probes = probe_controller->OnNetworkAvailability(
|
||||
{.at_time = fixture.CurrentTime(), .network_available = true});
|
||||
@ -121,45 +112,46 @@ TEST(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
// Long enough to time out exponential probing.
|
||||
fixture.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
|
||||
fixture.AdvanceTime(kExponentialProbingTimeout);
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
kStartBitrateBps, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps + 100, fixture.NowMs());
|
||||
kStartBitrate, /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate + DataRate::BitsPerSec(100),
|
||||
fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), kMaxBitrateBps + 100);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), kMaxBitrate.bps() + 100);
|
||||
}
|
||||
|
||||
TEST(ProbeControllerTest, ProbesOnMaxBitrateIncreaseOnlyWhenInAlr) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
kMaxBitrateBps - 1, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
kMaxBitrate - DataRate::BitsPerSec(1),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
|
||||
// Wait long enough to time out exponential probing.
|
||||
fixture.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(kExponentialProbingTimeout);
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 0u);
|
||||
|
||||
// Probe when in alr.
|
||||
probe_controller->SetAlrStartTimeMs(fixture.NowMs());
|
||||
probes = probe_controller->OnMaxTotalAllocatedBitrate(kMaxBitrateBps + 1,
|
||||
fixture.NowMs());
|
||||
probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
|
||||
probes = probe_controller->OnMaxTotalAllocatedBitrate(
|
||||
kMaxBitrate + DataRate::BitsPerSec(1), fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 2u);
|
||||
|
||||
// Do not probe when not in alr.
|
||||
probe_controller->SetAlrStartTimeMs(absl::nullopt);
|
||||
probes = probe_controller->OnMaxTotalAllocatedBitrate(kMaxBitrateBps + 2,
|
||||
fixture.NowMs());
|
||||
probes = probe_controller->OnMaxTotalAllocatedBitrate(
|
||||
kMaxBitrate + DataRate::BitsPerSec(2), fixture.CurrentTime());
|
||||
EXPECT_TRUE(probes.empty());
|
||||
}
|
||||
|
||||
@ -167,38 +159,42 @@ TEST(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
// Long enough to time out exponential probing.
|
||||
fixture.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
|
||||
fixture.AdvanceTime(kExponentialProbingTimeout);
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
kStartBitrateBps, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
kStartBitrate, /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
kMaxBitrateBps, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps + 100, fixture.NowMs());
|
||||
kMaxBitrate, /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate + DataRate::BitsPerSec(100),
|
||||
fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), kMaxBitrateBps + 100);
|
||||
EXPECT_EQ(probes[0].target_data_rate,
|
||||
kMaxBitrate + DataRate::BitsPerSec(100));
|
||||
}
|
||||
|
||||
TEST(ProbeControllerTest, TestExponentialProbing) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
|
||||
// Repeated probe should only be sent when estimated bitrate climbs above
|
||||
// 0.7 * 6 * kStartBitrateBps = 1260.
|
||||
// 0.7 * 6 * kStartBitrate = 1260.
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
1000, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(1000),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 0u);
|
||||
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
1800, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(1800),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), 2 * 1800);
|
||||
}
|
||||
@ -207,15 +203,15 @@ TEST(ProbeControllerTest, TestExponentialProbingTimeout) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
// Advance far enough to cause a time out in waiting for probing result.
|
||||
fixture.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(kExponentialProbingTimeout);
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
1800, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(1800),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 0u);
|
||||
}
|
||||
|
||||
@ -223,19 +219,20 @@ TEST(ProbeControllerTest, RequestProbeInAlr) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
EXPECT_GE(probes.size(), 2u);
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
|
||||
probe_controller->SetAlrStartTimeMs(fixture.NowMs());
|
||||
fixture.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
|
||||
fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
250, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
probes = probe_controller->RequestProbe(fixture.NowMs());
|
||||
DataRate::BitsPerSec(250),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
probes = probe_controller->RequestProbe(fixture.CurrentTime());
|
||||
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), 0.85 * 500);
|
||||
@ -245,21 +242,22 @@ TEST(ProbeControllerTest, RequestProbeWhenAlrEndedRecently) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 2u);
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
|
||||
probe_controller->SetAlrStartTimeMs(absl::nullopt);
|
||||
fixture.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
250, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
probe_controller->SetAlrEndedTimeMs(fixture.NowMs());
|
||||
fixture.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs - 1);
|
||||
probes = probe_controller->RequestProbe(fixture.NowMs());
|
||||
DataRate::BitsPerSec(250),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
probe_controller->SetAlrEndedTimeMs(fixture.CurrentTime().ms());
|
||||
fixture.AdvanceTime(kAlrEndedTimeout - TimeDelta::Millis(1));
|
||||
probes = probe_controller->RequestProbe(fixture.CurrentTime());
|
||||
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), 0.85 * 500);
|
||||
@ -269,21 +267,22 @@ TEST(ProbeControllerTest, RequestProbeWhenAlrNotEndedRecently) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 2u);
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
|
||||
probe_controller->SetAlrStartTimeMs(absl::nullopt);
|
||||
fixture.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
250, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
probe_controller->SetAlrEndedTimeMs(fixture.NowMs());
|
||||
fixture.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs + 1);
|
||||
probes = probe_controller->RequestProbe(fixture.NowMs());
|
||||
DataRate::BitsPerSec(250),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
probe_controller->SetAlrEndedTimeMs(fixture.CurrentTime().ms());
|
||||
fixture.AdvanceTime(kAlrEndedTimeout + TimeDelta::Millis(1));
|
||||
probes = probe_controller->RequestProbe(fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 0u);
|
||||
}
|
||||
|
||||
@ -291,20 +290,21 @@ TEST(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 2u);
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
|
||||
probe_controller->SetAlrStartTimeMs(fixture.NowMs());
|
||||
fixture.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
|
||||
fixture.AdvanceTime(kAlrProbeInterval + TimeDelta::Millis(1));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
250, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
fixture.AdvanceTimeMilliseconds(kBitrateDropTimeoutMs + 1);
|
||||
probes = probe_controller->RequestProbe(fixture.NowMs());
|
||||
DataRate::BitsPerSec(250),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
fixture.AdvanceTime(kBitrateDropTimeout + TimeDelta::Millis(1));
|
||||
probes = probe_controller->RequestProbe(fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 0u);
|
||||
}
|
||||
|
||||
@ -312,40 +312,43 @@ TEST(ProbeControllerTest, PeriodicProbing) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
probe_controller->EnablePeriodicAlrProbing(true);
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 2u);
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
|
||||
int64_t start_time = fixture.NowMs();
|
||||
Timestamp start_time = fixture.CurrentTime();
|
||||
|
||||
// Expect the controller to send a new probe after 5s has passed.
|
||||
probe_controller->SetAlrStartTimeMs(start_time);
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
probe_controller->SetAlrStartTimeMs(start_time.ms());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), 1000);
|
||||
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
|
||||
// The following probe should be sent at 10s into ALR.
|
||||
probe_controller->SetAlrStartTimeMs(start_time);
|
||||
fixture.AdvanceTimeMilliseconds(4000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
probe_controller->SetAlrStartTimeMs(start_time.ms());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(4));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 0u);
|
||||
|
||||
probe_controller->SetAlrStartTimeMs(start_time);
|
||||
fixture.AdvanceTimeMilliseconds(1000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
probe_controller->SetAlrStartTimeMs(start_time.ms());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(1));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 0u);
|
||||
}
|
||||
|
||||
@ -353,49 +356,50 @@ TEST(ProbeControllerTest, PeriodicProbingAfterReset) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
int64_t alr_start_time = fixture.NowMs();
|
||||
Timestamp alr_start_time = fixture.CurrentTime();
|
||||
|
||||
probe_controller->SetAlrStartTimeMs(alr_start_time);
|
||||
probe_controller->SetAlrStartTimeMs(alr_start_time.ms());
|
||||
probe_controller->EnablePeriodicAlrProbing(true);
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
probe_controller->Reset(fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
probe_controller->Reset(fixture.CurrentTime());
|
||||
|
||||
fixture.AdvanceTimeMilliseconds(10000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(10));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
// Since bitrates are not yet set, no probe is sent event though we are in ALR
|
||||
// mode.
|
||||
EXPECT_EQ(probes.size(), 0u);
|
||||
|
||||
probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
probes = probe_controller->SetBitrates(kMinBitrate, kStartBitrate,
|
||||
kMaxBitrate, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 2u);
|
||||
|
||||
// Make sure we use `kStartBitrateBps` as the estimated bitrate
|
||||
// until SetEstimatedBitrate is called with an updated estimate.
|
||||
fixture.AdvanceTimeMilliseconds(10000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(10));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), kStartBitrateBps * 2);
|
||||
EXPECT_EQ(probes[0].target_data_rate, kStartBitrate * 2);
|
||||
}
|
||||
|
||||
TEST(ProbeControllerTest, TestExponentialProbingOverflow) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
const int64_t kMbpsMultiplier = 1000000;
|
||||
auto probes =
|
||||
probe_controller->SetBitrates(kMinBitrateBps, 10 * kMbpsMultiplier,
|
||||
100 * kMbpsMultiplier, fixture.NowMs());
|
||||
const DataRate kMbpsMultiplier = DataRate::KilobitsPerSec(1000);
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrate, 10 * kMbpsMultiplier,
|
||||
100 * kMbpsMultiplier,
|
||||
fixture.CurrentTime());
|
||||
// Verify that probe bitrate is capped at the specified max bitrate.
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
60 * kMbpsMultiplier, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
60 * kMbpsMultiplier, /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), 100 * kMbpsMultiplier);
|
||||
EXPECT_EQ(probes[0].target_data_rate, 100 * kMbpsMultiplier);
|
||||
// Verify that repeated probes aren't sent.
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
100 * kMbpsMultiplier, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
100 * kMbpsMultiplier, /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 0u);
|
||||
}
|
||||
|
||||
@ -403,40 +407,42 @@ TEST(ProbeControllerTest, TestAllocatedBitrateCap) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
const int64_t kMbpsMultiplier = 1000000;
|
||||
const int64_t kMaxBitrateBps = 100 * kMbpsMultiplier;
|
||||
const DataRate kMbpsMultiplier = DataRate::KilobitsPerSec(1000);
|
||||
const DataRate kMaxBitrate = 100 * kMbpsMultiplier;
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrateBps, 10 * kMbpsMultiplier, kMaxBitrateBps, fixture.NowMs());
|
||||
kMinBitrate, 10 * kMbpsMultiplier, kMaxBitrate, fixture.CurrentTime());
|
||||
|
||||
// Configure ALR for periodic probing.
|
||||
probe_controller->EnablePeriodicAlrProbing(true);
|
||||
int64_t alr_start_time = fixture.NowMs();
|
||||
probe_controller->SetAlrStartTimeMs(alr_start_time);
|
||||
Timestamp alr_start_time = fixture.CurrentTime();
|
||||
probe_controller->SetAlrStartTimeMs(alr_start_time.ms());
|
||||
|
||||
int64_t estimated_bitrate_bps = kMaxBitrateBps / 10;
|
||||
DataRate estimated_bitrate = kMaxBitrate / 10;
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
estimated_bitrate_bps, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
estimated_bitrate, /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
|
||||
// Set a max allocated bitrate below the current estimate.
|
||||
int64_t max_allocated_bps = estimated_bitrate_bps - 1 * kMbpsMultiplier;
|
||||
probes = probe_controller->OnMaxTotalAllocatedBitrate(max_allocated_bps,
|
||||
fixture.NowMs());
|
||||
DataRate max_allocated = estimated_bitrate - 1 * kMbpsMultiplier;
|
||||
probes = probe_controller->OnMaxTotalAllocatedBitrate(max_allocated,
|
||||
fixture.CurrentTime());
|
||||
EXPECT_TRUE(probes.empty()); // No probe since lower than current max.
|
||||
|
||||
// Probes such as ALR capped at 2x the max allocation limit.
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), 2 * max_allocated_bps);
|
||||
EXPECT_EQ(probes[0].target_data_rate, 2 * max_allocated);
|
||||
|
||||
// Remove allocation limit.
|
||||
EXPECT_TRUE(
|
||||
probe_controller->OnMaxTotalAllocatedBitrate(0, fixture.NowMs()).empty());
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
probe_controller
|
||||
->OnMaxTotalAllocatedBitrate(DataRate::Zero(), fixture.CurrentTime())
|
||||
.empty());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), estimated_bitrate_bps * 2);
|
||||
EXPECT_EQ(probes[0].target_data_rate, estimated_bitrate * 2);
|
||||
}
|
||||
|
||||
TEST(ProbeControllerTest, ConfigurableProbingFieldTrial) {
|
||||
@ -446,10 +452,10 @@ TEST(ProbeControllerTest, ConfigurableProbingFieldTrial) {
|
||||
"alloc_p1:2,alloc_p2/");
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
const bool kBweLimitedDuetoPacketLoss = false;
|
||||
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
5000000, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrate, kStartBitrate,
|
||||
DataRate::KilobitsPerSec(5000),
|
||||
fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 2u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), 600);
|
||||
EXPECT_EQ(probes[1].target_data_rate.bps(), 1500);
|
||||
@ -457,22 +463,24 @@ TEST(ProbeControllerTest, ConfigurableProbingFieldTrial) {
|
||||
// Repeated probe should only be sent when estimated bitrate climbs above
|
||||
// 0.8 * 5 * kStartBitrateBps = 1200.
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
1100, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(1100),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 0u);
|
||||
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
1250, kBweLimitedDuetoPacketLoss, fixture.NowMs());
|
||||
DataRate::BitsPerSec(1250),
|
||||
/*bwe_limited_due_to_packet_loss=*/false, fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), 3 * 1250);
|
||||
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
|
||||
probe_controller->SetAlrStartTimeMs(fixture.NowMs());
|
||||
probes =
|
||||
probe_controller->OnMaxTotalAllocatedBitrate(200000, fixture.NowMs());
|
||||
probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
|
||||
probes = probe_controller->OnMaxTotalAllocatedBitrate(
|
||||
DataRate::KilobitsPerSec(200), fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), 400000);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), 400'000);
|
||||
}
|
||||
|
||||
TEST(ProbeControllerTest, PauseAlrProbeWhenLossBasedBweLimited) {
|
||||
@ -482,27 +490,30 @@ TEST(ProbeControllerTest, PauseAlrProbeWhenLossBasedBweLimited) {
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
probe_controller->EnablePeriodicAlrProbing(true);
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
// Expect the controller to send a new probe after 5s has passed.
|
||||
probe_controller->SetAlrStartTimeMs(fixture.NowMs());
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
ASSERT_EQ(probes.size(), 1u);
|
||||
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, /*bwe_limited_due_to_packet_loss*/ true, fixture.NowMs());
|
||||
fixture.AdvanceTimeMilliseconds(6000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss*/ true,
|
||||
fixture.CurrentTime());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(6));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_TRUE(probes.empty());
|
||||
// ALR probing resumed when estimate is no longer restricted by loss based
|
||||
// BWE.
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs());
|
||||
fixture.AdvanceTimeMilliseconds(6000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(6));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_TRUE(!probes.empty());
|
||||
}
|
||||
|
||||
@ -513,19 +524,21 @@ TEST(ProbeControllerTest, AlrProbeStartWhenNotLossBasedBweLimited) {
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
probe_controller->EnablePeriodicAlrProbing(true);
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, /*bwe_limited_due_to_packet_loss=*/true, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/true,
|
||||
fixture.CurrentTime());
|
||||
// Expect the controller to send a new probe after 5s has passed.
|
||||
probe_controller->SetAlrStartTimeMs(fixture.NowMs());
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_TRUE(probes.empty());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, /*bwe_limited_due_to_packet_loss*/ false, fixture.NowMs());
|
||||
fixture.AdvanceTimeMilliseconds(1000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss*/ false,
|
||||
fixture.CurrentTime());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(1));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_TRUE(!probes.empty());
|
||||
}
|
||||
|
||||
@ -535,21 +548,22 @@ TEST(ProbeControllerTest, PeriodicProbeAtUpperNetworkStateEstimate) {
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
5000, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs());
|
||||
DataRate::BitsPerSec(5000), /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
// Expect the controller to send a new probe after 5s has passed.
|
||||
NetworkStateEstimate state_estimate;
|
||||
state_estimate.link_capacity_upper = DataRate::BitsPerSec(6000);
|
||||
state_estimate.link_capacity_upper = DataRate::KilobitsPerSec(6);
|
||||
probe_controller->SetNetworkStateEstimate(state_estimate);
|
||||
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
ASSERT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate, state_estimate.link_capacity_upper);
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
ASSERT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate, state_estimate.link_capacity_upper);
|
||||
}
|
||||
@ -562,29 +576,32 @@ TEST(ProbeControllerTest,
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
// Expect the controller to send a new probe after 5s has passed.
|
||||
NetworkStateEstimate state_estimate;
|
||||
state_estimate.link_capacity_upper = DataRate::KilobitsPerSec(600);
|
||||
probe_controller->SetNetworkStateEstimate(state_estimate);
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
ASSERT_EQ(probes.size(), 1u);
|
||||
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, /*bwe_limited_due_to_packet_loss=*/true, fixture.NowMs());
|
||||
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/true,
|
||||
fixture.CurrentTime());
|
||||
// Expect the controller to send a new probe after 5s has passed.
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_TRUE(probes.empty());
|
||||
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
500, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs());
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
DataRate::BitsPerSec(500), /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_FALSE(probes.empty());
|
||||
}
|
||||
|
||||
@ -594,22 +611,23 @@ TEST(ProbeControllerTest, AlrProbesLimitedByNetworkStateEstimate) {
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
probe_controller->EnablePeriodicAlrProbing(true);
|
||||
auto probes = probe_controller->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||
kMaxBitrateBps, fixture.NowMs());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
6000, /*bwe_limited_due_to_packet_loss=*/false, fixture.NowMs());
|
||||
probe_controller->SetAlrStartTimeMs(fixture.NowMs());
|
||||
DataRate::KilobitsPerSec(6), /*bwe_limited_due_to_packet_loss=*/false,
|
||||
fixture.CurrentTime());
|
||||
probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms());
|
||||
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
ASSERT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), kMaxBitrateBps);
|
||||
EXPECT_EQ(probes[0].target_data_rate, kMaxBitrate);
|
||||
|
||||
NetworkStateEstimate state_estimate;
|
||||
state_estimate.link_capacity_upper = DataRate::BitsPerSec(8000);
|
||||
probe_controller->SetNetworkStateEstimate(state_estimate);
|
||||
fixture.AdvanceTimeMilliseconds(5000);
|
||||
probes = probe_controller->Process(fixture.NowMs());
|
||||
fixture.AdvanceTime(TimeDelta::Seconds(5));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
ASSERT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate, state_estimate.link_capacity_upper);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user