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