JitterEstimator: rename some member variables to include unit

This makes it easier to read the code, and to visually verify
that the computations make sense from a dimensional perspective.

No functional changes are intended.

Bug: webrtc:14151
Change-Id: Ic059f3c53618903d63a270b901ac5cec6139d2c4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/274120
Commit-Queue: Rasmus Brandt <brandtr@webrtc.org>
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38006}
This commit is contained in:
Rasmus Brandt 2022-09-05 09:37:58 +02:00 committed by WebRTC LUCI CQ
parent e1e2c466f9
commit 8cd8d2292c
2 changed files with 52 additions and 48 deletions

View File

@ -60,21 +60,20 @@ JitterEstimator::~JitterEstimator() = default;
// Resets the JitterEstimate.
void JitterEstimator::Reset() {
var_noise_ = 4.0;
avg_frame_size_bytes_ = kDefaultAvgAndMaxFrameSize;
max_frame_size_bytes_ = kDefaultAvgAndMaxFrameSize;
var_frame_size_ = 100;
var_frame_size_bytes2_ = 100;
last_update_time_ = absl::nullopt;
prev_estimate_ = absl::nullopt;
prev_frame_size_ = absl::nullopt;
avg_noise_ = 0.0;
avg_noise_ms_ = 0.0;
var_noise_ms2_ = 4.0;
alpha_count_ = 1;
filter_jitter_estimate_ = TimeDelta::Zero();
latest_nack_ = Timestamp::Zero();
nack_count_ = 0;
frame_size_sum_bytes_ = 0;
frame_size_count_ = 0;
startup_frame_size_sum_bytes_ = 0;
startup_frame_size_count_ = 0;
startup_count_ = 0;
rtt_filter_.Reset();
fps_counter_.Reset();
@ -91,27 +90,28 @@ void JitterEstimator::UpdateEstimate(TimeDelta frame_delay,
// Can't use DataSize since this can be negative.
double delta_frame_bytes =
frame_size.bytes() - prev_frame_size_.value_or(DataSize::Zero()).bytes();
if (frame_size_count_ < kFsAccuStartupSamples) {
frame_size_sum_bytes_ += frame_size.bytes();
frame_size_count_++;
} else if (frame_size_count_ == kFsAccuStartupSamples) {
if (startup_frame_size_count_ < kFsAccuStartupSamples) {
startup_frame_size_sum_bytes_ += frame_size.bytes();
startup_frame_size_count_++;
} else if (startup_frame_size_count_ == kFsAccuStartupSamples) {
// Give the frame size filter.
avg_frame_size_bytes_ =
frame_size_sum_bytes_ / static_cast<double>(frame_size_count_);
frame_size_count_++;
avg_frame_size_bytes_ = startup_frame_size_sum_bytes_ /
static_cast<double>(startup_frame_size_count_);
startup_frame_size_count_++;
}
double avg_frame_size_bytes =
kPhi * avg_frame_size_bytes_ + (1 - kPhi) * frame_size.bytes();
double deviation_size_bytes = 2 * sqrt(var_frame_size_);
double deviation_size_bytes = 2 * sqrt(var_frame_size_bytes2_);
if (frame_size.bytes() < avg_frame_size_bytes_ + deviation_size_bytes) {
// Only update the average frame size if this sample wasn't a key frame.
avg_frame_size_bytes_ = avg_frame_size_bytes;
}
double delta_bytes = frame_size.bytes() - avg_frame_size_bytes;
var_frame_size_ = std::max(
kPhi * var_frame_size_ + (1 - kPhi) * (delta_bytes * delta_bytes), 1.0);
var_frame_size_bytes2_ = std::max(
kPhi * var_frame_size_bytes2_ + (1 - kPhi) * (delta_bytes * delta_bytes),
1.0);
// Update max_frame_size_bytes_ estimate.
max_frame_size_bytes_ =
@ -125,23 +125,24 @@ void JitterEstimator::UpdateEstimate(TimeDelta frame_delay,
// Cap frame_delay based on the current time deviation noise.
TimeDelta max_time_deviation = TimeDelta::Millis(
kDefaultMaxTimestampDeviationInSigmas * sqrt(var_noise_) + 0.5);
kDefaultMaxTimestampDeviationInSigmas * sqrt(var_noise_ms2_) + 0.5);
frame_delay.Clamp(-max_time_deviation, max_time_deviation);
// Only update the Kalman filter if the sample is not considered an extreme
// outlier. Even if it is an extreme outlier from a delay point of view, if
// the frame size also is large the deviation is probably due to an incorrect
// line slope.
double deviation =
double deviation_ms =
frame_delay.ms() -
kalman_filter_.GetFrameDelayVariationEstimateTotal(delta_frame_bytes);
if (fabs(deviation) < kNumStdDevDelayOutlier * sqrt(var_noise_) ||
frame_size.bytes() > avg_frame_size_bytes_ + kNumStdDevFrameSizeOutlier *
sqrt(var_frame_size_)) {
if (fabs(deviation_ms) < kNumStdDevDelayOutlier * sqrt(var_noise_ms2_) ||
frame_size.bytes() >
avg_frame_size_bytes_ +
kNumStdDevFrameSizeOutlier * sqrt(var_frame_size_bytes2_)) {
// Update the variance of the deviation from the line given by the Kalman
// filter.
EstimateRandomJitter(deviation);
EstimateRandomJitter(deviation_ms);
// Prevent updating with frames which have been congested by a large frame,
// and therefore arrives almost at the same time as that frame.
// This can occur when we receive a large frame (key frame) which has been
@ -151,12 +152,12 @@ void JitterEstimator::UpdateEstimate(TimeDelta frame_delay,
if (delta_frame_bytes > -0.25 * max_frame_size_bytes_) {
// Update the Kalman filter with the new data
kalman_filter_.PredictAndUpdate(frame_delay.ms(), delta_frame_bytes,
max_frame_size_bytes_, var_noise_);
max_frame_size_bytes_, var_noise_ms2_);
}
} else {
int nStdDev =
(deviation >= 0) ? kNumStdDevDelayOutlier : -kNumStdDevDelayOutlier;
EstimateRandomJitter(nStdDev * sqrt(var_noise_));
(deviation_ms >= 0) ? kNumStdDevDelayOutlier : -kNumStdDevDelayOutlier;
EstimateRandomJitter(nStdDev * sqrt(var_noise_ms2_));
}
// Post process the total estimated jitter
if (startup_count_ >= kStartupDelaySamples) {
@ -210,24 +211,26 @@ void JitterEstimator::EstimateRandomJitter(double d_dT) {
alpha = pow(alpha, rate_scale);
}
double avgNoise = alpha * avg_noise_ + (1 - alpha) * d_dT;
double varNoise = alpha * var_noise_ +
(1 - alpha) * (d_dT - avg_noise_) * (d_dT - avg_noise_);
avg_noise_ = avgNoise;
var_noise_ = varNoise;
if (var_noise_ < 1.0) {
double avg_noise_ms = alpha * avg_noise_ms_ + (1 - alpha) * d_dT;
double var_noise_ms2 = alpha * var_noise_ms2_ + (1 - alpha) *
(d_dT - avg_noise_ms_) *
(d_dT - avg_noise_ms_);
avg_noise_ms_ = avg_noise_ms;
var_noise_ms2_ = var_noise_ms2;
if (var_noise_ms2_ < 1.0) {
// The variance should never be zero, since we might get stuck and consider
// all samples as outliers.
var_noise_ = 1.0;
var_noise_ms2_ = 1.0;
}
}
double JitterEstimator::NoiseThreshold() const {
double noiseThreshold = kNoiseStdDevs * sqrt(var_noise_) - kNoiseStdDevOffset;
if (noiseThreshold < 1.0) {
noiseThreshold = 1.0;
double noise_threshold_ms =
kNoiseStdDevs * sqrt(var_noise_ms2_) - kNoiseStdDevOffset;
if (noise_threshold_ms < 1.0) {
noise_threshold_ms = 1.0;
}
return noiseThreshold;
return noise_threshold_ms;
}
// Calculates the current jitter estimate from the filtered estimates.

View File

@ -67,8 +67,6 @@ class JitterEstimator {
static constexpr TimeDelta OPERATING_SYSTEM_JITTER = TimeDelta::Millis(10);
private:
double var_noise_; // Variance of the time-deviation from the line
// Updates the random jitter estimate, i.e. the variance of the time
// deviations from the line given by the Kalman filter.
//
@ -86,6 +84,7 @@ class JitterEstimator {
// Post process the calculated estimate.
void PostProcessEstimate();
// Returns the estimated incoming frame rate.
Frequency GetFrameRate() const;
// Filters the {frame_delay_delta, frame_size_delta} measurements through
@ -95,33 +94,35 @@ class JitterEstimator {
// TODO(bugs.webrtc.org/14381): Update `avg_frame_size_bytes_` to DataSize
// when api/units have sufficient precision.
double avg_frame_size_bytes_; // Average frame size
double var_frame_size_; // Frame size variance. Unit is bytes^2.
double var_frame_size_bytes2_; // Frame size variance. Unit is bytes^2.
// Largest frame size received (descending with a factor kPsi)
// TODO(bugs.webrtc.org/14381): Update `max_frame_size_bytes_` to DataSize
// when api/units have sufficient precision.
double max_frame_size_bytes_;
// TODO(bugs.webrtc.org/14381): Update `frame_size_sum_bytes_` to DataSize
// when api/units have sufficient precision.
double frame_size_sum_bytes_;
uint32_t frame_size_count_;
// TODO(bugs.webrtc.org/14381): Update `startup_frame_size_sum_bytes_` to
// DataSize when api/units have sufficient precision.
double startup_frame_size_sum_bytes_;
size_t startup_frame_size_count_;
absl::optional<Timestamp> last_update_time_;
// The previously returned jitter estimate
absl::optional<TimeDelta> prev_estimate_;
// Frame size of the previous frame
absl::optional<DataSize> prev_frame_size_;
// Average of the random jitter
double avg_noise_;
uint32_t alpha_count_;
// Average of the random jitter. Unit is milliseconds.
double avg_noise_ms_;
// Variance of the time-deviation from the line. Unit is milliseconds^2.
double var_noise_ms2_;
size_t alpha_count_;
// The filtered sum of jitter estimates
TimeDelta filter_jitter_estimate_ = TimeDelta::Zero();
uint32_t startup_count_;
size_t startup_count_;
// Time when the latest nack was seen
Timestamp latest_nack_ = Timestamp::Zero();
// Keeps track of the number of nacks received, but never goes above
// kNackLimit.
uint32_t nack_count_;
size_t nack_count_;
RttFilter rtt_filter_;
// Tracks frame rates in microseconds.