Change behaviour of repeated initial probes
Repeated initial probes are sent every second until ProbeController::OnMaxAllocatedBitrate is invoked (Media is beeing sent) or 5s has passed. Each probe has a duration of 100ms, sent in packet bursts every 20ms. ProbeController::waiting_for_initial_probe_result_ is no longer needed and is removed. Setting field trial for duration between probe packets bursts are moved from BitrateProber to ProbeController. Bug: webrtc:14928 Change-Id: I3170533f679fc2cc2aa5402e248fa1f6996d3ccd Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/350640 Reviewed-by: Diep Bui <diepbp@google.com> Commit-Queue: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42323}
This commit is contained in:
parent
d122464b6a
commit
b25c747d5d
@ -214,7 +214,10 @@ struct PacerConfig {
|
||||
struct ProbeClusterConfig {
|
||||
Timestamp at_time = Timestamp::PlusInfinity();
|
||||
DataRate target_data_rate = DataRate::Zero();
|
||||
// Duration of a probe.
|
||||
TimeDelta target_duration = TimeDelta::Zero();
|
||||
// Delta time between sent bursts of packets during probe.
|
||||
TimeDelta min_probe_delta = TimeDelta::Millis(2);
|
||||
int32_t target_probe_count = 0;
|
||||
int32_t id = 0;
|
||||
};
|
||||
|
||||
@ -89,8 +89,10 @@ ProbeControllerConfig::ProbeControllerConfig(
|
||||
further_exponential_probe_scale("step_size", 2),
|
||||
further_probe_threshold("further_probe_threshold", 0.7),
|
||||
abort_further_probe_if_max_lower_than_current("abort_further", false),
|
||||
repeated_initial_probing_duration("initial_probing_duration",
|
||||
TimeDelta::Seconds(5)),
|
||||
repeated_initial_probing_time_period("initial_probing",
|
||||
TimeDelta::Seconds(5)),
|
||||
initial_probe_duration("initial_probe_duration", TimeDelta::Millis(100)),
|
||||
initial_min_probe_delta("initial_min_probe_delta", TimeDelta::Millis(20)),
|
||||
alr_probing_interval("alr_interval", TimeDelta::Seconds(5)),
|
||||
alr_probe_scale("alr_scale", 2),
|
||||
network_state_estimate_probing_interval("network_state_interval",
|
||||
@ -104,13 +106,13 @@ ProbeControllerConfig::ProbeControllerConfig(
|
||||
network_state_probe_scale("network_state_scale", 1.0),
|
||||
network_state_probe_duration("network_state_probe_duration",
|
||||
TimeDelta::Millis(15)),
|
||||
|
||||
probe_on_max_allocated_bitrate_change("probe_max_allocation", true),
|
||||
first_allocation_probe_scale("alloc_p1", 1),
|
||||
second_allocation_probe_scale("alloc_p2", 2),
|
||||
allocation_probe_limit_by_current_scale("alloc_current_bwe_limit"),
|
||||
min_probe_packets_sent("min_probe_packets_sent", 5),
|
||||
min_probe_duration("min_probe_duration", TimeDelta::Millis(15)),
|
||||
min_probe_delta("min_probe_delta", TimeDelta::Millis(2)),
|
||||
loss_limited_probe_scale("loss_limited_scale", 1.5),
|
||||
skip_if_estimate_larger_than_fraction_of_max(
|
||||
"skip_if_est_larger_than_fraction_of_max",
|
||||
@ -120,7 +122,8 @@ ProbeControllerConfig::ProbeControllerConfig(
|
||||
&further_exponential_probe_scale,
|
||||
&further_probe_threshold,
|
||||
&abort_further_probe_if_max_lower_than_current,
|
||||
&repeated_initial_probing_duration,
|
||||
&repeated_initial_probing_time_period,
|
||||
&initial_probe_duration,
|
||||
&alr_probing_interval,
|
||||
&alr_probe_scale,
|
||||
&probe_on_max_allocated_bitrate_change,
|
||||
@ -128,6 +131,8 @@ ProbeControllerConfig::ProbeControllerConfig(
|
||||
&second_allocation_probe_scale,
|
||||
&allocation_probe_limit_by_current_scale,
|
||||
&min_probe_duration,
|
||||
&min_probe_delta,
|
||||
&initial_min_probe_delta,
|
||||
&network_state_estimate_probing_interval,
|
||||
&probe_if_estimate_lower_than_network_state_estimate_ratio,
|
||||
&estimate_lower_than_network_state_estimate_probing_interval,
|
||||
@ -217,7 +222,6 @@ std::vector<ProbeClusterConfig> ProbeController::OnMaxTotalAllocatedBitrate(
|
||||
Timestamp at_time) {
|
||||
const bool in_alr = alr_start_time_.has_value();
|
||||
const bool allow_allocation_probe = in_alr;
|
||||
|
||||
if (config_.probe_on_max_allocated_bitrate_change &&
|
||||
state_ == State::kProbingComplete &&
|
||||
max_total_allocated_bitrate != max_total_allocated_bitrate_ &&
|
||||
@ -257,6 +261,10 @@ std::vector<ProbeClusterConfig> ProbeController::OnMaxTotalAllocatedBitrate(
|
||||
|
||||
return InitiateProbing(at_time, probes, allow_further_probing);
|
||||
}
|
||||
if (!max_total_allocated_bitrate.IsZero()) {
|
||||
last_allowed_repeated_initial_probe_ = at_time;
|
||||
}
|
||||
|
||||
max_total_allocated_bitrate_ = max_total_allocated_bitrate;
|
||||
return std::vector<ProbeClusterConfig>();
|
||||
}
|
||||
@ -285,7 +293,6 @@ void ProbeController::UpdateState(State new_state) {
|
||||
break;
|
||||
case State::kProbingComplete:
|
||||
state_ = State::kProbingComplete;
|
||||
waiting_for_initial_probe_result_ = false;
|
||||
min_bitrate_to_probe_further_ = DataRate::PlusInfinity();
|
||||
break;
|
||||
}
|
||||
@ -306,13 +313,13 @@ std::vector<ProbeClusterConfig> ProbeController::InitiateExponentialProbing(
|
||||
probes.push_back(config_.second_exponential_probe_scale.Value() *
|
||||
start_bitrate_);
|
||||
}
|
||||
waiting_for_initial_probe_result_ = true;
|
||||
if (repeated_initial_probing_enabled_) {
|
||||
if (repeated_initial_probing_enabled_ &&
|
||||
max_total_allocated_bitrate_.IsZero()) {
|
||||
last_allowed_repeated_initial_probe_ =
|
||||
at_time + config_.repeated_initial_probing_duration;
|
||||
at_time + config_.repeated_initial_probing_time_period;
|
||||
RTC_LOG(LS_INFO) << "Repeated initial probing enabled, last allowed probe: "
|
||||
<< last_allowed_repeated_initial_probe_
|
||||
<< "now: " << at_time;
|
||||
<< " now: " << at_time;
|
||||
}
|
||||
|
||||
return InitiateProbing(at_time, probes, true);
|
||||
@ -335,8 +342,6 @@ std::vector<ProbeClusterConfig> ProbeController::SetEstimatedBitrate(
|
||||
if (config_.abort_further_probe_if_max_lower_than_current &&
|
||||
(bitrate > max_bitrate_ ||
|
||||
(!max_total_allocated_bitrate_.IsZero() &&
|
||||
!(waiting_for_initial_probe_result_ &&
|
||||
repeated_initial_probing_enabled_) &&
|
||||
bitrate > 2 * max_total_allocated_bitrate_))) {
|
||||
// No need to continue probing.
|
||||
min_bitrate_to_probe_further_ = DataRate::PlusInfinity();
|
||||
@ -425,7 +430,6 @@ void ProbeController::SetNetworkStateEstimate(
|
||||
void ProbeController::Reset(Timestamp at_time) {
|
||||
bandwidth_limited_cause_ = BandwidthLimitedCause::kDelayBasedLimited;
|
||||
state_ = State::kInit;
|
||||
waiting_for_initial_probe_result_ = false;
|
||||
min_bitrate_to_probe_further_ = DataRate::PlusInfinity();
|
||||
time_last_probing_initiated_ = Timestamp::Zero();
|
||||
estimated_bitrate_ = DataRate::Zero();
|
||||
@ -437,7 +441,6 @@ void ProbeController::Reset(Timestamp at_time) {
|
||||
alr_end_time_.reset();
|
||||
time_of_last_large_drop_ = now;
|
||||
bitrate_before_last_large_drop_ = DataRate::Zero();
|
||||
max_total_allocated_bitrate_ = DataRate::Zero();
|
||||
}
|
||||
|
||||
bool ProbeController::TimeForAlrProbe(Timestamp at_time) const {
|
||||
@ -506,7 +509,6 @@ std::vector<ProbeClusterConfig> ProbeController::Process(Timestamp at_time) {
|
||||
return {};
|
||||
}
|
||||
if (TimeForNextRepeatedInitialProbe(at_time)) {
|
||||
waiting_for_initial_probe_result_ = true;
|
||||
return InitiateProbing(
|
||||
at_time, {estimated_bitrate_ * config_.first_exponential_probe_scale},
|
||||
true);
|
||||
@ -518,6 +520,29 @@ std::vector<ProbeClusterConfig> ProbeController::Process(Timestamp at_time) {
|
||||
return std::vector<ProbeClusterConfig>();
|
||||
}
|
||||
|
||||
ProbeClusterConfig ProbeController::CreateProbeClusterConfig(Timestamp at_time,
|
||||
DataRate bitrate) {
|
||||
ProbeClusterConfig config;
|
||||
config.at_time = at_time;
|
||||
config.target_data_rate = bitrate;
|
||||
if (network_estimate_ &&
|
||||
config_.network_state_estimate_probing_interval->IsFinite()) {
|
||||
config.target_duration = config_.network_state_probe_duration;
|
||||
config.min_probe_delta = config_.min_probe_delta;
|
||||
} else if (at_time < last_allowed_repeated_initial_probe_) {
|
||||
config.target_duration = config_.initial_probe_duration;
|
||||
config.min_probe_delta = config_.initial_min_probe_delta;
|
||||
} else {
|
||||
config.target_duration = config_.min_probe_duration;
|
||||
config.min_probe_delta = config_.min_probe_delta;
|
||||
}
|
||||
config.target_probe_count = config_.min_probe_packets_sent;
|
||||
config.id = next_probe_cluster_id_;
|
||||
next_probe_cluster_id_++;
|
||||
MaybeLogProbeClusterCreated(event_log_, config);
|
||||
return config;
|
||||
}
|
||||
|
||||
std::vector<ProbeClusterConfig> ProbeController::InitiateProbing(
|
||||
Timestamp now,
|
||||
std::vector<DataRate> bitrates_to_probe,
|
||||
@ -538,9 +563,7 @@ std::vector<ProbeClusterConfig> ProbeController::InitiateProbing(
|
||||
}
|
||||
|
||||
DataRate max_probe_bitrate = max_bitrate_;
|
||||
if (max_total_allocated_bitrate_ > DataRate::Zero() &&
|
||||
!(repeated_initial_probing_enabled_ &&
|
||||
waiting_for_initial_probe_result_)) {
|
||||
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
|
||||
@ -556,7 +579,8 @@ std::vector<ProbeClusterConfig> ProbeController::InitiateProbing(
|
||||
case BandwidthLimitedCause::kRttBasedBackOffHighRtt:
|
||||
case BandwidthLimitedCause::kDelayBasedLimitedDelayIncreased:
|
||||
case BandwidthLimitedCause::kLossLimitedBwe:
|
||||
RTC_LOG(LS_INFO) << "Not sending probe in bandwidth limited state.";
|
||||
RTC_LOG(LS_INFO) << "Not sending probe in bandwidth limited state. "
|
||||
<< static_cast<int>(bandwidth_limited_cause_);
|
||||
return {};
|
||||
case BandwidthLimitedCause::kLossLimitedBweIncreasing:
|
||||
estimate_capped_bitrate =
|
||||
@ -590,21 +614,7 @@ std::vector<ProbeClusterConfig> ProbeController::InitiateProbing(
|
||||
probe_further = false;
|
||||
}
|
||||
|
||||
ProbeClusterConfig config;
|
||||
config.at_time = now;
|
||||
config.target_data_rate = bitrate;
|
||||
if (network_estimate_ &&
|
||||
config_.network_state_estimate_probing_interval->IsFinite()) {
|
||||
config.target_duration = config_.network_state_probe_duration;
|
||||
} else {
|
||||
config.target_duration = config_.min_probe_duration;
|
||||
}
|
||||
|
||||
config.target_probe_count = config_.min_probe_packets_sent;
|
||||
config.id = next_probe_cluster_id_;
|
||||
next_probe_cluster_id_++;
|
||||
MaybeLogProbeClusterCreated(event_log_, config);
|
||||
pending_probes.push_back(config);
|
||||
pending_probes.push_back(CreateProbeClusterConfig(now, bitrate));
|
||||
}
|
||||
time_last_probing_initiated_ = now;
|
||||
if (probe_further) {
|
||||
|
||||
@ -45,12 +45,16 @@ struct ProbeControllerConfig {
|
||||
FieldTrialParameter<bool> abort_further_probe_if_max_lower_than_current;
|
||||
// Duration of time from the first initial probe where repeated initial probes
|
||||
// are sent if repeated initial probing is enabled.
|
||||
FieldTrialParameter<TimeDelta> repeated_initial_probing_duration;
|
||||
|
||||
FieldTrialParameter<TimeDelta> repeated_initial_probing_time_period;
|
||||
// The minimum probing duration of an individual probe during
|
||||
// the repeated_initial_probing_time_period.
|
||||
FieldTrialParameter<TimeDelta> initial_probe_duration;
|
||||
// Delta time between sent bursts of packets in a probe during
|
||||
// the repeated_initial_probing_time_period.
|
||||
FieldTrialParameter<TimeDelta> initial_min_probe_delta;
|
||||
// Configures how often we send ALR probes and how big they are.
|
||||
FieldTrialParameter<TimeDelta> alr_probing_interval;
|
||||
FieldTrialParameter<double> alr_probe_scale;
|
||||
|
||||
// Configures how often we send probes if NetworkStateEstimate is available.
|
||||
FieldTrialParameter<TimeDelta> network_state_estimate_probing_interval;
|
||||
// Periodically probe as long as the ratio between current estimate and
|
||||
@ -74,6 +78,8 @@ struct ProbeControllerConfig {
|
||||
FieldTrialParameter<int> min_probe_packets_sent;
|
||||
// The minimum probing duration.
|
||||
FieldTrialParameter<TimeDelta> min_probe_duration;
|
||||
// Delta time between sent bursts of packets in a probe.
|
||||
FieldTrialParameter<TimeDelta> min_probe_delta;
|
||||
FieldTrialParameter<double> loss_limited_probe_scale;
|
||||
// Don't send a probe if min(estimate, network state estimate) is larger than
|
||||
// this fraction of the set max bitrate.
|
||||
@ -83,7 +89,7 @@ struct ProbeControllerConfig {
|
||||
// Reason that bandwidth estimate is limited. Bandwidth estimate can be limited
|
||||
// by either delay based bwe, or loss based bwe when it increases/decreases the
|
||||
// estimate.
|
||||
enum class BandwidthLimitedCause {
|
||||
enum class BandwidthLimitedCause : int {
|
||||
kLossLimitedBweIncreasing = 0,
|
||||
kLossLimitedBwe = 1,
|
||||
kDelayBasedLimited = 2,
|
||||
@ -126,8 +132,10 @@ class ProbeController {
|
||||
void EnablePeriodicAlrProbing(bool enable);
|
||||
|
||||
// Probes are sent periodically every 1s during the first 5s after the network
|
||||
// becomes available. The probes ignores allocated bitrate constraints and
|
||||
// probe up to max configured bitrate configured via SetBitrates.
|
||||
// becomes available or until OnMaxTotalAllocatedBitrate is invoked with a
|
||||
// none zero max_total_allocated_bitrate (there are active streams being
|
||||
// sent.) Probe rate is up to max configured bitrate configured via
|
||||
// SetBitrates.
|
||||
void EnableRepeatedInitialProbing(bool enable);
|
||||
|
||||
void SetAlrStartTimeMs(absl::optional<int64_t> alr_start_time);
|
||||
@ -139,8 +147,9 @@ class ProbeController {
|
||||
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_` and
|
||||
// `network_available_`.
|
||||
// created EXCEPT for configuration settings like
|
||||
// `enable_periodic_alr_probing_` `network_available_` and
|
||||
// `max_total_allocated_bitrate_`.
|
||||
void Reset(Timestamp at_time);
|
||||
|
||||
ABSL_MUST_USE_RESULT std::vector<ProbeClusterConfig> Process(
|
||||
@ -166,9 +175,10 @@ class ProbeController {
|
||||
bool TimeForAlrProbe(Timestamp at_time) const;
|
||||
bool TimeForNetworkStateProbe(Timestamp at_time) const;
|
||||
bool TimeForNextRepeatedInitialProbe(Timestamp at_time) const;
|
||||
ProbeClusterConfig CreateProbeClusterConfig(Timestamp at_time,
|
||||
DataRate bitrate);
|
||||
|
||||
bool network_available_;
|
||||
bool waiting_for_initial_probe_result_ = false;
|
||||
bool repeated_initial_probing_enabled_ = false;
|
||||
Timestamp last_allowed_repeated_initial_probe_ = Timestamp::MinusInfinity();
|
||||
BandwidthLimitedCause bandwidth_limited_cause_ =
|
||||
|
||||
@ -378,37 +378,6 @@ TEST(ProbeControllerTest, ExponentialProbingStopIfMaxAllocatedBitrateLow) {
|
||||
EXPECT_THAT(probes, IsEmpty());
|
||||
}
|
||||
|
||||
TEST(ProbeControllerTest, RepeatedInitialProbingIgnoreLowMaxAllocatedbitrate) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
ASSERT_THAT(
|
||||
probe_controller->OnNetworkAvailability({.network_available = true}),
|
||||
IsEmpty());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
ASSERT_THAT(probes, SizeIs(Gt(0)));
|
||||
probe_controller->EnableRepeatedInitialProbing(true);
|
||||
|
||||
// Repeated probe is sent when estimated bitrate climbs above
|
||||
// 0.7 * 6 * kStartBitrate = 1260. During the initial probe, we ignore the
|
||||
// allocation limit and probe up to the max.
|
||||
probes = probe_controller->OnMaxTotalAllocatedBitrate(kStartBitrate,
|
||||
fixture.CurrentTime());
|
||||
EXPECT_THAT(probes, IsEmpty());
|
||||
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
DataRate::BitsPerSec(1800), BandwidthLimitedCause::kDelayBasedLimited,
|
||||
fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
EXPECT_EQ(probes[0].target_data_rate.bps(), 2 * 1800);
|
||||
|
||||
probes = probe_controller->SetEstimatedBitrate(
|
||||
probes[0].target_data_rate, BandwidthLimitedCause::kDelayBasedLimited,
|
||||
fixture.CurrentTime());
|
||||
EXPECT_EQ(probes.size(), 1u);
|
||||
}
|
||||
|
||||
TEST(ProbeControllerTest, InitialProbingToLowMaxAllocatedbitrate) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
@ -475,6 +444,8 @@ TEST(ProbeControllerTest, RepeatedInitialProbingSendsNewProbeAfterTimeout) {
|
||||
// Expect a probe every second.
|
||||
EXPECT_EQ(fixture.CurrentTime() - last_probe_time,
|
||||
TimeDelta::Seconds(1.1));
|
||||
EXPECT_EQ(probes[0].min_probe_delta, TimeDelta::Millis(20));
|
||||
EXPECT_EQ(probes[0].target_duration, TimeDelta::Millis(100));
|
||||
last_probe_time = fixture.CurrentTime();
|
||||
} else {
|
||||
EXPECT_LT(fixture.CurrentTime() - last_probe_time,
|
||||
@ -486,6 +457,28 @@ TEST(ProbeControllerTest, RepeatedInitialProbingSendsNewProbeAfterTimeout) {
|
||||
EXPECT_THAT(probe_controller->Process(fixture.CurrentTime()), IsEmpty());
|
||||
}
|
||||
|
||||
TEST(ProbeControllerTest, RepeatedInitialProbingStopIfMaxAllocatedBitrateSet) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
probe_controller->EnableRepeatedInitialProbing(true);
|
||||
ASSERT_THAT(
|
||||
probe_controller->OnNetworkAvailability({.network_available = true}),
|
||||
IsEmpty());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
EXPECT_THAT(probes, SizeIs(Gt(0)));
|
||||
|
||||
fixture.AdvanceTime(TimeDelta::Millis(1100));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_THAT(probes, SizeIs(1));
|
||||
probes = probe_controller->OnMaxTotalAllocatedBitrate(kMinBitrate,
|
||||
fixture.CurrentTime());
|
||||
fixture.AdvanceTime(TimeDelta::Millis(1100));
|
||||
probes = probe_controller->Process(fixture.CurrentTime());
|
||||
EXPECT_THAT(probes, IsEmpty());
|
||||
}
|
||||
|
||||
TEST(ProbeControllerTest, RequestProbeInAlr) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
@ -1274,6 +1267,27 @@ TEST(ProbeControllerTest,
|
||||
EXPECT_TRUE(probes.empty());
|
||||
}
|
||||
|
||||
TEST(ProbeControllerTest, MaxAllocatedBitrateNotReset) {
|
||||
ProbeControllerFixture fixture;
|
||||
std::unique_ptr<ProbeController> probe_controller =
|
||||
fixture.CreateController();
|
||||
ASSERT_THAT(
|
||||
probe_controller->OnNetworkAvailability({.network_available = true}),
|
||||
IsEmpty());
|
||||
auto probes = probe_controller->SetBitrates(
|
||||
kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime());
|
||||
ASSERT_FALSE(probes.empty());
|
||||
|
||||
probes = probe_controller->OnMaxTotalAllocatedBitrate(kStartBitrate / 4,
|
||||
fixture.CurrentTime());
|
||||
probe_controller->Reset(fixture.CurrentTime());
|
||||
|
||||
probes = probe_controller->SetBitrates(kMinBitrate, kStartBitrate,
|
||||
kMaxBitrate, fixture.CurrentTime());
|
||||
ASSERT_FALSE(probes.empty());
|
||||
EXPECT_EQ(probes[0].target_data_rate, kStartBitrate / 4 * 2);
|
||||
}
|
||||
|
||||
TEST(ProbeControllerTest, SkipAlrProbeIfEstimateLargerThanMaxProbe) {
|
||||
ProbeControllerFixture fixture(
|
||||
"WebRTC-Bwe-ProbingConfiguration/"
|
||||
|
||||
@ -98,6 +98,7 @@ if (rtc_include_tests) {
|
||||
":interval_budget",
|
||||
":pacing",
|
||||
"../../api/task_queue:task_queue",
|
||||
"../../api/transport:field_trial_based_config",
|
||||
"../../api/transport:network_control",
|
||||
"../../api/units:data_rate",
|
||||
"../../api/units:data_size",
|
||||
|
||||
@ -12,7 +12,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
@ -26,10 +28,9 @@ constexpr size_t kMaxPendingProbeClusters = 5;
|
||||
|
||||
BitrateProberConfig::BitrateProberConfig(
|
||||
const FieldTrialsView* key_value_config)
|
||||
: min_probe_delta("min_probe_delta", TimeDelta::Millis(2)),
|
||||
max_probe_delay("max_probe_delay", TimeDelta::Millis(10)),
|
||||
: max_probe_delay("max_probe_delay", TimeDelta::Millis(10)),
|
||||
min_packet_size("min_packet_size", DataSize::Bytes(200)) {
|
||||
ParseFieldTrial({&min_probe_delta, &max_probe_delay, &min_packet_size},
|
||||
ParseFieldTrial({&max_probe_delay, &min_packet_size},
|
||||
key_value_config->Lookup("WebRTC-Bwe-ProbingBehavior"));
|
||||
}
|
||||
|
||||
@ -93,6 +94,7 @@ void BitrateProber::OnIncomingPacket(DataSize packet_size) {
|
||||
void BitrateProber::CreateProbeCluster(
|
||||
const ProbeClusterConfig& cluster_config) {
|
||||
RTC_DCHECK(probing_state_ != ProbingState::kDisabled);
|
||||
RTC_DCHECK(cluster_config.min_probe_delta > TimeDelta::Zero());
|
||||
|
||||
while (!clusters_.empty() &&
|
||||
(cluster_config.at_time - clusters_.front().requested_at >
|
||||
@ -109,6 +111,7 @@ void BitrateProber::CreateProbeCluster(
|
||||
(cluster_config.target_data_rate * cluster_config.target_duration)
|
||||
.bytes();
|
||||
RTC_DCHECK_GE(cluster.pace_info.probe_cluster_min_bytes, 0);
|
||||
cluster.min_probe_delta = cluster_config.min_probe_delta;
|
||||
cluster.pace_info.send_bitrate = cluster_config.target_data_rate;
|
||||
cluster.pace_info.probe_cluster_id = cluster_config.id;
|
||||
clusters_.push(cluster);
|
||||
@ -164,7 +167,7 @@ DataSize BitrateProber::RecommendedMinProbeSize() const {
|
||||
return DataSize::Zero();
|
||||
}
|
||||
DataRate send_rate = clusters_.front().pace_info.send_bitrate;
|
||||
return send_rate * config_.min_probe_delta;
|
||||
return send_rate * clusters_.front().min_probe_delta;
|
||||
}
|
||||
|
||||
void BitrateProber::ProbeSent(Timestamp now, DataSize size) {
|
||||
|
||||
@ -16,8 +16,10 @@
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -29,8 +31,6 @@ struct BitrateProberConfig {
|
||||
BitrateProberConfig& operator=(const BitrateProberConfig&) = default;
|
||||
~BitrateProberConfig() = default;
|
||||
|
||||
// A minimum interval between probes to allow scheduling to be feasible.
|
||||
FieldTrialParameter<TimeDelta> min_probe_delta;
|
||||
// Maximum amount of time each probe can be delayed.
|
||||
FieldTrialParameter<TimeDelta> max_probe_delay;
|
||||
// This is used to start sending a probe after a large enough packet.
|
||||
@ -103,9 +103,9 @@ class BitrateProber {
|
||||
|
||||
int sent_probes = 0;
|
||||
int sent_bytes = 0;
|
||||
TimeDelta min_probe_delta = TimeDelta::Zero();
|
||||
Timestamp requested_at = Timestamp::MinusInfinity();
|
||||
Timestamp started_at = Timestamp::MinusInfinity();
|
||||
int retries = 0;
|
||||
};
|
||||
|
||||
Timestamp CalculateNextProbeTime(const ProbeCluster& cluster) const;
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#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"
|
||||
@ -39,11 +40,13 @@ TEST(BitrateProberTest, VerifyStatesAndTimeBetweenProbes) {
|
||||
prober.CreateProbeCluster({.at_time = now,
|
||||
.target_data_rate = kTestBitrate1,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
prober.CreateProbeCluster({.at_time = now,
|
||||
.target_data_rate = kTestBitrate2,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 1});
|
||||
EXPECT_FALSE(prober.is_probing());
|
||||
@ -100,6 +103,7 @@ TEST(BitrateProberTest, DoesntProbeWithoutRecentPackets) {
|
||||
prober.CreateProbeCluster({.at_time = now,
|
||||
.target_data_rate = DataRate::KilobitsPerSec(900),
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
EXPECT_FALSE(prober.is_probing());
|
||||
@ -125,6 +129,7 @@ TEST(BitrateProberTest, DiscardsDelayedProbes) {
|
||||
prober.CreateProbeCluster({.at_time = now,
|
||||
.target_data_rate = DataRate::KilobitsPerSec(900),
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
|
||||
@ -154,6 +159,7 @@ TEST(BitrateProberTest, LimitsNumberOfPendingProbeClusters) {
|
||||
prober.CreateProbeCluster({.at_time = now,
|
||||
.target_data_rate = DataRate::KilobitsPerSec(900),
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
prober.OnIncomingPacket(kProbeSize);
|
||||
@ -165,6 +171,7 @@ TEST(BitrateProberTest, LimitsNumberOfPendingProbeClusters) {
|
||||
{.at_time = now,
|
||||
.target_data_rate = DataRate::KilobitsPerSec(900),
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = i});
|
||||
prober.OnIncomingPacket(kProbeSize);
|
||||
@ -190,6 +197,7 @@ TEST(BitrateProberTest, DoesntInitializeProbingForSmallPackets) {
|
||||
prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
|
||||
.target_data_rate = DataRate::KilobitsPerSec(1000),
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
prober.OnIncomingPacket(DataSize::Bytes(100));
|
||||
@ -208,6 +216,7 @@ TEST(BitrateProberTest, DoesInitializeProbingForSmallPacketsIfConfigured) {
|
||||
prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
|
||||
.target_data_rate = DataRate::KilobitsPerSec(1000),
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
prober.OnIncomingPacket(DataSize::Bytes(10));
|
||||
@ -224,6 +233,7 @@ TEST(BitrateProberTest, VerifyProbeSizeOnHighBitrate) {
|
||||
prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
|
||||
.target_data_rate = kHighBitrate,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
// Probe size should ensure a minimum of 1 ms interval.
|
||||
@ -231,10 +241,9 @@ TEST(BitrateProberTest, VerifyProbeSizeOnHighBitrate) {
|
||||
kHighBitrate * TimeDelta::Millis(1));
|
||||
}
|
||||
|
||||
TEST(BitrateProberTest, ProbeSizeCanBeSetWithFieldTrial) {
|
||||
const test::ExplicitKeyValueConfig trials(
|
||||
"WebRTC-Bwe-ProbingBehavior/min_probe_delta:20ms/");
|
||||
BitrateProber prober(trials);
|
||||
TEST(BitrateProberTest, ProbeSizeCanBeSetInProbeClusterConfig) {
|
||||
const FieldTrialBasedConfig config;
|
||||
BitrateProber prober(config);
|
||||
prober.SetEnabled(true);
|
||||
|
||||
const DataRate kHighBitrate = DataRate::KilobitsPerSec(10000); // 10 Mbps
|
||||
@ -242,6 +251,7 @@ TEST(BitrateProberTest, ProbeSizeCanBeSetWithFieldTrial) {
|
||||
prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
|
||||
.target_data_rate = kHighBitrate,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(20),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
EXPECT_EQ(prober.RecommendedMinProbeSize(),
|
||||
@ -267,6 +277,7 @@ TEST(BitrateProberTest, MinumumNumberOfProbingPackets) {
|
||||
prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
|
||||
.target_data_rate = kBitrate,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
|
||||
@ -290,6 +301,7 @@ TEST(BitrateProberTest, ScaleBytesUsedForProbing) {
|
||||
prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
|
||||
.target_data_rate = kBitrate,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
prober.OnIncomingPacket(kPacketSize);
|
||||
@ -314,6 +326,7 @@ TEST(BitrateProberTest, HighBitrateProbing) {
|
||||
prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
|
||||
.target_data_rate = kBitrate,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
prober.OnIncomingPacket(kPacketSize);
|
||||
@ -340,6 +353,7 @@ TEST(BitrateProberTest, ProbeClusterTimeout) {
|
||||
prober.CreateProbeCluster({.at_time = now,
|
||||
.target_data_rate = kBitrate,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
prober.OnIncomingPacket(kSmallPacketSize);
|
||||
@ -348,6 +362,7 @@ TEST(BitrateProberTest, ProbeClusterTimeout) {
|
||||
prober.CreateProbeCluster({.at_time = now,
|
||||
.target_data_rate = kBitrate / 10,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 1});
|
||||
prober.OnIncomingPacket(kSmallPacketSize);
|
||||
@ -356,6 +371,7 @@ TEST(BitrateProberTest, ProbeClusterTimeout) {
|
||||
prober.CreateProbeCluster({.at_time = now,
|
||||
.target_data_rate = kBitrate / 10,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 2});
|
||||
prober.OnIncomingPacket(kSmallPacketSize);
|
||||
@ -378,6 +394,7 @@ TEST(BitrateProberTest, CanProbeImmediatelyIfConfigured) {
|
||||
prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
|
||||
.target_data_rate = DataRate::KilobitsPerSec(300),
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 5,
|
||||
.id = 0});
|
||||
EXPECT_TRUE(prober.is_probing());
|
||||
@ -392,6 +409,7 @@ TEST(BitrateProberTest, CanProbeImmediatelyAgainAfterProbeIfConfigured) {
|
||||
.at_time = Timestamp::Zero(),
|
||||
.target_data_rate = DataRate::KilobitsPerSec(300),
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = TimeDelta::Millis(2),
|
||||
.target_probe_count = 1,
|
||||
.id = 0};
|
||||
prober.CreateProbeCluster(cluster_config);
|
||||
|
||||
@ -443,8 +443,7 @@ TEST(TaskQueuePacedSenderTest, SchedulesProbeAtSentTime) {
|
||||
TEST(TaskQueuePacedSenderTest, NoMinSleepTimeWhenProbing) {
|
||||
// Set min_probe_delta to be less than kMinSleepTime (1ms).
|
||||
const TimeDelta kMinProbeDelta = TimeDelta::Micros(200);
|
||||
ScopedKeyValueConfig trials(
|
||||
"WebRTC-Bwe-ProbingBehavior/min_probe_delta:200us/");
|
||||
ScopedKeyValueConfig trials;
|
||||
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
|
||||
MockPacketRouter packet_router;
|
||||
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
||||
@ -473,6 +472,7 @@ TEST(TaskQueuePacedSenderTest, NoMinSleepTimeWhenProbing) {
|
||||
{{.at_time = time_controller.GetClock()->CurrentTime(),
|
||||
.target_data_rate = kProbingRate,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.min_probe_delta = kMinProbeDelta,
|
||||
.target_probe_count = 5,
|
||||
.id = kProbeClusterId}});
|
||||
|
||||
|
||||
@ -199,7 +199,7 @@ TEST_P(BweRampupWithInitialProbeTest, BweRampUpBothDirectionsWithoutMedia) {
|
||||
|
||||
// Test that 1s after offer/answer exchange finish, we have a BWE estimate,
|
||||
// even though no video frames have been sent.
|
||||
s.ProcessMessages(TimeDelta::Seconds(1));
|
||||
s.ProcessMessages(TimeDelta::Seconds(2));
|
||||
|
||||
auto callee_inbound_stats =
|
||||
GetStatsAndProcess(s, callee)->GetStatsOfType<RTCInboundRtpStreamStats>();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user