Make the BWE threshold adaptive.
This improves self-fairness and competing for resources with TCP flows. BUG=4711 Review URL: https://codereview.webrtc.org/1151603008 Cr-Commit-Position: refs/heads/master@{#9545}
This commit is contained in:
@@ -763,8 +763,8 @@ struct OverUseDetectorOptions {
|
|||||||
initial_e[0][0] = 100;
|
initial_e[0][0] = 100;
|
||||||
initial_e[1][1] = 1e-1;
|
initial_e[1][1] = 1e-1;
|
||||||
initial_e[0][1] = initial_e[1][0] = 0;
|
initial_e[0][1] = initial_e[1][0] = 0;
|
||||||
initial_process_noise[0] = 1e-10;
|
initial_process_noise[0] = 1e-13;
|
||||||
initial_process_noise[1] = 1e-2;
|
initial_process_noise[1] = 1e-3;
|
||||||
}
|
}
|
||||||
double initial_slope;
|
double initial_slope;
|
||||||
double initial_offset;
|
double initial_offset;
|
||||||
|
|||||||
@@ -175,6 +175,8 @@ class IntervalBudget {
|
|||||||
|
|
||||||
void set_target_rate_kbps(int target_rate_kbps) {
|
void set_target_rate_kbps(int target_rate_kbps) {
|
||||||
target_rate_kbps_ = target_rate_kbps;
|
target_rate_kbps_ = target_rate_kbps;
|
||||||
|
bytes_remaining_ =
|
||||||
|
std::max(-kWindowMs * target_rate_kbps_ / 8, bytes_remaining_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IncreaseBudget(int64_t delta_time_ms) {
|
void IncreaseBudget(int64_t delta_time_ms) {
|
||||||
@@ -190,7 +192,7 @@ class IntervalBudget {
|
|||||||
|
|
||||||
void UseBudget(size_t bytes) {
|
void UseBudget(size_t bytes) {
|
||||||
bytes_remaining_ = std::max(bytes_remaining_ - static_cast<int>(bytes),
|
bytes_remaining_ = std::max(bytes_remaining_ - static_cast<int>(bytes),
|
||||||
-500 * target_rate_kbps_ / 8);
|
-kWindowMs * target_rate_kbps_ / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t bytes_remaining() const {
|
size_t bytes_remaining() const {
|
||||||
@@ -200,6 +202,8 @@ class IntervalBudget {
|
|||||||
int target_rate_kbps() const { return target_rate_kbps_; }
|
int target_rate_kbps() const { return target_rate_kbps_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const int kWindowMs = 500;
|
||||||
|
|
||||||
int target_rate_kbps_;
|
int target_rate_kbps_;
|
||||||
int bytes_remaining_;
|
int bytes_remaining_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "webrtc/modules/remote_bitrate_estimator/overuse_detector.h"
|
||||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
|
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@@ -27,20 +28,20 @@ AimdRateControl::AimdRateControl(uint32_t min_bitrate_bps)
|
|||||||
: min_configured_bitrate_bps_(min_bitrate_bps),
|
: min_configured_bitrate_bps_(min_bitrate_bps),
|
||||||
max_configured_bitrate_bps_(30000000),
|
max_configured_bitrate_bps_(30000000),
|
||||||
current_bitrate_bps_(max_configured_bitrate_bps_),
|
current_bitrate_bps_(max_configured_bitrate_bps_),
|
||||||
max_hold_rate_bps_(0),
|
|
||||||
avg_max_bitrate_kbps_(-1.0f),
|
avg_max_bitrate_kbps_(-1.0f),
|
||||||
var_max_bitrate_kbps_(0.4f),
|
var_max_bitrate_kbps_(0.4f),
|
||||||
rate_control_state_(kRcHold),
|
rate_control_state_(kRcHold),
|
||||||
came_from_state_(kRcDecrease),
|
|
||||||
rate_control_region_(kRcMaxUnknown),
|
rate_control_region_(kRcMaxUnknown),
|
||||||
time_last_bitrate_change_(-1),
|
time_last_bitrate_change_(-1),
|
||||||
current_input_(kBwNormal, 0, 1.0),
|
current_input_(kBwNormal, 0, 1.0),
|
||||||
updated_(false),
|
updated_(false),
|
||||||
time_first_incoming_estimate_(-1),
|
time_first_incoming_estimate_(-1),
|
||||||
bitrate_is_initialized_(false),
|
bitrate_is_initialized_(false),
|
||||||
beta_(0.9f),
|
beta_(0.85f),
|
||||||
rtt_(kDefaultRttMs),
|
rtt_(kDefaultRttMs),
|
||||||
time_of_last_log_(-1) {}
|
time_of_last_log_(-1),
|
||||||
|
in_experiment_(AdaptiveThresholdExperimentIsEnabled()) {
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t AimdRateControl::GetMinBitrate() const {
|
uint32_t AimdRateControl::GetMinBitrate() const {
|
||||||
return min_configured_bitrate_bps_;
|
return min_configured_bitrate_bps_;
|
||||||
@@ -95,8 +96,7 @@ void AimdRateControl::SetRtt(int64_t rtt) {
|
|||||||
rtt_ = rtt;
|
rtt_ = rtt;
|
||||||
}
|
}
|
||||||
|
|
||||||
RateControlRegion AimdRateControl::Update(const RateControlInput* input,
|
void AimdRateControl::Update(const RateControlInput* input, int64_t now_ms) {
|
||||||
int64_t now_ms) {
|
|
||||||
assert(input);
|
assert(input);
|
||||||
|
|
||||||
// Set the initial bit rate value to what we're receiving the first half
|
// Set the initial bit rate value to what we're receiving the first half
|
||||||
@@ -122,7 +122,6 @@ RateControlRegion AimdRateControl::Update(const RateControlInput* input,
|
|||||||
updated_ = true;
|
updated_ = true;
|
||||||
current_input_ = *input;
|
current_input_ = *input;
|
||||||
}
|
}
|
||||||
return rate_control_region_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AimdRateControl::SetEstimate(int bitrate_bps, int64_t now_ms) {
|
void AimdRateControl::SetEstimate(int bitrate_bps, int64_t now_ms) {
|
||||||
@@ -145,22 +144,16 @@ uint32_t AimdRateControl::ChangeBitrate(uint32_t current_bitrate_bps,
|
|||||||
// variance and the current incoming bit rate.
|
// variance and the current incoming bit rate.
|
||||||
const float std_max_bit_rate = sqrt(var_max_bitrate_kbps_ *
|
const float std_max_bit_rate = sqrt(var_max_bitrate_kbps_ *
|
||||||
avg_max_bitrate_kbps_);
|
avg_max_bitrate_kbps_);
|
||||||
bool fast_recovery_after_hold = false;
|
|
||||||
switch (rate_control_state_) {
|
switch (rate_control_state_) {
|
||||||
case kRcHold: {
|
case kRcHold:
|
||||||
max_hold_rate_bps_ = std::max(max_hold_rate_bps_, incoming_bitrate_bps);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case kRcIncrease: {
|
case kRcIncrease:
|
||||||
if (avg_max_bitrate_kbps_ >= 0) {
|
if (avg_max_bitrate_kbps_ >= 0 &&
|
||||||
if (incoming_bitrate_kbps > avg_max_bitrate_kbps_ +
|
incoming_bitrate_kbps >
|
||||||
3 * std_max_bit_rate) {
|
avg_max_bitrate_kbps_ + 3 * std_max_bit_rate) {
|
||||||
ChangeRegion(kRcMaxUnknown);
|
ChangeRegion(kRcMaxUnknown);
|
||||||
avg_max_bitrate_kbps_ = -1.0;
|
avg_max_bitrate_kbps_ = -1.0;
|
||||||
} else if (incoming_bitrate_kbps > avg_max_bitrate_kbps_ +
|
|
||||||
2.5 * std_max_bit_rate) {
|
|
||||||
ChangeRegion(kRcAboveMax);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (rate_control_region_ == kRcNearMax) {
|
if (rate_control_region_ == kRcNearMax) {
|
||||||
// Approximate the over-use estimator delay to 100 ms.
|
// Approximate the over-use estimator delay to 100 ms.
|
||||||
@@ -175,18 +168,10 @@ uint32_t AimdRateControl::ChangeBitrate(uint32_t current_bitrate_bps,
|
|||||||
current_bitrate_bps += multiplicative_increase_bps;
|
current_bitrate_bps += multiplicative_increase_bps;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_hold_rate_bps_ > 0 &&
|
|
||||||
beta_ * max_hold_rate_bps_ > current_bitrate_bps) {
|
|
||||||
current_bitrate_bps = static_cast<uint32_t>(beta_ * max_hold_rate_bps_);
|
|
||||||
avg_max_bitrate_kbps_ = beta_ * max_hold_rate_bps_ / 1000.0f;
|
|
||||||
ChangeRegion(kRcNearMax);
|
|
||||||
fast_recovery_after_hold = true;
|
|
||||||
}
|
|
||||||
max_hold_rate_bps_ = 0;
|
|
||||||
time_last_bitrate_change_ = now_ms;
|
time_last_bitrate_change_ = now_ms;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case kRcDecrease: {
|
case kRcDecrease:
|
||||||
if (incoming_bitrate_bps < min_configured_bitrate_bps_) {
|
if (incoming_bitrate_bps < min_configured_bitrate_bps_) {
|
||||||
current_bitrate_bps = min_configured_bitrate_bps_;
|
current_bitrate_bps = min_configured_bitrate_bps_;
|
||||||
} else {
|
} else {
|
||||||
@@ -216,12 +201,11 @@ uint32_t AimdRateControl::ChangeBitrate(uint32_t current_bitrate_bps,
|
|||||||
ChangeState(kRcHold);
|
ChangeState(kRcHold);
|
||||||
time_last_bitrate_change_ = now_ms;
|
time_last_bitrate_change_ = now_ms;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
if (!fast_recovery_after_hold && (incoming_bitrate_bps > 100000 ||
|
if ((incoming_bitrate_bps > 100000 || current_bitrate_bps > 150000) &&
|
||||||
current_bitrate_bps > 150000) &&
|
|
||||||
current_bitrate_bps > 1.5 * incoming_bitrate_bps) {
|
current_bitrate_bps > 1.5 * incoming_bitrate_bps) {
|
||||||
// Allow changing the bit rate if we are operating at very low rates
|
// Allow changing the bit rate if we are operating at very low rates
|
||||||
// Don't change the bit rate if the send side is too far off
|
// Don't change the bit rate if the send side is too far off
|
||||||
@@ -249,8 +233,10 @@ uint32_t AimdRateControl::AdditiveRateIncrease(
|
|||||||
assert(response_time_ms > 0);
|
assert(response_time_ms > 0);
|
||||||
double beta = 0.0;
|
double beta = 0.0;
|
||||||
if (last_ms > 0) {
|
if (last_ms > 0) {
|
||||||
beta = std::min((now_ms - last_ms) /
|
beta = std::min((now_ms - last_ms) / static_cast<double>(response_time_ms),
|
||||||
static_cast<double>(response_time_ms), 1.0);
|
1.0);
|
||||||
|
if (in_experiment_)
|
||||||
|
beta /= 2.0;
|
||||||
}
|
}
|
||||||
double bits_per_frame = static_cast<double>(current_bitrate_bps_) / 30.0;
|
double bits_per_frame = static_cast<double>(current_bitrate_bps_) / 30.0;
|
||||||
double packets_per_frame = std::ceil(bits_per_frame / (8.0 * 1200.0));
|
double packets_per_frame = std::ceil(bits_per_frame / (8.0 * 1200.0));
|
||||||
@@ -308,21 +294,9 @@ void AimdRateControl::ChangeState(const RateControlInput& input,
|
|||||||
|
|
||||||
void AimdRateControl::ChangeRegion(RateControlRegion region) {
|
void AimdRateControl::ChangeRegion(RateControlRegion region) {
|
||||||
rate_control_region_ = region;
|
rate_control_region_ = region;
|
||||||
switch (rate_control_region_) {
|
|
||||||
case kRcAboveMax:
|
|
||||||
case kRcMaxUnknown:
|
|
||||||
beta_ = 0.9f;
|
|
||||||
break;
|
|
||||||
case kRcNearMax:
|
|
||||||
beta_ = 0.95f;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AimdRateControl::ChangeState(RateControlState new_state) {
|
void AimdRateControl::ChangeState(RateControlState new_state) {
|
||||||
came_from_state_ = rate_control_state_;
|
|
||||||
rate_control_state_ = new_state;
|
rate_control_state_ = new_state;
|
||||||
}
|
}
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class AimdRateControl {
|
|||||||
uint32_t LatestEstimate() const;
|
uint32_t LatestEstimate() const;
|
||||||
uint32_t UpdateBandwidthEstimate(int64_t now_ms);
|
uint32_t UpdateBandwidthEstimate(int64_t now_ms);
|
||||||
void SetRtt(int64_t rtt);
|
void SetRtt(int64_t rtt);
|
||||||
RateControlRegion Update(const RateControlInput* input, int64_t now_ms);
|
void Update(const RateControlInput* input, int64_t now_ms);
|
||||||
void SetEstimate(int bitrate_bps, int64_t now_ms);
|
void SetEstimate(int bitrate_bps, int64_t now_ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -71,7 +71,6 @@ class AimdRateControl {
|
|||||||
float avg_max_bitrate_kbps_;
|
float avg_max_bitrate_kbps_;
|
||||||
float var_max_bitrate_kbps_;
|
float var_max_bitrate_kbps_;
|
||||||
RateControlState rate_control_state_;
|
RateControlState rate_control_state_;
|
||||||
RateControlState came_from_state_;
|
|
||||||
RateControlRegion rate_control_region_;
|
RateControlRegion rate_control_region_;
|
||||||
int64_t time_last_bitrate_change_;
|
int64_t time_last_bitrate_change_;
|
||||||
RateControlInput current_input_;
|
RateControlInput current_input_;
|
||||||
@@ -81,6 +80,7 @@ class AimdRateControl {
|
|||||||
float beta_;
|
float beta_;
|
||||||
int64_t rtt_;
|
int64_t rtt_;
|
||||||
int64_t time_of_last_log_;
|
int64_t time_of_last_log_;
|
||||||
|
bool in_experiment_;
|
||||||
|
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(AimdRateControl);
|
DISALLOW_IMPLICIT_CONSTRUCTORS(AimdRateControl);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ TEST_P(BweSimulation, Choke1000kbps500kbps1000kbps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, PacerChoke1000kbps500kbps1000kbps) {
|
TEST_P(BweSimulation, PacerChoke1000kbps500kbps1000kbps) {
|
||||||
PeriodicKeyFrameSource source(0, 30, 300, 0, 0, 1000);
|
AdaptiveVideoSource source(0, 30, 300, 0, 0);
|
||||||
PacedVideoSender sender(&uplink_, &source, GetParam());
|
PacedVideoSender sender(&uplink_, &source, GetParam());
|
||||||
ChokeFilter filter(&uplink_, 0);
|
ChokeFilter filter(&uplink_, 0);
|
||||||
RateCounterFilter counter(&uplink_, 0, "receiver_input");
|
RateCounterFilter counter(&uplink_, 0, "receiver_input");
|
||||||
@@ -142,7 +142,7 @@ TEST_P(BweSimulation, PacerChoke10000kbps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, PacerChoke200kbps30kbps200kbps) {
|
TEST_P(BweSimulation, PacerChoke200kbps30kbps200kbps) {
|
||||||
PeriodicKeyFrameSource source(0, 30, 300, 0, 0, 1000);
|
AdaptiveVideoSource source(0, 30, 300, 0, 0);
|
||||||
PacedVideoSender sender(&uplink_, &source, GetParam());
|
PacedVideoSender sender(&uplink_, &source, GetParam());
|
||||||
ChokeFilter filter(&uplink_, 0);
|
ChokeFilter filter(&uplink_, 0);
|
||||||
RateCounterFilter counter(&uplink_, 0, "receiver_input");
|
RateCounterFilter counter(&uplink_, 0, "receiver_input");
|
||||||
@@ -234,15 +234,16 @@ TEST_P(BweSimulation, PacerGoogleWifiTrace3Mbps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, SelfFairnessTest) {
|
TEST_P(BweSimulation, SelfFairnessTest) {
|
||||||
const int kAllFlowIds[] = {0, 1, 2};
|
srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
|
||||||
|
const int kAllFlowIds[] = {0, 1, 2, 3};
|
||||||
const size_t kNumFlows = sizeof(kAllFlowIds) / sizeof(kAllFlowIds[0]);
|
const size_t kNumFlows = sizeof(kAllFlowIds) / sizeof(kAllFlowIds[0]);
|
||||||
rtc::scoped_ptr<AdaptiveVideoSource> sources[kNumFlows];
|
rtc::scoped_ptr<VideoSource> sources[kNumFlows];
|
||||||
rtc::scoped_ptr<VideoSender> senders[kNumFlows];
|
rtc::scoped_ptr<VideoSender> senders[kNumFlows];
|
||||||
for (size_t i = 0; i < kNumFlows; ++i) {
|
for (size_t i = 0; i < kNumFlows; ++i) {
|
||||||
// Streams started 20 seconds apart to give them different advantage when
|
// Streams started 20 seconds apart to give them different advantage when
|
||||||
// competing for the bandwidth.
|
// competing for the bandwidth.
|
||||||
sources[i].reset(
|
sources[i].reset(new AdaptiveVideoSource(kAllFlowIds[i], 30, 300, 0,
|
||||||
new AdaptiveVideoSource(kAllFlowIds[i], 30, 300, 0, i * 20000));
|
i * (rand() % 40000)));
|
||||||
senders[i].reset(new VideoSender(&uplink_, sources[i].get(), GetParam()));
|
senders[i].reset(new VideoSender(&uplink_, sources[i].get(), GetParam()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,11 +268,16 @@ TEST_P(BweSimulation, SelfFairnessTest) {
|
|||||||
RunFor(30 * 60 * 1000);
|
RunFor(30 * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, PacedSelfFairnessTest) {
|
TEST_P(BweSimulation, PacedSelfFairness50msTest) {
|
||||||
srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
|
srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
|
||||||
RunFairnessTest(GetParam(), 4, 0, 1000, 3000, 50);
|
RunFairnessTest(GetParam(), 4, 0, 1000, 3000, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(BweSimulation, PacedSelfFairness500msTest) {
|
||||||
|
srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
|
||||||
|
RunFairnessTest(GetParam(), 4, 0, 1000, 3000, 500);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, PacedSelfFairness1000msTest) {
|
TEST_P(BweSimulation, PacedSelfFairness1000msTest) {
|
||||||
srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
|
srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
|
||||||
RunFairnessTest(GetParam(), 4, 0, 1000, 3000, 1000);
|
RunFairnessTest(GetParam(), 4, 0, 1000, 3000, 1000);
|
||||||
|
|||||||
@@ -11,25 +11,60 @@
|
|||||||
#include "webrtc/modules/remote_bitrate_estimator/overuse_detector.h"
|
#include "webrtc/modules/remote_bitrate_estimator/overuse_detector.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "webrtc/base/checks.h"
|
||||||
|
#include "webrtc/base/common.h"
|
||||||
#include "webrtc/modules/remote_bitrate_estimator/include/bwe_defines.h"
|
#include "webrtc/modules/remote_bitrate_estimator/include/bwe_defines.h"
|
||||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
|
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
|
||||||
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
|
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
|
||||||
|
#include "webrtc/system_wrappers/interface/field_trial.h"
|
||||||
#include "webrtc/system_wrappers/interface/trace.h"
|
#include "webrtc/system_wrappers/interface/trace.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
enum { kOverUsingTimeThreshold = 100 };
|
const char kAdaptiveThresholdExperiment[] = "WebRTC-AdaptiveBweThreshold";
|
||||||
|
const char kEnabledPrefix[] = "Enabled";
|
||||||
|
const size_t kEnabledPrefixLength = sizeof(kEnabledPrefix) - 1;
|
||||||
|
const size_t kMinExperimentLength = kEnabledPrefixLength + 3;
|
||||||
|
|
||||||
|
const double kMaxAdaptOffsetMs = 15.0;
|
||||||
|
const double kOverUsingTimeThreshold = 10;
|
||||||
|
|
||||||
|
bool AdaptiveThresholdExperimentIsEnabled() {
|
||||||
|
std::string experiment_string =
|
||||||
|
webrtc::field_trial::FindFullName(kAdaptiveThresholdExperiment);
|
||||||
|
if (experiment_string.length() < kMinExperimentLength)
|
||||||
|
return false;
|
||||||
|
return experiment_string.substr(0, kEnabledPrefixLength) == kEnabledPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets thresholds from the experiment name following the format
|
||||||
|
// "WebRTC-AdaptiveBweThreshold/Enabled-0.5,0.002/".
|
||||||
|
bool ReadExperimentConstants(double* k_up, double* k_down) {
|
||||||
|
std::string experiment_string =
|
||||||
|
webrtc::field_trial::FindFullName(kAdaptiveThresholdExperiment);
|
||||||
|
return sscanf(experiment_string.substr(kEnabledPrefixLength + 1).c_str(),
|
||||||
|
"%lf,%lf", k_up, k_down) == 2;
|
||||||
|
}
|
||||||
|
|
||||||
OveruseDetector::OveruseDetector(const OverUseDetectorOptions& options)
|
OveruseDetector::OveruseDetector(const OverUseDetectorOptions& options)
|
||||||
: options_(options),
|
: in_experiment_(AdaptiveThresholdExperimentIsEnabled()),
|
||||||
threshold_(options_.initial_threshold),
|
k_up_(0.01),
|
||||||
|
k_down_(0.00018),
|
||||||
|
overusing_time_threshold_(100),
|
||||||
|
options_(options),
|
||||||
|
threshold_(12.5),
|
||||||
|
last_update_ms_(-1),
|
||||||
prev_offset_(0.0),
|
prev_offset_(0.0),
|
||||||
time_over_using_(-1),
|
time_over_using_(-1),
|
||||||
overuse_counter_(0),
|
overuse_counter_(0),
|
||||||
hypothesis_(kBwNormal) {}
|
hypothesis_(kBwNormal) {
|
||||||
|
if (in_experiment_)
|
||||||
|
InitializeExperiment();
|
||||||
|
}
|
||||||
|
|
||||||
OveruseDetector::~OveruseDetector() {}
|
OveruseDetector::~OveruseDetector() {}
|
||||||
|
|
||||||
@@ -37,21 +72,6 @@ BandwidthUsage OveruseDetector::State() const {
|
|||||||
return hypothesis_;
|
return hypothesis_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void OveruseDetector::SetRateControlRegion(RateControlRegion region) {
|
|
||||||
switch (region) {
|
|
||||||
case kRcMaxUnknown: {
|
|
||||||
threshold_ = options_.initial_threshold;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kRcAboveMax:
|
|
||||||
case kRcNearMax: {
|
|
||||||
threshold_ = options_.initial_threshold / 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BandwidthUsage OveruseDetector::Detect(double offset,
|
BandwidthUsage OveruseDetector::Detect(double offset,
|
||||||
double ts_delta,
|
double ts_delta,
|
||||||
int num_of_deltas,
|
int num_of_deltas,
|
||||||
@@ -64,7 +84,6 @@ BandwidthUsage OveruseDetector::Detect(double offset,
|
|||||||
const double T = std::min(num_of_deltas, 60) * offset;
|
const double T = std::min(num_of_deltas, 60) * offset;
|
||||||
BWE_TEST_LOGGING_PLOT(1, "offset", now_ms, T);
|
BWE_TEST_LOGGING_PLOT(1, "offset", now_ms, T);
|
||||||
BWE_TEST_LOGGING_PLOT(1, "threshold", now_ms, threshold_);
|
BWE_TEST_LOGGING_PLOT(1, "threshold", now_ms, threshold_);
|
||||||
|
|
||||||
if (T > threshold_) {
|
if (T > threshold_) {
|
||||||
if (time_over_using_ == -1) {
|
if (time_over_using_ == -1) {
|
||||||
// Initialize the timer. Assume that we've been
|
// Initialize the timer. Assume that we've been
|
||||||
@@ -76,8 +95,7 @@ BandwidthUsage OveruseDetector::Detect(double offset,
|
|||||||
time_over_using_ += ts_delta;
|
time_over_using_ += ts_delta;
|
||||||
}
|
}
|
||||||
overuse_counter_++;
|
overuse_counter_++;
|
||||||
if (time_over_using_ > kOverUsingTimeThreshold
|
if (time_over_using_ > overusing_time_threshold_ && overuse_counter_ > 1) {
|
||||||
&& overuse_counter_ > 1) {
|
|
||||||
if (offset >= prev_offset) {
|
if (offset >= prev_offset) {
|
||||||
time_over_using_ = 0;
|
time_over_using_ = 0;
|
||||||
overuse_counter_ = 0;
|
overuse_counter_ = 0;
|
||||||
@@ -93,6 +111,45 @@ BandwidthUsage OveruseDetector::Detect(double offset,
|
|||||||
overuse_counter_ = 0;
|
overuse_counter_ = 0;
|
||||||
hypothesis_ = kBwNormal;
|
hypothesis_ = kBwNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateThreshold(T, now_ms);
|
||||||
|
|
||||||
return hypothesis_;
|
return hypothesis_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OveruseDetector::UpdateThreshold(double modified_offset, int64_t now_ms) {
|
||||||
|
if (!in_experiment_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (last_update_ms_ == -1)
|
||||||
|
last_update_ms_ = now_ms;
|
||||||
|
|
||||||
|
if (fabs(modified_offset) > threshold_ + kMaxAdaptOffsetMs) {
|
||||||
|
// Avoid adapting the threshold to big latency spikes, caused e.g.,
|
||||||
|
// by a sudden capacity drop.
|
||||||
|
last_update_ms_ = now_ms;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const double k = fabs(modified_offset) < threshold_ ? k_down_ : k_up_;
|
||||||
|
threshold_ +=
|
||||||
|
k * (fabs(modified_offset) - threshold_) * (now_ms - last_update_ms_);
|
||||||
|
|
||||||
|
const double kMinThreshold = 6;
|
||||||
|
const double kMaxThreshold = 600;
|
||||||
|
threshold_ = std::min(std::max(threshold_, kMinThreshold), kMaxThreshold);
|
||||||
|
|
||||||
|
last_update_ms_ = now_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OveruseDetector::InitializeExperiment() {
|
||||||
|
DCHECK(in_experiment_);
|
||||||
|
double k_up = 0.0;
|
||||||
|
double k_down = 0.0;
|
||||||
|
overusing_time_threshold_ = kOverUsingTimeThreshold;
|
||||||
|
if (ReadExperimentConstants(&k_up, &k_down)) {
|
||||||
|
k_up_ = k_up;
|
||||||
|
k_down_ = k_down;
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@@ -20,10 +20,12 @@
|
|||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
enum RateControlRegion;
|
enum RateControlRegion;
|
||||||
|
|
||||||
|
bool AdaptiveThresholdExperimentIsEnabled();
|
||||||
|
|
||||||
class OveruseDetector {
|
class OveruseDetector {
|
||||||
public:
|
public:
|
||||||
explicit OveruseDetector(const OverUseDetectorOptions& options);
|
explicit OveruseDetector(const OverUseDetectorOptions& options);
|
||||||
~OveruseDetector();
|
virtual ~OveruseDetector();
|
||||||
|
|
||||||
// Update the detection state based on the estimated inter-arrival time delta
|
// Update the detection state based on the estimated inter-arrival time delta
|
||||||
// offset. |timestamp_delta| is the delta between the last timestamp which the
|
// offset. |timestamp_delta| is the delta between the last timestamp which the
|
||||||
@@ -39,15 +41,19 @@ class OveruseDetector {
|
|||||||
// Returns the current detector state.
|
// Returns the current detector state.
|
||||||
BandwidthUsage State() const;
|
BandwidthUsage State() const;
|
||||||
|
|
||||||
// Sets the current rate-control region as decided by RemoteRateControl. This
|
|
||||||
// affects the sensitivity of the detector.
|
|
||||||
void SetRateControlRegion(webrtc::RateControlRegion region);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void UpdateThreshold(double modified_offset, int64_t now_ms);
|
||||||
|
void InitializeExperiment();
|
||||||
|
|
||||||
|
const bool in_experiment_;
|
||||||
|
double k_up_;
|
||||||
|
double k_down_;
|
||||||
|
double overusing_time_threshold_;
|
||||||
// Must be first member variable. Cannot be const because we need to be
|
// Must be first member variable. Cannot be const because we need to be
|
||||||
// copyable.
|
// copyable.
|
||||||
webrtc::OverUseDetectorOptions options_;
|
webrtc::OverUseDetectorOptions options_;
|
||||||
double threshold_;
|
double threshold_;
|
||||||
|
int64_t last_update_ms_;
|
||||||
double prev_offset_;
|
double prev_offset_;
|
||||||
double time_over_using_;
|
double time_over_using_;
|
||||||
int overuse_counter_;
|
int overuse_counter_;
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
#include "webrtc/modules/remote_bitrate_estimator/inter_arrival.h"
|
#include "webrtc/modules/remote_bitrate_estimator/inter_arrival.h"
|
||||||
#include "webrtc/modules/remote_bitrate_estimator/overuse_detector.h"
|
#include "webrtc/modules/remote_bitrate_estimator/overuse_detector.h"
|
||||||
#include "webrtc/modules/remote_bitrate_estimator/overuse_estimator.h"
|
#include "webrtc/modules/remote_bitrate_estimator/overuse_estimator.h"
|
||||||
|
#include "webrtc/modules/remote_bitrate_estimator/rate_statistics.h"
|
||||||
|
#include "webrtc/modules/remote_bitrate_estimator/test/random.h"
|
||||||
|
#include "webrtc/test/field_trial.h"
|
||||||
#include "webrtc/test/testsupport/gtest_disable.h"
|
#include "webrtc/test/testsupport/gtest_disable.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@@ -27,25 +30,19 @@ namespace testing {
|
|||||||
const double kRtpTimestampToMs = 1.0 / 90.0;
|
const double kRtpTimestampToMs = 1.0 / 90.0;
|
||||||
|
|
||||||
class OveruseDetectorTest : public ::testing::Test {
|
class OveruseDetectorTest : public ::testing::Test {
|
||||||
|
public:
|
||||||
|
OveruseDetectorTest()
|
||||||
|
: now_ms_(0),
|
||||||
|
receive_time_ms_(0),
|
||||||
|
rtp_timestamp_(10 * 90),
|
||||||
|
overuse_detector_(),
|
||||||
|
overuse_estimator_(new OveruseEstimator(options_)),
|
||||||
|
inter_arrival_(new InterArrival(5 * 90, kRtpTimestampToMs, true)),
|
||||||
|
random_(1234) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetUp() {
|
void SetUp() override {
|
||||||
srand(1234);
|
|
||||||
now_ms_ = 0;
|
|
||||||
receive_time_ms_ = 0;
|
|
||||||
rtp_timestamp_ = 10 * 90;
|
|
||||||
overuse_detector_.reset(new OveruseDetector(options_));
|
overuse_detector_.reset(new OveruseDetector(options_));
|
||||||
overuse_estimator_.reset(new OveruseEstimator(options_));
|
|
||||||
inter_arrival_.reset(new InterArrival(5 * 90, kRtpTimestampToMs, true));
|
|
||||||
}
|
|
||||||
// Normal Distribution.
|
|
||||||
#define PI 3.14159265
|
|
||||||
int GaussianRandom(int mean_ms, int standard_deviation_ms) {
|
|
||||||
// Creating a Normal distribution variable from two independent uniform
|
|
||||||
// variables based on the Box-Muller transform.
|
|
||||||
double uniform1 = (std::rand() + 1.0) / (RAND_MAX + 1.0);
|
|
||||||
double uniform2 = (std::rand() + 1.0) / (RAND_MAX + 1.0);
|
|
||||||
return static_cast<int>(mean_ms + standard_deviation_ms *
|
|
||||||
sqrt(-2 * log(uniform1)) * cos(2 * PI * uniform2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Run100000Samples(int packets_per_frame, size_t packet_size, int mean_ms,
|
int Run100000Samples(int packets_per_frame, size_t packet_size, int mean_ms,
|
||||||
@@ -58,8 +55,9 @@ class OveruseDetectorTest : public ::testing::Test {
|
|||||||
}
|
}
|
||||||
rtp_timestamp_ += mean_ms * 90;
|
rtp_timestamp_ += mean_ms * 90;
|
||||||
now_ms_ += mean_ms;
|
now_ms_ += mean_ms;
|
||||||
receive_time_ms_ = std::max(receive_time_ms_,
|
receive_time_ms_ =
|
||||||
now_ms_ + GaussianRandom(0, standard_deviation_ms));
|
std::max(receive_time_ms_,
|
||||||
|
now_ms_ + random_.Gaussian(0, standard_deviation_ms));
|
||||||
if (kBwOverusing == overuse_detector_->State()) {
|
if (kBwOverusing == overuse_detector_->State()) {
|
||||||
if (last_overuse + 1 != i) {
|
if (last_overuse + 1 != i) {
|
||||||
unique_overuse++;
|
unique_overuse++;
|
||||||
@@ -79,8 +77,9 @@ class OveruseDetectorTest : public ::testing::Test {
|
|||||||
}
|
}
|
||||||
rtp_timestamp_ += mean_ms * 90;
|
rtp_timestamp_ += mean_ms * 90;
|
||||||
now_ms_ += mean_ms + drift_per_frame_ms;
|
now_ms_ += mean_ms + drift_per_frame_ms;
|
||||||
receive_time_ms_ = std::max(receive_time_ms_,
|
receive_time_ms_ =
|
||||||
now_ms_ + GaussianRandom(0, standard_deviation_ms));
|
std::max(receive_time_ms_,
|
||||||
|
now_ms_ + random_.Gaussian(0, standard_deviation_ms));
|
||||||
if (kBwOverusing == overuse_detector_->State()) {
|
if (kBwOverusing == overuse_detector_->State()) {
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
@@ -102,9 +101,9 @@ class OveruseDetectorTest : public ::testing::Test {
|
|||||||
double timestamp_delta_ms = timestamp_delta / 90.0;
|
double timestamp_delta_ms = timestamp_delta / 90.0;
|
||||||
overuse_estimator_->Update(time_delta, timestamp_delta_ms, size_delta,
|
overuse_estimator_->Update(time_delta, timestamp_delta_ms, size_delta,
|
||||||
overuse_detector_->State());
|
overuse_detector_->State());
|
||||||
overuse_detector_->Detect(overuse_estimator_->offset(),
|
overuse_detector_->Detect(
|
||||||
timestamp_delta_ms,
|
overuse_estimator_->offset(), timestamp_delta_ms,
|
||||||
overuse_estimator_->num_of_deltas(), 0);
|
overuse_estimator_->num_of_deltas(), receive_time_ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,13 +114,14 @@ class OveruseDetectorTest : public ::testing::Test {
|
|||||||
rtc::scoped_ptr<OveruseDetector> overuse_detector_;
|
rtc::scoped_ptr<OveruseDetector> overuse_detector_;
|
||||||
rtc::scoped_ptr<OveruseEstimator> overuse_estimator_;
|
rtc::scoped_ptr<OveruseEstimator> overuse_estimator_;
|
||||||
rtc::scoped_ptr<InterArrival> inter_arrival_;
|
rtc::scoped_ptr<InterArrival> inter_arrival_;
|
||||||
|
Random random_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, GaussianRandom) {
|
TEST_F(OveruseDetectorTest, GaussianRandom) {
|
||||||
int buckets[100];
|
int buckets[100];
|
||||||
memset(buckets, 0, sizeof(buckets));
|
memset(buckets, 0, sizeof(buckets));
|
||||||
for (int i = 0; i < 100000; ++i) {
|
for (int i = 0; i < 100000; ++i) {
|
||||||
int index = GaussianRandom(49, 10);
|
int index = random_.Gaussian(49, 10);
|
||||||
if (index >= 0 && index < 100)
|
if (index >= 0 && index < 100)
|
||||||
buckets[index]++;
|
buckets[index]++;
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ TEST_F(OveruseDetectorTest, SimpleOveruse2000Kbit30fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_EQ(6, frames_until_overuse);
|
EXPECT_EQ(13, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, SimpleOveruse100kbit10fps) {
|
TEST_F(OveruseDetectorTest, SimpleOveruse100kbit10fps) {
|
||||||
@@ -207,7 +207,7 @@ TEST_F(OveruseDetectorTest, SimpleOveruse100kbit10fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_EQ(4, frames_until_overuse);
|
EXPECT_EQ(11, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, DISABLED_OveruseWithHighVariance100Kbit10fps) {
|
TEST_F(OveruseDetectorTest, DISABLED_OveruseWithHighVariance100Kbit10fps) {
|
||||||
@@ -299,7 +299,7 @@ TEST_F(OveruseDetectorTest, OveruseWithLowVariance2000Kbit30fps) {
|
|||||||
}
|
}
|
||||||
// Simulate a higher send pace, that is too high.
|
// Simulate a higher send pace, that is too high.
|
||||||
// Total build up of 30 ms.
|
// Total build up of 30 ms.
|
||||||
for (int j = 0; j < 5; ++j) {
|
for (int j = 0; j < 6; ++j) {
|
||||||
UpdateDetector(rtp_timestamp, now_ms_, packet_size);
|
UpdateDetector(rtp_timestamp, now_ms_, packet_size);
|
||||||
UpdateDetector(rtp_timestamp, now_ms_, packet_size);
|
UpdateDetector(rtp_timestamp, now_ms_, packet_size);
|
||||||
UpdateDetector(rtp_timestamp, now_ms_, packet_size);
|
UpdateDetector(rtp_timestamp, now_ms_, packet_size);
|
||||||
@@ -326,7 +326,7 @@ TEST_F(OveruseDetectorTest,
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(29, frames_until_overuse, 5);
|
EXPECT_EQ(36, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift30Kbit3fps) {
|
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift30Kbit3fps) {
|
||||||
@@ -340,7 +340,7 @@ TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift30Kbit3fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(4, frames_until_overuse, 1);
|
EXPECT_EQ(4, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, HighGaussianVariance30Kbit3fps) {
|
TEST_F(OveruseDetectorTest, HighGaussianVariance30Kbit3fps) {
|
||||||
@@ -354,7 +354,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVariance30Kbit3fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(79, frames_until_overuse, 30);
|
EXPECT_EQ(119, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift30Kbit3fps) {
|
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift30Kbit3fps) {
|
||||||
@@ -368,7 +368,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift30Kbit3fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(4, frames_until_overuse, 1);
|
EXPECT_EQ(5, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest,
|
TEST_F(OveruseDetectorTest,
|
||||||
@@ -383,7 +383,7 @@ TEST_F(OveruseDetectorTest,
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(29, frames_until_overuse, 5);
|
EXPECT_EQ(35, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest,
|
TEST_F(OveruseDetectorTest,
|
||||||
@@ -398,7 +398,7 @@ TEST_F(OveruseDetectorTest,
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(79, frames_until_overuse, 15);
|
EXPECT_EQ(115, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest,
|
TEST_F(OveruseDetectorTest,
|
||||||
@@ -413,7 +413,7 @@ TEST_F(OveruseDetectorTest,
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(29, frames_until_overuse, 5);
|
EXPECT_EQ(30, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest,
|
TEST_F(OveruseDetectorTest,
|
||||||
@@ -428,7 +428,7 @@ TEST_F(OveruseDetectorTest,
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(79, frames_until_overuse, 15);
|
EXPECT_EQ(98, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest,
|
TEST_F(OveruseDetectorTest,
|
||||||
@@ -443,7 +443,7 @@ TEST_F(OveruseDetectorTest,
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(30, frames_until_overuse, 5);
|
EXPECT_EQ(36, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift300Kbit30fps) {
|
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift300Kbit30fps) {
|
||||||
@@ -457,7 +457,7 @@ TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift300Kbit30fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(7, frames_until_overuse, 1);
|
EXPECT_EQ(8, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, HighGaussianVariance300Kbit30fps) {
|
TEST_F(OveruseDetectorTest, HighGaussianVariance300Kbit30fps) {
|
||||||
@@ -471,7 +471,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVariance300Kbit30fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(98, frames_until_overuse, 22);
|
EXPECT_EQ(108, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift300Kbit30fps) {
|
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift300Kbit30fps) {
|
||||||
@@ -485,7 +485,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift300Kbit30fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(12, frames_until_overuse, 2);
|
EXPECT_EQ(14, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest,
|
TEST_F(OveruseDetectorTest,
|
||||||
@@ -500,7 +500,7 @@ TEST_F(OveruseDetectorTest,
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(30, frames_until_overuse, 5);
|
EXPECT_EQ(36, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift1000Kbit30fps) {
|
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift1000Kbit30fps) {
|
||||||
@@ -514,7 +514,7 @@ TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift1000Kbit30fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(7, frames_until_overuse, 1);
|
EXPECT_EQ(8, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, HighGaussianVariance1000Kbit30fps) {
|
TEST_F(OveruseDetectorTest, HighGaussianVariance1000Kbit30fps) {
|
||||||
@@ -528,7 +528,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVariance1000Kbit30fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(98, frames_until_overuse, 22);
|
EXPECT_EQ(108, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift1000Kbit30fps) {
|
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift1000Kbit30fps) {
|
||||||
@@ -542,7 +542,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift1000Kbit30fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(12, frames_until_overuse, 2);
|
EXPECT_EQ(14, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest,
|
TEST_F(OveruseDetectorTest,
|
||||||
@@ -557,7 +557,7 @@ TEST_F(OveruseDetectorTest,
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(30, frames_until_overuse, 5);
|
EXPECT_EQ(36, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift2000Kbit30fps) {
|
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift2000Kbit30fps) {
|
||||||
@@ -571,7 +571,7 @@ TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift2000Kbit30fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(7, frames_until_overuse, 1);
|
EXPECT_EQ(8, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, HighGaussianVariance2000Kbit30fps) {
|
TEST_F(OveruseDetectorTest, HighGaussianVariance2000Kbit30fps) {
|
||||||
@@ -585,7 +585,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVariance2000Kbit30fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(98, frames_until_overuse, 22);
|
EXPECT_EQ(108, frames_until_overuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift2000Kbit30fps) {
|
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift2000Kbit30fps) {
|
||||||
@@ -599,7 +599,139 @@ TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift2000Kbit30fps) {
|
|||||||
EXPECT_EQ(0, unique_overuse);
|
EXPECT_EQ(0, unique_overuse);
|
||||||
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
|
||||||
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
frame_duration_ms, sigma_ms, drift_per_frame_ms);
|
||||||
EXPECT_NEAR(12, frames_until_overuse, 2);
|
EXPECT_EQ(14, frames_until_overuse);
|
||||||
|
}
|
||||||
|
|
||||||
|
class OveruseDetectorExperimentTest : public OveruseDetectorTest {
|
||||||
|
protected:
|
||||||
|
void SetUp() override {
|
||||||
|
test::InitFieldTrialsFromString(
|
||||||
|
"WebRTC-AdaptiveBweThreshold/Enabled-0.01,0.00018/");
|
||||||
|
overuse_detector_.reset(new OveruseDetector(options_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override { test::InitFieldTrialsFromString(""); }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(OveruseDetectorExperimentTest, ThresholdAdapts) {
|
||||||
|
const double kOffset = 0.21;
|
||||||
|
double kTsDelta = 3000.0;
|
||||||
|
int64_t now_ms = 0;
|
||||||
|
int num_deltas = 60;
|
||||||
|
const int kBatchLength = 10;
|
||||||
|
|
||||||
|
// Pass in a positive offset and verify it triggers overuse.
|
||||||
|
bool overuse_detected = false;
|
||||||
|
for (int i = 0; i < kBatchLength; ++i) {
|
||||||
|
BandwidthUsage overuse_state =
|
||||||
|
overuse_detector_->Detect(kOffset, kTsDelta, num_deltas, now_ms);
|
||||||
|
if (overuse_state == kBwOverusing) {
|
||||||
|
overuse_detected = true;
|
||||||
|
}
|
||||||
|
++num_deltas;
|
||||||
|
now_ms += 5;
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(overuse_detected);
|
||||||
|
|
||||||
|
// Force the threshold to increase by passing in a higher offset.
|
||||||
|
overuse_detected = false;
|
||||||
|
for (int i = 0; i < kBatchLength; ++i) {
|
||||||
|
BandwidthUsage overuse_state =
|
||||||
|
overuse_detector_->Detect(1.1 * kOffset, kTsDelta, num_deltas, now_ms);
|
||||||
|
if (overuse_state == kBwOverusing) {
|
||||||
|
overuse_detected = true;
|
||||||
|
}
|
||||||
|
++num_deltas;
|
||||||
|
now_ms += 5;
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(overuse_detected);
|
||||||
|
|
||||||
|
// Verify that the same offset as before no longer triggers overuse.
|
||||||
|
overuse_detected = false;
|
||||||
|
for (int i = 0; i < kBatchLength; ++i) {
|
||||||
|
BandwidthUsage overuse_state =
|
||||||
|
overuse_detector_->Detect(kOffset, kTsDelta, num_deltas, now_ms);
|
||||||
|
if (overuse_state == kBwOverusing) {
|
||||||
|
overuse_detected = true;
|
||||||
|
}
|
||||||
|
++num_deltas;
|
||||||
|
now_ms += 5;
|
||||||
|
}
|
||||||
|
EXPECT_FALSE(overuse_detected);
|
||||||
|
|
||||||
|
// Pass in a low offset to make the threshold adapt down.
|
||||||
|
for (int i = 0; i < 15 * kBatchLength; ++i) {
|
||||||
|
BandwidthUsage overuse_state =
|
||||||
|
overuse_detector_->Detect(0.7 * kOffset, kTsDelta, num_deltas, now_ms);
|
||||||
|
if (overuse_state == kBwOverusing) {
|
||||||
|
overuse_detected = true;
|
||||||
|
}
|
||||||
|
++num_deltas;
|
||||||
|
now_ms += 5;
|
||||||
|
}
|
||||||
|
EXPECT_FALSE(overuse_detected);
|
||||||
|
|
||||||
|
// Make sure the original offset now again triggers overuse.
|
||||||
|
for (int i = 0; i < kBatchLength; ++i) {
|
||||||
|
BandwidthUsage overuse_state =
|
||||||
|
overuse_detector_->Detect(kOffset, kTsDelta, num_deltas, now_ms);
|
||||||
|
if (overuse_state == kBwOverusing) {
|
||||||
|
overuse_detected = true;
|
||||||
|
}
|
||||||
|
++num_deltas;
|
||||||
|
now_ms += 5;
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(overuse_detected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OveruseDetectorExperimentTest, DoesntAdaptToSpikes) {
|
||||||
|
const double kOffset = 1.0;
|
||||||
|
const double kLargeOffset = 20.0;
|
||||||
|
double kTsDelta = 3000.0;
|
||||||
|
int64_t now_ms = 0;
|
||||||
|
int num_deltas = 60;
|
||||||
|
const int kBatchLength = 10;
|
||||||
|
const int kShortBatchLength = 3;
|
||||||
|
|
||||||
|
// Pass in a positive offset and verify it triggers overuse.
|
||||||
|
bool overuse_detected = false;
|
||||||
|
for (int i = 0; i < kBatchLength; ++i) {
|
||||||
|
BandwidthUsage overuse_state =
|
||||||
|
overuse_detector_->Detect(kOffset, kTsDelta, num_deltas, now_ms);
|
||||||
|
if (overuse_state == kBwOverusing) {
|
||||||
|
overuse_detected = true;
|
||||||
|
}
|
||||||
|
++num_deltas;
|
||||||
|
now_ms += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass in a large offset. This shouldn't have a too big impact on the
|
||||||
|
// threshold, but still trigger an overuse.
|
||||||
|
now_ms += 100;
|
||||||
|
overuse_detected = false;
|
||||||
|
for (int i = 0; i < kShortBatchLength; ++i) {
|
||||||
|
BandwidthUsage overuse_state =
|
||||||
|
overuse_detector_->Detect(kLargeOffset, kTsDelta, num_deltas, now_ms);
|
||||||
|
if (overuse_state == kBwOverusing) {
|
||||||
|
overuse_detected = true;
|
||||||
|
}
|
||||||
|
++num_deltas;
|
||||||
|
now_ms += 5;
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(overuse_detected);
|
||||||
|
|
||||||
|
// Pass in a positive normal offset and verify it still triggers.
|
||||||
|
overuse_detected = false;
|
||||||
|
for (int i = 0; i < kBatchLength; ++i) {
|
||||||
|
BandwidthUsage overuse_state =
|
||||||
|
overuse_detector_->Detect(kOffset, kTsDelta, num_deltas, now_ms);
|
||||||
|
if (overuse_state == kBwOverusing) {
|
||||||
|
overuse_detected = true;
|
||||||
|
}
|
||||||
|
++num_deltas;
|
||||||
|
now_ms += 5;
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(overuse_detected);
|
||||||
}
|
}
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ void OveruseEstimator::UpdateNoiseEstimate(double residual,
|
|||||||
+ (1 - beta) * residual;
|
+ (1 - beta) * residual;
|
||||||
var_noise_ = beta * var_noise_
|
var_noise_ = beta * var_noise_
|
||||||
+ (1 - beta) * (avg_noise_ - residual) * (avg_noise_ - residual);
|
+ (1 - beta) * (avg_noise_ - residual) * (avg_noise_ - residual);
|
||||||
if (var_noise_ < 1e-7) {
|
if (var_noise_ < 1) {
|
||||||
var_noise_ = 1e-7;
|
var_noise_ = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@@ -78,6 +78,8 @@
|
|||||||
'test/packet_sender.cc',
|
'test/packet_sender.cc',
|
||||||
'test/packet_sender.h',
|
'test/packet_sender.h',
|
||||||
'test/packet.h',
|
'test/packet.h',
|
||||||
|
'test/random.cc',
|
||||||
|
'test/random.h',
|
||||||
'test/estimators/nada.cc',
|
'test/estimators/nada.cc',
|
||||||
'test/estimators/nada.h',
|
'test/estimators/nada.h',
|
||||||
'test/estimators/nada_unittest.cc',
|
'test/estimators/nada_unittest.cc',
|
||||||
|
|||||||
@@ -296,13 +296,13 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
|
|||||||
double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
|
double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
|
||||||
estimator_.Update(t_delta, ts_delta_ms, size_delta, detector_.State());
|
estimator_.Update(t_delta, ts_delta_ms, size_delta, detector_.State());
|
||||||
detector_.Detect(estimator_.offset(), ts_delta_ms,
|
detector_.Detect(estimator_.offset(), ts_delta_ms,
|
||||||
estimator_.num_of_deltas(), now_ms);
|
estimator_.num_of_deltas(), arrival_time_ms);
|
||||||
UpdateStats(static_cast<int>(t_delta - ts_delta_ms), now_ms);
|
UpdateStats(static_cast<int>(t_delta - ts_delta_ms), now_ms);
|
||||||
}
|
}
|
||||||
if (detector_.State() == kBwOverusing) {
|
if (detector_.State() == kBwOverusing) {
|
||||||
unsigned int incoming_bitrate = incoming_bitrate_.Rate(now_ms);
|
uint32_t incoming_bitrate_bps = incoming_bitrate_.Rate(now_ms);
|
||||||
if (prior_state != kBwOverusing ||
|
if (prior_state != kBwOverusing ||
|
||||||
remote_rate_.TimeToReduceFurther(now_ms, incoming_bitrate)) {
|
remote_rate_.TimeToReduceFurther(now_ms, incoming_bitrate_bps)) {
|
||||||
// The first overuse should immediately trigger a new estimate.
|
// The first overuse should immediately trigger a new estimate.
|
||||||
// We also have to update the estimate immediately if we are overusing
|
// We also have to update the estimate immediately if we are overusing
|
||||||
// and the target bitrate is too high compared to what we are receiving.
|
// and the target bitrate is too high compared to what we are receiving.
|
||||||
@@ -357,13 +357,12 @@ void RemoteBitrateEstimatorAbsSendTime::UpdateEstimate(int64_t now_ms) {
|
|||||||
const RateControlInput input(detector_.State(),
|
const RateControlInput input(detector_.State(),
|
||||||
incoming_bitrate_.Rate(now_ms),
|
incoming_bitrate_.Rate(now_ms),
|
||||||
estimator_.var_noise());
|
estimator_.var_noise());
|
||||||
const RateControlRegion region = remote_rate_.Update(&input, now_ms);
|
remote_rate_.Update(&input, now_ms);
|
||||||
unsigned int target_bitrate = remote_rate_.UpdateBandwidthEstimate(now_ms);
|
unsigned int target_bitrate = remote_rate_.UpdateBandwidthEstimate(now_ms);
|
||||||
if (remote_rate_.ValidEstimate()) {
|
if (remote_rate_.ValidEstimate()) {
|
||||||
process_interval_ms_ = remote_rate_.GetFeedbackInterval();
|
process_interval_ms_ = remote_rate_.GetFeedbackInterval();
|
||||||
observer_->OnReceiveBitrateChanged(Keys(ssrcs_), target_bitrate);
|
observer_->OnReceiveBitrateChanged(Keys(ssrcs_), target_bitrate);
|
||||||
}
|
}
|
||||||
detector_.SetRateControlRegion(region);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteBitrateEstimatorAbsSendTime::OnRttUpdate(int64_t rtt) {
|
void RemoteBitrateEstimatorAbsSendTime::OnRttUpdate(int64_t rtt) {
|
||||||
|
|||||||
@@ -42,35 +42,35 @@ TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, RateIncreaseRtpTimestamps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropOneStream) {
|
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropOneStream) {
|
||||||
CapacityDropTestHelper(1, false, 700);
|
CapacityDropTestHelper(1, false, 567);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropOneStreamWrap) {
|
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropOneStreamWrap) {
|
||||||
CapacityDropTestHelper(1, true, 700);
|
CapacityDropTestHelper(1, true, 567);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropTwoStreamsWrap) {
|
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropTwoStreamsWrap) {
|
||||||
CapacityDropTestHelper(2, true, 700);
|
CapacityDropTestHelper(2, true, 667);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThreeStreamsWrap) {
|
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThreeStreamsWrap) {
|
||||||
CapacityDropTestHelper(3, true, 700);
|
CapacityDropTestHelper(3, true, 633);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThirteenStreamsWrap) {
|
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThirteenStreamsWrap) {
|
||||||
CapacityDropTestHelper(13, true, 666);
|
CapacityDropTestHelper(13, true, 633);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropNineteenStreamsWrap) {
|
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropNineteenStreamsWrap) {
|
||||||
CapacityDropTestHelper(19, true, 666);
|
CapacityDropTestHelper(19, true, 633);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThirtyStreamsWrap) {
|
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThirtyStreamsWrap) {
|
||||||
CapacityDropTestHelper(30, true, 666);
|
CapacityDropTestHelper(30, true, 633);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, TestTimestampGrouping) {
|
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, TestTimestampGrouping) {
|
||||||
TestTimestampGroupingTestHelper();
|
TestTimestampGroupingTestHelper(361080u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, TestGetStats) {
|
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, TestGetStats) {
|
||||||
|
|||||||
@@ -105,9 +105,9 @@ void RemoteBitrateEstimatorSingleStream::IncomingPacket(int64_t arrival_time_ms,
|
|||||||
estimator->estimator.num_of_deltas(), now_ms);
|
estimator->estimator.num_of_deltas(), now_ms);
|
||||||
}
|
}
|
||||||
if (estimator->detector.State() == kBwOverusing) {
|
if (estimator->detector.State() == kBwOverusing) {
|
||||||
uint32_t incoming_bitrate = incoming_bitrate_.Rate(now_ms);
|
uint32_t incoming_bitrate_bps = incoming_bitrate_.Rate(now_ms);
|
||||||
if (prior_state != kBwOverusing ||
|
if (prior_state != kBwOverusing ||
|
||||||
remote_rate_->TimeToReduceFurther(now_ms, incoming_bitrate)) {
|
remote_rate_->TimeToReduceFurther(now_ms, incoming_bitrate_bps)) {
|
||||||
// The first overuse should immediately trigger a new estimate.
|
// The first overuse should immediately trigger a new estimate.
|
||||||
// We also have to update the estimate immediately if we are overusing
|
// We also have to update the estimate immediately if we are overusing
|
||||||
// and the target bitrate is too high compared to what we are receiving.
|
// and the target bitrate is too high compared to what we are receiving.
|
||||||
@@ -172,7 +172,7 @@ void RemoteBitrateEstimatorSingleStream::UpdateEstimate(int64_t now_ms) {
|
|||||||
const RateControlInput input(bw_state,
|
const RateControlInput input(bw_state,
|
||||||
incoming_bitrate_.Rate(now_ms),
|
incoming_bitrate_.Rate(now_ms),
|
||||||
mean_noise_var);
|
mean_noise_var);
|
||||||
const RateControlRegion region = remote_rate_->Update(&input, now_ms);
|
remote_rate_->Update(&input, now_ms);
|
||||||
unsigned int target_bitrate = remote_rate_->UpdateBandwidthEstimate(now_ms);
|
unsigned int target_bitrate = remote_rate_->UpdateBandwidthEstimate(now_ms);
|
||||||
if (remote_rate_->ValidEstimate()) {
|
if (remote_rate_->ValidEstimate()) {
|
||||||
process_interval_ms_ = remote_rate_->GetFeedbackInterval();
|
process_interval_ms_ = remote_rate_->GetFeedbackInterval();
|
||||||
@@ -180,9 +180,6 @@ void RemoteBitrateEstimatorSingleStream::UpdateEstimate(int64_t now_ms) {
|
|||||||
GetSsrcs(&ssrcs);
|
GetSsrcs(&ssrcs);
|
||||||
observer_->OnReceiveBitrateChanged(ssrcs, target_bitrate);
|
observer_->OnReceiveBitrateChanged(ssrcs, target_bitrate);
|
||||||
}
|
}
|
||||||
for (it = overuse_detectors_.begin(); it != overuse_detectors_.end(); ++it) {
|
|
||||||
it->second->detector.SetRateControlRegion(region);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteBitrateEstimatorSingleStream::OnRttUpdate(int64_t rtt) {
|
void RemoteBitrateEstimatorSingleStream::OnRttUpdate(int64_t rtt) {
|
||||||
|
|||||||
@@ -42,34 +42,34 @@ TEST_F(RemoteBitrateEstimatorSingleTest, RateIncreaseRtpTimestamps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStream) {
|
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStream) {
|
||||||
CapacityDropTestHelper(1, false, 700);
|
CapacityDropTestHelper(1, false, 567);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStreamWrap) {
|
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStreamWrap) {
|
||||||
CapacityDropTestHelper(1, true, 700);
|
CapacityDropTestHelper(1, true, 567);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropTwoStreamsWrap) {
|
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropTwoStreamsWrap) {
|
||||||
CapacityDropTestHelper(2, true, 666);
|
CapacityDropTestHelper(2, true, 667);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThreeStreamsWrap) {
|
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThreeStreamsWrap) {
|
||||||
CapacityDropTestHelper(3, true, 700);
|
CapacityDropTestHelper(3, true, 633);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirteenStreamsWrap) {
|
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirteenStreamsWrap) {
|
||||||
CapacityDropTestHelper(13, true, 700);
|
CapacityDropTestHelper(13, true, 633);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropNineteenStreamsWrap) {
|
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropNineteenStreamsWrap) {
|
||||||
CapacityDropTestHelper(19, true, 700);
|
CapacityDropTestHelper(19, true, 633);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirtyStreamsWrap) {
|
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirtyStreamsWrap) {
|
||||||
CapacityDropTestHelper(30, true, 700);
|
CapacityDropTestHelper(30, true, 600);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorSingleTest, TestTimestampGrouping) {
|
TEST_F(RemoteBitrateEstimatorSingleTest, TestTimestampGrouping) {
|
||||||
TestTimestampGroupingTestHelper();
|
TestTimestampGroupingTestHelper(361080u);
|
||||||
}
|
}
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@@ -513,7 +513,8 @@ void RemoteBitrateEstimatorTest::CapacityDropTestHelper(
|
|||||||
EXPECT_EQ(0u, latest_bps);
|
EXPECT_EQ(0u, latest_bps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteBitrateEstimatorTest::TestTimestampGroupingTestHelper() {
|
void RemoteBitrateEstimatorTest::TestTimestampGroupingTestHelper(
|
||||||
|
uint32_t bitrate_bps) {
|
||||||
const int kFramerate = 50; // 50 fps to avoid rounding errors.
|
const int kFramerate = 50; // 50 fps to avoid rounding errors.
|
||||||
const int kFrameIntervalMs = 1000 / kFramerate;
|
const int kFrameIntervalMs = 1000 / kFramerate;
|
||||||
const uint32_t kFrameIntervalAbsSendTime = AbsSendTime(1, kFramerate);
|
const uint32_t kFrameIntervalAbsSendTime = AbsSendTime(1, kFramerate);
|
||||||
@@ -561,7 +562,7 @@ void RemoteBitrateEstimatorTest::TestTimestampGroupingTestHelper() {
|
|||||||
}
|
}
|
||||||
EXPECT_TRUE(bitrate_observer_->updated());
|
EXPECT_TRUE(bitrate_observer_->updated());
|
||||||
// Should have reduced the estimate.
|
// Should have reduced the estimate.
|
||||||
EXPECT_EQ(378720u, bitrate_observer_->latest_bitrate());
|
EXPECT_EQ(bitrate_bps, bitrate_observer_->latest_bitrate());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteBitrateEstimatorTest::TestGetStatsHelper() {
|
void RemoteBitrateEstimatorTest::TestGetStatsHelper() {
|
||||||
|
|||||||
@@ -190,8 +190,7 @@ class RemoteBitrateEstimatorTest : public ::testing::Test {
|
|||||||
unsigned int max_bitrate,
|
unsigned int max_bitrate,
|
||||||
unsigned int target_bitrate);
|
unsigned int target_bitrate);
|
||||||
|
|
||||||
|
void TestTimestampGroupingTestHelper(uint32_t bitrate_bps);
|
||||||
void TestTimestampGroupingTestHelper();
|
|
||||||
|
|
||||||
void TestGetStatsHelper();
|
void TestGetStatsHelper();
|
||||||
|
|
||||||
|
|||||||
@@ -264,6 +264,20 @@ INSTANTIATE_TEST_CASE_P(VideoSendersTest,
|
|||||||
::testing::Values(kRembEstimator,
|
::testing::Values(kRembEstimator,
|
||||||
kFullSendSideEstimator));
|
kFullSendSideEstimator));
|
||||||
|
|
||||||
|
TEST_P(BweFeedbackTest, ConstantCapacity) {
|
||||||
|
AdaptiveVideoSource source(0, 30, 300, 0, 0);
|
||||||
|
PacedVideoSender sender(&uplink_, &source, GetParam());
|
||||||
|
ChokeFilter filter(&uplink_, 0);
|
||||||
|
RateCounterFilter counter(&uplink_, 0, "receiver_input");
|
||||||
|
PacketReceiver receiver(&uplink_, 0, GetParam(), false, false);
|
||||||
|
const int kCapacityKbps = 1000;
|
||||||
|
filter.SetCapacity(kCapacityKbps);
|
||||||
|
filter.SetMaxDelay(500);
|
||||||
|
RunFor(180 * 1000);
|
||||||
|
PrintResults(kCapacityKbps, counter.GetBitrateStats(), 0,
|
||||||
|
receiver.GetDelayStats(), counter.GetBitrateStats());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(BweFeedbackTest, Choke1000kbps500kbps1000kbps) {
|
TEST_P(BweFeedbackTest, Choke1000kbps500kbps1000kbps) {
|
||||||
AdaptiveVideoSource source(0, 30, 300, 0, 0);
|
AdaptiveVideoSource source(0, 30, 300, 0, 0);
|
||||||
PacedVideoSender sender(&uplink_, &source, GetParam());
|
PacedVideoSender sender(&uplink_, &source, GetParam());
|
||||||
@@ -338,7 +352,7 @@ TEST_P(BweFeedbackTest, PacedSelfFairness50msTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweFeedbackTest, PacedSelfFairness500msTest) {
|
TEST_P(BweFeedbackTest, PacedSelfFairness500msTest) {
|
||||||
RunFairnessTest(GetParam(), 4, 0, 300, 3000, 50);
|
RunFairnessTest(GetParam(), 4, 0, 300, 3000, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweFeedbackTest, PacedSelfFairness1000msTest) {
|
TEST_P(BweFeedbackTest, PacedSelfFairness1000msTest) {
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class LinkedSet {
|
|||||||
std::list<PacketIdentifierNode*> list_;
|
std::list<PacketIdentifierNode*> list_;
|
||||||
};
|
};
|
||||||
|
|
||||||
const int kMinBitrateKbps = 150;
|
const int kMinBitrateKbps = 20;
|
||||||
const int kMaxBitrateKbps = 3000;
|
const int kMaxBitrateKbps = 3000;
|
||||||
|
|
||||||
class BweSender : public Module {
|
class BweSender : public Module {
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ void BweTest::RunFairnessTest(BandwidthEstimatorType bwe_type,
|
|||||||
std::vector<VideoSource*> sources;
|
std::vector<VideoSource*> sources;
|
||||||
std::vector<PacketSender*> senders;
|
std::vector<PacketSender*> senders;
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 1;
|
||||||
for (int media_flow : media_flow_ids) {
|
for (int media_flow : media_flow_ids) {
|
||||||
// Streams started 20 seconds apart to give them different advantage when
|
// Streams started 20 seconds apart to give them different advantage when
|
||||||
// competing for the bandwidth.
|
// competing for the bandwidth.
|
||||||
|
|||||||
@@ -94,33 +94,6 @@ class RateCounter {
|
|||||||
std::list<TimeSizePair> window_;
|
std::list<TimeSizePair> window_;
|
||||||
};
|
};
|
||||||
|
|
||||||
Random::Random(uint32_t seed)
|
|
||||||
: a_(0x531FDB97 ^ seed),
|
|
||||||
b_(0x6420ECA8 + seed) {
|
|
||||||
}
|
|
||||||
|
|
||||||
float Random::Rand() {
|
|
||||||
const float kScale = 1.0f / 0xffffffff;
|
|
||||||
float result = kScale * b_;
|
|
||||||
a_ ^= b_;
|
|
||||||
b_ += a_;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Random::Gaussian(int mean, int standard_deviation) {
|
|
||||||
// Creating a Normal distribution variable from two independent uniform
|
|
||||||
// variables based on the Box-Muller transform, which is defined on the
|
|
||||||
// interval (0, 1], hence the mask+add below.
|
|
||||||
const double kPi = 3.14159265358979323846;
|
|
||||||
const double kScale = 1.0 / 0x80000000ul;
|
|
||||||
double u1 = kScale * ((a_ & 0x7ffffffful) + 1);
|
|
||||||
double u2 = kScale * ((b_ & 0x7ffffffful) + 1);
|
|
||||||
a_ ^= b_;
|
|
||||||
b_ += a_;
|
|
||||||
return static_cast<int>(mean + standard_deviation *
|
|
||||||
sqrt(-2 * log(u1)) * cos(2 * kPi * u2));
|
|
||||||
}
|
|
||||||
|
|
||||||
Packet::Packet()
|
Packet::Packet()
|
||||||
: flow_id_(0), creation_time_us_(-1), send_time_us_(-1), payload_size_(0) {
|
: flow_id_(0), creation_time_us_(-1), send_time_us_(-1), payload_size_(0) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
||||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
|
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
|
||||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet.h"
|
#include "webrtc/modules/remote_bitrate_estimator/test/packet.h"
|
||||||
|
#include "webrtc/modules/remote_bitrate_estimator/test/random.h"
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
|
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
|
||||||
#include "webrtc/system_wrappers/interface/clock.h"
|
#include "webrtc/system_wrappers/interface/clock.h"
|
||||||
|
|
||||||
@@ -142,26 +143,6 @@ template<typename T> class Stats {
|
|||||||
T max_;
|
T max_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Random {
|
|
||||||
public:
|
|
||||||
explicit Random(uint32_t seed);
|
|
||||||
|
|
||||||
// Return pseudo random number in the interval [0.0, 1.0].
|
|
||||||
float Rand();
|
|
||||||
|
|
||||||
// Normal Distribution.
|
|
||||||
int Gaussian(int mean, int standard_deviation);
|
|
||||||
|
|
||||||
// TODO(solenberg): Random from histogram.
|
|
||||||
// template<typename T> int Distribution(const std::vector<T> histogram) {
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t a_;
|
|
||||||
uint32_t b_;
|
|
||||||
|
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Random);
|
|
||||||
};
|
|
||||||
|
|
||||||
bool IsTimeSorted(const Packets& packets);
|
bool IsTimeSorted(const Packets& packets);
|
||||||
|
|
||||||
class PacketProcessor;
|
class PacketProcessor;
|
||||||
|
|||||||
41
webrtc/modules/remote_bitrate_estimator/test/random.cc
Normal file
41
webrtc/modules/remote_bitrate_estimator/test/random.cc
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "webrtc/modules/remote_bitrate_estimator/test/random.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
Random::Random(uint32_t seed) : a_(0x531FDB97 ^ seed), b_(0x6420ECA8 + seed) {
|
||||||
|
}
|
||||||
|
|
||||||
|
float Random::Rand() {
|
||||||
|
const float kScale = 1.0f / 0xffffffff;
|
||||||
|
float result = kScale * b_;
|
||||||
|
a_ ^= b_;
|
||||||
|
b_ += a_;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Random::Gaussian(int mean, int standard_deviation) {
|
||||||
|
// Creating a Normal distribution variable from two independent uniform
|
||||||
|
// variables based on the Box-Muller transform, which is defined on the
|
||||||
|
// interval (0, 1], hence the mask+add below.
|
||||||
|
const double kPi = 3.14159265358979323846;
|
||||||
|
const double kScale = 1.0 / 0x80000000ul;
|
||||||
|
double u1 = kScale * ((a_ & 0x7ffffffful) + 1);
|
||||||
|
double u2 = kScale * ((b_ & 0x7ffffffful) + 1);
|
||||||
|
a_ ^= b_;
|
||||||
|
b_ += a_;
|
||||||
|
return static_cast<int>(
|
||||||
|
mean + standard_deviation * sqrt(-2 * log(u1)) * cos(2 * kPi * u2));
|
||||||
|
}
|
||||||
|
} // namespace webrtc
|
||||||
40
webrtc/modules/remote_bitrate_estimator/test/random.h
Normal file
40
webrtc/modules/remote_bitrate_estimator/test/random.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_RANDOM_H_
|
||||||
|
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_RANDOM_H_
|
||||||
|
|
||||||
|
#include "webrtc/typedefs.h"
|
||||||
|
#include "webrtc/base/constructormagic.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
class Random {
|
||||||
|
public:
|
||||||
|
explicit Random(uint32_t seed);
|
||||||
|
|
||||||
|
// Return pseudo-random number in the interval [0.0, 1.0].
|
||||||
|
float Rand();
|
||||||
|
|
||||||
|
// Normal Distribution.
|
||||||
|
int Gaussian(int mean, int standard_deviation);
|
||||||
|
|
||||||
|
// TODO(solenberg): Random from histogram.
|
||||||
|
// template<typename T> int Distribution(const std::vector<T> histogram) {
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t a_;
|
||||||
|
uint32_t b_;
|
||||||
|
|
||||||
|
DISALLOW_IMPLICIT_CONSTRUCTORS(Random);
|
||||||
|
};
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_RANDOM_H_
|
||||||
@@ -45,11 +45,12 @@ namespace test {
|
|||||||
void InitFieldTrialsFromString(const std::string& trials_string) {
|
void InitFieldTrialsFromString(const std::string& trials_string) {
|
||||||
static const char kPersistentStringSeparator = '/';
|
static const char kPersistentStringSeparator = '/';
|
||||||
|
|
||||||
// Catch an error if this is called more than once.
|
|
||||||
assert(field_trials_initiated_ == false);
|
|
||||||
field_trials_initiated_ = true;
|
field_trials_initiated_ = true;
|
||||||
|
|
||||||
if (trials_string.empty()) return;
|
if (trials_string.empty()) {
|
||||||
|
field_trials_.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t next_item = 0;
|
size_t next_item = 0;
|
||||||
while (next_item < trials_string.length()) {
|
while (next_item < trials_string.length()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user