blob: 3d46ce2bcdf626d777b8996cb722f7cf042cf18b [file] [log] [blame]
/* 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/jitter_estimator.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/include/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);
}
}