Reduce jitter delay for low fps streams.
Enabled by finch flag. BUG= R=stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/31389005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7288 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@@ -237,6 +237,7 @@
|
|||||||
'video_coding/main/interface/mock/mock_vcm_callbacks.h',
|
'video_coding/main/interface/mock/mock_vcm_callbacks.h',
|
||||||
'video_coding/main/source/decoding_state_unittest.cc',
|
'video_coding/main/source/decoding_state_unittest.cc',
|
||||||
'video_coding/main/source/jitter_buffer_unittest.cc',
|
'video_coding/main/source/jitter_buffer_unittest.cc',
|
||||||
|
'video_coding/main/source/jitter_estimator_tests.cc',
|
||||||
'video_coding/main/source/media_optimization_unittest.cc',
|
'video_coding/main/source/media_optimization_unittest.cc',
|
||||||
'video_coding/main/source/receiver_unittest.cc',
|
'video_coding/main/source/receiver_unittest.cc',
|
||||||
'video_coding/main/source/session_info_unittest.cc',
|
'video_coding/main/source/session_info_unittest.cc',
|
||||||
|
|||||||
@@ -122,8 +122,7 @@ void FrameList::Reset(UnorderedFrameList* free_frames) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VCMJitterBuffer::VCMJitterBuffer(Clock* clock,
|
VCMJitterBuffer::VCMJitterBuffer(Clock* clock, EventFactory* event_factory)
|
||||||
EventFactory* event_factory)
|
|
||||||
: clock_(clock),
|
: clock_(clock),
|
||||||
running_(false),
|
running_(false),
|
||||||
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
|
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||||
@@ -145,7 +144,7 @@ VCMJitterBuffer::VCMJitterBuffer(Clock* clock,
|
|||||||
num_consecutive_old_frames_(0),
|
num_consecutive_old_frames_(0),
|
||||||
num_consecutive_old_packets_(0),
|
num_consecutive_old_packets_(0),
|
||||||
num_discarded_packets_(0),
|
num_discarded_packets_(0),
|
||||||
jitter_estimate_(),
|
jitter_estimate_(clock),
|
||||||
inter_frame_delay_(clock_->TimeInMilliseconds()),
|
inter_frame_delay_(clock_->TimeInMilliseconds()),
|
||||||
rtt_ms_(kDefaultRtt),
|
rtt_ms_(kDefaultRtt),
|
||||||
nack_mode_(kNoNack),
|
nack_mode_(kNoNack),
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
#include "webrtc/modules/video_coding/main/source/internal_defines.h"
|
#include "webrtc/modules/video_coding/main/source/internal_defines.h"
|
||||||
#include "webrtc/modules/video_coding/main/source/jitter_estimator.h"
|
#include "webrtc/modules/video_coding/main/source/jitter_estimator.h"
|
||||||
#include "webrtc/modules/video_coding/main/source/rtt_filter.h"
|
#include "webrtc/modules/video_coding/main/source/rtt_filter.h"
|
||||||
|
#include "webrtc/system_wrappers/interface/clock.h"
|
||||||
|
#include "webrtc/system_wrappers/interface/field_trial.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@@ -19,7 +21,13 @@
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
VCMJitterEstimator::VCMJitterEstimator(int32_t vcmId, int32_t receiverId)
|
enum { kStartupDelaySamples = 30 };
|
||||||
|
enum { kFsAccuStartupSamples = 5 };
|
||||||
|
enum { kMaxFramerateEstimate = 200 };
|
||||||
|
|
||||||
|
VCMJitterEstimator::VCMJitterEstimator(const Clock* clock,
|
||||||
|
int32_t vcmId,
|
||||||
|
int32_t receiverId)
|
||||||
: _vcmId(vcmId),
|
: _vcmId(vcmId),
|
||||||
_receiverId(receiverId),
|
_receiverId(receiverId),
|
||||||
_phi(0.97),
|
_phi(0.97),
|
||||||
@@ -32,10 +40,17 @@ VCMJitterEstimator::VCMJitterEstimator(int32_t vcmId, int32_t receiverId)
|
|||||||
_noiseStdDevs(2.33), // ~Less than 1% chance
|
_noiseStdDevs(2.33), // ~Less than 1% chance
|
||||||
// (look up in normal distribution table)...
|
// (look up in normal distribution table)...
|
||||||
_noiseStdDevOffset(30.0), // ...of getting 30 ms freezes
|
_noiseStdDevOffset(30.0), // ...of getting 30 ms freezes
|
||||||
_rttFilter() {
|
_rttFilter(),
|
||||||
|
fps_counter_(30), // TODO(sprang): Use an estimator with limit based on
|
||||||
|
// time, rather than number of samples.
|
||||||
|
low_rate_experiment_(kInit),
|
||||||
|
clock_(clock) {
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VCMJitterEstimator::~VCMJitterEstimator() {
|
||||||
|
}
|
||||||
|
|
||||||
VCMJitterEstimator&
|
VCMJitterEstimator&
|
||||||
VCMJitterEstimator::operator=(const VCMJitterEstimator& rhs)
|
VCMJitterEstimator::operator=(const VCMJitterEstimator& rhs)
|
||||||
{
|
{
|
||||||
@@ -94,6 +109,7 @@ VCMJitterEstimator::Reset()
|
|||||||
_fsCount = 0;
|
_fsCount = 0;
|
||||||
_startupCount = 0;
|
_startupCount = 0;
|
||||||
_rttFilter.Reset();
|
_rttFilter.Reset();
|
||||||
|
fps_counter_.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -297,31 +313,50 @@ VCMJitterEstimator::DeviationFromExpectedDelay(int64_t frameDelayMS,
|
|||||||
|
|
||||||
// Estimates the random jitter by calculating the variance of the
|
// Estimates the random jitter by calculating the variance of the
|
||||||
// sample distance from the line given by theta.
|
// sample distance from the line given by theta.
|
||||||
void
|
void VCMJitterEstimator::EstimateRandomJitter(double d_dT,
|
||||||
VCMJitterEstimator::EstimateRandomJitter(double d_dT, bool incompleteFrame)
|
bool incompleteFrame) {
|
||||||
{
|
uint64_t now = clock_->TimeInMicroseconds();
|
||||||
double alpha;
|
if (_lastUpdateT != -1) {
|
||||||
if (_alphaCount == 0)
|
fps_counter_.AddSample(now - _lastUpdateT);
|
||||||
{
|
}
|
||||||
assert(_alphaCount > 0);
|
_lastUpdateT = now;
|
||||||
|
|
||||||
|
if (_alphaCount == 0) {
|
||||||
|
assert(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
alpha = static_cast<double>(_alphaCount - 1) / static_cast<double>(_alphaCount);
|
double alpha =
|
||||||
|
static_cast<double>(_alphaCount - 1) / static_cast<double>(_alphaCount);
|
||||||
_alphaCount++;
|
_alphaCount++;
|
||||||
if (_alphaCount > _alphaCountMax)
|
if (_alphaCount > _alphaCountMax)
|
||||||
{
|
|
||||||
_alphaCount = _alphaCountMax;
|
_alphaCount = _alphaCountMax;
|
||||||
|
|
||||||
|
if (LowRateExperimentEnabled()) {
|
||||||
|
// In order to avoid a low frame rate stream to react slower to changes,
|
||||||
|
// scale the alpha weight relative a 30 fps stream.
|
||||||
|
double fps = GetFrameRate();
|
||||||
|
if (fps > 0.0) {
|
||||||
|
double rate_scale = 30.0 / fps;
|
||||||
|
// At startup, there can be a lot of noise in the fps estimate.
|
||||||
|
// Interpolate rate_scale linearly, from 1.0 at sample #1, to 30.0 / fps
|
||||||
|
// at sample #kStartupDelaySamples.
|
||||||
|
if (_alphaCount < kStartupDelaySamples) {
|
||||||
|
rate_scale =
|
||||||
|
(_alphaCount * rate_scale + (kStartupDelaySamples - _alphaCount)) /
|
||||||
|
kStartupDelaySamples;
|
||||||
}
|
}
|
||||||
|
alpha = pow(alpha, rate_scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double avgNoise = alpha * _avgNoise + (1 - alpha) * d_dT;
|
double avgNoise = alpha * _avgNoise + (1 - alpha) * d_dT;
|
||||||
double varNoise = alpha * _varNoise +
|
double varNoise =
|
||||||
(1 - alpha) * (d_dT - _avgNoise) * (d_dT - _avgNoise);
|
alpha * _varNoise + (1 - alpha) * (d_dT - _avgNoise) * (d_dT - _avgNoise);
|
||||||
if (!incompleteFrame || varNoise > _varNoise)
|
if (!incompleteFrame || varNoise > _varNoise) {
|
||||||
{
|
|
||||||
_avgNoise = avgNoise;
|
_avgNoise = avgNoise;
|
||||||
_varNoise = varNoise;
|
_varNoise = varNoise;
|
||||||
}
|
}
|
||||||
if (_varNoise < 1.0)
|
if (_varNoise < 1.0) {
|
||||||
{
|
|
||||||
// The variance should never be zero, since we might get
|
// The variance should never be zero, since we might get
|
||||||
// stuck and consider all samples as outliers.
|
// stuck and consider all samples as outliers.
|
||||||
_varNoise = 1.0;
|
_varNoise = 1.0;
|
||||||
@@ -387,19 +422,61 @@ VCMJitterEstimator::UpdateMaxFrameSize(uint32_t frameSizeBytes)
|
|||||||
|
|
||||||
// Returns the current filtered estimate if available,
|
// Returns the current filtered estimate if available,
|
||||||
// otherwise tries to calculate an estimate.
|
// otherwise tries to calculate an estimate.
|
||||||
int
|
int VCMJitterEstimator::GetJitterEstimate(double rttMultiplier) {
|
||||||
VCMJitterEstimator::GetJitterEstimate(double rttMultiplier)
|
|
||||||
{
|
|
||||||
double jitterMS = CalculateEstimate() + OPERATING_SYSTEM_JITTER;
|
double jitterMS = CalculateEstimate() + OPERATING_SYSTEM_JITTER;
|
||||||
if (_filterJitterEstimate > jitterMS)
|
if (_filterJitterEstimate > jitterMS)
|
||||||
{
|
|
||||||
jitterMS = _filterJitterEstimate;
|
jitterMS = _filterJitterEstimate;
|
||||||
}
|
|
||||||
if (_nackCount >= _nackLimit)
|
if (_nackCount >= _nackLimit)
|
||||||
{
|
|
||||||
jitterMS += _rttFilter.RttMs() * rttMultiplier;
|
jitterMS += _rttFilter.RttMs() * rttMultiplier;
|
||||||
|
|
||||||
|
if (LowRateExperimentEnabled()) {
|
||||||
|
static const double kJitterScaleLowThreshold = 5.0;
|
||||||
|
static const double kJitterScaleHighThreshold = 10.0;
|
||||||
|
double fps = GetFrameRate();
|
||||||
|
// Ignore jitter for very low fps streams.
|
||||||
|
if (fps < kJitterScaleLowThreshold) {
|
||||||
|
if (fps == 0.0) {
|
||||||
|
return jitterMS;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Semi-low frame rate; scale by factor linearly interpolated from 0.0 at
|
||||||
|
// kJitterScaleLowThreshold to 1.0 at kJitterScaleHighThreshold.
|
||||||
|
if (fps < kJitterScaleHighThreshold) {
|
||||||
|
jitterMS =
|
||||||
|
(1.0 / (kJitterScaleHighThreshold - kJitterScaleLowThreshold)) *
|
||||||
|
(fps - kJitterScaleLowThreshold) * jitterMS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return static_cast<uint32_t>(jitterMS + 0.5);
|
return static_cast<uint32_t>(jitterMS + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VCMJitterEstimator::LowRateExperimentEnabled() {
|
||||||
|
if (low_rate_experiment_ == kInit) {
|
||||||
|
std::string group =
|
||||||
|
webrtc::field_trial::FindFullName("WebRTC-ReducedJitterDelay");
|
||||||
|
if (group == "Disabled") {
|
||||||
|
low_rate_experiment_ = kDisabled;
|
||||||
|
} else {
|
||||||
|
low_rate_experiment_ = kEnabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return low_rate_experiment_ == kEnabled ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double VCMJitterEstimator::GetFrameRate() const {
|
||||||
|
if (fps_counter_.count() == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
double fps = 1000000.0 / fps_counter_.ComputeMean();
|
||||||
|
// Sanity check.
|
||||||
|
assert(fps >= 0.0);
|
||||||
|
if (fps > kMaxFramerateEstimate) {
|
||||||
|
fps = kMaxFramerateEstimate;
|
||||||
|
}
|
||||||
|
return fps;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,17 +11,22 @@
|
|||||||
#ifndef WEBRTC_MODULES_VIDEO_CODING_JITTER_ESTIMATOR_H_
|
#ifndef WEBRTC_MODULES_VIDEO_CODING_JITTER_ESTIMATOR_H_
|
||||||
#define WEBRTC_MODULES_VIDEO_CODING_JITTER_ESTIMATOR_H_
|
#define WEBRTC_MODULES_VIDEO_CODING_JITTER_ESTIMATOR_H_
|
||||||
|
|
||||||
|
#include "webrtc/base/rollingaccumulator.h"
|
||||||
#include "webrtc/modules/video_coding/main/source/rtt_filter.h"
|
#include "webrtc/modules/video_coding/main/source/rtt_filter.h"
|
||||||
#include "webrtc/typedefs.h"
|
#include "webrtc/typedefs.h"
|
||||||
|
|
||||||
namespace webrtc
|
namespace webrtc
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class Clock;
|
||||||
|
|
||||||
class VCMJitterEstimator
|
class VCMJitterEstimator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VCMJitterEstimator(int32_t vcmId = 0, int32_t receiverId = 0);
|
VCMJitterEstimator(const Clock* clock,
|
||||||
|
int32_t vcmId = 0,
|
||||||
|
int32_t receiverId = 0);
|
||||||
|
virtual ~VCMJitterEstimator();
|
||||||
VCMJitterEstimator& operator=(const VCMJitterEstimator& rhs);
|
VCMJitterEstimator& operator=(const VCMJitterEstimator& rhs);
|
||||||
|
|
||||||
// Resets the estimate to the initial state
|
// Resets the estimate to the initial state
|
||||||
@@ -68,6 +73,8 @@ protected:
|
|||||||
double _theta[2]; // Estimated line parameters (slope, offset)
|
double _theta[2]; // Estimated line parameters (slope, offset)
|
||||||
double _varNoise; // Variance of the time-deviation from the line
|
double _varNoise; // Variance of the time-deviation from the line
|
||||||
|
|
||||||
|
virtual bool LowRateExperimentEnabled();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Updates the Kalman filter for the line describing
|
// Updates the Kalman filter for the line describing
|
||||||
// the frame size dependent jitter.
|
// the frame size dependent jitter.
|
||||||
@@ -109,6 +116,8 @@ private:
|
|||||||
double DeviationFromExpectedDelay(int64_t frameDelayMS,
|
double DeviationFromExpectedDelay(int64_t frameDelayMS,
|
||||||
int32_t deltaFSBytes) const;
|
int32_t deltaFSBytes) const;
|
||||||
|
|
||||||
|
double GetFrameRate() const;
|
||||||
|
|
||||||
// Constants, filter parameters
|
// Constants, filter parameters
|
||||||
int32_t _vcmId;
|
int32_t _vcmId;
|
||||||
int32_t _receiverId;
|
int32_t _receiverId;
|
||||||
@@ -145,8 +154,10 @@ private:
|
|||||||
// but never goes above _nackLimit
|
// but never goes above _nackLimit
|
||||||
VCMRttFilter _rttFilter;
|
VCMRttFilter _rttFilter;
|
||||||
|
|
||||||
enum { kStartupDelaySamples = 30 };
|
rtc::RollingAccumulator<uint64_t> fps_counter_;
|
||||||
enum { kFsAccuStartupSamples = 5 };
|
enum ExperimentFlag { kInit, kEnabled, kDisabled };
|
||||||
|
ExperimentFlag low_rate_experiment_;
|
||||||
|
const Clock* clock_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
/* Copyright (c) 2014 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/video_coding/main/source/jitter_estimator.h"
|
||||||
|
|
||||||
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
#include "webrtc/system_wrappers/interface/clock.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
class TestEstimator : public VCMJitterEstimator {
|
||||||
|
public:
|
||||||
|
explicit TestEstimator(bool exp_enabled)
|
||||||
|
: VCMJitterEstimator(&fake_clock_, 0, 0),
|
||||||
|
fake_clock_(0),
|
||||||
|
exp_enabled_(exp_enabled) {}
|
||||||
|
|
||||||
|
virtual bool LowRateExperimentEnabled() { return exp_enabled_; }
|
||||||
|
|
||||||
|
void AdvanceClock(int64_t microseconds) {
|
||||||
|
fake_clock_.AdvanceTimeMicroseconds(microseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SimulatedClock fake_clock_;
|
||||||
|
const bool exp_enabled_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestVCMJitterEstimator : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
TestVCMJitterEstimator()
|
||||||
|
: regular_estimator_(false), low_rate_estimator_(true) {}
|
||||||
|
|
||||||
|
virtual void SetUp() { regular_estimator_.Reset(); }
|
||||||
|
|
||||||
|
TestEstimator regular_estimator_;
|
||||||
|
TestEstimator low_rate_estimator_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generates some simple test data in the form of a sawtooth wave.
|
||||||
|
class ValueGenerator {
|
||||||
|
public:
|
||||||
|
ValueGenerator(int32_t amplitude) : amplitude_(amplitude), counter_(0) {}
|
||||||
|
virtual ~ValueGenerator() {}
|
||||||
|
|
||||||
|
int64_t Delay() { return ((counter_ % 11) - 5) * amplitude_; }
|
||||||
|
|
||||||
|
uint32_t FrameSize() { return 1000 + Delay(); }
|
||||||
|
|
||||||
|
void Advance() { ++counter_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int32_t amplitude_;
|
||||||
|
int64_t counter_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 5 fps, disable jitter delay altogether.
|
||||||
|
TEST_F(TestVCMJitterEstimator, TestLowRate) {
|
||||||
|
ValueGenerator gen(10);
|
||||||
|
uint64_t time_delta = 1000000 / 5;
|
||||||
|
for (int i = 0; i < 60; ++i) {
|
||||||
|
regular_estimator_.UpdateEstimate(gen.Delay(), gen.FrameSize());
|
||||||
|
regular_estimator_.AdvanceClock(time_delta);
|
||||||
|
low_rate_estimator_.UpdateEstimate(gen.Delay(), gen.FrameSize());
|
||||||
|
low_rate_estimator_.AdvanceClock(time_delta);
|
||||||
|
EXPECT_GT(regular_estimator_.GetJitterEstimate(0), 0);
|
||||||
|
if (i > 2)
|
||||||
|
EXPECT_EQ(low_rate_estimator_.GetJitterEstimate(0), 0);
|
||||||
|
gen.Advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8 fps, steady state estimate should be in interpolated interval between 0
|
||||||
|
// and value of previous method.
|
||||||
|
TEST_F(TestVCMJitterEstimator, TestMidRate) {
|
||||||
|
ValueGenerator gen(10);
|
||||||
|
uint64_t time_delta = 1000000 / 8;
|
||||||
|
for (int i = 0; i < 60; ++i) {
|
||||||
|
regular_estimator_.UpdateEstimate(gen.Delay(), gen.FrameSize());
|
||||||
|
regular_estimator_.AdvanceClock(time_delta);
|
||||||
|
low_rate_estimator_.UpdateEstimate(gen.Delay(), gen.FrameSize());
|
||||||
|
low_rate_estimator_.AdvanceClock(time_delta);
|
||||||
|
EXPECT_GT(regular_estimator_.GetJitterEstimate(0), 0);
|
||||||
|
EXPECT_GT(low_rate_estimator_.GetJitterEstimate(0), 0);
|
||||||
|
EXPECT_GE(regular_estimator_.GetJitterEstimate(0),
|
||||||
|
low_rate_estimator_.GetJitterEstimate(0));
|
||||||
|
gen.Advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 30 fps, steady state estimate should be same as previous method.
|
||||||
|
TEST_F(TestVCMJitterEstimator, TestHighRate) {
|
||||||
|
ValueGenerator gen(10);
|
||||||
|
uint64_t time_delta = 1000000 / 30;
|
||||||
|
for (int i = 0; i < 60; ++i) {
|
||||||
|
regular_estimator_.UpdateEstimate(gen.Delay(), gen.FrameSize());
|
||||||
|
regular_estimator_.AdvanceClock(time_delta);
|
||||||
|
low_rate_estimator_.UpdateEstimate(gen.Delay(), gen.FrameSize());
|
||||||
|
low_rate_estimator_.AdvanceClock(time_delta);
|
||||||
|
EXPECT_EQ(regular_estimator_.GetJitterEstimate(0),
|
||||||
|
low_rate_estimator_.GetJitterEstimate(0));
|
||||||
|
gen.Advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 10 fps, high jitter then low jitter. Low rate estimator should converge
|
||||||
|
// faster to low noise estimate.
|
||||||
|
TEST_F(TestVCMJitterEstimator, TestConvergence) {
|
||||||
|
// Reach a steady state with high noise.
|
||||||
|
ValueGenerator gen(50);
|
||||||
|
uint64_t time_delta = 1000000 / 10;
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
regular_estimator_.UpdateEstimate(gen.Delay(), gen.FrameSize());
|
||||||
|
regular_estimator_.AdvanceClock(time_delta * 2);
|
||||||
|
low_rate_estimator_.UpdateEstimate(gen.Delay(), gen.FrameSize());
|
||||||
|
low_rate_estimator_.AdvanceClock(time_delta * 2);
|
||||||
|
gen.Advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
int threshold = regular_estimator_.GetJitterEstimate(0) / 2;
|
||||||
|
|
||||||
|
// New generator with zero noise.
|
||||||
|
ValueGenerator low_gen(0);
|
||||||
|
int regular_iterations = 0;
|
||||||
|
int low_rate_iterations = 0;
|
||||||
|
for (int i = 0; i < 500; ++i) {
|
||||||
|
if (regular_iterations == 0) {
|
||||||
|
regular_estimator_.UpdateEstimate(low_gen.Delay(), low_gen.FrameSize());
|
||||||
|
regular_estimator_.AdvanceClock(time_delta);
|
||||||
|
if (regular_estimator_.GetJitterEstimate(0) < threshold) {
|
||||||
|
regular_iterations = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (low_rate_iterations == 0) {
|
||||||
|
low_rate_estimator_.UpdateEstimate(low_gen.Delay(), low_gen.FrameSize());
|
||||||
|
low_rate_estimator_.AdvanceClock(time_delta);
|
||||||
|
if (low_rate_estimator_.GetJitterEstimate(0) < threshold) {
|
||||||
|
low_rate_iterations = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regular_iterations != 0 && low_rate_iterations != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gen.Advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_NE(regular_iterations, 0);
|
||||||
|
EXPECT_NE(low_rate_iterations, 0);
|
||||||
|
EXPECT_LE(low_rate_iterations, regular_iterations);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user