Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(419)

Side by Side Diff: webrtc/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc

Issue 2678423005: Finalization of the first version of EchoCanceller 3 (Closed)
Patch Set: Fixed compilation error Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h"
12
13 #include <algorithm>
14 #include <numeric>
15 #include <string>
16 #include "webrtc/typedefs.h"
17 #if defined(WEBRTC_ARCH_X86_FAMILY)
18 #include <emmintrin.h>
19 #endif
20 #include "webrtc/base/arraysize.h"
21 #include "webrtc/base/random.h"
22 #include "webrtc/modules/audio_processing/aec3/aec_state.h"
23 #include "webrtc/modules/audio_processing/aec3/aec3_fft.h"
24 #include "webrtc/modules/audio_processing/aec3/render_signal_analyzer.h"
25 #include "webrtc/modules/audio_processing/aec3/shadow_filter_update_gain.h"
26 #include "webrtc/modules/audio_processing/logging/apm_data_dumper.h"
27 #include "webrtc/modules/audio_processing/test/echo_canceller_test_tools.h"
28 #include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
29 #include "webrtc/test/gtest.h"
30
31 namespace webrtc {
32 namespace aec3 {
33 namespace {
34
35 std::string ProduceDebugText(size_t delay) {
36 std::ostringstream ss;
37 ss << ", Delay: " << delay;
38 return ss.str();
39 }
40
41 } // namespace
42
43 #if defined(WEBRTC_ARCH_X86_FAMILY)
44 // Verifies that the optimized methods are bitexact to their reference
45 // counterparts.
46 TEST(AdaptiveFirFilter, TestOptimizations) {
47 bool use_sse2 = (WebRtc_GetCPUInfo(kSSE2) != 0);
48 if (use_sse2) {
49 FftBuffer X_buffer(Aec3Optimization::kNone, 12, std::vector<size_t>(1, 12));
50 std::array<float, kBlockSize> x_old;
51 x_old.fill(0.f);
52 Random random_generator(42U);
53 std::vector<float> x(kBlockSize, 0.f);
54 FftData X;
55 FftData S_C;
56 FftData S_SSE2;
57 FftData G;
58 Aec3Fft fft;
59 std::vector<FftData> H_C(10);
60 std::vector<FftData> H_SSE2(10);
61 for (auto& H_j : H_C) {
62 H_j.Clear();
63 }
64 for (auto& H_j : H_SSE2) {
65 H_j.Clear();
66 }
67
68 for (size_t k = 0; k < 500; ++k) {
69 RandomizeSampleVector(&random_generator, x);
70 fft.PaddedFft(x, x_old, &X);
71 X_buffer.Insert(X);
72
73 ApplyFilter_SSE2(X_buffer, H_SSE2, &S_SSE2);
74 ApplyFilter(X_buffer, H_C, &S_C);
75 for (size_t j = 0; j < S_C.re.size(); ++j) {
76 EXPECT_FLOAT_EQ(S_C.re[j], S_SSE2.re[j]);
77 EXPECT_FLOAT_EQ(S_C.im[j], S_SSE2.im[j]);
78 }
79
80 std::for_each(G.re.begin(), G.re.end(),
81 [&](float& a) { a = random_generator.Rand<float>(); });
82 std::for_each(G.im.begin(), G.im.end(),
83 [&](float& a) { a = random_generator.Rand<float>(); });
84
85 AdaptPartitions_SSE2(X_buffer, G, H_SSE2);
86 AdaptPartitions(X_buffer, G, H_C);
87
88 for (size_t k = 0; k < H_C.size(); ++k) {
89 for (size_t j = 0; j < H_C[k].re.size(); ++j) {
90 EXPECT_FLOAT_EQ(H_C[k].re[j], H_SSE2[k].re[j]);
91 EXPECT_FLOAT_EQ(H_C[k].im[j], H_SSE2[k].im[j]);
92 }
93 }
94 }
95 }
96 }
97
98 #endif
99
100 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
101 // Verifies that the check for non-null data dumper works.
102 TEST(AdaptiveFirFilter, NullDataDumper) {
103 EXPECT_DEATH(AdaptiveFirFilter(9, true, DetectOptimization(), nullptr), "");
104 }
105
106 // Verifies that the check for non-null filter output works.
107 TEST(AdaptiveFirFilter, NullFilterOutput) {
108 ApmDataDumper data_dumper(42);
109 AdaptiveFirFilter filter(9, true, DetectOptimization(), &data_dumper);
110 FftBuffer X_buffer(Aec3Optimization::kNone, filter.SizePartitions(),
111 std::vector<size_t>(1, filter.SizePartitions()));
112 EXPECT_DEATH(filter.Filter(X_buffer, nullptr), "");
113 }
114
115 // Verifies that the check for whether filter statistics are being generated
116 // works when retrieving the ERL.
117 TEST(AdaptiveFirFilter, ErlAccessWhenNoFilterStatistics) {
118 ApmDataDumper data_dumper(42);
119 AdaptiveFirFilter filter(9, false, DetectOptimization(), &data_dumper);
120 EXPECT_DEATH(filter.Erl(), "");
121 }
122
123 // Verifies that the check for whether filter statistics are being generated
124 // works when retrieving the filter frequencyResponse.
125 TEST(AdaptiveFirFilter, FilterFrequencyResponseAccessWhenNoFilterStatistics) {
126 ApmDataDumper data_dumper(42);
127 AdaptiveFirFilter filter(9, false, DetectOptimization(), &data_dumper);
128 EXPECT_DEATH(filter.FilterFrequencyResponse(), "");
129 }
130
131 #endif
132
133 // Verifies that the filter statistics can be accessed when filter statistics
134 // are turned on.
135 TEST(AdaptiveFirFilter, FilterStatisticsAccess) {
136 ApmDataDumper data_dumper(42);
137 AdaptiveFirFilter filter(9, true, DetectOptimization(), &data_dumper);
138 filter.Erl();
139 filter.FilterFrequencyResponse();
140 }
141
142 // Verifies that the filter size if correctly repported.
143 TEST(AdaptiveFirFilter, FilterSize) {
144 ApmDataDumper data_dumper(42);
145 for (size_t filter_size = 1; filter_size < 5; ++filter_size) {
146 AdaptiveFirFilter filter(filter_size, false, DetectOptimization(),
147 &data_dumper);
148 EXPECT_EQ(filter_size, filter.SizePartitions());
149 }
150 }
151
152 // Verifies that the filter is being able to properly filter a signal and to
153 // adapt its coefficients.
154 TEST(AdaptiveFirFilter, FilterAndAdapt) {
155 constexpr size_t kNumBlocksToProcess = 500;
156 ApmDataDumper data_dumper(42);
157 AdaptiveFirFilter filter(9, true, DetectOptimization(), &data_dumper);
158 Aec3Fft fft;
159 FftBuffer X_buffer(Aec3Optimization::kNone, filter.SizePartitions(),
160 std::vector<size_t>(1, filter.SizePartitions()));
161 std::array<float, kBlockSize> x_old;
162 x_old.fill(0.f);
163 ShadowFilterUpdateGain gain;
164 Random random_generator(42U);
165 std::vector<float> x(kBlockSize, 0.f);
166 std::vector<float> y(kBlockSize, 0.f);
167 AecState aec_state;
168 RenderSignalAnalyzer render_signal_analyzer;
169 FftData X;
170 std::vector<float> e(kBlockSize, 0.f);
171 std::array<float, kFftLength> s;
172 FftData S;
173 FftData G;
174 FftData E;
175 std::array<float, kFftLengthBy2Plus1> Y2;
176 std::array<float, kFftLengthBy2Plus1> E2_main;
177 std::array<float, kFftLengthBy2Plus1> E2_shadow;
178 Y2.fill(0.f);
179 E2_main.fill(0.f);
180 E2_shadow.fill(0.f);
181
182 constexpr float kScale = 1.0f / kFftLengthBy2;
183
184 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
185 DelayBuffer<float> delay_buffer(delay_samples);
186 SCOPED_TRACE(ProduceDebugText(delay_samples));
187 for (size_t k = 0; k < kNumBlocksToProcess; ++k) {
188 RandomizeSampleVector(&random_generator, x);
189 delay_buffer.Delay(x, y);
190
191 fft.PaddedFft(x, x_old, &X);
192 X_buffer.Insert(X);
193 render_signal_analyzer.Update(X_buffer, aec_state.FilterDelay());
194
195 filter.Filter(X_buffer, &S);
196 fft.Ifft(S, &s);
197 std::transform(y.begin(), y.end(), s.begin() + kFftLengthBy2, e.begin(),
198 [&](float a, float b) { return a - b * kScale; });
199 std::for_each(e.begin(), e.end(), [](float& a) {
200 a = std::max(std::min(a, 32767.0f), -32768.0f);
201 });
202 fft.ZeroPaddedFft(e, &E);
203
204 gain.Compute(X_buffer, render_signal_analyzer, E, filter.SizePartitions(),
205 false, &G);
206 filter.Adapt(X_buffer, G);
207 aec_state.Update(filter.FilterFrequencyResponse(),
208 rtc::Optional<size_t>(), X_buffer, E2_main, E2_shadow,
209 Y2, x, EchoPathVariability(false, false), false);
210 }
211 // Verify that the filter is able to perform well.
212 EXPECT_LT(1000 * std::inner_product(e.begin(), e.end(), e.begin(), 0.f),
213 std::inner_product(y.begin(), y.end(), y.begin(), 0.f));
214 ASSERT_TRUE(aec_state.FilterDelay());
215 EXPECT_EQ(delay_samples / kBlockSize, *aec_state.FilterDelay());
216 }
217 }
218 } // namespace aec3
219 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698