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 |