| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include <cmath> | 11 #include <cmath> |
| 12 #include <memory> | 12 #include <memory> |
| 13 | 13 |
| 14 #include "webrtc/base/fakeclock.h" |
| 14 #include "webrtc/common_audio/smoothing_filter.h" | 15 #include "webrtc/common_audio/smoothing_filter.h" |
| 15 #include "webrtc/test/gtest.h" | 16 #include "webrtc/test/gtest.h" |
| 16 | 17 |
| 17 namespace webrtc { | 18 namespace webrtc { |
| 18 | 19 |
| 19 namespace { | 20 namespace { |
| 20 | 21 |
| 21 constexpr float kMaxAbsError = 1e-5f; | 22 constexpr float kMaxAbsError = 1e-5f; |
| 22 constexpr int64_t kClockInitialTime = 123456; | 23 constexpr int64_t kClockInitialTime = 123456; |
| 23 | 24 |
| 24 struct SmoothingFilterStates { | 25 struct SmoothingFilterStates { |
| 25 std::unique_ptr<SimulatedClock> simulated_clock; | 26 explicit SmoothingFilterStates(int init_time_ms) |
| 26 std::unique_ptr<SmoothingFilterImpl> smoothing_filter; | 27 : smoothing_filter(init_time_ms) { |
| 28 fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kClockInitialTime)); |
| 29 } |
| 30 rtc::ScopedFakeClock fake_clock; |
| 31 SmoothingFilterImpl smoothing_filter; |
| 27 }; | 32 }; |
| 28 | 33 |
| 29 SmoothingFilterStates CreateSmoothingFilter(int init_time_ms) { | |
| 30 SmoothingFilterStates states; | |
| 31 states.simulated_clock.reset(new SimulatedClock(kClockInitialTime)); | |
| 32 states.smoothing_filter.reset( | |
| 33 new SmoothingFilterImpl(init_time_ms, states.simulated_clock.get())); | |
| 34 return states; | |
| 35 } | |
| 36 | |
| 37 // This function does the following: | 34 // This function does the following: |
| 38 // 1. Add a sample to filter at current clock, | 35 // 1. Add a sample to filter at current clock, |
| 39 // 2. Advance the clock by |advance_time_ms|, | 36 // 2. Advance the clock by |advance_time_ms|, |
| 40 // 3. Get the output of both SmoothingFilter and verify that it equals to an | 37 // 3. Get the output of both SmoothingFilter and verify that it equals to an |
| 41 // expected value. | 38 // expected value. |
| 42 void CheckOutput(SmoothingFilterStates* states, | 39 void CheckOutput(SmoothingFilterStates* states, |
| 43 float sample, | 40 float sample, |
| 44 int advance_time_ms, | 41 int advance_time_ms, |
| 45 float expected_ouput) { | 42 float expected_ouput) { |
| 46 states->smoothing_filter->AddSample(sample); | 43 states->smoothing_filter.AddSample(sample); |
| 47 states->simulated_clock->AdvanceTimeMilliseconds(advance_time_ms); | 44 states->fake_clock.AdvanceTime( |
| 48 auto output = states->smoothing_filter->GetAverage(); | 45 rtc::TimeDelta::FromMilliseconds(advance_time_ms)); |
| 46 auto output = states->smoothing_filter.GetAverage(); |
| 49 EXPECT_TRUE(output); | 47 EXPECT_TRUE(output); |
| 50 EXPECT_NEAR(expected_ouput, *output, kMaxAbsError); | 48 EXPECT_NEAR(expected_ouput, *output, kMaxAbsError); |
| 51 } | 49 } |
| 52 | 50 |
| 53 } // namespace | 51 } // namespace |
| 54 | 52 |
| 55 TEST(SmoothingFilterTest, NoOutputWhenNoSampleAdded) { | 53 TEST(SmoothingFilterTest, NoOutputWhenNoSampleAdded) { |
| 56 constexpr int kInitTimeMs = 100; | 54 constexpr int kInitTimeMs = 100; |
| 57 auto states = CreateSmoothingFilter(kInitTimeMs); | 55 SmoothingFilterStates states(kInitTimeMs); |
| 58 EXPECT_FALSE(states.smoothing_filter->GetAverage()); | 56 EXPECT_FALSE(states.smoothing_filter.GetAverage()); |
| 59 } | 57 } |
| 60 | 58 |
| 61 // Python script to calculate the reference values used in this test. | 59 // Python script to calculate the reference values used in this test. |
| 62 // import math | 60 // import math |
| 63 // | 61 // |
| 64 // class ExpFilter: | 62 // class ExpFilter: |
| 65 // def add_sample(self, new_value): | 63 // def add_sample(self, new_value): |
| 66 // self.state = self.state * self.alpha + (1.0 - self.alpha) * new_value | 64 // self.state = self.state * self.alpha + (1.0 - self.alpha) * new_value |
| 67 // | 65 // |
| 68 // filter = ExpFilter() | 66 // filter = ExpFilter() |
| (...skipping 28 matching lines...) Expand all Loading... |
| 97 // | 95 // |
| 98 // for i in range(800, 900): | 96 // for i in range(800, 900): |
| 99 // filter.add_sample(0.5) | 97 // filter.add_sample(0.5) |
| 100 // print filter.state | 98 // print filter.state |
| 101 // | 99 // |
| 102 // for i in range(900, 1000): | 100 // for i in range(900, 1000): |
| 103 // filter.add_sample(1.0) | 101 // filter.add_sample(1.0) |
| 104 // print filter.state | 102 // print filter.state |
| 105 TEST(SmoothingFilterTest, CheckBehaviorAroundInitTime) { | 103 TEST(SmoothingFilterTest, CheckBehaviorAroundInitTime) { |
| 106 constexpr int kInitTimeMs = 795; | 104 constexpr int kInitTimeMs = 795; |
| 107 auto states = CreateSmoothingFilter(kInitTimeMs); | 105 SmoothingFilterStates states(kInitTimeMs); |
| 108 CheckOutput(&states, 1.0f, 500, 1.0f); | 106 CheckOutput(&states, 1.0f, 500, 1.0f); |
| 109 CheckOutput(&states, 0.5f, 100, 0.680562264029f); | 107 CheckOutput(&states, 0.5f, 100, 0.680562264029f); |
| 110 CheckOutput(&states, 1.0f, 100, 0.794207139813f); | 108 CheckOutput(&states, 1.0f, 100, 0.794207139813f); |
| 111 // Next step will go across initialization time. | 109 // Next step will go across initialization time. |
| 112 CheckOutput(&states, 1.0f, 100, 0.829803409752f); | 110 CheckOutput(&states, 1.0f, 100, 0.829803409752f); |
| 113 CheckOutput(&states, 0.5f, 100, 0.790821764210f); | 111 CheckOutput(&states, 0.5f, 100, 0.790821764210f); |
| 114 CheckOutput(&states, 1.0f, 100, 0.815545922911f); | 112 CheckOutput(&states, 1.0f, 100, 0.815545922911f); |
| 115 } | 113 } |
| 116 | 114 |
| 117 TEST(SmoothingFilterTest, InitTimeEqualsZero) { | 115 TEST(SmoothingFilterTest, InitTimeEqualsZero) { |
| 118 constexpr int kInitTimeMs = 0; | 116 constexpr int kInitTimeMs = 0; |
| 119 auto states = CreateSmoothingFilter(kInitTimeMs); | 117 SmoothingFilterStates states(kInitTimeMs); |
| 120 CheckOutput(&states, 1.0f, 1, 1.0f); | 118 CheckOutput(&states, 1.0f, 1, 1.0f); |
| 121 CheckOutput(&states, 0.5f, 1, 0.5f); | 119 CheckOutput(&states, 0.5f, 1, 0.5f); |
| 122 } | 120 } |
| 123 | 121 |
| 124 TEST(SmoothingFilterTest, InitTimeEqualsOne) { | 122 TEST(SmoothingFilterTest, InitTimeEqualsOne) { |
| 125 constexpr int kInitTimeMs = 1; | 123 constexpr int kInitTimeMs = 1; |
| 126 auto states = CreateSmoothingFilter(kInitTimeMs); | 124 SmoothingFilterStates states(kInitTimeMs); |
| 127 CheckOutput(&states, 1.0f, 1, 1.0f); | 125 CheckOutput(&states, 1.0f, 1, 1.0f); |
| 128 CheckOutput(&states, 0.5f, 1, 1.0f * exp(-1.0f) + (1.0f - exp(-1.0f)) * 0.5f); | 126 CheckOutput(&states, 0.5f, 1, 1.0f * exp(-1.0f) + (1.0f - exp(-1.0f)) * 0.5f); |
| 129 } | 127 } |
| 130 | 128 |
| 131 TEST(SmoothingFilterTest, GetAverageOutputsEmptyBeforeFirstSample) { | 129 TEST(SmoothingFilterTest, GetAverageOutputsEmptyBeforeFirstSample) { |
| 132 constexpr int kInitTimeMs = 100; | 130 constexpr int kInitTimeMs = 100; |
| 133 auto states = CreateSmoothingFilter(kInitTimeMs); | 131 SmoothingFilterStates states(kInitTimeMs); |
| 134 EXPECT_FALSE(states.smoothing_filter->GetAverage()); | 132 EXPECT_FALSE(states.smoothing_filter.GetAverage()); |
| 135 constexpr float kFirstSample = 1.2345f; | 133 constexpr float kFirstSample = 1.2345f; |
| 136 states.smoothing_filter->AddSample(kFirstSample); | 134 states.smoothing_filter.AddSample(kFirstSample); |
| 137 EXPECT_EQ(rtc::Optional<float>(kFirstSample), | 135 EXPECT_EQ(rtc::Optional<float>(kFirstSample), |
| 138 states.smoothing_filter->GetAverage()); | 136 states.smoothing_filter.GetAverage()); |
| 139 } | 137 } |
| 140 | 138 |
| 141 TEST(SmoothingFilterTest, CannotChangeTimeConstantDuringInitialization) { | 139 TEST(SmoothingFilterTest, CannotChangeTimeConstantDuringInitialization) { |
| 142 constexpr int kInitTimeMs = 100; | 140 constexpr int kInitTimeMs = 100; |
| 143 auto states = CreateSmoothingFilter(kInitTimeMs); | 141 SmoothingFilterStates states(kInitTimeMs); |
| 144 states.smoothing_filter->AddSample(0.0); | 142 states.smoothing_filter.AddSample(0.0); |
| 145 | 143 |
| 146 // During initialization, |SetTimeConstantMs| does not take effect. | 144 // During initialization, |SetTimeConstantMs| does not take effect. |
| 147 states.simulated_clock->AdvanceTimeMilliseconds(kInitTimeMs - 1); | 145 states.fake_clock.AdvanceTime( |
| 148 states.smoothing_filter->AddSample(0.0); | 146 rtc::TimeDelta::FromMilliseconds(kInitTimeMs - 1)); |
| 147 states.smoothing_filter.AddSample(0.0); |
| 149 | 148 |
| 150 EXPECT_FALSE(states.smoothing_filter->SetTimeConstantMs(kInitTimeMs * 2)); | 149 EXPECT_FALSE(states.smoothing_filter.SetTimeConstantMs(kInitTimeMs * 2)); |
| 151 EXPECT_NE(exp(-1.0f / (kInitTimeMs * 2)), states.smoothing_filter->alpha()); | 150 EXPECT_NE(exp(-1.0f / (kInitTimeMs * 2)), states.smoothing_filter.alpha()); |
| 152 | 151 |
| 153 states.simulated_clock->AdvanceTimeMilliseconds(1); | 152 states.fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(1)); |
| 154 states.smoothing_filter->AddSample(0.0); | 153 states.smoothing_filter.AddSample(0.0); |
| 155 // When initialization finishes, the time constant should be come | 154 // When initialization finishes, the time constant should be come |
| 156 // |kInitTimeConstantMs|. | 155 // |kInitTimeConstantMs|. |
| 157 EXPECT_FLOAT_EQ(exp(-1.0f / kInitTimeMs), states.smoothing_filter->alpha()); | 156 EXPECT_FLOAT_EQ(exp(-1.0f / kInitTimeMs), states.smoothing_filter.alpha()); |
| 158 | 157 |
| 159 // After initialization, |SetTimeConstantMs| takes effect. | 158 // After initialization, |SetTimeConstantMs| takes effect. |
| 160 EXPECT_TRUE(states.smoothing_filter->SetTimeConstantMs(kInitTimeMs * 2)); | 159 EXPECT_TRUE(states.smoothing_filter.SetTimeConstantMs(kInitTimeMs * 2)); |
| 161 EXPECT_FLOAT_EQ(exp(-1.0f / (kInitTimeMs * 2)), | 160 EXPECT_FLOAT_EQ(exp(-1.0f / (kInitTimeMs * 2)), |
| 162 states.smoothing_filter->alpha()); | 161 states.smoothing_filter.alpha()); |
| 163 } | 162 } |
| 164 | 163 |
| 165 } // namespace webrtc | 164 } // namespace webrtc |
| OLD | NEW |