1 /*
2 * Copyright (c) 2018 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 #include <vector>
11
12 #include "api/array_view.h"
13 #include "modules/audio_processing/audio_buffer.h"
14 #include "modules/audio_processing/echo_control_mobile_impl.h"
15 #include "modules/audio_processing/test/audio_buffer_tools.h"
16 #include "modules/audio_processing/test/bitexactness_tools.h"
17 #include "test/gtest.h"
18
19 namespace webrtc {
20 namespace {
21
22 // TODO(peah): Increase the number of frames to proces when the issue of
23 // non repeatable test results have been found.
24 const int kNumFramesToProcess = 200;
25
SetupComponent(int sample_rate_hz,EchoControlMobileImpl::RoutingMode routing_mode,bool comfort_noise_enabled,EchoControlMobileImpl * echo_control_mobile)26 void SetupComponent(int sample_rate_hz,
27 EchoControlMobileImpl::RoutingMode routing_mode,
28 bool comfort_noise_enabled,
29 EchoControlMobileImpl* echo_control_mobile) {
30 echo_control_mobile->Initialize(
31 sample_rate_hz > 16000 ? 16000 : sample_rate_hz, 1, 1);
32 echo_control_mobile->set_routing_mode(routing_mode);
33 echo_control_mobile->enable_comfort_noise(comfort_noise_enabled);
34 }
35
ProcessOneFrame(int sample_rate_hz,int stream_delay_ms,AudioBuffer * render_audio_buffer,AudioBuffer * capture_audio_buffer,EchoControlMobileImpl * echo_control_mobile)36 void ProcessOneFrame(int sample_rate_hz,
37 int stream_delay_ms,
38 AudioBuffer* render_audio_buffer,
39 AudioBuffer* capture_audio_buffer,
40 EchoControlMobileImpl* echo_control_mobile) {
41 if (sample_rate_hz > AudioProcessing::kSampleRate16kHz) {
42 render_audio_buffer->SplitIntoFrequencyBands();
43 capture_audio_buffer->SplitIntoFrequencyBands();
44 }
45
46 std::vector<int16_t> render_audio;
47 EchoControlMobileImpl::PackRenderAudioBuffer(
48 render_audio_buffer, 1, render_audio_buffer->num_channels(),
49 &render_audio);
50 echo_control_mobile->ProcessRenderAudio(render_audio);
51
52 echo_control_mobile->ProcessCaptureAudio(capture_audio_buffer,
53 stream_delay_ms);
54
55 if (sample_rate_hz > AudioProcessing::kSampleRate16kHz) {
56 capture_audio_buffer->MergeFrequencyBands();
57 }
58 }
59
RunBitexactnessTest(int sample_rate_hz,size_t num_channels,int stream_delay_ms,EchoControlMobileImpl::RoutingMode routing_mode,bool comfort_noise_enabled,const rtc::ArrayView<const float> & output_reference)60 void RunBitexactnessTest(int sample_rate_hz,
61 size_t num_channels,
62 int stream_delay_ms,
63 EchoControlMobileImpl::RoutingMode routing_mode,
64 bool comfort_noise_enabled,
65 const rtc::ArrayView<const float>& output_reference) {
66 EchoControlMobileImpl echo_control_mobile;
67 SetupComponent(sample_rate_hz, routing_mode, comfort_noise_enabled,
68 &echo_control_mobile);
69
70 const int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100);
71 const StreamConfig render_config(sample_rate_hz, num_channels, false);
72 AudioBuffer render_buffer(
73 render_config.sample_rate_hz(), render_config.num_channels(),
74 render_config.sample_rate_hz(), 1, render_config.sample_rate_hz(), 1);
75 test::InputAudioFile render_file(
76 test::GetApmRenderTestVectorFileName(sample_rate_hz));
77 std::vector<float> render_input(samples_per_channel * num_channels);
78
79 const StreamConfig capture_config(sample_rate_hz, num_channels, false);
80 AudioBuffer capture_buffer(
81 capture_config.sample_rate_hz(), capture_config.num_channels(),
82 capture_config.sample_rate_hz(), 1, capture_config.sample_rate_hz(), 1);
83 test::InputAudioFile capture_file(
84 test::GetApmCaptureTestVectorFileName(sample_rate_hz));
85 std::vector<float> capture_input(samples_per_channel * num_channels);
86
87 for (int frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) {
88 ReadFloatSamplesFromStereoFile(samples_per_channel, num_channels,
89 &render_file, render_input);
90 ReadFloatSamplesFromStereoFile(samples_per_channel, num_channels,
91 &capture_file, capture_input);
92
93 test::CopyVectorToAudioBuffer(render_config, render_input, &render_buffer);
94 test::CopyVectorToAudioBuffer(capture_config, capture_input,
95 &capture_buffer);
96
97 ProcessOneFrame(sample_rate_hz, stream_delay_ms, &render_buffer,
98 &capture_buffer, &echo_control_mobile);
99 }
100
101 // Extract and verify the test results.
102 std::vector<float> capture_output;
103 test::ExtractVectorFromAudioBuffer(capture_config, &capture_buffer,
104 &capture_output);
105
106 // Compare the output with the reference. Only the first values of the output
107 // from last frame processed are compared in order not having to specify all
108 // preceeding frames as testvectors. As the algorithm being tested has a
109 // memory, testing only the last frame implicitly also tests the preceeding
110 // frames.
111 const float kElementErrorBound = 1.0f / 32768.0f;
112 EXPECT_TRUE(test::VerifyDeinterleavedArray(
113 capture_config.num_frames(), capture_config.num_channels(),
114 output_reference, capture_output, kElementErrorBound));
115 }
116
117 } // namespace
118
119 // TODO(peah): Renable once the integer overflow issue in aecm_core.c:932:69
120 // has been solved.
TEST(EchoControlMobileBitExactnessTest,DISABLED_Mono8kHz_LoudSpeakerPhone_CngOn_StreamDelay0)121 TEST(EchoControlMobileBitExactnessTest,
122 DISABLED_Mono8kHz_LoudSpeakerPhone_CngOn_StreamDelay0) {
123 const float kOutputReference[] = {0.005280f, 0.002380f, -0.000427f};
124
125 RunBitexactnessTest(8000, 1, 0,
126 EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone,
127 true, kOutputReference);
128 }
129
TEST(EchoControlMobileBitExactnessTest,DISABLED_Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay0)130 TEST(EchoControlMobileBitExactnessTest,
131 DISABLED_Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay0) {
132 const float kOutputReference[] = {0.003601f, 0.002991f, 0.001923f};
133 RunBitexactnessTest(16000, 1, 0,
134 EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone,
135 true, kOutputReference);
136 }
137
TEST(EchoControlMobileBitExactnessTest,DISABLED_Mono32kHz_LoudSpeakerPhone_CngOn_StreamDelay0)138 TEST(EchoControlMobileBitExactnessTest,
139 DISABLED_Mono32kHz_LoudSpeakerPhone_CngOn_StreamDelay0) {
140 const float kOutputReference[] = {0.002258f, 0.002899f, 0.003906f};
141
142 RunBitexactnessTest(32000, 1, 0,
143 EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone,
144 true, kOutputReference);
145 }
146
TEST(EchoControlMobileBitExactnessTest,DISABLED_Mono48kHz_LoudSpeakerPhone_CngOn_StreamDelay0)147 TEST(EchoControlMobileBitExactnessTest,
148 DISABLED_Mono48kHz_LoudSpeakerPhone_CngOn_StreamDelay0) {
149 const float kOutputReference[] = {-0.000046f, 0.000041f, 0.000249f};
150
151 RunBitexactnessTest(48000, 1, 0,
152 EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone,
153 true, kOutputReference);
154 }
155
TEST(EchoControlMobileBitExactnessTest,DISABLED_Mono16kHz_LoudSpeakerPhone_CngOff_StreamDelay0)156 TEST(EchoControlMobileBitExactnessTest,
157 DISABLED_Mono16kHz_LoudSpeakerPhone_CngOff_StreamDelay0) {
158 const float kOutputReference[] = {0.000000f, 0.000000f, 0.000000f};
159
160 RunBitexactnessTest(16000, 1, 0,
161 EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone,
162 false, kOutputReference);
163 }
164
165 // TODO(peah): Renable once the integer overflow issue in aecm_core.c:932:69
166 // has been solved.
TEST(EchoControlMobileBitExactnessTest,DISABLED_Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay5)167 TEST(EchoControlMobileBitExactnessTest,
168 DISABLED_Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay5) {
169 const float kOutputReference[] = {0.003693f, 0.002930f, 0.001801f};
170
171 RunBitexactnessTest(16000, 1, 5,
172 EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone,
173 true, kOutputReference);
174 }
175
TEST(EchoControlMobileBitExactnessTest,Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay10)176 TEST(EchoControlMobileBitExactnessTest,
177 Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay10) {
178 const float kOutputReference[] = {-0.002380f, -0.002533f, -0.002563f};
179
180 RunBitexactnessTest(16000, 1, 10,
181 EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone,
182 true, kOutputReference);
183 }
184
TEST(EchoControlMobileBitExactnessTest,DISABLED_Mono16kHz_QuietEarpieceOrHeadset_CngOn_StreamDelay0)185 TEST(EchoControlMobileBitExactnessTest,
186 DISABLED_Mono16kHz_QuietEarpieceOrHeadset_CngOn_StreamDelay0) {
187 const float kOutputReference[] = {0.000397f, 0.000000f, -0.000305f};
188
189 RunBitexactnessTest(
190 16000, 1, 0, EchoControlMobileImpl::RoutingMode::kQuietEarpieceOrHeadset,
191 true, kOutputReference);
192 }
193
TEST(EchoControlMobileBitExactnessTest,DISABLED_Mono16kHz_Earpiece_CngOn_StreamDelay0)194 TEST(EchoControlMobileBitExactnessTest,
195 DISABLED_Mono16kHz_Earpiece_CngOn_StreamDelay0) {
196 const float kOutputReference[] = {0.002167f, 0.001617f, 0.001038f};
197
198 RunBitexactnessTest(16000, 1, 0,
199 EchoControlMobileImpl::RoutingMode::kEarpiece, true,
200 kOutputReference);
201 }
202
TEST(EchoControlMobileBitExactnessTest,DISABLED_Mono16kHz_LoudEarpiece_CngOn_StreamDelay0)203 TEST(EchoControlMobileBitExactnessTest,
204 DISABLED_Mono16kHz_LoudEarpiece_CngOn_StreamDelay0) {
205 const float kOutputReference[] = {0.003540f, 0.002899f, 0.001862f};
206
207 RunBitexactnessTest(16000, 1, 0,
208 EchoControlMobileImpl::RoutingMode::kLoudEarpiece, true,
209 kOutputReference);
210 }
211
TEST(EchoControlMobileBitExactnessTest,DISABLED_Mono16kHz_SpeakerPhone_CngOn_StreamDelay0)212 TEST(EchoControlMobileBitExactnessTest,
213 DISABLED_Mono16kHz_SpeakerPhone_CngOn_StreamDelay0) {
214 const float kOutputReference[] = {0.003632f, 0.003052f, 0.001984f};
215
216 RunBitexactnessTest(16000, 1, 0,
217 EchoControlMobileImpl::RoutingMode::kSpeakerphone, true,
218 kOutputReference);
219 }
220
221 } // namespace webrtc
222