blob: 78191c1cd23585d3b72d7d76b1900162af934c7a [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
ajm@google.com59e41402011-07-28 17:34:04 +000011#include <stdio.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000012
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000013#include <algorithm>
bjornv@webrtc.org3e102492013-02-14 15:29:09 +000014#include <queue>
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000015
bjornv@webrtc.org3e102492013-02-14 15:29:09 +000016#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
17#include "webrtc/modules/audio_processing/include/audio_processing.h"
18#include "webrtc/modules/interface/module_common_types.h"
19#include "webrtc/system_wrappers/interface/event_wrapper.h"
20#include "webrtc/system_wrappers/interface/scoped_ptr.h"
21#include "webrtc/system_wrappers/interface/thread_wrapper.h"
22#include "webrtc/system_wrappers/interface/trace.h"
23#include "webrtc/test/testsupport/fileutils.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000024#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000025#include "gtest/gtest.h"
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000026#include "external/webrtc/webrtc/modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000027#else
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000028#include "testing/gtest/include/gtest/gtest.h"
ajm@google.com808e0e02011-08-03 21:08:51 +000029#include "webrtc/audio_processing/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000030#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000031
andrew@webrtc.org293d22b2012-01-30 22:04:26 +000032#if (defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)) || \
33 (defined(WEBRTC_LINUX) && defined(WEBRTC_ARCH_X86_64) && !defined(NDEBUG))
34# define WEBRTC_AUDIOPROC_BIT_EXACT
35#endif
36
niklase@google.com470e71d2011-07-07 08:21:25 +000037using webrtc::AudioProcessing;
38using webrtc::AudioFrame;
39using webrtc::GainControl;
40using webrtc::NoiseSuppression;
41using webrtc::EchoCancellation;
42using webrtc::EventWrapper;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000043using webrtc::scoped_array;
niklase@google.com470e71d2011-07-07 08:21:25 +000044using webrtc::Trace;
45using webrtc::LevelEstimator;
46using webrtc::EchoCancellation;
47using webrtc::EchoControlMobile;
48using webrtc::VoiceDetection;
49
50namespace {
ajm@google.com59e41402011-07-28 17:34:04 +000051// When false, this will compare the output data with the results stored to
niklase@google.com470e71d2011-07-07 08:21:25 +000052// file. This is the typical case. When the file should be updated, it can
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +000053// be set to true with the command-line switch --write_ref_data.
54bool write_ref_data = false;
ajm@google.com59e41402011-07-28 17:34:04 +000055
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +000056const int kSampleRates[] = {8000, 16000, 32000};
57const size_t kSampleRatesSize = sizeof(kSampleRates) / sizeof(*kSampleRates);
58const int kChannels[] = {1, 2};
59const size_t kChannelsSize = sizeof(kChannels) / sizeof(*kChannels);
60
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000061#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
62// AECM doesn't support super-wb.
63const int kProcessSampleRates[] = {8000, 16000};
64#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
65const int kProcessSampleRates[] = {8000, 16000, 32000};
66#endif
67const size_t kProcessSampleRatesSize = sizeof(kProcessSampleRates) /
68 sizeof(*kProcessSampleRates);
69
bjornv@webrtc.org3e102492013-02-14 15:29:09 +000070int TruncateToMultipleOf10(int value) {
71 return (value / 10) * 10;
72}
73
andrew@webrtc.org81865342012-10-27 00:28:27 +000074// TODO(andrew): Use the MonoToStereo routine from AudioFrameOperations.
75void MixStereoToMono(const int16_t* stereo,
76 int16_t* mono,
77 int samples_per_channel) {
78 for (int i = 0; i < samples_per_channel; i++) {
bjornv@webrtc.org3e102492013-02-14 15:29:09 +000079 int32_t mono_s32 = (static_cast<int32_t>(stereo[i * 2]) +
80 static_cast<int32_t>(stereo[i * 2 + 1])) >> 1;
81 mono[i] = static_cast<int16_t>(mono_s32);
andrew@webrtc.org81865342012-10-27 00:28:27 +000082 }
83}
84
85void CopyLeftToRightChannel(int16_t* stereo, int samples_per_channel) {
86 for (int i = 0; i < samples_per_channel; i++) {
87 stereo[i * 2 + 1] = stereo[i * 2];
88 }
89}
90
91void VerifyChannelsAreEqual(int16_t* stereo, int samples_per_channel) {
92 for (int i = 0; i < samples_per_channel; i++) {
93 EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
94 }
95}
96
97void SetFrameTo(AudioFrame* frame, int16_t value) {
98 for (int i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
99 ++i) {
100 frame->data_[i] = value;
101 }
102}
103
104void SetFrameTo(AudioFrame* frame, int16_t left, int16_t right) {
105 ASSERT_EQ(2, frame->num_channels_);
106 for (int i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
107 frame->data_[i] = left;
108 frame->data_[i + 1] = right;
109 }
110}
111
112template <class T>
113T AbsValue(T a) {
114 return a > 0 ? a: -a;
115}
116
117int16_t MaxAudioFrame(const AudioFrame& frame) {
118 const int length = frame.samples_per_channel_ * frame.num_channels_;
119 int16_t max_data = AbsValue(frame.data_[0]);
120 for (int i = 1; i < length; i++) {
121 max_data = std::max(max_data, AbsValue(frame.data_[i]));
122 }
123
124 return max_data;
125}
126
127bool FrameDataAreEqual(const AudioFrame& frame1, const AudioFrame& frame2) {
128 if (frame1.samples_per_channel_ !=
129 frame2.samples_per_channel_) {
130 return false;
131 }
132 if (frame1.num_channels_ !=
133 frame2.num_channels_) {
134 return false;
135 }
136 if (memcmp(frame1.data_, frame2.data_,
137 frame1.samples_per_channel_ * frame1.num_channels_ *
138 sizeof(int16_t))) {
139 return false;
140 }
141 return true;
142}
143
144void TestStats(const AudioProcessing::Statistic& test,
145 const webrtc::audioproc::Test::Statistic& reference) {
146 EXPECT_EQ(reference.instant(), test.instant);
147 EXPECT_EQ(reference.average(), test.average);
148 EXPECT_EQ(reference.maximum(), test.maximum);
149 EXPECT_EQ(reference.minimum(), test.minimum);
150}
151
152void WriteStatsMessage(const AudioProcessing::Statistic& output,
153 webrtc::audioproc::Test::Statistic* message) {
154 message->set_instant(output.instant);
155 message->set_average(output.average);
156 message->set_maximum(output.maximum);
157 message->set_minimum(output.minimum);
158}
159
160void WriteMessageLiteToFile(const std::string filename,
161 const ::google::protobuf::MessageLite& message) {
162 FILE* file = fopen(filename.c_str(), "wb");
163 ASSERT_TRUE(file != NULL) << "Could not open " << filename;
164 int size = message.ByteSize();
165 ASSERT_GT(size, 0);
166 unsigned char* array = new unsigned char[size];
167 ASSERT_TRUE(message.SerializeToArray(array, size));
168
169 ASSERT_EQ(1u, fwrite(&size, sizeof(int), 1, file));
170 ASSERT_EQ(static_cast<size_t>(size),
171 fwrite(array, sizeof(unsigned char), size, file));
172
173 delete [] array;
174 fclose(file);
175}
176
177void ReadMessageLiteFromFile(const std::string filename,
178 ::google::protobuf::MessageLite* message) {
179 assert(message != NULL);
180
181 FILE* file = fopen(filename.c_str(), "rb");
182 ASSERT_TRUE(file != NULL) << "Could not open " << filename;
183 int size = 0;
184 ASSERT_EQ(1u, fread(&size, sizeof(int), 1, file));
185 ASSERT_GT(size, 0);
186 unsigned char* array = new unsigned char[size];
187 ASSERT_EQ(static_cast<size_t>(size),
188 fread(array, sizeof(unsigned char), size, file));
189
190 ASSERT_TRUE(message->ParseFromArray(array, size));
191
192 delete [] array;
193 fclose(file);
194}
195
196struct ThreadData {
197 ThreadData(int thread_num_, AudioProcessing* ap_)
198 : thread_num(thread_num_),
199 error(false),
200 ap(ap_) {}
201 int thread_num;
202 bool error;
203 AudioProcessing* ap;
204};
205
niklase@google.com470e71d2011-07-07 08:21:25 +0000206class ApmTest : public ::testing::Test {
207 protected:
208 ApmTest();
209 virtual void SetUp();
210 virtual void TearDown();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000211
212 static void SetUpTestCase() {
213 Trace::CreateTrace();
214 std::string trace_filename = webrtc::test::OutputPath() +
andrew@webrtc.org81865342012-10-27 00:28:27 +0000215 "audioproc_trace.txt";
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000216 ASSERT_EQ(0, Trace::SetTraceFile(trace_filename.c_str()));
217 }
218
219 static void TearDownTestCase() {
220 Trace::ReturnTrace();
221 }
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000222
223 void Init(int sample_rate_hz, int num_reverse_channels,
224 int num_input_channels, int num_output_channels,
225 bool open_output_file);
226 std::string ResourceFilePath(std::string name, int sample_rate_hz);
227 std::string OutputFilePath(std::string name,
228 int sample_rate_hz,
229 int num_reverse_channels,
230 int num_input_channels,
231 int num_output_channels);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000232 void EnableAllComponents();
233 bool ReadFrame(FILE* file, AudioFrame* frame);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000234 void ProcessWithDefaultStreamParameters(AudioFrame* frame);
235 template <typename F>
236 void ChangeTriggersInit(F f, AudioProcessing* ap, int initial_value,
237 int changed_value);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000238 void ProcessDelayVerificationTest(int delay_ms, int system_delay_ms,
239 int delay_min, int delay_max);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000240
241 const std::string output_path_;
242 const std::string ref_path_;
243 const std::string ref_filename_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000244 webrtc::AudioProcessing* apm_;
245 webrtc::AudioFrame* frame_;
246 webrtc::AudioFrame* revframe_;
247 FILE* far_file_;
248 FILE* near_file_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000249 FILE* out_file_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000250};
251
252ApmTest::ApmTest()
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000253 : output_path_(webrtc::test::OutputPath()),
254 ref_path_(webrtc::test::ProjectRootPath() +
andrew@webrtc.org9dc45da2012-05-23 15:39:01 +0000255 "data/audio_processing/"),
andrew@webrtc.org293d22b2012-01-30 22:04:26 +0000256#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000257 ref_filename_(ref_path_ + "output_data_fixed.pb"),
andrew@webrtc.org293d22b2012-01-30 22:04:26 +0000258#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000259 ref_filename_(ref_path_ + "output_data_float.pb"),
kjellander@webrtc.org61f07c32011-10-18 06:54:58 +0000260#endif
261 apm_(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000262 frame_(NULL),
ajm@google.com22e65152011-07-18 18:03:01 +0000263 revframe_(NULL),
264 far_file_(NULL),
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000265 near_file_(NULL),
266 out_file_(NULL) {}
niklase@google.com470e71d2011-07-07 08:21:25 +0000267
268void ApmTest::SetUp() {
269 apm_ = AudioProcessing::Create(0);
270 ASSERT_TRUE(apm_ != NULL);
271
272 frame_ = new AudioFrame();
273 revframe_ = new AudioFrame();
274
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000275 Init(32000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000276}
277
278void ApmTest::TearDown() {
279 if (frame_) {
280 delete frame_;
281 }
282 frame_ = NULL;
283
284 if (revframe_) {
285 delete revframe_;
286 }
287 revframe_ = NULL;
288
289 if (far_file_) {
290 ASSERT_EQ(0, fclose(far_file_));
291 }
292 far_file_ = NULL;
293
294 if (near_file_) {
295 ASSERT_EQ(0, fclose(near_file_));
296 }
297 near_file_ = NULL;
298
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000299 if (out_file_) {
300 ASSERT_EQ(0, fclose(out_file_));
301 }
302 out_file_ = NULL;
303
niklase@google.com470e71d2011-07-07 08:21:25 +0000304 if (apm_ != NULL) {
305 AudioProcessing::Destroy(apm_);
306 }
307 apm_ = NULL;
308}
309
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000310std::string ApmTest::ResourceFilePath(std::string name, int sample_rate_hz) {
311 std::ostringstream ss;
312 // Resource files are all stereo.
313 ss << name << sample_rate_hz / 1000 << "_stereo";
314 return webrtc::test::ResourcePath(ss.str(), "pcm");
315}
316
317std::string ApmTest::OutputFilePath(std::string name,
318 int sample_rate_hz,
319 int num_reverse_channels,
320 int num_input_channels,
321 int num_output_channels) {
322 std::ostringstream ss;
323 ss << name << sample_rate_hz / 1000 << "_" << num_reverse_channels << "r" <<
324 num_input_channels << "i" << "_";
325 if (num_output_channels == 1) {
326 ss << "mono";
327 } else if (num_output_channels == 2) {
328 ss << "stereo";
329 } else {
330 assert(false);
331 return "";
332 }
333 ss << ".pcm";
334
335 return output_path_ + ss.str();
336}
337
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000338void ApmTest::Init(int sample_rate_hz, int num_reverse_channels,
339 int num_input_channels, int num_output_channels,
340 bool open_output_file) {
341 ASSERT_EQ(apm_->kNoError, apm_->Initialize());
342
343 // Handles error checking of the parameters as well. No need to repeat it.
344 ASSERT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(sample_rate_hz));
345 ASSERT_EQ(apm_->kNoError, apm_->set_num_channels(num_input_channels,
346 num_output_channels));
347 ASSERT_EQ(apm_->kNoError,
348 apm_->set_num_reverse_channels(num_reverse_channels));
349
350 // We always use 10 ms frames.
351 const int samples_per_channel = sample_rate_hz / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000352 frame_->samples_per_channel_ = samples_per_channel;
353 frame_->num_channels_ = num_input_channels;
354 frame_->sample_rate_hz_ = sample_rate_hz;
355 revframe_->samples_per_channel_ = samples_per_channel;
356 revframe_->num_channels_ = num_reverse_channels;
357 revframe_->sample_rate_hz_ = sample_rate_hz;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000358
359 if (far_file_) {
360 ASSERT_EQ(0, fclose(far_file_));
361 }
362 std::string filename = ResourceFilePath("far", sample_rate_hz);
363 far_file_ = fopen(filename.c_str(), "rb");
364 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " <<
365 filename << "\n";
366
367 if (near_file_) {
368 ASSERT_EQ(0, fclose(near_file_));
369 }
370 filename = ResourceFilePath("near", sample_rate_hz);
371 near_file_ = fopen(filename.c_str(), "rb");
372 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " <<
373 filename << "\n";
374
375 if (open_output_file) {
376 if (out_file_) {
377 ASSERT_EQ(0, fclose(out_file_));
378 }
379 filename = OutputFilePath("out", sample_rate_hz, num_reverse_channels,
380 num_input_channels, num_output_channels);
381 out_file_ = fopen(filename.c_str(), "wb");
382 ASSERT_TRUE(out_file_ != NULL) << "Could not open file " <<
383 filename << "\n";
384 }
385}
386
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000387void ApmTest::EnableAllComponents() {
388#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
389 EXPECT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(16000));
390 EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true));
391
392 EXPECT_EQ(apm_->kNoError,
393 apm_->gain_control()->set_mode(GainControl::kAdaptiveDigital));
394 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
395#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
396 EXPECT_EQ(apm_->kNoError,
397 apm_->echo_cancellation()->enable_drift_compensation(true));
398 EXPECT_EQ(apm_->kNoError,
399 apm_->echo_cancellation()->enable_metrics(true));
400 EXPECT_EQ(apm_->kNoError,
401 apm_->echo_cancellation()->enable_delay_logging(true));
402 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
403
404 EXPECT_EQ(apm_->kNoError,
405 apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
406 EXPECT_EQ(apm_->kNoError,
407 apm_->gain_control()->set_analog_level_limits(0, 255));
408 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
409#endif
410
411 EXPECT_EQ(apm_->kNoError,
412 apm_->high_pass_filter()->Enable(true));
413
414 EXPECT_EQ(apm_->kNoError,
415 apm_->level_estimator()->Enable(true));
416
417 EXPECT_EQ(apm_->kNoError,
418 apm_->noise_suppression()->Enable(true));
419
420 EXPECT_EQ(apm_->kNoError,
421 apm_->voice_detection()->Enable(true));
422}
423
424bool ApmTest::ReadFrame(FILE* file, AudioFrame* frame) {
425 // The files always contain stereo audio.
426 size_t frame_size = frame->samples_per_channel_ * 2;
427 size_t read_count = fread(frame->data_,
428 sizeof(int16_t),
429 frame_size,
430 file);
431 if (read_count != frame_size) {
432 // Check that the file really ended.
433 EXPECT_NE(0, feof(file));
434 return false; // This is expected.
435 }
436
437 if (frame->num_channels_ == 1) {
438 MixStereoToMono(frame->data_, frame->data_,
439 frame->samples_per_channel_);
440 }
441
442 return true;
ajm@google.coma769fa52011-07-13 21:57:58 +0000443}
444
andrew@webrtc.org81865342012-10-27 00:28:27 +0000445void ApmTest::ProcessWithDefaultStreamParameters(AudioFrame* frame) {
446 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000447 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000448 EXPECT_EQ(apm_->kNoError,
449 apm_->gain_control()->set_stream_analog_level(127));
450 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000451}
452
andrew@webrtc.org81865342012-10-27 00:28:27 +0000453template <typename F>
454void ApmTest::ChangeTriggersInit(F f, AudioProcessing* ap, int initial_value,
455 int changed_value) {
456 EnableAllComponents();
457 Init(16000, 2, 2, 2, false);
458 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000459 AudioFrame frame_copy;
460 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000461 ProcessWithDefaultStreamParameters(frame_);
462 // Verify the processing has actually changed the frame.
463 EXPECT_FALSE(FrameDataAreEqual(*frame_, frame_copy));
464
465 // Test that a change in value triggers an init.
466 f(apm_, changed_value);
467 f(apm_, initial_value);
468 ProcessWithDefaultStreamParameters(&frame_copy);
469 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
470
471 apm_->Initialize();
472 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000473 AudioFrame initial_frame;
474 initial_frame.CopyFrom(*frame_);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000475 ProcessWithDefaultStreamParameters(frame_);
476 ProcessWithDefaultStreamParameters(frame_);
477 // Verify the processing has actually changed the frame.
478 EXPECT_FALSE(FrameDataAreEqual(*frame_, initial_frame));
479
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000480 frame_copy.CopyFrom(initial_frame);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000481 apm_->Initialize();
482 ProcessWithDefaultStreamParameters(&frame_copy);
483 // Verify an init here would result in different output.
484 apm_->Initialize();
485 ProcessWithDefaultStreamParameters(&frame_copy);
486 EXPECT_FALSE(FrameDataAreEqual(*frame_, frame_copy));
487
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000488 frame_copy.CopyFrom(initial_frame);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000489 apm_->Initialize();
490 ProcessWithDefaultStreamParameters(&frame_copy);
491 // Test that the same value does not trigger an init.
492 f(apm_, initial_value);
493 ProcessWithDefaultStreamParameters(&frame_copy);
494 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +0000495}
496
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000497void ApmTest::ProcessDelayVerificationTest(int delay_ms, int system_delay_ms,
498 int delay_min, int delay_max) {
499 // The |revframe_| and |frame_| should include the proper frame information,
500 // hence can be used for extracting information.
501 webrtc::AudioFrame tmp_frame;
502 std::queue<webrtc::AudioFrame*> frame_queue;
503 bool causal = true;
504
505 tmp_frame.CopyFrom(*revframe_);
506 SetFrameTo(&tmp_frame, 0);
507
508 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
509 // Initialize the |frame_queue| with empty frames.
510 int frame_delay = delay_ms / 10;
511 while (frame_delay < 0) {
512 webrtc::AudioFrame* frame = new AudioFrame();
513 frame->CopyFrom(tmp_frame);
514 frame_queue.push(frame);
515 frame_delay++;
516 causal = false;
517 }
518 while (frame_delay > 0) {
519 webrtc::AudioFrame* frame = new AudioFrame();
520 frame->CopyFrom(tmp_frame);
521 frame_queue.push(frame);
522 frame_delay--;
523 }
524 // Run for 4.5 seconds, skipping statistics from the first second. We need
525 // enough frames with audio to have reliable estimates, but as few as possible
526 // to keep processing time down. 4.5 seconds seemed to be a good compromise
527 // for this recording.
528 for (int frame_count = 0; frame_count < 450; ++frame_count) {
529 webrtc::AudioFrame* frame = new AudioFrame();
530 frame->CopyFrom(tmp_frame);
531 // Use the near end recording, since that has more speech in it.
532 ASSERT_TRUE(ReadFrame(near_file_, frame));
533 frame_queue.push(frame);
534 webrtc::AudioFrame* reverse_frame = frame;
535 webrtc::AudioFrame* process_frame = frame_queue.front();
536 if (!causal) {
537 reverse_frame = frame_queue.front();
538 // When we call ProcessStream() the frame is modified, so we can't use the
539 // pointer directly when things are non-causal. Use an intermediate frame
540 // and copy the data.
541 process_frame = &tmp_frame;
542 process_frame->CopyFrom(*frame);
543 }
544 EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(reverse_frame));
545 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
546 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(process_frame));
547 frame = frame_queue.front();
548 frame_queue.pop();
549 delete frame;
550
551 if (frame_count == 100) {
552 int median;
553 int std;
554 // Discard the first delay metrics to avoid convergence effects.
555 EXPECT_EQ(apm_->kNoError,
556 apm_->echo_cancellation()->GetDelayMetrics(&median, &std));
557 }
558 }
559
560 rewind(near_file_);
561 while (!frame_queue.empty()) {
562 webrtc::AudioFrame* frame = frame_queue.front();
563 frame_queue.pop();
564 delete frame;
565 }
566 // Calculate expected delay estimate and acceptable regions. Further,
567 // limit them w.r.t. AEC delay estimation support.
568 const int samples_per_ms = std::min(16, frame_->samples_per_channel_ / 10);
569 int expected_median = std::min(std::max(delay_ms - system_delay_ms,
570 delay_min), delay_max);
571 int expected_median_high = std::min(std::max(
572 expected_median + 96 / samples_per_ms, delay_min), delay_max);
573 int expected_median_low = std::min(std::max(
574 expected_median - 96 / samples_per_ms, delay_min), delay_max);
575 // Verify delay metrics.
576 int median;
577 int std;
578 EXPECT_EQ(apm_->kNoError,
579 apm_->echo_cancellation()->GetDelayMetrics(&median, &std));
580 EXPECT_GE(expected_median_high, median);
581 EXPECT_LE(expected_median_low, median);
582}
583
niklase@google.com470e71d2011-07-07 08:21:25 +0000584TEST_F(ApmTest, StreamParameters) {
585 // No errors when the components are disabled.
586 EXPECT_EQ(apm_->kNoError,
587 apm_->ProcessStream(frame_));
588
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000589 // -- Missing AGC level --
niklase@google.com470e71d2011-07-07 08:21:25 +0000590 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
591 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000592 EXPECT_EQ(apm_->kStreamParameterNotSetError, apm_->ProcessStream(frame_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000593
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000594 // Resets after successful ProcessStream().
niklase@google.com470e71d2011-07-07 08:21:25 +0000595 EXPECT_EQ(apm_->kNoError,
596 apm_->gain_control()->set_stream_analog_level(127));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000597 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
598 EXPECT_EQ(apm_->kStreamParameterNotSetError, apm_->ProcessStream(frame_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000599
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000600 // Other stream parameters set correctly.
601 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 EXPECT_EQ(apm_->kNoError,
603 apm_->echo_cancellation()->enable_drift_compensation(true));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000604 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000605 apm_->echo_cancellation()->set_stream_drift_samples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000606 EXPECT_EQ(apm_->kStreamParameterNotSetError,
607 apm_->ProcessStream(frame_));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000608 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false));
609 EXPECT_EQ(apm_->kNoError,
610 apm_->echo_cancellation()->enable_drift_compensation(false));
611
612 // -- Missing delay --
613 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
614 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
615 EXPECT_EQ(apm_->kStreamParameterNotSetError, apm_->ProcessStream(frame_));
616
617 // Resets after successful ProcessStream().
618 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
619 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
620 EXPECT_EQ(apm_->kStreamParameterNotSetError, apm_->ProcessStream(frame_));
621
622 // Other stream parameters set correctly.
623 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
624 EXPECT_EQ(apm_->kNoError,
625 apm_->echo_cancellation()->enable_drift_compensation(true));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000626 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000627 EXPECT_EQ(apm_->kNoError,
628 apm_->gain_control()->set_stream_analog_level(127));
629 EXPECT_EQ(apm_->kStreamParameterNotSetError, apm_->ProcessStream(frame_));
630 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false));
631
632 // -- Missing drift --
633 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
634 EXPECT_EQ(apm_->kStreamParameterNotSetError, apm_->ProcessStream(frame_));
635
636 // Resets after successful ProcessStream().
637 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000638 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000639 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
640 EXPECT_EQ(apm_->kStreamParameterNotSetError, apm_->ProcessStream(frame_));
641
642 // Other stream parameters set correctly.
niklase@google.com470e71d2011-07-07 08:21:25 +0000643 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
644 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
645 EXPECT_EQ(apm_->kNoError,
646 apm_->gain_control()->set_stream_analog_level(127));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000647 EXPECT_EQ(apm_->kStreamParameterNotSetError, apm_->ProcessStream(frame_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000648
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000649 // -- No stream parameters --
niklase@google.com470e71d2011-07-07 08:21:25 +0000650 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
651 EXPECT_EQ(apm_->kNoError,
652 apm_->AnalyzeReverseStream(revframe_));
653 EXPECT_EQ(apm_->kStreamParameterNotSetError,
654 apm_->ProcessStream(frame_));
655
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000656 // -- All there --
niklase@google.com470e71d2011-07-07 08:21:25 +0000657 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
658 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000659 apm_->echo_cancellation()->set_stream_drift_samples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000660 EXPECT_EQ(apm_->kNoError,
661 apm_->gain_control()->set_stream_analog_level(127));
662 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
663}
664
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000665TEST_F(ApmTest, DefaultDelayOffsetIsZero) {
666 EXPECT_EQ(0, apm_->delay_offset_ms());
667 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(50));
668 EXPECT_EQ(50, apm_->stream_delay_ms());
669}
670
671TEST_F(ApmTest, DelayOffsetWithLimitsIsSetProperly) {
672 // High limit of 500 ms.
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000673 apm_->set_delay_offset_ms(100);
674 EXPECT_EQ(100, apm_->delay_offset_ms());
675 EXPECT_EQ(apm_->kBadStreamParameterWarning, apm_->set_stream_delay_ms(450));
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000676 EXPECT_EQ(500, apm_->stream_delay_ms());
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000677 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
678 EXPECT_EQ(200, apm_->stream_delay_ms());
679
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000680 // Low limit of 0 ms.
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000681 apm_->set_delay_offset_ms(-50);
682 EXPECT_EQ(-50, apm_->delay_offset_ms());
andrew@webrtc.org5f23d642012-05-29 21:14:06 +0000683 EXPECT_EQ(apm_->kBadStreamParameterWarning, apm_->set_stream_delay_ms(20));
684 EXPECT_EQ(0, apm_->stream_delay_ms());
andrew@webrtc.org6f9f8172012-03-06 19:03:39 +0000685 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
686 EXPECT_EQ(50, apm_->stream_delay_ms());
687}
688
niklase@google.com470e71d2011-07-07 08:21:25 +0000689TEST_F(ApmTest, Channels) {
690 // Testing number of invalid channels
691 EXPECT_EQ(apm_->kBadParameterError, apm_->set_num_channels(0, 1));
692 EXPECT_EQ(apm_->kBadParameterError, apm_->set_num_channels(1, 0));
693 EXPECT_EQ(apm_->kBadParameterError, apm_->set_num_channels(3, 1));
694 EXPECT_EQ(apm_->kBadParameterError, apm_->set_num_channels(1, 3));
695 EXPECT_EQ(apm_->kBadParameterError, apm_->set_num_reverse_channels(0));
696 EXPECT_EQ(apm_->kBadParameterError, apm_->set_num_reverse_channels(3));
697 // Testing number of valid channels
698 for (int i = 1; i < 3; i++) {
699 for (int j = 1; j < 3; j++) {
700 if (j > i) {
701 EXPECT_EQ(apm_->kBadParameterError, apm_->set_num_channels(i, j));
702 } else {
703 EXPECT_EQ(apm_->kNoError, apm_->set_num_channels(i, j));
704 EXPECT_EQ(j, apm_->num_output_channels());
705 }
706 }
707 EXPECT_EQ(i, apm_->num_input_channels());
708 EXPECT_EQ(apm_->kNoError, apm_->set_num_reverse_channels(i));
709 EXPECT_EQ(i, apm_->num_reverse_channels());
710 }
711}
712
713TEST_F(ApmTest, SampleRates) {
714 // Testing invalid sample rates
715 EXPECT_EQ(apm_->kBadParameterError, apm_->set_sample_rate_hz(10000));
716 // Testing valid sample rates
717 int fs[] = {8000, 16000, 32000};
718 for (size_t i = 0; i < sizeof(fs) / sizeof(*fs); i++) {
719 EXPECT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(fs[i]));
720 EXPECT_EQ(fs[i], apm_->sample_rate_hz());
721 }
722}
723
andrew@webrtc.org81865342012-10-27 00:28:27 +0000724void SetSampleRate(AudioProcessing* ap, int value) {
725 EXPECT_EQ(ap->kNoError, ap->set_sample_rate_hz(value));
726}
727
728void SetNumReverseChannels(AudioProcessing* ap, int value) {
729 EXPECT_EQ(ap->kNoError, ap->set_num_reverse_channels(value));
730}
731
732void SetNumOutputChannels(AudioProcessing* ap, int value) {
733 EXPECT_EQ(ap->kNoError, ap->set_num_channels(2, value));
734}
735
736TEST_F(ApmTest, SampleRateChangeTriggersInit) {
737 ChangeTriggersInit(SetSampleRate, apm_, 16000, 8000);
738}
739
740TEST_F(ApmTest, ReverseChannelChangeTriggersInit) {
741 ChangeTriggersInit(SetNumReverseChannels, apm_, 2, 1);
742}
743
744TEST_F(ApmTest, ChannelChangeTriggersInit) {
745 ChangeTriggersInit(SetNumOutputChannels, apm_, 2, 1);
746}
niklase@google.com470e71d2011-07-07 08:21:25 +0000747
748TEST_F(ApmTest, EchoCancellation) {
749 EXPECT_EQ(apm_->kNoError,
750 apm_->echo_cancellation()->enable_drift_compensation(true));
751 EXPECT_TRUE(apm_->echo_cancellation()->is_drift_compensation_enabled());
752 EXPECT_EQ(apm_->kNoError,
753 apm_->echo_cancellation()->enable_drift_compensation(false));
754 EXPECT_FALSE(apm_->echo_cancellation()->is_drift_compensation_enabled());
755
756 EXPECT_EQ(apm_->kBadParameterError,
757 apm_->echo_cancellation()->set_device_sample_rate_hz(4000));
758 EXPECT_EQ(apm_->kBadParameterError,
759 apm_->echo_cancellation()->set_device_sample_rate_hz(100000));
760
761 int rate[] = {16000, 44100, 48000};
762 for (size_t i = 0; i < sizeof(rate)/sizeof(*rate); i++) {
763 EXPECT_EQ(apm_->kNoError,
764 apm_->echo_cancellation()->set_device_sample_rate_hz(rate[i]));
765 EXPECT_EQ(rate[i],
766 apm_->echo_cancellation()->device_sample_rate_hz());
767 }
768
niklase@google.com470e71d2011-07-07 08:21:25 +0000769 EchoCancellation::SuppressionLevel level[] = {
770 EchoCancellation::kLowSuppression,
771 EchoCancellation::kModerateSuppression,
772 EchoCancellation::kHighSuppression,
773 };
774 for (size_t i = 0; i < sizeof(level)/sizeof(*level); i++) {
775 EXPECT_EQ(apm_->kNoError,
776 apm_->echo_cancellation()->set_suppression_level(level[i]));
777 EXPECT_EQ(level[i],
778 apm_->echo_cancellation()->suppression_level());
779 }
780
781 EchoCancellation::Metrics metrics;
782 EXPECT_EQ(apm_->kNotEnabledError,
783 apm_->echo_cancellation()->GetMetrics(&metrics));
784
785 EXPECT_EQ(apm_->kNoError,
786 apm_->echo_cancellation()->enable_metrics(true));
787 EXPECT_TRUE(apm_->echo_cancellation()->are_metrics_enabled());
788 EXPECT_EQ(apm_->kNoError,
789 apm_->echo_cancellation()->enable_metrics(false));
790 EXPECT_FALSE(apm_->echo_cancellation()->are_metrics_enabled());
791
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000792 int median = 0;
793 int std = 0;
794 EXPECT_EQ(apm_->kNotEnabledError,
795 apm_->echo_cancellation()->GetDelayMetrics(&median, &std));
796
797 EXPECT_EQ(apm_->kNoError,
798 apm_->echo_cancellation()->enable_delay_logging(true));
799 EXPECT_TRUE(apm_->echo_cancellation()->is_delay_logging_enabled());
800 EXPECT_EQ(apm_->kNoError,
801 apm_->echo_cancellation()->enable_delay_logging(false));
802 EXPECT_FALSE(apm_->echo_cancellation()->is_delay_logging_enabled());
803
niklase@google.com470e71d2011-07-07 08:21:25 +0000804 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
805 EXPECT_TRUE(apm_->echo_cancellation()->is_enabled());
806 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
807 EXPECT_FALSE(apm_->echo_cancellation()->is_enabled());
bjornv@webrtc.org91d11b32013-03-05 16:53:09 +0000808
809 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
810 EXPECT_TRUE(apm_->echo_cancellation()->is_enabled());
811 EXPECT_TRUE(apm_->echo_cancellation()->aec_core() != NULL);
812 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
813 EXPECT_FALSE(apm_->echo_cancellation()->is_enabled());
814 EXPECT_FALSE(apm_->echo_cancellation()->aec_core() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000815}
816
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000817TEST_F(ApmTest, EchoCancellationReportsCorrectDelays) {
818 // Enable AEC only.
819 EXPECT_EQ(apm_->kNoError,
820 apm_->echo_cancellation()->enable_drift_compensation(false));
821 EXPECT_EQ(apm_->kNoError,
822 apm_->echo_cancellation()->enable_metrics(false));
823 EXPECT_EQ(apm_->kNoError,
824 apm_->echo_cancellation()->enable_delay_logging(true));
825 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
826
827 // Internally in the AEC the amount of lookahead the delay estimation can
828 // handle is 15 blocks and the maximum delay is set to 60 blocks.
829 const int kLookaheadBlocks = 15;
830 const int kMaxDelayBlocks = 60;
831 // The AEC has a startup time before it actually starts to process. This
832 // procedure can flush the internal far-end buffer, which of course affects
833 // the delay estimation. Therefore, we set a system_delay high enough to
834 // avoid that. The smallest system_delay you can report without flushing the
835 // buffer is 66 ms in 8 kHz.
836 //
837 // It is known that for 16 kHz (and 32 kHz) sampling frequency there is an
838 // additional stuffing of 8 ms on the fly, but it seems to have no impact on
839 // delay estimation. This should be noted though. In case of test failure,
840 // this could be the cause.
841 const int kSystemDelayMs = 66;
842 // Test a couple of corner cases and verify that the estimated delay is
843 // within a valid region (set to +-1.5 blocks). Note that these cases are
844 // sampling frequency dependent.
845 for (size_t i = 0; i < kProcessSampleRatesSize; i++) {
846 Init(kProcessSampleRates[i], 2, 2, 2, false);
847 // Sampling frequency dependent variables.
848 const int num_ms_per_block = std::max(4,
849 640 / frame_->samples_per_channel_);
850 const int delay_min_ms = -kLookaheadBlocks * num_ms_per_block;
851 const int delay_max_ms = (kMaxDelayBlocks - 1) * num_ms_per_block;
852
853 // 1) Verify correct delay estimate at lookahead boundary.
854 int delay_ms = TruncateToMultipleOf10(kSystemDelayMs + delay_min_ms);
855 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
856 delay_max_ms);
857 // 2) A delay less than maximum lookahead should give an delay estimate at
858 // the boundary (= -kLookaheadBlocks * num_ms_per_block).
859 delay_ms -= 20;
860 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
861 delay_max_ms);
862 // 3) Three values around zero delay. Note that we need to compensate for
863 // the fake system_delay.
864 delay_ms = TruncateToMultipleOf10(kSystemDelayMs - 10);
865 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
866 delay_max_ms);
867 delay_ms = TruncateToMultipleOf10(kSystemDelayMs);
868 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
869 delay_max_ms);
870 delay_ms = TruncateToMultipleOf10(kSystemDelayMs + 10);
871 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
872 delay_max_ms);
873 // 4) Verify correct delay estimate at maximum delay boundary.
874 delay_ms = TruncateToMultipleOf10(kSystemDelayMs + delay_max_ms);
875 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
876 delay_max_ms);
877 // 5) A delay above the maximum delay should give an estimate at the
878 // boundary (= (kMaxDelayBlocks - 1) * num_ms_per_block).
879 delay_ms += 20;
880 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
881 delay_max_ms);
882 }
883}
884
niklase@google.com470e71d2011-07-07 08:21:25 +0000885TEST_F(ApmTest, EchoControlMobile) {
886 // AECM won't use super-wideband.
887 EXPECT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(32000));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000888 EXPECT_EQ(apm_->kBadSampleRateError,
889 apm_->echo_control_mobile()->Enable(true));
andrew@webrtc.org78693fe2013-03-01 16:36:19 +0000890 EXPECT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(16000));
891 EXPECT_EQ(apm_->kNoError,
892 apm_->echo_control_mobile()->Enable(true));
893 EXPECT_EQ(apm_->kUnsupportedComponentError, apm_->set_sample_rate_hz(32000));
894
niklase@google.com470e71d2011-07-07 08:21:25 +0000895 // Turn AECM on (and AEC off)
andrew@webrtc.org75f19482012-02-09 17:16:18 +0000896 Init(16000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000897 EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true));
898 EXPECT_TRUE(apm_->echo_control_mobile()->is_enabled());
899
niklase@google.com470e71d2011-07-07 08:21:25 +0000900 // Toggle routing modes
901 EchoControlMobile::RoutingMode mode[] = {
902 EchoControlMobile::kQuietEarpieceOrHeadset,
903 EchoControlMobile::kEarpiece,
904 EchoControlMobile::kLoudEarpiece,
905 EchoControlMobile::kSpeakerphone,
906 EchoControlMobile::kLoudSpeakerphone,
907 };
908 for (size_t i = 0; i < sizeof(mode)/sizeof(*mode); i++) {
909 EXPECT_EQ(apm_->kNoError,
910 apm_->echo_control_mobile()->set_routing_mode(mode[i]));
911 EXPECT_EQ(mode[i],
912 apm_->echo_control_mobile()->routing_mode());
913 }
914 // Turn comfort noise off/on
915 EXPECT_EQ(apm_->kNoError,
916 apm_->echo_control_mobile()->enable_comfort_noise(false));
917 EXPECT_FALSE(apm_->echo_control_mobile()->is_comfort_noise_enabled());
918 EXPECT_EQ(apm_->kNoError,
919 apm_->echo_control_mobile()->enable_comfort_noise(true));
920 EXPECT_TRUE(apm_->echo_control_mobile()->is_comfort_noise_enabled());
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000921 // Set and get echo path
ajm@google.com22e65152011-07-18 18:03:01 +0000922 const size_t echo_path_size =
923 apm_->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000924 scoped_array<char> echo_path_in(new char[echo_path_size]);
925 scoped_array<char> echo_path_out(new char[echo_path_size]);
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000926 EXPECT_EQ(apm_->kNullPointerError,
927 apm_->echo_control_mobile()->SetEchoPath(NULL, echo_path_size));
928 EXPECT_EQ(apm_->kNullPointerError,
929 apm_->echo_control_mobile()->GetEchoPath(NULL, echo_path_size));
930 EXPECT_EQ(apm_->kBadParameterError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000931 apm_->echo_control_mobile()->GetEchoPath(echo_path_out.get(), 1));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000932 EXPECT_EQ(apm_->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000933 apm_->echo_control_mobile()->GetEchoPath(echo_path_out.get(),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000934 echo_path_size));
ajm@google.com22e65152011-07-18 18:03:01 +0000935 for (size_t i = 0; i < echo_path_size; i++) {
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000936 echo_path_in[i] = echo_path_out[i] + 1;
937 }
938 EXPECT_EQ(apm_->kBadParameterError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000939 apm_->echo_control_mobile()->SetEchoPath(echo_path_in.get(), 1));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000940 EXPECT_EQ(apm_->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000941 apm_->echo_control_mobile()->SetEchoPath(echo_path_in.get(),
942 echo_path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000943 EXPECT_EQ(apm_->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000944 apm_->echo_control_mobile()->GetEchoPath(echo_path_out.get(),
945 echo_path_size));
ajm@google.com22e65152011-07-18 18:03:01 +0000946 for (size_t i = 0; i < echo_path_size; i++) {
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000947 EXPECT_EQ(echo_path_in[i], echo_path_out[i]);
948 }
andrew@webrtc.org75f19482012-02-09 17:16:18 +0000949
950 // Process a few frames with NS in the default disabled state. This exercises
951 // a different codepath than with it enabled.
952 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
953 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
954 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
955 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
956
niklase@google.com470e71d2011-07-07 08:21:25 +0000957 // Turn AECM off
958 EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false));
959 EXPECT_FALSE(apm_->echo_control_mobile()->is_enabled());
960}
961
962TEST_F(ApmTest, GainControl) {
963 // Testing gain modes
niklase@google.com470e71d2011-07-07 08:21:25 +0000964 EXPECT_EQ(apm_->kNoError,
965 apm_->gain_control()->set_mode(
966 apm_->gain_control()->mode()));
967
968 GainControl::Mode mode[] = {
969 GainControl::kAdaptiveAnalog,
970 GainControl::kAdaptiveDigital,
971 GainControl::kFixedDigital
972 };
973 for (size_t i = 0; i < sizeof(mode)/sizeof(*mode); i++) {
974 EXPECT_EQ(apm_->kNoError,
975 apm_->gain_control()->set_mode(mode[i]));
976 EXPECT_EQ(mode[i], apm_->gain_control()->mode());
977 }
978 // Testing invalid target levels
979 EXPECT_EQ(apm_->kBadParameterError,
980 apm_->gain_control()->set_target_level_dbfs(-3));
981 EXPECT_EQ(apm_->kBadParameterError,
982 apm_->gain_control()->set_target_level_dbfs(-40));
983 // Testing valid target levels
984 EXPECT_EQ(apm_->kNoError,
985 apm_->gain_control()->set_target_level_dbfs(
986 apm_->gain_control()->target_level_dbfs()));
987
988 int level_dbfs[] = {0, 6, 31};
989 for (size_t i = 0; i < sizeof(level_dbfs)/sizeof(*level_dbfs); i++) {
990 EXPECT_EQ(apm_->kNoError,
991 apm_->gain_control()->set_target_level_dbfs(level_dbfs[i]));
992 EXPECT_EQ(level_dbfs[i], apm_->gain_control()->target_level_dbfs());
993 }
994
995 // Testing invalid compression gains
996 EXPECT_EQ(apm_->kBadParameterError,
997 apm_->gain_control()->set_compression_gain_db(-1));
998 EXPECT_EQ(apm_->kBadParameterError,
999 apm_->gain_control()->set_compression_gain_db(100));
1000
1001 // Testing valid compression gains
1002 EXPECT_EQ(apm_->kNoError,
1003 apm_->gain_control()->set_compression_gain_db(
1004 apm_->gain_control()->compression_gain_db()));
1005
1006 int gain_db[] = {0, 10, 90};
1007 for (size_t i = 0; i < sizeof(gain_db)/sizeof(*gain_db); i++) {
1008 EXPECT_EQ(apm_->kNoError,
1009 apm_->gain_control()->set_compression_gain_db(gain_db[i]));
1010 EXPECT_EQ(gain_db[i], apm_->gain_control()->compression_gain_db());
1011 }
1012
1013 // Testing limiter off/on
1014 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->enable_limiter(false));
1015 EXPECT_FALSE(apm_->gain_control()->is_limiter_enabled());
1016 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->enable_limiter(true));
1017 EXPECT_TRUE(apm_->gain_control()->is_limiter_enabled());
1018
1019 // Testing invalid level limits
1020 EXPECT_EQ(apm_->kBadParameterError,
1021 apm_->gain_control()->set_analog_level_limits(-1, 512));
1022 EXPECT_EQ(apm_->kBadParameterError,
1023 apm_->gain_control()->set_analog_level_limits(100000, 512));
1024 EXPECT_EQ(apm_->kBadParameterError,
1025 apm_->gain_control()->set_analog_level_limits(512, -1));
1026 EXPECT_EQ(apm_->kBadParameterError,
1027 apm_->gain_control()->set_analog_level_limits(512, 100000));
1028 EXPECT_EQ(apm_->kBadParameterError,
1029 apm_->gain_control()->set_analog_level_limits(512, 255));
1030
1031 // Testing valid level limits
1032 EXPECT_EQ(apm_->kNoError,
1033 apm_->gain_control()->set_analog_level_limits(
1034 apm_->gain_control()->analog_level_minimum(),
1035 apm_->gain_control()->analog_level_maximum()));
1036
1037 int min_level[] = {0, 255, 1024};
1038 for (size_t i = 0; i < sizeof(min_level)/sizeof(*min_level); i++) {
1039 EXPECT_EQ(apm_->kNoError,
1040 apm_->gain_control()->set_analog_level_limits(min_level[i], 1024));
1041 EXPECT_EQ(min_level[i], apm_->gain_control()->analog_level_minimum());
1042 }
1043
1044 int max_level[] = {0, 1024, 65535};
1045 for (size_t i = 0; i < sizeof(min_level)/sizeof(*min_level); i++) {
1046 EXPECT_EQ(apm_->kNoError,
1047 apm_->gain_control()->set_analog_level_limits(0, max_level[i]));
1048 EXPECT_EQ(max_level[i], apm_->gain_control()->analog_level_maximum());
1049 }
1050
1051 // TODO(ajm): stream_is_saturated() and stream_analog_level()
1052
1053 // Turn AGC off
1054 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false));
1055 EXPECT_FALSE(apm_->gain_control()->is_enabled());
1056}
1057
1058TEST_F(ApmTest, NoiseSuppression) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001059 // Test valid suppression levels.
niklase@google.com470e71d2011-07-07 08:21:25 +00001060 NoiseSuppression::Level level[] = {
1061 NoiseSuppression::kLow,
1062 NoiseSuppression::kModerate,
1063 NoiseSuppression::kHigh,
1064 NoiseSuppression::kVeryHigh
1065 };
1066 for (size_t i = 0; i < sizeof(level)/sizeof(*level); i++) {
1067 EXPECT_EQ(apm_->kNoError,
1068 apm_->noise_suppression()->set_level(level[i]));
1069 EXPECT_EQ(level[i], apm_->noise_suppression()->level());
1070 }
1071
andrew@webrtc.org648af742012-02-08 01:57:29 +00001072 // Turn NS on/off
niklase@google.com470e71d2011-07-07 08:21:25 +00001073 EXPECT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true));
1074 EXPECT_TRUE(apm_->noise_suppression()->is_enabled());
1075 EXPECT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(false));
1076 EXPECT_FALSE(apm_->noise_suppression()->is_enabled());
1077}
1078
1079TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001080 // Turn HP filter on/off
niklase@google.com470e71d2011-07-07 08:21:25 +00001081 EXPECT_EQ(apm_->kNoError, apm_->high_pass_filter()->Enable(true));
1082 EXPECT_TRUE(apm_->high_pass_filter()->is_enabled());
1083 EXPECT_EQ(apm_->kNoError, apm_->high_pass_filter()->Enable(false));
1084 EXPECT_FALSE(apm_->high_pass_filter()->is_enabled());
1085}
1086
1087TEST_F(ApmTest, LevelEstimator) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001088 // Turn level estimator on/off
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001089 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(false));
niklase@google.com470e71d2011-07-07 08:21:25 +00001090 EXPECT_FALSE(apm_->level_estimator()->is_enabled());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001091
1092 EXPECT_EQ(apm_->kNotEnabledError, apm_->level_estimator()->RMS());
1093
1094 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
1095 EXPECT_TRUE(apm_->level_estimator()->is_enabled());
1096
1097 // Run this test in wideband; in super-wb, the splitting filter distorts the
1098 // audio enough to cause deviation from the expectation for small values.
1099 EXPECT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(16000));
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001100 frame_->samples_per_channel_ = 160;
1101 frame_->num_channels_ = 2;
1102 frame_->sample_rate_hz_ = 16000;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001103
1104 // Min value if no frames have been processed.
1105 EXPECT_EQ(127, apm_->level_estimator()->RMS());
1106
1107 // Min value on zero frames.
1108 SetFrameTo(frame_, 0);
1109 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1110 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1111 EXPECT_EQ(127, apm_->level_estimator()->RMS());
1112
1113 // Try a few RMS values.
1114 // (These also test that the value resets after retrieving it.)
1115 SetFrameTo(frame_, 32767);
1116 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1117 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1118 EXPECT_EQ(0, apm_->level_estimator()->RMS());
1119
1120 SetFrameTo(frame_, 30000);
1121 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1122 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1123 EXPECT_EQ(1, apm_->level_estimator()->RMS());
1124
1125 SetFrameTo(frame_, 10000);
1126 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1127 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1128 EXPECT_EQ(10, apm_->level_estimator()->RMS());
1129
1130 SetFrameTo(frame_, 10);
1131 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1132 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1133 EXPECT_EQ(70, apm_->level_estimator()->RMS());
1134
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001135 // Min value if energy_ == 0.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001136 SetFrameTo(frame_, 10000);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001137 uint32_t energy = frame_->energy_; // Save default to restore below.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001138 frame_->energy_ = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001139 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1140 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1141 EXPECT_EQ(127, apm_->level_estimator()->RMS());
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001142 frame_->energy_ = energy;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001143
1144 // Verify reset after enable/disable.
1145 SetFrameTo(frame_, 32767);
1146 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1147 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(false));
1148 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
1149 SetFrameTo(frame_, 1);
1150 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1151 EXPECT_EQ(90, apm_->level_estimator()->RMS());
1152
1153 // Verify reset after initialize.
1154 SetFrameTo(frame_, 32767);
1155 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1156 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
1157 SetFrameTo(frame_, 1);
1158 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1159 EXPECT_EQ(90, apm_->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +00001160}
1161
1162TEST_F(ApmTest, VoiceDetection) {
1163 // Test external VAD
1164 EXPECT_EQ(apm_->kNoError,
1165 apm_->voice_detection()->set_stream_has_voice(true));
1166 EXPECT_TRUE(apm_->voice_detection()->stream_has_voice());
1167 EXPECT_EQ(apm_->kNoError,
1168 apm_->voice_detection()->set_stream_has_voice(false));
1169 EXPECT_FALSE(apm_->voice_detection()->stream_has_voice());
1170
andrew@webrtc.org648af742012-02-08 01:57:29 +00001171 // Test valid likelihoods
niklase@google.com470e71d2011-07-07 08:21:25 +00001172 VoiceDetection::Likelihood likelihood[] = {
1173 VoiceDetection::kVeryLowLikelihood,
1174 VoiceDetection::kLowLikelihood,
1175 VoiceDetection::kModerateLikelihood,
1176 VoiceDetection::kHighLikelihood
1177 };
1178 for (size_t i = 0; i < sizeof(likelihood)/sizeof(*likelihood); i++) {
1179 EXPECT_EQ(apm_->kNoError,
1180 apm_->voice_detection()->set_likelihood(likelihood[i]));
1181 EXPECT_EQ(likelihood[i], apm_->voice_detection()->likelihood());
1182 }
1183
1184 /* TODO(bjornv): Enable once VAD supports other frame lengths than 10 ms
andrew@webrtc.org648af742012-02-08 01:57:29 +00001185 // Test invalid frame sizes
niklase@google.com470e71d2011-07-07 08:21:25 +00001186 EXPECT_EQ(apm_->kBadParameterError,
1187 apm_->voice_detection()->set_frame_size_ms(12));
1188
andrew@webrtc.org648af742012-02-08 01:57:29 +00001189 // Test valid frame sizes
niklase@google.com470e71d2011-07-07 08:21:25 +00001190 for (int i = 10; i <= 30; i += 10) {
1191 EXPECT_EQ(apm_->kNoError,
1192 apm_->voice_detection()->set_frame_size_ms(i));
1193 EXPECT_EQ(i, apm_->voice_detection()->frame_size_ms());
1194 }
1195 */
1196
andrew@webrtc.org648af742012-02-08 01:57:29 +00001197 // Turn VAD on/off
niklase@google.com470e71d2011-07-07 08:21:25 +00001198 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
1199 EXPECT_TRUE(apm_->voice_detection()->is_enabled());
1200 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false));
1201 EXPECT_FALSE(apm_->voice_detection()->is_enabled());
1202
andrew@webrtc.orged083d42011-09-19 15:28:51 +00001203 // Test that AudioFrame activity is maintained when VAD is disabled.
1204 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false));
1205 AudioFrame::VADActivity activity[] = {
1206 AudioFrame::kVadActive,
1207 AudioFrame::kVadPassive,
1208 AudioFrame::kVadUnknown
1209 };
1210 for (size_t i = 0; i < sizeof(activity)/sizeof(*activity); i++) {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001211 frame_->vad_activity_ = activity[i];
andrew@webrtc.orged083d42011-09-19 15:28:51 +00001212 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001213 EXPECT_EQ(activity[i], frame_->vad_activity_);
andrew@webrtc.orged083d42011-09-19 15:28:51 +00001214 }
1215
1216 // Test that AudioFrame activity is set when VAD is enabled.
1217 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001218 frame_->vad_activity_ = AudioFrame::kVadUnknown;
andrew@webrtc.orged083d42011-09-19 15:28:51 +00001219 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001220 EXPECT_NE(AudioFrame::kVadUnknown, frame_->vad_activity_);
andrew@webrtc.orged083d42011-09-19 15:28:51 +00001221
niklase@google.com470e71d2011-07-07 08:21:25 +00001222 // TODO(bjornv): Add tests for streamed voice; stream_has_voice()
1223}
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001224
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001225TEST_F(ApmTest, VerifyDownMixing) {
1226 for (size_t i = 0; i < kSampleRatesSize; i++) {
1227 Init(kSampleRates[i], 2, 2, 1, false);
1228 SetFrameTo(frame_, 1000, 2000);
1229 AudioFrame mono_frame;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001230 mono_frame.samples_per_channel_ = frame_->samples_per_channel_;
1231 mono_frame.num_channels_ = 1;
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001232 SetFrameTo(&mono_frame, 1500);
1233 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1234 EXPECT_TRUE(FrameDataAreEqual(*frame_, mono_frame));
1235 }
1236}
1237
1238TEST_F(ApmTest, AllProcessingDisabledByDefault) {
1239 EXPECT_FALSE(apm_->echo_cancellation()->is_enabled());
1240 EXPECT_FALSE(apm_->echo_control_mobile()->is_enabled());
1241 EXPECT_FALSE(apm_->gain_control()->is_enabled());
1242 EXPECT_FALSE(apm_->high_pass_filter()->is_enabled());
1243 EXPECT_FALSE(apm_->level_estimator()->is_enabled());
1244 EXPECT_FALSE(apm_->noise_suppression()->is_enabled());
1245 EXPECT_FALSE(apm_->voice_detection()->is_enabled());
1246}
1247
1248TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabled) {
1249 for (size_t i = 0; i < kSampleRatesSize; i++) {
1250 Init(kSampleRates[i], 2, 2, 2, false);
1251 SetFrameTo(frame_, 1000, 2000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00001252 AudioFrame frame_copy;
1253 frame_copy.CopyFrom(*frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001254 for (int j = 0; j < 1000; j++) {
1255 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1256 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1257 }
1258 }
1259}
1260
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001261TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1262 EnableAllComponents();
1263
1264 for (size_t i = 0; i < kProcessSampleRatesSize; i++) {
1265 Init(kProcessSampleRates[i], 2, 2, 2, false);
1266 int analog_level = 127;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001267 EXPECT_EQ(0, feof(far_file_));
1268 EXPECT_EQ(0, feof(near_file_));
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001269 while (1) {
1270 if (!ReadFrame(far_file_, revframe_)) break;
1271 CopyLeftToRightChannel(revframe_->data_, revframe_->samples_per_channel_);
1272
1273 EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(revframe_));
1274
1275 if (!ReadFrame(near_file_, frame_)) break;
1276 CopyLeftToRightChannel(frame_->data_, frame_->samples_per_channel_);
1277 frame_->vad_activity_ = AudioFrame::kVadUnknown;
1278
1279 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +00001280 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001281 EXPECT_EQ(apm_->kNoError,
1282 apm_->gain_control()->set_stream_analog_level(analog_level));
1283 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1284 analog_level = apm_->gain_control()->stream_analog_level();
1285
1286 VerifyChannelsAreEqual(frame_->data_, frame_->samples_per_channel_);
1287 }
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001288 rewind(far_file_);
1289 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001290 }
1291}
1292
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001293TEST_F(ApmTest, SplittingFilter) {
1294 // Verify the filter is not active through undistorted audio when:
1295 // 1. No components are enabled...
1296 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00001297 AudioFrame frame_copy;
1298 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001299 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1300 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1301 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1302
1303 // 2. Only the level estimator is enabled...
1304 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00001305 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001306 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
1307 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1308 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1309 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1310 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(false));
1311
1312 // 3. Only VAD is enabled...
1313 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00001314 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001315 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
1316 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1317 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1318 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1319 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false));
1320
1321 // 4. Both VAD and the level estimator are enabled...
1322 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00001323 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001324 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
1325 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
1326 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1327 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1328 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1329 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(false));
1330 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false));
1331
1332 // 5. Not using super-wb.
1333 EXPECT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(16000));
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001334 frame_->samples_per_channel_ = 160;
1335 frame_->num_channels_ = 2;
1336 frame_->sample_rate_hz_ = 16000;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001337 // Enable AEC, which would require the filter in super-wb. We rely on the
1338 // first few frames of data being unaffected by the AEC.
1339 // TODO(andrew): This test, and the one below, rely rather tenuously on the
1340 // behavior of the AEC. Think of something more robust.
1341 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
1342 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00001343 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001344 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +00001345 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001346 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1347 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +00001348 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001349 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1350 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1351
1352 // Check the test is valid. We should have distortion from the filter
1353 // when AEC is enabled (which won't affect the audio).
1354 EXPECT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(32000));
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001355 frame_->samples_per_channel_ = 320;
1356 frame_->num_channels_ = 2;
1357 frame_->sample_rate_hz_ = 32000;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001358 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00001359 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001360 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +00001361 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001362 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1363 EXPECT_FALSE(FrameDataAreEqual(*frame_, frame_copy));
1364}
1365
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001366// TODO(andrew): expand test to verify output.
1367TEST_F(ApmTest, DebugDump) {
1368 const std::string filename = webrtc::test::OutputPath() + "debug.aec";
1369 EXPECT_EQ(apm_->kNullPointerError, apm_->StartDebugRecording(NULL));
1370
1371#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1372 // Stopping without having started should be OK.
1373 EXPECT_EQ(apm_->kNoError, apm_->StopDebugRecording());
1374
1375 EXPECT_EQ(apm_->kNoError, apm_->StartDebugRecording(filename.c_str()));
1376 EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(revframe_));
1377 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1378 EXPECT_EQ(apm_->kNoError, apm_->StopDebugRecording());
1379
1380 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001381 FILE* fid = fopen(filename.c_str(), "r");
1382 ASSERT_TRUE(fid != NULL);
1383
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001384 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001385 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001386 ASSERT_EQ(0, remove(filename.c_str()));
1387#else
1388 EXPECT_EQ(apm_->kUnsupportedFunctionError,
1389 apm_->StartDebugRecording(filename.c_str()));
1390 EXPECT_EQ(apm_->kUnsupportedFunctionError, apm_->StopDebugRecording());
1391
1392 // Verify the file has NOT been written.
1393 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1394#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1395}
1396
andrew@webrtc.org75f19482012-02-09 17:16:18 +00001397// TODO(andrew): Add a test to process a few frames with different combinations
1398// of enabled components.
1399
andrew@webrtc.orge2ed5ba2012-01-20 19:06:38 +00001400// TODO(andrew): Make this test more robust such that it can be run on multiple
1401// platforms. It currently requires bit-exactness.
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00001402#ifdef WEBRTC_AUDIOPROC_BIT_EXACT
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001403TEST_F(ApmTest, Process) {
1404 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001405 webrtc::audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001406
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001407 if (!write_ref_data) {
1408 ReadMessageLiteFromFile(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001409 } else {
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001410 // Write the desired tests to the protobuf reference file.
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001411 for (size_t i = 0; i < kChannelsSize; i++) {
1412 for (size_t j = 0; j < kChannelsSize; j++) {
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001413 // We can't have more output than input channels.
1414 for (size_t k = 0; k <= j; k++) {
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001415 for (size_t l = 0; l < kProcessSampleRatesSize; l++) {
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001416 webrtc::audioproc::Test* test = ref_data.add_test();
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001417 test->set_num_reverse_channels(kChannels[i]);
1418 test->set_num_input_channels(kChannels[j]);
1419 test->set_num_output_channels(kChannels[k]);
1420 test->set_sample_rate(kProcessSampleRates[l]);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001421 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001422 }
1423 }
1424 }
1425 }
1426
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001427 EnableAllComponents();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001428
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001429 for (int i = 0; i < ref_data.test_size(); i++) {
1430 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001431
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001432 webrtc::audioproc::Test* test = ref_data.mutable_test(i);
1433 Init(test->sample_rate(), test->num_reverse_channels(),
1434 test->num_input_channels(), test->num_output_channels(), true);
1435
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001436 int frame_count = 0;
1437 int has_echo_count = 0;
1438 int has_voice_count = 0;
1439 int is_saturated_count = 0;
1440 int analog_level = 127;
1441 int analog_level_average = 0;
1442 int max_output_average = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001443 float ns_speech_prob_average = 0.0f;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001444
1445 while (1) {
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001446 if (!ReadFrame(far_file_, revframe_)) break;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001447 EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(revframe_));
1448
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001449 if (!ReadFrame(near_file_, frame_)) break;
1450 frame_->vad_activity_ = AudioFrame::kVadUnknown;
1451
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001452 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +00001453 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001454 EXPECT_EQ(apm_->kNoError,
1455 apm_->gain_control()->set_stream_analog_level(analog_level));
1456
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001457 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001458 // Ensure the frame was downmixed properly.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001459 EXPECT_EQ(test->num_output_channels(), frame_->num_channels_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001460
1461 max_output_average += MaxAudioFrame(*frame_);
1462
1463 if (apm_->echo_cancellation()->stream_has_echo()) {
1464 has_echo_count++;
1465 }
1466
1467 analog_level = apm_->gain_control()->stream_analog_level();
1468 analog_level_average += analog_level;
1469 if (apm_->gain_control()->stream_is_saturated()) {
1470 is_saturated_count++;
1471 }
1472 if (apm_->voice_detection()->stream_has_voice()) {
1473 has_voice_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001474 EXPECT_EQ(AudioFrame::kVadActive, frame_->vad_activity_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001475 } else {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001476 EXPECT_EQ(AudioFrame::kVadPassive, frame_->vad_activity_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001477 }
1478
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001479 ns_speech_prob_average += apm_->noise_suppression()->speech_probability();
1480
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001481 size_t frame_size = frame_->samples_per_channel_ * frame_->num_channels_;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001482 size_t write_count = fwrite(frame_->data_,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001483 sizeof(int16_t),
1484 frame_size,
1485 out_file_);
1486 ASSERT_EQ(frame_size, write_count);
1487
1488 // Reset in case of downmixing.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001489 frame_->num_channels_ = test->num_input_channels();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001490 frame_count++;
1491 }
1492 max_output_average /= frame_count;
1493 analog_level_average /= frame_count;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001494 ns_speech_prob_average /= frame_count;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001495
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00001496#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001497 EchoCancellation::Metrics echo_metrics;
1498 EXPECT_EQ(apm_->kNoError,
1499 apm_->echo_cancellation()->GetMetrics(&echo_metrics));
1500 int median = 0;
1501 int std = 0;
1502 EXPECT_EQ(apm_->kNoError,
1503 apm_->echo_cancellation()->GetDelayMetrics(&median, &std));
1504
1505 int rms_level = apm_->level_estimator()->RMS();
1506 EXPECT_LE(0, rms_level);
1507 EXPECT_GE(127, rms_level);
1508#endif
1509
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001510 if (!write_ref_data) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001511 EXPECT_EQ(test->has_echo_count(), has_echo_count);
1512 EXPECT_EQ(test->has_voice_count(), has_voice_count);
1513 EXPECT_EQ(test->is_saturated_count(), is_saturated_count);
1514
1515 EXPECT_EQ(test->analog_level_average(), analog_level_average);
1516 EXPECT_EQ(test->max_output_average(), max_output_average);
1517
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00001518#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001519 webrtc::audioproc::Test::EchoMetrics reference =
1520 test->echo_metrics();
1521 TestStats(echo_metrics.residual_echo_return_loss,
1522 reference.residual_echo_return_loss());
1523 TestStats(echo_metrics.echo_return_loss,
1524 reference.echo_return_loss());
1525 TestStats(echo_metrics.echo_return_loss_enhancement,
1526 reference.echo_return_loss_enhancement());
1527 TestStats(echo_metrics.a_nlp,
1528 reference.a_nlp());
1529
1530 webrtc::audioproc::Test::DelayMetrics reference_delay =
1531 test->delay_metrics();
andrew@webrtc.org828af1b2011-11-22 22:40:27 +00001532 EXPECT_EQ(reference_delay.median(), median);
1533 EXPECT_EQ(reference_delay.std(), std);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001534
1535 EXPECT_EQ(test->rms_level(), rms_level);
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001536
1537 EXPECT_FLOAT_EQ(test->ns_speech_probability_average(),
1538 ns_speech_prob_average);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001539#endif
1540 } else {
1541 test->set_has_echo_count(has_echo_count);
1542 test->set_has_voice_count(has_voice_count);
1543 test->set_is_saturated_count(is_saturated_count);
1544
1545 test->set_analog_level_average(analog_level_average);
1546 test->set_max_output_average(max_output_average);
1547
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00001548#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001549 webrtc::audioproc::Test::EchoMetrics* message =
1550 test->mutable_echo_metrics();
1551 WriteStatsMessage(echo_metrics.residual_echo_return_loss,
1552 message->mutable_residual_echo_return_loss());
1553 WriteStatsMessage(echo_metrics.echo_return_loss,
1554 message->mutable_echo_return_loss());
1555 WriteStatsMessage(echo_metrics.echo_return_loss_enhancement,
1556 message->mutable_echo_return_loss_enhancement());
1557 WriteStatsMessage(echo_metrics.a_nlp,
1558 message->mutable_a_nlp());
1559
1560 webrtc::audioproc::Test::DelayMetrics* message_delay =
1561 test->mutable_delay_metrics();
1562 message_delay->set_median(median);
1563 message_delay->set_std(std);
1564
1565 test->set_rms_level(rms_level);
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001566
1567 EXPECT_LE(0.0f, ns_speech_prob_average);
1568 EXPECT_GE(1.0f, ns_speech_prob_average);
1569 test->set_ns_speech_probability_average(ns_speech_prob_average);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001570#endif
1571 }
1572
1573 rewind(far_file_);
1574 rewind(near_file_);
1575 }
1576
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001577 if (write_ref_data) {
1578 WriteMessageLiteToFile(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001579 }
1580}
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00001581#endif // WEBRTC_AUDIOPROC_BIT_EXACT
andrew@webrtc.orge2ed5ba2012-01-20 19:06:38 +00001582
niklase@google.com470e71d2011-07-07 08:21:25 +00001583} // namespace
1584
1585int main(int argc, char** argv) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001586 for (int i = 1; i < argc; i++) {
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001587 if (strcmp(argv[i], "--write_ref_data") == 0) {
1588 write_ref_data = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001589 }
1590 }
1591
andrew@webrtc.org28d01402012-10-18 00:42:32 +00001592 // We don't use TestSuite here because it would require the Android platform
1593 // build to depend on Gmock.
1594 webrtc::test::SetExecutablePath(argv[0]);
1595 testing::InitGoogleTest(&argc, argv);
1596 int result = RUN_ALL_TESTS();
andrew@webrtc.org64235092011-08-19 21:22:08 +00001597 // Optional, but removes memory leak noise from Valgrind.
1598 google::protobuf::ShutdownProtobufLibrary();
andrew@webrtc.org28d01402012-10-18 00:42:32 +00001599 return result;
niklase@google.com470e71d2011-07-07 08:21:25 +00001600}