| /* 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 "webrtc/system_wrappers/include/clock.h" |
| #include "webrtc/test/gtest.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: |
| explicit 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); |
| } |
| } // namespace webrtc |