blob: bfb77664caf8bc8ebbc1056f571afc32049db54a [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:251/*
andrew@webrtc.org293d22b2012-01-30 22:04:262 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:253 *
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
andrew@webrtc.orgddbb8a22014-04-22 21:00:0411#include <math.h>
ajm@google.com59e41402011-07-28 17:34:0412#include <stdio.h>
andrew@webrtc.org07bf9a02012-05-05 00:32:0013#include <algorithm>
andrew@webrtc.orgddbb8a22014-04-22 21:00:0414#include <limits>
bjornv@webrtc.org3e102492013-02-14 15:29:0915#include <queue>
andrew@webrtc.org07bf9a02012-05-05 00:32:0016
andrew@webrtc.org27c69802014-02-18 20:24:5617#include "webrtc/common_audio/include/audio_util.h"
andrew@webrtc.orgddbb8a22014-04-22 21:00:0418#include "webrtc/common_audio/resampler/include/push_resampler.h"
19#include "webrtc/common_audio/resampler/push_sinc_resampler.h"
bjornv@webrtc.org3e102492013-02-14 15:29:0920#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
21#include "webrtc/modules/audio_processing/include/audio_processing.h"
andrew@webrtc.org60730cf2014-01-07 17:45:0922#include "webrtc/modules/audio_processing/test/test_utils.h"
bjornv@webrtc.org3e102492013-02-14 15:29:0923#include "webrtc/modules/interface/module_common_types.h"
24#include "webrtc/system_wrappers/interface/event_wrapper.h"
25#include "webrtc/system_wrappers/interface/scoped_ptr.h"
bjornv@webrtc.org3e102492013-02-14 15:29:0926#include "webrtc/system_wrappers/interface/trace.h"
27#include "webrtc/test/testsupport/fileutils.h"
henrike@webrtc.orga950300b2013-07-08 18:53:5428#include "webrtc/test/testsupport/gtest_disable.h"
leozwang@webrtc.orga3736342012-03-16 21:36:0029#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
pbos@webrtc.org8c34cee2013-05-28 09:24:0330#include "gtest/gtest.h"
leozwang@webrtc.org534e4952012-10-22 21:21:5231#include "external/webrtc/webrtc/modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:0032#else
pbos@webrtc.org8c34cee2013-05-28 09:24:0333#include "testing/gtest/include/gtest/gtest.h"
ajm@google.com808e0e02011-08-03 21:08:5134#include "webrtc/audio_processing/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:0035#endif
niklase@google.com470e71d2011-07-07 08:21:2536
andrew@webrtc.org293d22b2012-01-30 22:04:2637#if (defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)) || \
38 (defined(WEBRTC_LINUX) && defined(WEBRTC_ARCH_X86_64) && !defined(NDEBUG))
39# define WEBRTC_AUDIOPROC_BIT_EXACT
40#endif
41
andrew@webrtc.org27c69802014-02-18 20:24:5642namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:2543namespace {
andrew@webrtc.org17e40642014-03-04 20:58:1344
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:3445// TODO(bjornv): This is not feasible until the functionality has been
46// re-implemented; see comment at the bottom of this file.
ajm@google.com59e41402011-07-28 17:34:0447// When false, this will compare the output data with the results stored to
niklase@google.com470e71d2011-07-07 08:21:2548// file. This is the typical case. When the file should be updated, it can
andrew@webrtc.orgdaacee82012-02-07 00:01:0449// be set to true with the command-line switch --write_ref_data.
henrike@webrtc.org83cebb22013-06-27 18:31:1350#ifdef WEBRTC_AUDIOPROC_BIT_EXACT
andrew@webrtc.orgdaacee82012-02-07 00:01:0451bool write_ref_data = false;
kjellander@webrtc.org35553032013-10-15 20:10:1752const int kChannels[] = {1, 2};
53const size_t kChannelsSize = sizeof(kChannels) / sizeof(*kChannels);
henrike@webrtc.org83cebb22013-06-27 18:31:1354#endif
ajm@google.com59e41402011-07-28 17:34:0455
andrew@webrtc.orgecac9b72012-05-02 00:04:1056const int kSampleRates[] = {8000, 16000, 32000};
57const size_t kSampleRatesSize = sizeof(kSampleRates) / sizeof(*kSampleRates);
andrew@webrtc.orgecac9b72012-05-02 00:04:1058
andrew@webrtc.org07bf9a02012-05-05 00:32:0059#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
60// AECM doesn't support super-wb.
61const int kProcessSampleRates[] = {8000, 16000};
62#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
63const int kProcessSampleRates[] = {8000, 16000, 32000};
64#endif
65const size_t kProcessSampleRatesSize = sizeof(kProcessSampleRates) /
66 sizeof(*kProcessSampleRates);
67
andrew@webrtc.orgddbb8a22014-04-22 21:00:0468void ConvertToFloat(const int16_t* int_data, ChannelBuffer<float>* cb) {
69 ChannelBuffer<int16_t> cb_int(cb->samples_per_channel(),
70 cb->num_channels());
71 Deinterleave(int_data,
72 cb->samples_per_channel(),
73 cb->num_channels(),
andrew@webrtc.orga8b97372014-03-10 22:26:1274 cb_int.channels());
75 ScaleToFloat(cb_int.data(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:0476 cb->samples_per_channel() * cb->num_channels(),
andrew@webrtc.orga8b97372014-03-10 22:26:1277 cb->data());
78}
andrew@webrtc.org17e40642014-03-04 20:58:1379
andrew@webrtc.orgddbb8a22014-04-22 21:00:0480void ConvertToFloat(const AudioFrame& frame, ChannelBuffer<float>* cb) {
81 ConvertToFloat(frame.data_, cb);
82}
83
andrew@webrtc.org103657b2014-04-24 18:28:5684// Number of channels including the keyboard channel.
85int TotalChannelsFromLayout(AudioProcessing::ChannelLayout layout) {
86 switch (layout) {
87 case AudioProcessing::kMono:
88 return 1;
89 case AudioProcessing::kMonoAndKeyboard:
90 case AudioProcessing::kStereo:
91 return 2;
92 case AudioProcessing::kStereoAndKeyboard:
93 return 3;
94 }
95 assert(false);
96 return -1;
97}
98
bjornv@webrtc.org3e102492013-02-14 15:29:0999int TruncateToMultipleOf10(int value) {
100 return (value / 10) * 10;
101}
102
andrew@webrtc.orgddbb8a22014-04-22 21:00:04103void MixStereoToMono(const float* stereo, float* mono,
andrew@webrtc.org81865342012-10-27 00:28:27104 int samples_per_channel) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04105 for (int i = 0; i < samples_per_channel; ++i) {
106 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) / 2;
andrew@webrtc.org81865342012-10-27 00:28:27107 }
108}
109
andrew@webrtc.orgddbb8a22014-04-22 21:00:04110void MixStereoToMono(const int16_t* stereo, int16_t* mono,
111 int samples_per_channel) {
112 for (int i = 0; i < samples_per_channel; i++)
113 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) >> 1;
114}
115
andrew@webrtc.org81865342012-10-27 00:28:27116void CopyLeftToRightChannel(int16_t* stereo, int samples_per_channel) {
117 for (int i = 0; i < samples_per_channel; i++) {
118 stereo[i * 2 + 1] = stereo[i * 2];
119 }
120}
121
122void VerifyChannelsAreEqual(int16_t* stereo, int samples_per_channel) {
123 for (int i = 0; i < samples_per_channel; i++) {
124 EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
125 }
126}
127
128void SetFrameTo(AudioFrame* frame, int16_t value) {
andrew@webrtc.org27c69802014-02-18 20:24:56129 for (int i = 0; i < frame->samples_per_channel_ * frame->num_channels_; ++i) {
andrew@webrtc.org81865342012-10-27 00:28:27130 frame->data_[i] = value;
131 }
132}
133
134void SetFrameTo(AudioFrame* frame, int16_t left, int16_t right) {
135 ASSERT_EQ(2, frame->num_channels_);
136 for (int i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
137 frame->data_[i] = left;
138 frame->data_[i + 1] = right;
139 }
140}
141
andrew@webrtc.org27c69802014-02-18 20:24:56142void ScaleFrame(AudioFrame* frame, float scale) {
143 for (int i = 0; i < frame->samples_per_channel_ * frame->num_channels_; ++i) {
andrew@webrtc.org17e40642014-03-04 20:58:13144 frame->data_[i] = RoundToInt16(frame->data_[i] * scale);
andrew@webrtc.org27c69802014-02-18 20:24:56145 }
146}
147
andrew@webrtc.org81865342012-10-27 00:28:27148bool FrameDataAreEqual(const AudioFrame& frame1, const AudioFrame& frame2) {
andrew@webrtc.org17e40642014-03-04 20:58:13149 if (frame1.samples_per_channel_ != frame2.samples_per_channel_) {
andrew@webrtc.org81865342012-10-27 00:28:27150 return false;
151 }
andrew@webrtc.org17e40642014-03-04 20:58:13152 if (frame1.num_channels_ != frame2.num_channels_) {
andrew@webrtc.org81865342012-10-27 00:28:27153 return false;
154 }
155 if (memcmp(frame1.data_, frame2.data_,
156 frame1.samples_per_channel_ * frame1.num_channels_ *
andrew@webrtc.org17e40642014-03-04 20:58:13157 sizeof(int16_t))) {
andrew@webrtc.org81865342012-10-27 00:28:27158 return false;
159 }
160 return true;
161}
162
andrew@webrtc.org17e40642014-03-04 20:58:13163void EnableAllAPComponents(AudioProcessing* ap) {
164#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
165 EXPECT_NOERR(ap->echo_control_mobile()->Enable(true));
166
167 EXPECT_NOERR(ap->gain_control()->set_mode(GainControl::kAdaptiveDigital));
168 EXPECT_NOERR(ap->gain_control()->Enable(true));
169#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
170 EXPECT_NOERR(ap->echo_cancellation()->enable_drift_compensation(true));
171 EXPECT_NOERR(ap->echo_cancellation()->enable_metrics(true));
172 EXPECT_NOERR(ap->echo_cancellation()->enable_delay_logging(true));
173 EXPECT_NOERR(ap->echo_cancellation()->Enable(true));
174
175 EXPECT_NOERR(ap->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
176 EXPECT_NOERR(ap->gain_control()->set_analog_level_limits(0, 255));
177 EXPECT_NOERR(ap->gain_control()->Enable(true));
178#endif
179
180 EXPECT_NOERR(ap->high_pass_filter()->Enable(true));
181 EXPECT_NOERR(ap->level_estimator()->Enable(true));
182 EXPECT_NOERR(ap->noise_suppression()->Enable(true));
183
184 EXPECT_NOERR(ap->voice_detection()->Enable(true));
185}
186
andrew@webrtc.orgd7696c42013-12-03 23:39:16187#ifdef WEBRTC_AUDIOPROC_BIT_EXACT
188// These functions are only used by the bit-exact test.
189template <class T>
190T AbsValue(T a) {
191 return a > 0 ? a: -a;
192}
193
194int16_t MaxAudioFrame(const AudioFrame& frame) {
195 const int length = frame.samples_per_channel_ * frame.num_channels_;
196 int16_t max_data = AbsValue(frame.data_[0]);
197 for (int i = 1; i < length; i++) {
198 max_data = std::max(max_data, AbsValue(frame.data_[i]));
199 }
200
201 return max_data;
202}
203
fischman@webrtc.orgf8be8df2013-12-17 23:46:39204#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
andrew@webrtc.org81865342012-10-27 00:28:27205void TestStats(const AudioProcessing::Statistic& test,
andrew@webrtc.org27c69802014-02-18 20:24:56206 const audioproc::Test::Statistic& reference) {
andrew@webrtc.org81865342012-10-27 00:28:27207 EXPECT_EQ(reference.instant(), test.instant);
208 EXPECT_EQ(reference.average(), test.average);
209 EXPECT_EQ(reference.maximum(), test.maximum);
210 EXPECT_EQ(reference.minimum(), test.minimum);
211}
212
213void WriteStatsMessage(const AudioProcessing::Statistic& output,
andrew@webrtc.orga8b97372014-03-10 22:26:12214 audioproc::Test::Statistic* msg) {
215 msg->set_instant(output.instant);
216 msg->set_average(output.average);
217 msg->set_maximum(output.maximum);
218 msg->set_minimum(output.minimum);
andrew@webrtc.org81865342012-10-27 00:28:27219}
fischman@webrtc.orgf8be8df2013-12-17 23:46:39220#endif
andrew@webrtc.org81865342012-10-27 00:28:27221
andrew@webrtc.orga8b97372014-03-10 22:26:12222void OpenFileAndWriteMessage(const std::string filename,
223 const ::google::protobuf::MessageLite& msg) {
andrew@webrtc.org81865342012-10-27 00:28:27224 FILE* file = fopen(filename.c_str(), "wb");
andrew@webrtc.orga8b97372014-03-10 22:26:12225 ASSERT_TRUE(file != NULL);
226
227 int32_t size = msg.ByteSize();
andrew@webrtc.org81865342012-10-27 00:28:27228 ASSERT_GT(size, 0);
andrew@webrtc.orga8b97372014-03-10 22:26:12229 scoped_ptr<uint8_t[]> array(new uint8_t[size]);
230 ASSERT_TRUE(msg.SerializeToArray(array.get(), size));
andrew@webrtc.org81865342012-10-27 00:28:27231
andrew@webrtc.orga8b97372014-03-10 22:26:12232 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
andrew@webrtc.org81865342012-10-27 00:28:27233 ASSERT_EQ(static_cast<size_t>(size),
andrew@webrtc.orga8b97372014-03-10 22:26:12234 fwrite(array.get(), sizeof(array[0]), size, file));
andrew@webrtc.org81865342012-10-27 00:28:27235 fclose(file);
236}
andrew@webrtc.org17e40642014-03-04 20:58:13237#endif // WEBRTC_AUDIOPROC_BIT_EXACT
andrew@webrtc.org81865342012-10-27 00:28:27238
andrew@webrtc.orgddbb8a22014-04-22 21:00:04239std::string ResourceFilePath(std::string name, int sample_rate_hz) {
240 std::ostringstream ss;
241 // Resource files are all stereo.
242 ss << name << sample_rate_hz / 1000 << "_stereo";
243 return test::ResourcePath(ss.str(), "pcm");
244}
245
246std::string OutputFilePath(std::string name,
andrew@webrtc.orgf26c9e82014-04-24 03:46:46247 int input_rate,
248 int output_rate,
249 int reverse_rate,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04250 int num_input_channels,
251 int num_output_channels,
252 int num_reverse_channels) {
253 std::ostringstream ss;
andrew@webrtc.orgf26c9e82014-04-24 03:46:46254 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000
255 << "_r" << num_reverse_channels << "_" << reverse_rate / 1000 << "_";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04256 if (num_output_channels == 1) {
257 ss << "mono";
258 } else if (num_output_channels == 2) {
259 ss << "stereo";
260 } else {
261 assert(false);
262 }
andrew@webrtc.orgf26c9e82014-04-24 03:46:46263 ss << output_rate / 1000 << ".pcm";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04264
265 return test::OutputPath() + ss.str();
266}
267
andrew@webrtc.orga8b97372014-03-10 22:26:12268void OpenFileAndReadMessage(const std::string filename,
269 ::google::protobuf::MessageLite* msg) {
andrew@webrtc.org81865342012-10-27 00:28:27270 FILE* file = fopen(filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12271 ASSERT_TRUE(file != NULL);
272 ReadMessageFromFile(file, msg);
andrew@webrtc.org81865342012-10-27 00:28:27273 fclose(file);
274}
275
niklase@google.com470e71d2011-07-07 08:21:25276class ApmTest : public ::testing::Test {
277 protected:
278 ApmTest();
279 virtual void SetUp();
280 virtual void TearDown();
andrew@webrtc.org755b04a2011-11-15 16:57:56281
282 static void SetUpTestCase() {
283 Trace::CreateTrace();
andrew@webrtc.org27c69802014-02-18 20:24:56284 std::string trace_filename = test::OutputPath() + "audioproc_trace.txt";
andrew@webrtc.org755b04a2011-11-15 16:57:56285 ASSERT_EQ(0, Trace::SetTraceFile(trace_filename.c_str()));
286 }
287
288 static void TearDownTestCase() {
289 Trace::ReturnTrace();
290 }
andrew@webrtc.orgdaacee82012-02-07 00:01:04291
andrew@webrtc.orga8b97372014-03-10 22:26:12292 // Used to select between int and float interface tests.
293 enum Format {
294 kIntFormat,
295 kFloatFormat
296 };
297
298 void Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04299 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12300 int reverse_sample_rate_hz,
301 int num_reverse_channels,
302 int num_input_channels,
303 int num_output_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04304 bool open_output_file);
andrew@webrtc.org17e40642014-03-04 20:58:13305 void Init(AudioProcessing* ap);
andrew@webrtc.org07bf9a02012-05-05 00:32:00306 void EnableAllComponents();
307 bool ReadFrame(FILE* file, AudioFrame* frame);
andrew@webrtc.org17e40642014-03-04 20:58:13308 bool ReadFrame(FILE* file, AudioFrame* frame, ChannelBuffer<float>* cb);
andrew@webrtc.org27c69802014-02-18 20:24:56309 void ReadFrameWithRewind(FILE* file, AudioFrame* frame);
andrew@webrtc.org17e40642014-03-04 20:58:13310 void ReadFrameWithRewind(FILE* file, AudioFrame* frame,
311 ChannelBuffer<float>* cb);
andrew@webrtc.org81865342012-10-27 00:28:27312 void ProcessWithDefaultStreamParameters(AudioFrame* frame);
bjornv@webrtc.org3e102492013-02-14 15:29:09313 void ProcessDelayVerificationTest(int delay_ms, int system_delay_ms,
314 int delay_min, int delay_max);
andrew@webrtc.org60730cf2014-01-07 17:45:09315 void TestChangingChannels(int num_channels,
316 AudioProcessing::Error expected_return);
andrew@webrtc.org27c69802014-02-18 20:24:56317 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate);
318 void RunManualVolumeChangeIsPossibleTest(int sample_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12319 void StreamParametersTest(Format format);
andrew@webrtc.orga8b97372014-03-10 22:26:12320 int ProcessStreamChooser(Format format);
321 int AnalyzeReverseStreamChooser(Format format);
322 void ProcessDebugDump(const std::string& in_filename,
323 const std::string& out_filename,
324 Format format);
325 void VerifyDebugDumpTest(Format format);
andrew@webrtc.orgdaacee82012-02-07 00:01:04326
327 const std::string output_path_;
328 const std::string ref_path_;
329 const std::string ref_filename_;
andrew@webrtc.org27c69802014-02-18 20:24:56330 scoped_ptr<AudioProcessing> apm_;
andrew@webrtc.orgf3930e92013-09-18 22:37:32331 AudioFrame* frame_;
332 AudioFrame* revframe_;
andrew@webrtc.org17e40642014-03-04 20:58:13333 scoped_ptr<ChannelBuffer<float> > float_cb_;
334 scoped_ptr<ChannelBuffer<float> > revfloat_cb_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04335 int output_sample_rate_hz_;
andrew@webrtc.orga8b97372014-03-10 22:26:12336 int num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25337 FILE* far_file_;
338 FILE* near_file_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04339 FILE* out_file_;
niklase@google.com470e71d2011-07-07 08:21:25340};
341
342ApmTest::ApmTest()
andrew@webrtc.org27c69802014-02-18 20:24:56343 : output_path_(test::OutputPath()),
344 ref_path_(test::ProjectRootPath() + "data/audio_processing/"),
andrew@webrtc.org293d22b2012-01-30 22:04:26345#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
andrew@webrtc.orgdaacee82012-02-07 00:01:04346 ref_filename_(ref_path_ + "output_data_fixed.pb"),
andrew@webrtc.org293d22b2012-01-30 22:04:26347#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
andrew@webrtc.orgdaacee82012-02-07 00:01:04348 ref_filename_(ref_path_ + "output_data_float.pb"),
kjellander@webrtc.org61f07c32011-10-18 06:54:58349#endif
niklase@google.com470e71d2011-07-07 08:21:25350 frame_(NULL),
ajm@google.com22e65152011-07-18 18:03:01351 revframe_(NULL),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04352 output_sample_rate_hz_(0),
andrew@webrtc.orga8b97372014-03-10 22:26:12353 num_output_channels_(0),
ajm@google.com22e65152011-07-18 18:03:01354 far_file_(NULL),
andrew@webrtc.orgdaacee82012-02-07 00:01:04355 near_file_(NULL),
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57356 out_file_(NULL) {
357 Config config;
358 config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
359 apm_.reset(AudioProcessing::Create(config));
360}
niklase@google.com470e71d2011-07-07 08:21:25361
362void ApmTest::SetUp() {
andrew@webrtc.orgf3930e92013-09-18 22:37:32363 ASSERT_TRUE(apm_.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25364
365 frame_ = new AudioFrame();
366 revframe_ = new AudioFrame();
367
andrew@webrtc.orgd3350942014-01-07 18:57:10368#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04369 Init(16000, 16000, 16000, 2, 2, 2, false);
andrew@webrtc.orgd3350942014-01-07 18:57:10370#else
andrew@webrtc.orgddbb8a22014-04-22 21:00:04371 Init(32000, 32000, 32000, 2, 2, 2, false);
andrew@webrtc.orgd3350942014-01-07 18:57:10372#endif
niklase@google.com470e71d2011-07-07 08:21:25373}
374
375void ApmTest::TearDown() {
376 if (frame_) {
377 delete frame_;
378 }
379 frame_ = NULL;
380
381 if (revframe_) {
382 delete revframe_;
383 }
384 revframe_ = NULL;
385
386 if (far_file_) {
387 ASSERT_EQ(0, fclose(far_file_));
388 }
389 far_file_ = NULL;
390
391 if (near_file_) {
392 ASSERT_EQ(0, fclose(near_file_));
393 }
394 near_file_ = NULL;
395
andrew@webrtc.orgdaacee82012-02-07 00:01:04396 if (out_file_) {
397 ASSERT_EQ(0, fclose(out_file_));
398 }
399 out_file_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25400}
401
andrew@webrtc.org17e40642014-03-04 20:58:13402void ApmTest::Init(AudioProcessing* ap) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04403 ASSERT_EQ(kNoErr,
404 ap->Initialize(frame_->sample_rate_hz_,
405 output_sample_rate_hz_,
406 revframe_->sample_rate_hz_,
407 LayoutFromChannels(frame_->num_channels_),
408 LayoutFromChannels(num_output_channels_),
409 LayoutFromChannels(revframe_->num_channels_)));
andrew@webrtc.org17e40642014-03-04 20:58:13410}
411
andrew@webrtc.orga8b97372014-03-10 22:26:12412void ApmTest::Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04413 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12414 int reverse_sample_rate_hz,
415 int num_input_channels,
416 int num_output_channels,
417 int num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04418 bool open_output_file) {
andrew@webrtc.orga8b97372014-03-10 22:26:12419 SetContainerFormat(sample_rate_hz, num_input_channels, frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04420 output_sample_rate_hz_ = output_sample_rate_hz;
andrew@webrtc.orga8b97372014-03-10 22:26:12421 num_output_channels_ = num_output_channels;
andrew@webrtc.orgdaacee82012-02-07 00:01:04422
andrew@webrtc.orga8b97372014-03-10 22:26:12423 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, revframe_,
424 &revfloat_cb_);
andrew@webrtc.org17e40642014-03-04 20:58:13425 Init(apm_.get());
andrew@webrtc.org60730cf2014-01-07 17:45:09426
andrew@webrtc.orgdaacee82012-02-07 00:01:04427 if (far_file_) {
428 ASSERT_EQ(0, fclose(far_file_));
429 }
430 std::string filename = ResourceFilePath("far", sample_rate_hz);
431 far_file_ = fopen(filename.c_str(), "rb");
432 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " <<
433 filename << "\n";
434
435 if (near_file_) {
436 ASSERT_EQ(0, fclose(near_file_));
437 }
438 filename = ResourceFilePath("near", sample_rate_hz);
439 near_file_ = fopen(filename.c_str(), "rb");
440 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " <<
441 filename << "\n";
442
443 if (open_output_file) {
444 if (out_file_) {
445 ASSERT_EQ(0, fclose(out_file_));
446 }
andrew@webrtc.orgf26c9e82014-04-24 03:46:46447 filename = OutputFilePath("out",
448 sample_rate_hz,
449 output_sample_rate_hz,
450 reverse_sample_rate_hz,
451 num_input_channels,
452 num_output_channels,
453 num_reverse_channels);
andrew@webrtc.orgdaacee82012-02-07 00:01:04454 out_file_ = fopen(filename.c_str(), "wb");
455 ASSERT_TRUE(out_file_ != NULL) << "Could not open file " <<
456 filename << "\n";
457 }
458}
459
andrew@webrtc.org07bf9a02012-05-05 00:32:00460void ApmTest::EnableAllComponents() {
andrew@webrtc.org17e40642014-03-04 20:58:13461 EnableAllAPComponents(apm_.get());
andrew@webrtc.org07bf9a02012-05-05 00:32:00462}
463
andrew@webrtc.org17e40642014-03-04 20:58:13464bool ApmTest::ReadFrame(FILE* file, AudioFrame* frame,
465 ChannelBuffer<float>* cb) {
andrew@webrtc.org07bf9a02012-05-05 00:32:00466 // The files always contain stereo audio.
467 size_t frame_size = frame->samples_per_channel_ * 2;
468 size_t read_count = fread(frame->data_,
469 sizeof(int16_t),
470 frame_size,
471 file);
472 if (read_count != frame_size) {
473 // Check that the file really ended.
474 EXPECT_NE(0, feof(file));
475 return false; // This is expected.
476 }
477
478 if (frame->num_channels_ == 1) {
479 MixStereoToMono(frame->data_, frame->data_,
480 frame->samples_per_channel_);
481 }
482
andrew@webrtc.org17e40642014-03-04 20:58:13483 if (cb) {
andrew@webrtc.orga8b97372014-03-10 22:26:12484 ConvertToFloat(*frame, cb);
andrew@webrtc.org17e40642014-03-04 20:58:13485 }
andrew@webrtc.org07bf9a02012-05-05 00:32:00486 return true;
ajm@google.coma769fa52011-07-13 21:57:58487}
488
andrew@webrtc.org17e40642014-03-04 20:58:13489bool ApmTest::ReadFrame(FILE* file, AudioFrame* frame) {
490 return ReadFrame(file, frame, NULL);
491}
492
andrew@webrtc.org27c69802014-02-18 20:24:56493// If the end of the file has been reached, rewind it and attempt to read the
494// frame again.
andrew@webrtc.org17e40642014-03-04 20:58:13495void ApmTest::ReadFrameWithRewind(FILE* file, AudioFrame* frame,
496 ChannelBuffer<float>* cb) {
497 if (!ReadFrame(near_file_, frame_, cb)) {
andrew@webrtc.org27c69802014-02-18 20:24:56498 rewind(near_file_);
andrew@webrtc.org17e40642014-03-04 20:58:13499 ASSERT_TRUE(ReadFrame(near_file_, frame_, cb));
andrew@webrtc.org27c69802014-02-18 20:24:56500 }
501}
502
andrew@webrtc.org17e40642014-03-04 20:58:13503void ApmTest::ReadFrameWithRewind(FILE* file, AudioFrame* frame) {
504 ReadFrameWithRewind(file, frame, NULL);
505}
506
andrew@webrtc.org81865342012-10-27 00:28:27507void ApmTest::ProcessWithDefaultStreamParameters(AudioFrame* frame) {
508 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:28509 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org81865342012-10-27 00:28:27510 EXPECT_EQ(apm_->kNoError,
511 apm_->gain_control()->set_stream_analog_level(127));
512 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame));
andrew@webrtc.org755b04a2011-11-15 16:57:56513}
514
andrew@webrtc.orga8b97372014-03-10 22:26:12515int ApmTest::ProcessStreamChooser(Format format) {
516 if (format == kIntFormat) {
andrew@webrtc.org17e40642014-03-04 20:58:13517 return apm_->ProcessStream(frame_);
518 }
andrew@webrtc.org17e40642014-03-04 20:58:13519 return apm_->ProcessStream(float_cb_->channels(),
520 frame_->samples_per_channel_,
521 frame_->sample_rate_hz_,
522 LayoutFromChannels(frame_->num_channels_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04523 output_sample_rate_hz_,
524 LayoutFromChannels(num_output_channels_),
525 float_cb_->channels());
andrew@webrtc.org17e40642014-03-04 20:58:13526}
527
andrew@webrtc.orga8b97372014-03-10 22:26:12528int ApmTest::AnalyzeReverseStreamChooser(Format format) {
529 if (format == kIntFormat) {
andrew@webrtc.org17e40642014-03-04 20:58:13530 return apm_->AnalyzeReverseStream(revframe_);
531 }
andrew@webrtc.org17e40642014-03-04 20:58:13532 return apm_->AnalyzeReverseStream(
533 revfloat_cb_->channels(),
534 revframe_->samples_per_channel_,
535 revframe_->sample_rate_hz_,
536 LayoutFromChannels(revframe_->num_channels_));
537}
538
bjornv@webrtc.org3e102492013-02-14 15:29:09539void ApmTest::ProcessDelayVerificationTest(int delay_ms, int system_delay_ms,
540 int delay_min, int delay_max) {
541 // The |revframe_| and |frame_| should include the proper frame information,
542 // hence can be used for extracting information.
andrew@webrtc.org27c69802014-02-18 20:24:56543 AudioFrame tmp_frame;
544 std::queue<AudioFrame*> frame_queue;
bjornv@webrtc.org3e102492013-02-14 15:29:09545 bool causal = true;
546
547 tmp_frame.CopyFrom(*revframe_);
548 SetFrameTo(&tmp_frame, 0);
549
550 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
551 // Initialize the |frame_queue| with empty frames.
552 int frame_delay = delay_ms / 10;
553 while (frame_delay < 0) {
andrew@webrtc.org27c69802014-02-18 20:24:56554 AudioFrame* frame = new AudioFrame();
bjornv@webrtc.org3e102492013-02-14 15:29:09555 frame->CopyFrom(tmp_frame);
556 frame_queue.push(frame);
557 frame_delay++;
558 causal = false;
559 }
560 while (frame_delay > 0) {
andrew@webrtc.org27c69802014-02-18 20:24:56561 AudioFrame* frame = new AudioFrame();
bjornv@webrtc.org3e102492013-02-14 15:29:09562 frame->CopyFrom(tmp_frame);
563 frame_queue.push(frame);
564 frame_delay--;
565 }
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34566 // Run for 4.5 seconds, skipping statistics from the first 2.5 seconds. We
567 // need enough frames with audio to have reliable estimates, but as few as
568 // possible to keep processing time down. 4.5 seconds seemed to be a good
569 // compromise for this recording.
bjornv@webrtc.org3e102492013-02-14 15:29:09570 for (int frame_count = 0; frame_count < 450; ++frame_count) {
andrew@webrtc.org27c69802014-02-18 20:24:56571 AudioFrame* frame = new AudioFrame();
bjornv@webrtc.org3e102492013-02-14 15:29:09572 frame->CopyFrom(tmp_frame);
573 // Use the near end recording, since that has more speech in it.
574 ASSERT_TRUE(ReadFrame(near_file_, frame));
575 frame_queue.push(frame);
andrew@webrtc.org27c69802014-02-18 20:24:56576 AudioFrame* reverse_frame = frame;
577 AudioFrame* process_frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09578 if (!causal) {
579 reverse_frame = frame_queue.front();
580 // When we call ProcessStream() the frame is modified, so we can't use the
581 // pointer directly when things are non-causal. Use an intermediate frame
582 // and copy the data.
583 process_frame = &tmp_frame;
584 process_frame->CopyFrom(*frame);
585 }
586 EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(reverse_frame));
587 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
588 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(process_frame));
589 frame = frame_queue.front();
590 frame_queue.pop();
591 delete frame;
592
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34593 if (frame_count == 250) {
bjornv@webrtc.org3e102492013-02-14 15:29:09594 int median;
595 int std;
596 // Discard the first delay metrics to avoid convergence effects.
597 EXPECT_EQ(apm_->kNoError,
598 apm_->echo_cancellation()->GetDelayMetrics(&median, &std));
599 }
600 }
601
602 rewind(near_file_);
603 while (!frame_queue.empty()) {
andrew@webrtc.org27c69802014-02-18 20:24:56604 AudioFrame* frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09605 frame_queue.pop();
606 delete frame;
607 }
608 // Calculate expected delay estimate and acceptable regions. Further,
609 // limit them w.r.t. AEC delay estimation support.
610 const int samples_per_ms = std::min(16, frame_->samples_per_channel_ / 10);
611 int expected_median = std::min(std::max(delay_ms - system_delay_ms,
612 delay_min), delay_max);
613 int expected_median_high = std::min(std::max(
614 expected_median + 96 / samples_per_ms, delay_min), delay_max);
615 int expected_median_low = std::min(std::max(
616 expected_median - 96 / samples_per_ms, delay_min), delay_max);
617 // Verify delay metrics.
618 int median;
619 int std;
620 EXPECT_EQ(apm_->kNoError,
621 apm_->echo_cancellation()->GetDelayMetrics(&median, &std));
622 EXPECT_GE(expected_median_high, median);
623 EXPECT_LE(expected_median_low, median);
624}
625
andrew@webrtc.orga8b97372014-03-10 22:26:12626void ApmTest::StreamParametersTest(Format format) {
niklase@google.com470e71d2011-07-07 08:21:25627 // No errors when the components are disabled.
andrew@webrtc.orga8b97372014-03-10 22:26:12628 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25629
andrew@webrtc.org1e916932011-11-29 18:28:57630 // -- Missing AGC level --
niklase@google.com470e71d2011-07-07 08:21:25631 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
andrew@webrtc.org17e40642014-03-04 20:58:13632 EXPECT_EQ(apm_->kStreamParameterNotSetError,
andrew@webrtc.orga8b97372014-03-10 22:26:12633 ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25634
andrew@webrtc.org1e916932011-11-29 18:28:57635 // Resets after successful ProcessStream().
niklase@google.com470e71d2011-07-07 08:21:25636 EXPECT_EQ(apm_->kNoError,
637 apm_->gain_control()->set_stream_analog_level(127));
andrew@webrtc.orga8b97372014-03-10 22:26:12638 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13639 EXPECT_EQ(apm_->kStreamParameterNotSetError,
andrew@webrtc.orga8b97372014-03-10 22:26:12640 ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25641
andrew@webrtc.org1e916932011-11-29 18:28:57642 // Other stream parameters set correctly.
643 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25644 EXPECT_EQ(apm_->kNoError,
645 apm_->echo_cancellation()->enable_drift_compensation(true));
andrew@webrtc.org1e916932011-11-29 18:28:57646 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.org6be1e932013-03-01 18:47:28647 apm_->echo_cancellation()->set_stream_drift_samples(0);
niklase@google.com470e71d2011-07-07 08:21:25648 EXPECT_EQ(apm_->kStreamParameterNotSetError,
andrew@webrtc.orga8b97372014-03-10 22:26:12649 ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57650 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false));
651 EXPECT_EQ(apm_->kNoError,
652 apm_->echo_cancellation()->enable_drift_compensation(false));
653
654 // -- Missing delay --
andrew@webrtc.org1e916932011-11-29 18:28:57655 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
andrew@webrtc.orga8b97372014-03-10 22:26:12656 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13657 EXPECT_EQ(apm_->kStreamParameterNotSetError,
andrew@webrtc.orga8b97372014-03-10 22:26:12658 ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57659
660 // Resets after successful ProcessStream().
661 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.orga8b97372014-03-10 22:26:12662 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13663 EXPECT_EQ(apm_->kStreamParameterNotSetError,
andrew@webrtc.orga8b97372014-03-10 22:26:12664 ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57665
666 // Other stream parameters set correctly.
667 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
668 EXPECT_EQ(apm_->kNoError,
669 apm_->echo_cancellation()->enable_drift_compensation(true));
andrew@webrtc.org6be1e932013-03-01 18:47:28670 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org1e916932011-11-29 18:28:57671 EXPECT_EQ(apm_->kNoError,
672 apm_->gain_control()->set_stream_analog_level(127));
andrew@webrtc.org17e40642014-03-04 20:58:13673 EXPECT_EQ(apm_->kStreamParameterNotSetError,
andrew@webrtc.orga8b97372014-03-10 22:26:12674 ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57675 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false));
676
677 // -- Missing drift --
andrew@webrtc.org17e40642014-03-04 20:58:13678 EXPECT_EQ(apm_->kStreamParameterNotSetError,
andrew@webrtc.orga8b97372014-03-10 22:26:12679 ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57680
681 // Resets after successful ProcessStream().
682 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.org6be1e932013-03-01 18:47:28683 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.orga8b97372014-03-10 22:26:12684 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13685 EXPECT_EQ(apm_->kStreamParameterNotSetError,
andrew@webrtc.orga8b97372014-03-10 22:26:12686 ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57687
688 // Other stream parameters set correctly.
niklase@google.com470e71d2011-07-07 08:21:25689 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
690 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
691 EXPECT_EQ(apm_->kNoError,
692 apm_->gain_control()->set_stream_analog_level(127));
andrew@webrtc.org17e40642014-03-04 20:58:13693 EXPECT_EQ(apm_->kStreamParameterNotSetError,
andrew@webrtc.orga8b97372014-03-10 22:26:12694 ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25695
andrew@webrtc.org1e916932011-11-29 18:28:57696 // -- No stream parameters --
niklase@google.com470e71d2011-07-07 08:21:25697 EXPECT_EQ(apm_->kNoError,
andrew@webrtc.orga8b97372014-03-10 22:26:12698 AnalyzeReverseStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25699 EXPECT_EQ(apm_->kStreamParameterNotSetError,
andrew@webrtc.orga8b97372014-03-10 22:26:12700 ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25701
andrew@webrtc.org1e916932011-11-29 18:28:57702 // -- All there --
niklase@google.com470e71d2011-07-07 08:21:25703 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.org6be1e932013-03-01 18:47:28704 apm_->echo_cancellation()->set_stream_drift_samples(0);
niklase@google.com470e71d2011-07-07 08:21:25705 EXPECT_EQ(apm_->kNoError,
706 apm_->gain_control()->set_stream_analog_level(127));
andrew@webrtc.orga8b97372014-03-10 22:26:12707 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13708}
709
710TEST_F(ApmTest, StreamParametersInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12711 StreamParametersTest(kIntFormat);
andrew@webrtc.org17e40642014-03-04 20:58:13712}
713
714TEST_F(ApmTest, StreamParametersFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12715 StreamParametersTest(kFloatFormat);
niklase@google.com470e71d2011-07-07 08:21:25716}
717
andrew@webrtc.org5f23d642012-05-29 21:14:06718TEST_F(ApmTest, DefaultDelayOffsetIsZero) {
719 EXPECT_EQ(0, apm_->delay_offset_ms());
720 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(50));
721 EXPECT_EQ(50, apm_->stream_delay_ms());
722}
723
724TEST_F(ApmTest, DelayOffsetWithLimitsIsSetProperly) {
725 // High limit of 500 ms.
andrew@webrtc.org6f9f8172012-03-06 19:03:39726 apm_->set_delay_offset_ms(100);
727 EXPECT_EQ(100, apm_->delay_offset_ms());
728 EXPECT_EQ(apm_->kBadStreamParameterWarning, apm_->set_stream_delay_ms(450));
andrew@webrtc.org5f23d642012-05-29 21:14:06729 EXPECT_EQ(500, apm_->stream_delay_ms());
andrew@webrtc.org6f9f8172012-03-06 19:03:39730 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
731 EXPECT_EQ(200, apm_->stream_delay_ms());
732
andrew@webrtc.org5f23d642012-05-29 21:14:06733 // Low limit of 0 ms.
andrew@webrtc.org6f9f8172012-03-06 19:03:39734 apm_->set_delay_offset_ms(-50);
735 EXPECT_EQ(-50, apm_->delay_offset_ms());
andrew@webrtc.org5f23d642012-05-29 21:14:06736 EXPECT_EQ(apm_->kBadStreamParameterWarning, apm_->set_stream_delay_ms(20));
737 EXPECT_EQ(0, apm_->stream_delay_ms());
andrew@webrtc.org6f9f8172012-03-06 19:03:39738 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
739 EXPECT_EQ(50, apm_->stream_delay_ms());
740}
741
andrew@webrtc.org60730cf2014-01-07 17:45:09742void ApmTest::TestChangingChannels(int num_channels,
743 AudioProcessing::Error expected_return) {
744 frame_->num_channels_ = num_channels;
745 EXPECT_EQ(expected_return, apm_->ProcessStream(frame_));
746 EXPECT_EQ(expected_return, apm_->AnalyzeReverseStream(frame_));
747}
748
niklase@google.com470e71d2011-07-07 08:21:25749TEST_F(ApmTest, Channels) {
andrew@webrtc.org60730cf2014-01-07 17:45:09750 // Testing number of invalid channels.
751 TestChangingChannels(0, apm_->kBadNumberChannelsError);
752 TestChangingChannels(3, apm_->kBadNumberChannelsError);
753 // Testing number of valid channels.
niklase@google.com470e71d2011-07-07 08:21:25754 for (int i = 1; i < 3; i++) {
andrew@webrtc.org60730cf2014-01-07 17:45:09755 TestChangingChannels(i, kNoErr);
niklase@google.com470e71d2011-07-07 08:21:25756 EXPECT_EQ(i, apm_->num_input_channels());
niklase@google.com470e71d2011-07-07 08:21:25757 EXPECT_EQ(i, apm_->num_reverse_channels());
758 }
759}
760
andrew@webrtc.orgddbb8a22014-04-22 21:00:04761TEST_F(ApmTest, SampleRatesInt) {
niklase@google.com470e71d2011-07-07 08:21:25762 // Testing invalid sample rates
andrew@webrtc.orga8b97372014-03-10 22:26:12763 SetContainerFormat(10000, 2, frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04764 EXPECT_EQ(apm_->kBadSampleRateError, ProcessStreamChooser(kIntFormat));
niklase@google.com470e71d2011-07-07 08:21:25765 // Testing valid sample rates
766 int fs[] = {8000, 16000, 32000};
767 for (size_t i = 0; i < sizeof(fs) / sizeof(*fs); i++) {
andrew@webrtc.orga8b97372014-03-10 22:26:12768 SetContainerFormat(fs[i], 2, frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04769 EXPECT_NOERR(ProcessStreamChooser(kIntFormat));
770 EXPECT_EQ(fs[i], apm_->input_sample_rate_hz());
niklase@google.com470e71d2011-07-07 08:21:25771 }
772}
773
niklase@google.com470e71d2011-07-07 08:21:25774TEST_F(ApmTest, EchoCancellation) {
775 EXPECT_EQ(apm_->kNoError,
776 apm_->echo_cancellation()->enable_drift_compensation(true));
777 EXPECT_TRUE(apm_->echo_cancellation()->is_drift_compensation_enabled());
778 EXPECT_EQ(apm_->kNoError,
779 apm_->echo_cancellation()->enable_drift_compensation(false));
780 EXPECT_FALSE(apm_->echo_cancellation()->is_drift_compensation_enabled());
781
niklase@google.com470e71d2011-07-07 08:21:25782 EchoCancellation::SuppressionLevel level[] = {
783 EchoCancellation::kLowSuppression,
784 EchoCancellation::kModerateSuppression,
785 EchoCancellation::kHighSuppression,
786 };
787 for (size_t i = 0; i < sizeof(level)/sizeof(*level); i++) {
788 EXPECT_EQ(apm_->kNoError,
789 apm_->echo_cancellation()->set_suppression_level(level[i]));
790 EXPECT_EQ(level[i],
791 apm_->echo_cancellation()->suppression_level());
792 }
793
794 EchoCancellation::Metrics metrics;
795 EXPECT_EQ(apm_->kNotEnabledError,
796 apm_->echo_cancellation()->GetMetrics(&metrics));
797
798 EXPECT_EQ(apm_->kNoError,
799 apm_->echo_cancellation()->enable_metrics(true));
800 EXPECT_TRUE(apm_->echo_cancellation()->are_metrics_enabled());
801 EXPECT_EQ(apm_->kNoError,
802 apm_->echo_cancellation()->enable_metrics(false));
803 EXPECT_FALSE(apm_->echo_cancellation()->are_metrics_enabled());
804
bjornv@google.com1ba3dbe2011-10-03 08:18:10805 int median = 0;
806 int std = 0;
807 EXPECT_EQ(apm_->kNotEnabledError,
808 apm_->echo_cancellation()->GetDelayMetrics(&median, &std));
809
810 EXPECT_EQ(apm_->kNoError,
811 apm_->echo_cancellation()->enable_delay_logging(true));
812 EXPECT_TRUE(apm_->echo_cancellation()->is_delay_logging_enabled());
813 EXPECT_EQ(apm_->kNoError,
814 apm_->echo_cancellation()->enable_delay_logging(false));
815 EXPECT_FALSE(apm_->echo_cancellation()->is_delay_logging_enabled());
816
niklase@google.com470e71d2011-07-07 08:21:25817 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
818 EXPECT_TRUE(apm_->echo_cancellation()->is_enabled());
819 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
820 EXPECT_FALSE(apm_->echo_cancellation()->is_enabled());
bjornv@webrtc.org91d11b32013-03-05 16:53:09821
822 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
823 EXPECT_TRUE(apm_->echo_cancellation()->is_enabled());
824 EXPECT_TRUE(apm_->echo_cancellation()->aec_core() != NULL);
825 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
826 EXPECT_FALSE(apm_->echo_cancellation()->is_enabled());
827 EXPECT_FALSE(apm_->echo_cancellation()->aec_core() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25828}
829
bjornv@webrtc.org3e102492013-02-14 15:29:09830TEST_F(ApmTest, EchoCancellationReportsCorrectDelays) {
831 // Enable AEC only.
832 EXPECT_EQ(apm_->kNoError,
833 apm_->echo_cancellation()->enable_drift_compensation(false));
834 EXPECT_EQ(apm_->kNoError,
835 apm_->echo_cancellation()->enable_metrics(false));
836 EXPECT_EQ(apm_->kNoError,
837 apm_->echo_cancellation()->enable_delay_logging(true));
838 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
839
840 // Internally in the AEC the amount of lookahead the delay estimation can
841 // handle is 15 blocks and the maximum delay is set to 60 blocks.
842 const int kLookaheadBlocks = 15;
843 const int kMaxDelayBlocks = 60;
844 // The AEC has a startup time before it actually starts to process. This
845 // procedure can flush the internal far-end buffer, which of course affects
846 // the delay estimation. Therefore, we set a system_delay high enough to
847 // avoid that. The smallest system_delay you can report without flushing the
848 // buffer is 66 ms in 8 kHz.
849 //
850 // It is known that for 16 kHz (and 32 kHz) sampling frequency there is an
851 // additional stuffing of 8 ms on the fly, but it seems to have no impact on
852 // delay estimation. This should be noted though. In case of test failure,
853 // this could be the cause.
854 const int kSystemDelayMs = 66;
855 // Test a couple of corner cases and verify that the estimated delay is
856 // within a valid region (set to +-1.5 blocks). Note that these cases are
857 // sampling frequency dependent.
858 for (size_t i = 0; i < kProcessSampleRatesSize; i++) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04859 Init(kProcessSampleRates[i],
860 kProcessSampleRates[i],
861 kProcessSampleRates[i],
862 2,
863 2,
864 2,
865 false);
bjornv@webrtc.org3e102492013-02-14 15:29:09866 // Sampling frequency dependent variables.
867 const int num_ms_per_block = std::max(4,
andrew@webrtc.org60730cf2014-01-07 17:45:09868 640 / frame_->samples_per_channel_);
bjornv@webrtc.org3e102492013-02-14 15:29:09869 const int delay_min_ms = -kLookaheadBlocks * num_ms_per_block;
870 const int delay_max_ms = (kMaxDelayBlocks - 1) * num_ms_per_block;
871
872 // 1) Verify correct delay estimate at lookahead boundary.
873 int delay_ms = TruncateToMultipleOf10(kSystemDelayMs + delay_min_ms);
874 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
875 delay_max_ms);
876 // 2) A delay less than maximum lookahead should give an delay estimate at
877 // the boundary (= -kLookaheadBlocks * num_ms_per_block).
878 delay_ms -= 20;
879 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
880 delay_max_ms);
881 // 3) Three values around zero delay. Note that we need to compensate for
882 // the fake system_delay.
883 delay_ms = TruncateToMultipleOf10(kSystemDelayMs - 10);
884 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
885 delay_max_ms);
886 delay_ms = TruncateToMultipleOf10(kSystemDelayMs);
887 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
888 delay_max_ms);
889 delay_ms = TruncateToMultipleOf10(kSystemDelayMs + 10);
890 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
891 delay_max_ms);
892 // 4) Verify correct delay estimate at maximum delay boundary.
893 delay_ms = TruncateToMultipleOf10(kSystemDelayMs + delay_max_ms);
894 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
895 delay_max_ms);
896 // 5) A delay above the maximum delay should give an estimate at the
897 // boundary (= (kMaxDelayBlocks - 1) * num_ms_per_block).
898 delay_ms += 20;
899 ProcessDelayVerificationTest(delay_ms, kSystemDelayMs, delay_min_ms,
900 delay_max_ms);
901 }
902}
903
niklase@google.com470e71d2011-07-07 08:21:25904TEST_F(ApmTest, EchoControlMobile) {
905 // AECM won't use super-wideband.
andrew@webrtc.org60730cf2014-01-07 17:45:09906 SetFrameSampleRate(frame_, 32000);
andrew@webrtc.orga8b97372014-03-10 22:26:12907 EXPECT_NOERR(apm_->ProcessStream(frame_));
bjornv@webrtc.org3e102492013-02-14 15:29:09908 EXPECT_EQ(apm_->kBadSampleRateError,
909 apm_->echo_control_mobile()->Enable(true));
andrew@webrtc.org60730cf2014-01-07 17:45:09910 SetFrameSampleRate(frame_, 16000);
andrew@webrtc.orga8b97372014-03-10 22:26:12911 EXPECT_NOERR(apm_->ProcessStream(frame_));
andrew@webrtc.org78693fe2013-03-01 16:36:19912 EXPECT_EQ(apm_->kNoError,
913 apm_->echo_control_mobile()->Enable(true));
andrew@webrtc.org60730cf2014-01-07 17:45:09914 SetFrameSampleRate(frame_, 32000);
915 EXPECT_EQ(apm_->kUnsupportedComponentError, apm_->ProcessStream(frame_));
andrew@webrtc.org78693fe2013-03-01 16:36:19916
niklase@google.com470e71d2011-07-07 08:21:25917 // Turn AECM on (and AEC off)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04918 Init(16000, 16000, 16000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25919 EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true));
920 EXPECT_TRUE(apm_->echo_control_mobile()->is_enabled());
921
niklase@google.com470e71d2011-07-07 08:21:25922 // Toggle routing modes
923 EchoControlMobile::RoutingMode mode[] = {
924 EchoControlMobile::kQuietEarpieceOrHeadset,
925 EchoControlMobile::kEarpiece,
926 EchoControlMobile::kLoudEarpiece,
927 EchoControlMobile::kSpeakerphone,
928 EchoControlMobile::kLoudSpeakerphone,
929 };
930 for (size_t i = 0; i < sizeof(mode)/sizeof(*mode); i++) {
931 EXPECT_EQ(apm_->kNoError,
932 apm_->echo_control_mobile()->set_routing_mode(mode[i]));
933 EXPECT_EQ(mode[i],
934 apm_->echo_control_mobile()->routing_mode());
935 }
936 // Turn comfort noise off/on
937 EXPECT_EQ(apm_->kNoError,
938 apm_->echo_control_mobile()->enable_comfort_noise(false));
939 EXPECT_FALSE(apm_->echo_control_mobile()->is_comfort_noise_enabled());
940 EXPECT_EQ(apm_->kNoError,
941 apm_->echo_control_mobile()->enable_comfort_noise(true));
942 EXPECT_TRUE(apm_->echo_control_mobile()->is_comfort_noise_enabled());
bjornv@google.comc4b939c2011-07-13 08:09:56943 // Set and get echo path
ajm@google.com22e65152011-07-18 18:03:01944 const size_t echo_path_size =
945 apm_->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04946 scoped_ptr<char[]> echo_path_in(new char[echo_path_size]);
947 scoped_ptr<char[]> echo_path_out(new char[echo_path_size]);
bjornv@google.comc4b939c2011-07-13 08:09:56948 EXPECT_EQ(apm_->kNullPointerError,
949 apm_->echo_control_mobile()->SetEchoPath(NULL, echo_path_size));
950 EXPECT_EQ(apm_->kNullPointerError,
951 apm_->echo_control_mobile()->GetEchoPath(NULL, echo_path_size));
952 EXPECT_EQ(apm_->kBadParameterError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18953 apm_->echo_control_mobile()->GetEchoPath(echo_path_out.get(), 1));
bjornv@google.comc4b939c2011-07-13 08:09:56954 EXPECT_EQ(apm_->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18955 apm_->echo_control_mobile()->GetEchoPath(echo_path_out.get(),
bjornv@google.comc4b939c2011-07-13 08:09:56956 echo_path_size));
ajm@google.com22e65152011-07-18 18:03:01957 for (size_t i = 0; i < echo_path_size; i++) {
bjornv@google.comc4b939c2011-07-13 08:09:56958 echo_path_in[i] = echo_path_out[i] + 1;
959 }
960 EXPECT_EQ(apm_->kBadParameterError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18961 apm_->echo_control_mobile()->SetEchoPath(echo_path_in.get(), 1));
bjornv@google.comc4b939c2011-07-13 08:09:56962 EXPECT_EQ(apm_->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18963 apm_->echo_control_mobile()->SetEchoPath(echo_path_in.get(),
964 echo_path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56965 EXPECT_EQ(apm_->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18966 apm_->echo_control_mobile()->GetEchoPath(echo_path_out.get(),
967 echo_path_size));
ajm@google.com22e65152011-07-18 18:03:01968 for (size_t i = 0; i < echo_path_size; i++) {
bjornv@google.comc4b939c2011-07-13 08:09:56969 EXPECT_EQ(echo_path_in[i], echo_path_out[i]);
970 }
andrew@webrtc.org75f19482012-02-09 17:16:18971
972 // Process a few frames with NS in the default disabled state. This exercises
973 // a different codepath than with it enabled.
974 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
975 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
976 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
977 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
978
niklase@google.com470e71d2011-07-07 08:21:25979 // Turn AECM off
980 EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false));
981 EXPECT_FALSE(apm_->echo_control_mobile()->is_enabled());
982}
983
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57984TEST_F(ApmTest, GainControl) {
niklase@google.com470e71d2011-07-07 08:21:25985 // Testing gain modes
niklase@google.com470e71d2011-07-07 08:21:25986 EXPECT_EQ(apm_->kNoError,
987 apm_->gain_control()->set_mode(
988 apm_->gain_control()->mode()));
989
990 GainControl::Mode mode[] = {
991 GainControl::kAdaptiveAnalog,
992 GainControl::kAdaptiveDigital,
993 GainControl::kFixedDigital
994 };
995 for (size_t i = 0; i < sizeof(mode)/sizeof(*mode); i++) {
996 EXPECT_EQ(apm_->kNoError,
997 apm_->gain_control()->set_mode(mode[i]));
998 EXPECT_EQ(mode[i], apm_->gain_control()->mode());
999 }
1000 // Testing invalid target levels
1001 EXPECT_EQ(apm_->kBadParameterError,
1002 apm_->gain_control()->set_target_level_dbfs(-3));
1003 EXPECT_EQ(apm_->kBadParameterError,
1004 apm_->gain_control()->set_target_level_dbfs(-40));
1005 // Testing valid target levels
1006 EXPECT_EQ(apm_->kNoError,
1007 apm_->gain_control()->set_target_level_dbfs(
1008 apm_->gain_control()->target_level_dbfs()));
1009
1010 int level_dbfs[] = {0, 6, 31};
1011 for (size_t i = 0; i < sizeof(level_dbfs)/sizeof(*level_dbfs); i++) {
1012 EXPECT_EQ(apm_->kNoError,
1013 apm_->gain_control()->set_target_level_dbfs(level_dbfs[i]));
1014 EXPECT_EQ(level_dbfs[i], apm_->gain_control()->target_level_dbfs());
1015 }
1016
1017 // Testing invalid compression gains
1018 EXPECT_EQ(apm_->kBadParameterError,
1019 apm_->gain_control()->set_compression_gain_db(-1));
1020 EXPECT_EQ(apm_->kBadParameterError,
1021 apm_->gain_control()->set_compression_gain_db(100));
1022
1023 // Testing valid compression gains
1024 EXPECT_EQ(apm_->kNoError,
1025 apm_->gain_control()->set_compression_gain_db(
1026 apm_->gain_control()->compression_gain_db()));
1027
1028 int gain_db[] = {0, 10, 90};
1029 for (size_t i = 0; i < sizeof(gain_db)/sizeof(*gain_db); i++) {
1030 EXPECT_EQ(apm_->kNoError,
1031 apm_->gain_control()->set_compression_gain_db(gain_db[i]));
1032 EXPECT_EQ(gain_db[i], apm_->gain_control()->compression_gain_db());
1033 }
1034
1035 // Testing limiter off/on
1036 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->enable_limiter(false));
1037 EXPECT_FALSE(apm_->gain_control()->is_limiter_enabled());
1038 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->enable_limiter(true));
1039 EXPECT_TRUE(apm_->gain_control()->is_limiter_enabled());
1040
1041 // Testing invalid level limits
1042 EXPECT_EQ(apm_->kBadParameterError,
1043 apm_->gain_control()->set_analog_level_limits(-1, 512));
1044 EXPECT_EQ(apm_->kBadParameterError,
1045 apm_->gain_control()->set_analog_level_limits(100000, 512));
1046 EXPECT_EQ(apm_->kBadParameterError,
1047 apm_->gain_control()->set_analog_level_limits(512, -1));
1048 EXPECT_EQ(apm_->kBadParameterError,
1049 apm_->gain_control()->set_analog_level_limits(512, 100000));
1050 EXPECT_EQ(apm_->kBadParameterError,
1051 apm_->gain_control()->set_analog_level_limits(512, 255));
1052
1053 // Testing valid level limits
1054 EXPECT_EQ(apm_->kNoError,
1055 apm_->gain_control()->set_analog_level_limits(
1056 apm_->gain_control()->analog_level_minimum(),
1057 apm_->gain_control()->analog_level_maximum()));
1058
1059 int min_level[] = {0, 255, 1024};
1060 for (size_t i = 0; i < sizeof(min_level)/sizeof(*min_level); i++) {
1061 EXPECT_EQ(apm_->kNoError,
1062 apm_->gain_control()->set_analog_level_limits(min_level[i], 1024));
1063 EXPECT_EQ(min_level[i], apm_->gain_control()->analog_level_minimum());
1064 }
1065
1066 int max_level[] = {0, 1024, 65535};
1067 for (size_t i = 0; i < sizeof(min_level)/sizeof(*min_level); i++) {
1068 EXPECT_EQ(apm_->kNoError,
1069 apm_->gain_control()->set_analog_level_limits(0, max_level[i]));
1070 EXPECT_EQ(max_level[i], apm_->gain_control()->analog_level_maximum());
1071 }
1072
1073 // TODO(ajm): stream_is_saturated() and stream_analog_level()
1074
1075 // Turn AGC off
1076 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false));
1077 EXPECT_FALSE(apm_->gain_control()->is_enabled());
1078}
1079
andrew@webrtc.org27c69802014-02-18 20:24:561080void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:041081 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
andrew@webrtc.org27c69802014-02-18 20:24:561082 EXPECT_EQ(apm_->kNoError,
1083 apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
1084 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
1085
1086 int out_analog_level = 0;
1087 for (int i = 0; i < 2000; ++i) {
1088 ReadFrameWithRewind(near_file_, frame_);
1089 // Ensure the audio is at a low level, so the AGC will try to increase it.
1090 ScaleFrame(frame_, 0.25);
1091
1092 // Always pass in the same volume.
1093 EXPECT_EQ(apm_->kNoError,
1094 apm_->gain_control()->set_stream_analog_level(100));
1095 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1096 out_analog_level = apm_->gain_control()->stream_analog_level();
1097 }
1098
1099 // Ensure the AGC is still able to reach the maximum.
1100 EXPECT_EQ(255, out_analog_level);
1101}
1102
1103// Verifies that despite volume slider quantization, the AGC can continue to
1104// increase its volume.
1105TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
1106 for (size_t i = 0; i < kSampleRatesSize; ++i) {
1107 RunQuantizedVolumeDoesNotGetStuckTest(kSampleRates[i]);
1108 }
1109}
1110
1111void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:041112 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
andrew@webrtc.org27c69802014-02-18 20:24:561113 EXPECT_EQ(apm_->kNoError,
1114 apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
1115 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
1116
1117 int out_analog_level = 100;
1118 for (int i = 0; i < 1000; ++i) {
1119 ReadFrameWithRewind(near_file_, frame_);
1120 // Ensure the audio is at a low level, so the AGC will try to increase it.
1121 ScaleFrame(frame_, 0.25);
1122
1123 EXPECT_EQ(apm_->kNoError,
1124 apm_->gain_control()->set_stream_analog_level(out_analog_level));
1125 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1126 out_analog_level = apm_->gain_control()->stream_analog_level();
1127 }
1128
1129 // Ensure the volume was raised.
1130 EXPECT_GT(out_analog_level, 100);
1131 int highest_level_reached = out_analog_level;
1132 // Simulate a user manual volume change.
1133 out_analog_level = 100;
1134
1135 for (int i = 0; i < 300; ++i) {
1136 ReadFrameWithRewind(near_file_, frame_);
1137 ScaleFrame(frame_, 0.25);
1138
1139 EXPECT_EQ(apm_->kNoError,
1140 apm_->gain_control()->set_stream_analog_level(out_analog_level));
1141 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1142 out_analog_level = apm_->gain_control()->stream_analog_level();
1143 // Check that AGC respected the manually adjusted volume.
1144 EXPECT_LT(out_analog_level, highest_level_reached);
1145 }
1146 // Check that the volume was still raised.
1147 EXPECT_GT(out_analog_level, 100);
1148}
1149
1150TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
1151 for (size_t i = 0; i < kSampleRatesSize; ++i) {
1152 RunManualVolumeChangeIsPossibleTest(kSampleRates[i]);
1153 }
1154}
1155
niklase@google.com470e71d2011-07-07 08:21:251156TEST_F(ApmTest, NoiseSuppression) {
andrew@webrtc.org648af742012-02-08 01:57:291157 // Test valid suppression levels.
niklase@google.com470e71d2011-07-07 08:21:251158 NoiseSuppression::Level level[] = {
1159 NoiseSuppression::kLow,
1160 NoiseSuppression::kModerate,
1161 NoiseSuppression::kHigh,
1162 NoiseSuppression::kVeryHigh
1163 };
1164 for (size_t i = 0; i < sizeof(level)/sizeof(*level); i++) {
1165 EXPECT_EQ(apm_->kNoError,
1166 apm_->noise_suppression()->set_level(level[i]));
1167 EXPECT_EQ(level[i], apm_->noise_suppression()->level());
1168 }
1169
andrew@webrtc.org648af742012-02-08 01:57:291170 // Turn NS on/off
niklase@google.com470e71d2011-07-07 08:21:251171 EXPECT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true));
1172 EXPECT_TRUE(apm_->noise_suppression()->is_enabled());
1173 EXPECT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(false));
1174 EXPECT_FALSE(apm_->noise_suppression()->is_enabled());
1175}
1176
1177TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:291178 // Turn HP filter on/off
niklase@google.com470e71d2011-07-07 08:21:251179 EXPECT_EQ(apm_->kNoError, apm_->high_pass_filter()->Enable(true));
1180 EXPECT_TRUE(apm_->high_pass_filter()->is_enabled());
1181 EXPECT_EQ(apm_->kNoError, apm_->high_pass_filter()->Enable(false));
1182 EXPECT_FALSE(apm_->high_pass_filter()->is_enabled());
1183}
1184
1185TEST_F(ApmTest, LevelEstimator) {
andrew@webrtc.org648af742012-02-08 01:57:291186 // Turn level estimator on/off
andrew@webrtc.org755b04a2011-11-15 16:57:561187 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(false));
niklase@google.com470e71d2011-07-07 08:21:251188 EXPECT_FALSE(apm_->level_estimator()->is_enabled());
andrew@webrtc.org755b04a2011-11-15 16:57:561189
1190 EXPECT_EQ(apm_->kNotEnabledError, apm_->level_estimator()->RMS());
1191
1192 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
1193 EXPECT_TRUE(apm_->level_estimator()->is_enabled());
1194
1195 // Run this test in wideband; in super-wb, the splitting filter distorts the
1196 // audio enough to cause deviation from the expectation for small values.
andrew@webrtc.org63a50982012-05-02 23:56:371197 frame_->samples_per_channel_ = 160;
1198 frame_->num_channels_ = 2;
1199 frame_->sample_rate_hz_ = 16000;
andrew@webrtc.org755b04a2011-11-15 16:57:561200
1201 // Min value if no frames have been processed.
1202 EXPECT_EQ(127, apm_->level_estimator()->RMS());
1203
1204 // Min value on zero frames.
1205 SetFrameTo(frame_, 0);
1206 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1207 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1208 EXPECT_EQ(127, apm_->level_estimator()->RMS());
1209
1210 // Try a few RMS values.
1211 // (These also test that the value resets after retrieving it.)
1212 SetFrameTo(frame_, 32767);
1213 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1214 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1215 EXPECT_EQ(0, apm_->level_estimator()->RMS());
1216
1217 SetFrameTo(frame_, 30000);
1218 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1219 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1220 EXPECT_EQ(1, apm_->level_estimator()->RMS());
1221
1222 SetFrameTo(frame_, 10000);
1223 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1224 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1225 EXPECT_EQ(10, apm_->level_estimator()->RMS());
1226
1227 SetFrameTo(frame_, 10);
1228 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1229 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1230 EXPECT_EQ(70, apm_->level_estimator()->RMS());
1231
andrew@webrtc.org755b04a2011-11-15 16:57:561232 // Verify reset after enable/disable.
1233 SetFrameTo(frame_, 32767);
1234 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1235 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(false));
1236 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
1237 SetFrameTo(frame_, 1);
1238 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1239 EXPECT_EQ(90, apm_->level_estimator()->RMS());
1240
1241 // Verify reset after initialize.
1242 SetFrameTo(frame_, 32767);
1243 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1244 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
1245 SetFrameTo(frame_, 1);
1246 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1247 EXPECT_EQ(90, apm_->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:251248}
1249
1250TEST_F(ApmTest, VoiceDetection) {
1251 // Test external VAD
1252 EXPECT_EQ(apm_->kNoError,
1253 apm_->voice_detection()->set_stream_has_voice(true));
1254 EXPECT_TRUE(apm_->voice_detection()->stream_has_voice());
1255 EXPECT_EQ(apm_->kNoError,
1256 apm_->voice_detection()->set_stream_has_voice(false));
1257 EXPECT_FALSE(apm_->voice_detection()->stream_has_voice());
1258
andrew@webrtc.org648af742012-02-08 01:57:291259 // Test valid likelihoods
niklase@google.com470e71d2011-07-07 08:21:251260 VoiceDetection::Likelihood likelihood[] = {
1261 VoiceDetection::kVeryLowLikelihood,
1262 VoiceDetection::kLowLikelihood,
1263 VoiceDetection::kModerateLikelihood,
1264 VoiceDetection::kHighLikelihood
1265 };
1266 for (size_t i = 0; i < sizeof(likelihood)/sizeof(*likelihood); i++) {
1267 EXPECT_EQ(apm_->kNoError,
1268 apm_->voice_detection()->set_likelihood(likelihood[i]));
1269 EXPECT_EQ(likelihood[i], apm_->voice_detection()->likelihood());
1270 }
1271
1272 /* TODO(bjornv): Enable once VAD supports other frame lengths than 10 ms
andrew@webrtc.org648af742012-02-08 01:57:291273 // Test invalid frame sizes
niklase@google.com470e71d2011-07-07 08:21:251274 EXPECT_EQ(apm_->kBadParameterError,
1275 apm_->voice_detection()->set_frame_size_ms(12));
1276
andrew@webrtc.org648af742012-02-08 01:57:291277 // Test valid frame sizes
niklase@google.com470e71d2011-07-07 08:21:251278 for (int i = 10; i <= 30; i += 10) {
1279 EXPECT_EQ(apm_->kNoError,
1280 apm_->voice_detection()->set_frame_size_ms(i));
1281 EXPECT_EQ(i, apm_->voice_detection()->frame_size_ms());
1282 }
1283 */
1284
andrew@webrtc.org648af742012-02-08 01:57:291285 // Turn VAD on/off
niklase@google.com470e71d2011-07-07 08:21:251286 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
1287 EXPECT_TRUE(apm_->voice_detection()->is_enabled());
1288 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false));
1289 EXPECT_FALSE(apm_->voice_detection()->is_enabled());
1290
andrew@webrtc.orged083d42011-09-19 15:28:511291 // Test that AudioFrame activity is maintained when VAD is disabled.
1292 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false));
1293 AudioFrame::VADActivity activity[] = {
1294 AudioFrame::kVadActive,
1295 AudioFrame::kVadPassive,
1296 AudioFrame::kVadUnknown
1297 };
1298 for (size_t i = 0; i < sizeof(activity)/sizeof(*activity); i++) {
andrew@webrtc.org63a50982012-05-02 23:56:371299 frame_->vad_activity_ = activity[i];
andrew@webrtc.orged083d42011-09-19 15:28:511300 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
andrew@webrtc.org63a50982012-05-02 23:56:371301 EXPECT_EQ(activity[i], frame_->vad_activity_);
andrew@webrtc.orged083d42011-09-19 15:28:511302 }
1303
1304 // Test that AudioFrame activity is set when VAD is enabled.
1305 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
andrew@webrtc.org63a50982012-05-02 23:56:371306 frame_->vad_activity_ = AudioFrame::kVadUnknown;
andrew@webrtc.orged083d42011-09-19 15:28:511307 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
andrew@webrtc.org63a50982012-05-02 23:56:371308 EXPECT_NE(AudioFrame::kVadUnknown, frame_->vad_activity_);
andrew@webrtc.orged083d42011-09-19 15:28:511309
niklase@google.com470e71d2011-07-07 08:21:251310 // TODO(bjornv): Add tests for streamed voice; stream_has_voice()
1311}
andrew@webrtc.org755b04a2011-11-15 16:57:561312
andrew@webrtc.orgecac9b72012-05-02 00:04:101313TEST_F(ApmTest, AllProcessingDisabledByDefault) {
1314 EXPECT_FALSE(apm_->echo_cancellation()->is_enabled());
1315 EXPECT_FALSE(apm_->echo_control_mobile()->is_enabled());
1316 EXPECT_FALSE(apm_->gain_control()->is_enabled());
1317 EXPECT_FALSE(apm_->high_pass_filter()->is_enabled());
1318 EXPECT_FALSE(apm_->level_estimator()->is_enabled());
1319 EXPECT_FALSE(apm_->noise_suppression()->is_enabled());
1320 EXPECT_FALSE(apm_->voice_detection()->is_enabled());
1321}
1322
1323TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabled) {
1324 for (size_t i = 0; i < kSampleRatesSize; i++) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:041325 Init(kSampleRates[i], kSampleRates[i], kSampleRates[i], 2, 2, 2, false);
andrew@webrtc.orgecac9b72012-05-02 00:04:101326 SetFrameTo(frame_, 1000, 2000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:301327 AudioFrame frame_copy;
1328 frame_copy.CopyFrom(*frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:101329 for (int j = 0; j < 1000; j++) {
1330 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1331 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1332 }
1333 }
1334}
1335
andrew@webrtc.org07bf9a02012-05-05 00:32:001336TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1337 EnableAllComponents();
1338
1339 for (size_t i = 0; i < kProcessSampleRatesSize; i++) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:041340 Init(kProcessSampleRates[i],
1341 kProcessSampleRates[i],
1342 kProcessSampleRates[i],
1343 2,
1344 2,
1345 2,
1346 false);
andrew@webrtc.org07bf9a02012-05-05 00:32:001347 int analog_level = 127;
andrew@webrtc.orgddbb8a22014-04-22 21:00:041348 ASSERT_EQ(0, feof(far_file_));
1349 ASSERT_EQ(0, feof(near_file_));
andrew@webrtc.org17e40642014-03-04 20:58:131350 while (ReadFrame(far_file_, revframe_) && ReadFrame(near_file_, frame_)) {
andrew@webrtc.org07bf9a02012-05-05 00:32:001351 CopyLeftToRightChannel(revframe_->data_, revframe_->samples_per_channel_);
1352
andrew@webrtc.orgddbb8a22014-04-22 21:00:041353 ASSERT_EQ(kNoErr, apm_->AnalyzeReverseStream(revframe_));
andrew@webrtc.org07bf9a02012-05-05 00:32:001354
andrew@webrtc.org07bf9a02012-05-05 00:32:001355 CopyLeftToRightChannel(frame_->data_, frame_->samples_per_channel_);
1356 frame_->vad_activity_ = AudioFrame::kVadUnknown;
1357
andrew@webrtc.orgddbb8a22014-04-22 21:00:041358 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:281359 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.orgddbb8a22014-04-22 21:00:041360 ASSERT_EQ(kNoErr,
andrew@webrtc.org07bf9a02012-05-05 00:32:001361 apm_->gain_control()->set_stream_analog_level(analog_level));
andrew@webrtc.orgddbb8a22014-04-22 21:00:041362 ASSERT_EQ(kNoErr, apm_->ProcessStream(frame_));
andrew@webrtc.org07bf9a02012-05-05 00:32:001363 analog_level = apm_->gain_control()->stream_analog_level();
1364
1365 VerifyChannelsAreEqual(frame_->data_, frame_->samples_per_channel_);
1366 }
bjornv@webrtc.org3e102492013-02-14 15:29:091367 rewind(far_file_);
1368 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:001369 }
1370}
1371
andrew@webrtc.org755b04a2011-11-15 16:57:561372TEST_F(ApmTest, SplittingFilter) {
1373 // Verify the filter is not active through undistorted audio when:
1374 // 1. No components are enabled...
1375 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:301376 AudioFrame frame_copy;
1377 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:561378 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1379 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1380 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1381
1382 // 2. Only the level estimator is enabled...
1383 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:301384 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:561385 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
1386 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1387 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1388 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1389 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(false));
1390
1391 // 3. Only VAD is enabled...
1392 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:301393 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:561394 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
1395 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1396 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1397 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1398 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false));
1399
1400 // 4. Both VAD and the level estimator are enabled...
1401 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:301402 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:561403 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
1404 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
1405 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1406 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1407 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1408 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(false));
1409 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false));
1410
1411 // 5. Not using super-wb.
andrew@webrtc.org63a50982012-05-02 23:56:371412 frame_->samples_per_channel_ = 160;
1413 frame_->num_channels_ = 2;
1414 frame_->sample_rate_hz_ = 16000;
andrew@webrtc.org755b04a2011-11-15 16:57:561415 // Enable AEC, which would require the filter in super-wb. We rely on the
1416 // first few frames of data being unaffected by the AEC.
1417 // TODO(andrew): This test, and the one below, rely rather tenuously on the
1418 // behavior of the AEC. Think of something more robust.
1419 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
1420 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:301421 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:561422 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:281423 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org755b04a2011-11-15 16:57:561424 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1425 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:281426 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org755b04a2011-11-15 16:57:561427 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1428 EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
1429
1430 // Check the test is valid. We should have distortion from the filter
1431 // when AEC is enabled (which won't affect the audio).
andrew@webrtc.org63a50982012-05-02 23:56:371432 frame_->samples_per_channel_ = 320;
1433 frame_->num_channels_ = 2;
1434 frame_->sample_rate_hz_ = 32000;
andrew@webrtc.org755b04a2011-11-15 16:57:561435 SetFrameTo(frame_, 1000);
andrew@webrtc.orgae1a58b2013-01-22 04:44:301436 frame_copy.CopyFrom(*frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:561437 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:281438 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org755b04a2011-11-15 16:57:561439 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1440 EXPECT_FALSE(FrameDataAreEqual(*frame_, frame_copy));
1441}
1442
andrew@webrtc.orga8b97372014-03-10 22:26:121443#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1444void ApmTest::ProcessDebugDump(const std::string& in_filename,
1445 const std::string& out_filename,
1446 Format format) {
1447 FILE* in_file = fopen(in_filename.c_str(), "rb");
1448 ASSERT_TRUE(in_file != NULL);
1449 audioproc::Event event_msg;
1450 bool first_init = true;
1451
1452 while (ReadMessageFromFile(in_file, &event_msg)) {
1453 if (event_msg.type() == audioproc::Event::INIT) {
1454 const audioproc::Init msg = event_msg.init();
1455 int reverse_sample_rate = msg.sample_rate();
1456 if (msg.has_reverse_sample_rate()) {
1457 reverse_sample_rate = msg.reverse_sample_rate();
1458 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:041459 int output_sample_rate = msg.sample_rate();
1460 if (msg.has_output_sample_rate()) {
1461 output_sample_rate = msg.output_sample_rate();
1462 }
1463
andrew@webrtc.orga8b97372014-03-10 22:26:121464 Init(msg.sample_rate(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:041465 output_sample_rate,
andrew@webrtc.orga8b97372014-03-10 22:26:121466 reverse_sample_rate,
1467 msg.num_input_channels(),
1468 msg.num_output_channels(),
1469 msg.num_reverse_channels(),
1470 false);
1471 if (first_init) {
1472 // StartDebugRecording() writes an additional init message. Don't start
1473 // recording until after the first init to avoid the extra message.
1474 EXPECT_NOERR(apm_->StartDebugRecording(out_filename.c_str()));
1475 first_init = false;
1476 }
1477
1478 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) {
1479 const audioproc::ReverseStream msg = event_msg.reverse_stream();
1480
1481 if (msg.channel_size() > 0) {
1482 ASSERT_EQ(revframe_->num_channels_, msg.channel_size());
1483 for (int i = 0; i < msg.channel_size(); ++i) {
1484 memcpy(revfloat_cb_->channel(i), msg.channel(i).data(),
1485 msg.channel(i).size());
1486 }
1487 } else {
1488 memcpy(revframe_->data_, msg.data().data(), msg.data().size());
1489 if (format == kFloatFormat) {
1490 // We're using an int16 input file; convert to float.
1491 ConvertToFloat(*revframe_, revfloat_cb_.get());
1492 }
1493 }
1494 AnalyzeReverseStreamChooser(format);
1495
1496 } else if (event_msg.type() == audioproc::Event::STREAM) {
1497 const audioproc::Stream msg = event_msg.stream();
1498 // ProcessStream could have changed this for the output frame.
1499 frame_->num_channels_ = apm_->num_input_channels();
1500
1501 EXPECT_NOERR(apm_->gain_control()->set_stream_analog_level(msg.level()));
1502 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
1503 apm_->echo_cancellation()->set_stream_drift_samples(msg.drift());
1504 if (msg.has_keypress()) {
1505 apm_->set_stream_key_pressed(msg.keypress());
1506 } else {
1507 apm_->set_stream_key_pressed(true);
1508 }
1509
1510 if (msg.input_channel_size() > 0) {
1511 ASSERT_EQ(frame_->num_channels_, msg.input_channel_size());
1512 for (int i = 0; i < msg.input_channel_size(); ++i) {
1513 memcpy(float_cb_->channel(i), msg.input_channel(i).data(),
1514 msg.input_channel(i).size());
1515 }
1516 } else {
1517 memcpy(frame_->data_, msg.input_data().data(), msg.input_data().size());
1518 if (format == kFloatFormat) {
1519 // We're using an int16 input file; convert to float.
1520 ConvertToFloat(*frame_, float_cb_.get());
1521 }
1522 }
1523 ProcessStreamChooser(format);
1524 }
1525 }
1526 EXPECT_NOERR(apm_->StopDebugRecording());
1527 fclose(in_file);
1528}
1529
1530void ApmTest::VerifyDebugDumpTest(Format format) {
1531 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
henrik.lundin@webrtc.org1092ea02014-04-02 07:46:491532 std::string format_string;
1533 switch (format) {
1534 case kIntFormat:
1535 format_string = "_int";
1536 break;
1537 case kFloatFormat:
1538 format_string = "_float";
1539 break;
1540 }
1541 const std::string ref_filename =
1542 test::OutputPath() + "ref" + format_string + ".aecdump";
1543 const std::string out_filename =
1544 test::OutputPath() + "out" + format_string + ".aecdump";
andrew@webrtc.orga8b97372014-03-10 22:26:121545 EnableAllComponents();
1546 ProcessDebugDump(in_filename, ref_filename, format);
1547 ProcessDebugDump(ref_filename, out_filename, format);
1548
1549 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1550 FILE* out_file = fopen(out_filename.c_str(), "rb");
1551 ASSERT_TRUE(ref_file != NULL);
1552 ASSERT_TRUE(out_file != NULL);
1553 scoped_ptr<uint8_t[]> ref_bytes;
1554 scoped_ptr<uint8_t[]> out_bytes;
1555
1556 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1557 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
1558 size_t bytes_read = 0;
1559 while (ref_size > 0 && out_size > 0) {
1560 bytes_read += ref_size;
1561 EXPECT_EQ(ref_size, out_size);
1562 EXPECT_EQ(0, memcmp(ref_bytes.get(), out_bytes.get(), ref_size));
1563 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1564 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
1565 }
1566 EXPECT_GT(bytes_read, 0u);
1567 EXPECT_NE(0, feof(ref_file));
1568 EXPECT_NE(0, feof(out_file));
1569 ASSERT_EQ(0, fclose(ref_file));
1570 ASSERT_EQ(0, fclose(out_file));
1571}
1572
1573TEST_F(ApmTest, VerifyDebugDumpInt) {
1574 VerifyDebugDumpTest(kIntFormat);
1575}
1576
1577TEST_F(ApmTest, VerifyDebugDumpFloat) {
1578 VerifyDebugDumpTest(kFloatFormat);
1579}
1580#endif
1581
andrew@webrtc.org7bf26462011-12-03 00:03:311582// TODO(andrew): expand test to verify output.
1583TEST_F(ApmTest, DebugDump) {
andrew@webrtc.org27c69802014-02-18 20:24:561584 const std::string filename = test::OutputPath() + "debug.aec";
henrikg@webrtc.org863b5362013-12-06 16:05:171585 EXPECT_EQ(apm_->kNullPointerError,
1586 apm_->StartDebugRecording(static_cast<const char*>(NULL)));
andrew@webrtc.org7bf26462011-12-03 00:03:311587
1588#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1589 // Stopping without having started should be OK.
1590 EXPECT_EQ(apm_->kNoError, apm_->StopDebugRecording());
1591
1592 EXPECT_EQ(apm_->kNoError, apm_->StartDebugRecording(filename.c_str()));
andrew@webrtc.org7bf26462011-12-03 00:03:311593 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
andrew@webrtc.org60730cf2014-01-07 17:45:091594 EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(revframe_));
andrew@webrtc.org7bf26462011-12-03 00:03:311595 EXPECT_EQ(apm_->kNoError, apm_->StopDebugRecording());
1596
1597 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:391598 FILE* fid = fopen(filename.c_str(), "r");
1599 ASSERT_TRUE(fid != NULL);
1600
andrew@webrtc.org7bf26462011-12-03 00:03:311601 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:391602 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:311603 ASSERT_EQ(0, remove(filename.c_str()));
1604#else
1605 EXPECT_EQ(apm_->kUnsupportedFunctionError,
1606 apm_->StartDebugRecording(filename.c_str()));
1607 EXPECT_EQ(apm_->kUnsupportedFunctionError, apm_->StopDebugRecording());
1608
1609 // Verify the file has NOT been written.
1610 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1611#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1612}
1613
henrikg@webrtc.org863b5362013-12-06 16:05:171614// TODO(andrew): expand test to verify output.
1615TEST_F(ApmTest, DebugDumpFromFileHandle) {
1616 FILE* fid = NULL;
1617 EXPECT_EQ(apm_->kNullPointerError, apm_->StartDebugRecording(fid));
andrew@webrtc.org27c69802014-02-18 20:24:561618 const std::string filename = test::OutputPath() + "debug.aec";
henrikg@webrtc.org863b5362013-12-06 16:05:171619 fid = fopen(filename.c_str(), "w");
1620 ASSERT_TRUE(fid);
1621
1622#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1623 // Stopping without having started should be OK.
1624 EXPECT_EQ(apm_->kNoError, apm_->StopDebugRecording());
1625
1626 EXPECT_EQ(apm_->kNoError, apm_->StartDebugRecording(fid));
1627 EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(revframe_));
1628 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
1629 EXPECT_EQ(apm_->kNoError, apm_->StopDebugRecording());
1630
1631 // Verify the file has been written.
1632 fid = fopen(filename.c_str(), "r");
1633 ASSERT_TRUE(fid != NULL);
1634
1635 // Clean it up.
1636 ASSERT_EQ(0, fclose(fid));
1637 ASSERT_EQ(0, remove(filename.c_str()));
1638#else
1639 EXPECT_EQ(apm_->kUnsupportedFunctionError,
1640 apm_->StartDebugRecording(fid));
1641 EXPECT_EQ(apm_->kUnsupportedFunctionError, apm_->StopDebugRecording());
1642
1643 ASSERT_EQ(0, fclose(fid));
1644#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1645}
1646
andrew@webrtc.org17e40642014-03-04 20:58:131647TEST_F(ApmTest, FloatAndIntInterfacesGiveIdenticalResults) {
1648 audioproc::OutputData ref_data;
andrew@webrtc.orga8b97372014-03-10 22:26:121649 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org17e40642014-03-04 20:58:131650
1651 Config config;
1652 config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
1653 scoped_ptr<AudioProcessing> fapm(AudioProcessing::Create(config));
1654 EnableAllComponents();
1655 EnableAllAPComponents(fapm.get());
1656 for (int i = 0; i < ref_data.test_size(); i++) {
1657 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
1658
1659 audioproc::Test* test = ref_data.mutable_test(i);
1660 // TODO(ajm): Restore downmixing test cases.
1661 if (test->num_input_channels() != test->num_output_channels())
1662 continue;
1663
1664 const int num_render_channels = test->num_reverse_channels();
1665 const int num_input_channels = test->num_input_channels();
1666 const int num_output_channels = test->num_output_channels();
andrew@webrtc.orgddbb8a22014-04-22 21:00:041667 const int samples_per_channel = test->sample_rate() *
1668 AudioProcessing::kChunkSizeMs / 1000;
andrew@webrtc.org17e40642014-03-04 20:58:131669 const int output_length = samples_per_channel * num_output_channels;
1670
andrew@webrtc.orgddbb8a22014-04-22 21:00:041671 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
1672 num_input_channels, num_output_channels, num_render_channels, true);
andrew@webrtc.org17e40642014-03-04 20:58:131673 Init(fapm.get());
1674
1675 ChannelBuffer<int16_t> output_cb(samples_per_channel, num_input_channels);
1676 scoped_ptr<int16_t[]> output_int16(new int16_t[output_length]);
1677
1678 int analog_level = 127;
1679 while (ReadFrame(far_file_, revframe_, revfloat_cb_.get()) &&
1680 ReadFrame(near_file_, frame_, float_cb_.get())) {
1681 frame_->vad_activity_ = AudioFrame::kVadUnknown;
1682
1683 EXPECT_NOERR(apm_->AnalyzeReverseStream(revframe_));
1684 EXPECT_NOERR(fapm->AnalyzeReverseStream(
1685 revfloat_cb_->channels(),
1686 samples_per_channel,
1687 test->sample_rate(),
1688 LayoutFromChannels(num_render_channels)));
1689
1690 EXPECT_NOERR(apm_->set_stream_delay_ms(0));
1691 EXPECT_NOERR(fapm->set_stream_delay_ms(0));
1692 apm_->echo_cancellation()->set_stream_drift_samples(0);
1693 fapm->echo_cancellation()->set_stream_drift_samples(0);
1694 EXPECT_NOERR(apm_->gain_control()->set_stream_analog_level(analog_level));
1695 EXPECT_NOERR(fapm->gain_control()->set_stream_analog_level(analog_level));
1696
1697 EXPECT_NOERR(apm_->ProcessStream(frame_));
andrew@webrtc.orgddbb8a22014-04-22 21:00:041698 // TODO(ajm): Update to support different output rates.
andrew@webrtc.org17e40642014-03-04 20:58:131699 EXPECT_NOERR(fapm->ProcessStream(
1700 float_cb_->channels(),
1701 samples_per_channel,
1702 test->sample_rate(),
1703 LayoutFromChannels(num_input_channels),
andrew@webrtc.orgddbb8a22014-04-22 21:00:041704 test->sample_rate(),
1705 LayoutFromChannels(num_output_channels),
1706 float_cb_->channels()));
andrew@webrtc.org17e40642014-03-04 20:58:131707
1708 // Convert to interleaved int16.
1709 ScaleAndRoundToInt16(float_cb_->data(), output_length, output_cb.data());
1710 Interleave(output_cb.channels(),
1711 samples_per_channel,
1712 num_output_channels,
1713 output_int16.get());
1714 // Verify float and int16 paths produce identical output.
1715 EXPECT_EQ(0, memcmp(frame_->data_, output_int16.get(), output_length));
1716
1717 analog_level = fapm->gain_control()->stream_analog_level();
1718 EXPECT_EQ(apm_->gain_control()->stream_analog_level(),
1719 fapm->gain_control()->stream_analog_level());
1720 EXPECT_EQ(apm_->echo_cancellation()->stream_has_echo(),
1721 fapm->echo_cancellation()->stream_has_echo());
1722 EXPECT_EQ(apm_->voice_detection()->stream_has_voice(),
1723 fapm->voice_detection()->stream_has_voice());
1724 EXPECT_EQ(apm_->noise_suppression()->speech_probability(),
1725 fapm->noise_suppression()->speech_probability());
1726
1727 // Reset in case of downmixing.
1728 frame_->num_channels_ = test->num_input_channels();
1729 }
1730 rewind(far_file_);
1731 rewind(near_file_);
1732 }
1733}
1734
andrew@webrtc.org75f19482012-02-09 17:16:181735// TODO(andrew): Add a test to process a few frames with different combinations
1736// of enabled components.
1737
andrew@webrtc.orge2ed5ba2012-01-20 19:06:381738// TODO(andrew): Make this test more robust such that it can be run on multiple
1739// platforms. It currently requires bit-exactness.
andrew@webrtc.org293d22b2012-01-30 22:04:261740#ifdef WEBRTC_AUDIOPROC_BIT_EXACT
aluebs@webrtc.orgc9ee4122014-02-03 14:41:571741TEST_F(ApmTest, DISABLED_ON_ANDROID(Process)) {
andrew@webrtc.org755b04a2011-11-15 16:57:561742 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.org27c69802014-02-18 20:24:561743 audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:561744
andrew@webrtc.orgdaacee82012-02-07 00:01:041745 if (!write_ref_data) {
andrew@webrtc.orga8b97372014-03-10 22:26:121746 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:561747 } else {
andrew@webrtc.orgdaacee82012-02-07 00:01:041748 // Write the desired tests to the protobuf reference file.
andrew@webrtc.orgecac9b72012-05-02 00:04:101749 for (size_t i = 0; i < kChannelsSize; i++) {
1750 for (size_t j = 0; j < kChannelsSize; j++) {
andrew@webrtc.org60730cf2014-01-07 17:45:091751 for (size_t l = 0; l < kProcessSampleRatesSize; l++) {
andrew@webrtc.org27c69802014-02-18 20:24:561752 audioproc::Test* test = ref_data.add_test();
andrew@webrtc.org60730cf2014-01-07 17:45:091753 test->set_num_reverse_channels(kChannels[i]);
1754 test->set_num_input_channels(kChannels[j]);
1755 test->set_num_output_channels(kChannels[j]);
1756 test->set_sample_rate(kProcessSampleRates[l]);
andrew@webrtc.org755b04a2011-11-15 16:57:561757 }
1758 }
1759 }
1760 }
1761
andrew@webrtc.org07bf9a02012-05-05 00:32:001762 EnableAllComponents();
andrew@webrtc.org755b04a2011-11-15 16:57:561763
andrew@webrtc.orgdaacee82012-02-07 00:01:041764 for (int i = 0; i < ref_data.test_size(); i++) {
1765 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:561766
andrew@webrtc.org27c69802014-02-18 20:24:561767 audioproc::Test* test = ref_data.mutable_test(i);
andrew@webrtc.org60730cf2014-01-07 17:45:091768 // TODO(ajm): We no longer allow different input and output channels. Skip
1769 // these tests for now, but they should be removed from the set.
1770 if (test->num_input_channels() != test->num_output_channels())
1771 continue;
1772
andrew@webrtc.orgddbb8a22014-04-22 21:00:041773 Init(test->sample_rate(),
1774 test->sample_rate(),
1775 test->sample_rate(),
1776 test->num_input_channels(),
1777 test->num_output_channels(),
1778 test->num_reverse_channels(),
1779 true);
andrew@webrtc.orgdaacee82012-02-07 00:01:041780
andrew@webrtc.org755b04a2011-11-15 16:57:561781 int frame_count = 0;
1782 int has_echo_count = 0;
1783 int has_voice_count = 0;
1784 int is_saturated_count = 0;
1785 int analog_level = 127;
1786 int analog_level_average = 0;
1787 int max_output_average = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:431788 float ns_speech_prob_average = 0.0f;
andrew@webrtc.org755b04a2011-11-15 16:57:561789
andrew@webrtc.org17e40642014-03-04 20:58:131790 while (ReadFrame(far_file_, revframe_) && ReadFrame(near_file_, frame_)) {
andrew@webrtc.org755b04a2011-11-15 16:57:561791 EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(revframe_));
1792
andrew@webrtc.org07bf9a02012-05-05 00:32:001793 frame_->vad_activity_ = AudioFrame::kVadUnknown;
1794
andrew@webrtc.org755b04a2011-11-15 16:57:561795 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
andrew@webrtc.org6be1e932013-03-01 18:47:281796 apm_->echo_cancellation()->set_stream_drift_samples(0);
andrew@webrtc.org755b04a2011-11-15 16:57:561797 EXPECT_EQ(apm_->kNoError,
1798 apm_->gain_control()->set_stream_analog_level(analog_level));
1799
andrew@webrtc.org755b04a2011-11-15 16:57:561800 EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
andrew@webrtc.org17e40642014-03-04 20:58:131801
andrew@webrtc.orgdaacee82012-02-07 00:01:041802 // Ensure the frame was downmixed properly.
andrew@webrtc.org63a50982012-05-02 23:56:371803 EXPECT_EQ(test->num_output_channels(), frame_->num_channels_);
andrew@webrtc.org755b04a2011-11-15 16:57:561804
1805 max_output_average += MaxAudioFrame(*frame_);
1806
1807 if (apm_->echo_cancellation()->stream_has_echo()) {
1808 has_echo_count++;
1809 }
1810
1811 analog_level = apm_->gain_control()->stream_analog_level();
1812 analog_level_average += analog_level;
1813 if (apm_->gain_control()->stream_is_saturated()) {
1814 is_saturated_count++;
1815 }
1816 if (apm_->voice_detection()->stream_has_voice()) {
1817 has_voice_count++;
andrew@webrtc.org63a50982012-05-02 23:56:371818 EXPECT_EQ(AudioFrame::kVadActive, frame_->vad_activity_);
andrew@webrtc.org755b04a2011-11-15 16:57:561819 } else {
andrew@webrtc.org63a50982012-05-02 23:56:371820 EXPECT_EQ(AudioFrame::kVadPassive, frame_->vad_activity_);
andrew@webrtc.org755b04a2011-11-15 16:57:561821 }
1822
bjornv@webrtc.org08329f42012-07-12 21:00:431823 ns_speech_prob_average += apm_->noise_suppression()->speech_probability();
1824
andrew@webrtc.org07bf9a02012-05-05 00:32:001825 size_t frame_size = frame_->samples_per_channel_ * frame_->num_channels_;
andrew@webrtc.org63a50982012-05-02 23:56:371826 size_t write_count = fwrite(frame_->data_,
andrew@webrtc.orgdaacee82012-02-07 00:01:041827 sizeof(int16_t),
1828 frame_size,
1829 out_file_);
1830 ASSERT_EQ(frame_size, write_count);
1831
1832 // Reset in case of downmixing.
andrew@webrtc.org63a50982012-05-02 23:56:371833 frame_->num_channels_ = test->num_input_channels();
andrew@webrtc.org755b04a2011-11-15 16:57:561834 frame_count++;
1835 }
1836 max_output_average /= frame_count;
1837 analog_level_average /= frame_count;
bjornv@webrtc.org08329f42012-07-12 21:00:431838 ns_speech_prob_average /= frame_count;
andrew@webrtc.org755b04a2011-11-15 16:57:561839
andrew@webrtc.org293d22b2012-01-30 22:04:261840#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
andrew@webrtc.org755b04a2011-11-15 16:57:561841 EchoCancellation::Metrics echo_metrics;
1842 EXPECT_EQ(apm_->kNoError,
1843 apm_->echo_cancellation()->GetMetrics(&echo_metrics));
1844 int median = 0;
1845 int std = 0;
1846 EXPECT_EQ(apm_->kNoError,
1847 apm_->echo_cancellation()->GetDelayMetrics(&median, &std));
1848
1849 int rms_level = apm_->level_estimator()->RMS();
1850 EXPECT_LE(0, rms_level);
1851 EXPECT_GE(127, rms_level);
1852#endif
1853
andrew@webrtc.orgdaacee82012-02-07 00:01:041854 if (!write_ref_data) {
andrew@webrtc.org755b04a2011-11-15 16:57:561855 EXPECT_EQ(test->has_echo_count(), has_echo_count);
1856 EXPECT_EQ(test->has_voice_count(), has_voice_count);
1857 EXPECT_EQ(test->is_saturated_count(), is_saturated_count);
1858
1859 EXPECT_EQ(test->analog_level_average(), analog_level_average);
1860 EXPECT_EQ(test->max_output_average(), max_output_average);
1861
andrew@webrtc.org293d22b2012-01-30 22:04:261862#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
andrew@webrtc.org27c69802014-02-18 20:24:561863 audioproc::Test::EchoMetrics reference = test->echo_metrics();
andrew@webrtc.org755b04a2011-11-15 16:57:561864 TestStats(echo_metrics.residual_echo_return_loss,
1865 reference.residual_echo_return_loss());
1866 TestStats(echo_metrics.echo_return_loss,
1867 reference.echo_return_loss());
1868 TestStats(echo_metrics.echo_return_loss_enhancement,
1869 reference.echo_return_loss_enhancement());
1870 TestStats(echo_metrics.a_nlp,
1871 reference.a_nlp());
1872
andrew@webrtc.org27c69802014-02-18 20:24:561873 audioproc::Test::DelayMetrics reference_delay = test->delay_metrics();
andrew@webrtc.org828af1b2011-11-22 22:40:271874 EXPECT_EQ(reference_delay.median(), median);
1875 EXPECT_EQ(reference_delay.std(), std);
andrew@webrtc.org755b04a2011-11-15 16:57:561876
1877 EXPECT_EQ(test->rms_level(), rms_level);
bjornv@webrtc.org08329f42012-07-12 21:00:431878
1879 EXPECT_FLOAT_EQ(test->ns_speech_probability_average(),
1880 ns_speech_prob_average);
andrew@webrtc.org755b04a2011-11-15 16:57:561881#endif
1882 } else {
1883 test->set_has_echo_count(has_echo_count);
1884 test->set_has_voice_count(has_voice_count);
1885 test->set_is_saturated_count(is_saturated_count);
1886
1887 test->set_analog_level_average(analog_level_average);
1888 test->set_max_output_average(max_output_average);
1889
andrew@webrtc.org293d22b2012-01-30 22:04:261890#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
andrew@webrtc.org27c69802014-02-18 20:24:561891 audioproc::Test::EchoMetrics* message = test->mutable_echo_metrics();
andrew@webrtc.org755b04a2011-11-15 16:57:561892 WriteStatsMessage(echo_metrics.residual_echo_return_loss,
1893 message->mutable_residual_echo_return_loss());
1894 WriteStatsMessage(echo_metrics.echo_return_loss,
1895 message->mutable_echo_return_loss());
1896 WriteStatsMessage(echo_metrics.echo_return_loss_enhancement,
1897 message->mutable_echo_return_loss_enhancement());
1898 WriteStatsMessage(echo_metrics.a_nlp,
1899 message->mutable_a_nlp());
1900
andrew@webrtc.org27c69802014-02-18 20:24:561901 audioproc::Test::DelayMetrics* message_delay =
andrew@webrtc.org755b04a2011-11-15 16:57:561902 test->mutable_delay_metrics();
1903 message_delay->set_median(median);
1904 message_delay->set_std(std);
1905
1906 test->set_rms_level(rms_level);
bjornv@webrtc.org08329f42012-07-12 21:00:431907
1908 EXPECT_LE(0.0f, ns_speech_prob_average);
1909 EXPECT_GE(1.0f, ns_speech_prob_average);
1910 test->set_ns_speech_probability_average(ns_speech_prob_average);
andrew@webrtc.org755b04a2011-11-15 16:57:561911#endif
1912 }
1913
1914 rewind(far_file_);
1915 rewind(near_file_);
1916 }
1917
andrew@webrtc.orgdaacee82012-02-07 00:01:041918 if (write_ref_data) {
andrew@webrtc.orga8b97372014-03-10 22:26:121919 OpenFileAndWriteMessage(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:561920 }
1921}
andrew@webrtc.orgddbb8a22014-04-22 21:00:041922
andrew@webrtc.org293d22b2012-01-30 22:04:261923#endif // WEBRTC_AUDIOPROC_BIT_EXACT
andrew@webrtc.orge2ed5ba2012-01-20 19:06:381924
andrew@webrtc.org103657b2014-04-24 18:28:561925TEST_F(ApmTest, NoErrorsWithKeyboardChannel) {
1926 struct ChannelFormat {
1927 AudioProcessing::ChannelLayout in_layout;
1928 AudioProcessing::ChannelLayout out_layout;
1929 };
1930 ChannelFormat cf[] = {
1931 {AudioProcessing::kMonoAndKeyboard, AudioProcessing::kMono},
1932 {AudioProcessing::kStereoAndKeyboard, AudioProcessing::kMono},
1933 {AudioProcessing::kStereoAndKeyboard, AudioProcessing::kStereo},
1934 };
1935 size_t channel_format_size = sizeof(cf) / sizeof(*cf);
1936
1937 scoped_ptr<AudioProcessing> ap(AudioProcessing::Create());
1938 // Enable one component just to ensure some processing takes place.
1939 ap->noise_suppression()->Enable(true);
1940 for (size_t i = 0; i < channel_format_size; ++i) {
1941 const int in_rate = 44100;
1942 const int out_rate = 48000;
1943 ChannelBuffer<float> in_cb(SamplesFromRate(in_rate),
1944 TotalChannelsFromLayout(cf[i].in_layout));
1945 ChannelBuffer<float> out_cb(SamplesFromRate(out_rate),
1946 ChannelsFromLayout(cf[i].out_layout));
1947
1948 // Run over a few chunks.
1949 for (int j = 0; j < 10; ++j) {
1950 EXPECT_NOERR(ap->ProcessStream(
1951 in_cb.channels(),
1952 in_cb.samples_per_channel(),
1953 in_rate,
1954 cf[i].in_layout,
1955 out_rate,
1956 cf[i].out_layout,
1957 out_cb.channels()));
1958 }
1959 }
1960}
1961
andrew@webrtc.orgddbb8a22014-04-22 21:00:041962// Reads a 10 ms chunk of int16 interleaved audio from the given (assumed
1963// stereo) file, converts to deinterleaved float (optionally downmixing) and
1964// returns the result in |cb|. Returns false if the file ended (or on error) and
1965// true otherwise.
1966//
1967// |int_data| and |float_data| are just temporary space that must be
1968// sufficiently large to hold the 10 ms chunk.
1969bool ReadChunk(FILE* file, int16_t* int_data, float* float_data,
1970 ChannelBuffer<float>* cb) {
1971 // The files always contain stereo audio.
1972 size_t frame_size = cb->samples_per_channel() * 2;
1973 size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file);
1974 if (read_count != frame_size) {
1975 // Check that the file really ended.
1976 assert(feof(file));
1977 return false; // This is expected.
1978 }
1979
1980 ScaleToFloat(int_data, frame_size, float_data);
1981 if (cb->num_channels() == 1) {
1982 MixStereoToMono(float_data, cb->data(), cb->samples_per_channel());
1983 } else {
1984 Deinterleave(float_data, cb->samples_per_channel(), 2,
1985 cb->channels());
1986 }
1987
1988 return true;
1989}
1990
1991// Compares the reference and test arrays over a region around the expected
1992// delay. Finds the highest SNR in that region and adds the variance and squared
1993// error results to the supplied accumulators.
1994void UpdateBestSNR(const float* ref,
1995 const float* test,
1996 int length,
1997 int expected_delay,
1998 double* variance_acc,
1999 double* sq_error_acc) {
2000 double best_snr = std::numeric_limits<double>::min();
2001 double best_variance = 0;
2002 double best_sq_error = 0;
2003 // Search over a region of eight samples around the expected delay.
2004 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
2005 ++delay) {
2006 double sq_error = 0;
2007 double variance = 0;
2008 for (int i = 0; i < length - delay; ++i) {
2009 double error = test[i + delay] - ref[i];
2010 sq_error += error * error;
2011 variance += ref[i] * ref[i];
2012 }
2013
2014 if (sq_error == 0) {
2015 *variance_acc += variance;
2016 return;
2017 }
2018 double snr = variance / sq_error;
2019 if (snr > best_snr) {
2020 best_snr = snr;
2021 best_variance = variance;
2022 best_sq_error = sq_error;
2023 }
2024 }
2025
2026 *variance_acc += best_variance;
2027 *sq_error_acc += best_sq_error;
2028}
2029
2030// Used to test a multitude of sample rate and channel combinations. It works
2031// by first producing a set of reference files (in SetUpTestCase) that are
2032// assumed to be correct, as the used parameters are verified by other tests
2033// in this collection. Primarily the reference files are all produced at
2034// "native" rates which do not involve any resampling.
2035
2036// Each test pass produces an output file with a particular format. The output
2037// is matched against the reference file closest to its internal processing
2038// format. If necessary the output is resampled back to its process format.
2039// Due to the resampling distortion, we don't expect identical results, but
2040// enforce SNR thresholds which vary depending on the format. 0 is a special
2041// case SNR which corresponds to inf, or zero error.
2042typedef std::tr1::tuple<int, int, int, double> AudioProcessingTestData;
2043class AudioProcessingTest
2044 : public testing::TestWithParam<AudioProcessingTestData> {
2045 public:
2046 AudioProcessingTest()
2047 : input_rate_(std::tr1::get<0>(GetParam())),
2048 output_rate_(std::tr1::get<1>(GetParam())),
2049 reverse_rate_(std::tr1::get<2>(GetParam())),
2050 expected_snr_(std::tr1::get<3>(GetParam())) {}
2051
2052 virtual ~AudioProcessingTest() {}
2053
2054 static void SetUpTestCase() {
2055 // Create all needed output reference files.
2056 const int kNativeRates[] = {8000, 16000, 32000};
2057 const size_t kNativeRatesSize =
2058 sizeof(kNativeRates) / sizeof(*kNativeRates);
2059 const int kNumChannels[] = {1, 2};
2060 const size_t kNumChannelsSize =
2061 sizeof(kNumChannels) / sizeof(*kNumChannels);
2062 for (size_t i = 0; i < kNativeRatesSize; ++i) {
2063 for (size_t j = 0; j < kNumChannelsSize; ++j) {
2064 for (size_t k = 0; k < kNumChannelsSize; ++k) {
2065 // The reference files always have matching input and output channels.
2066 ProcessFormat(kNativeRates[i],
2067 kNativeRates[i],
2068 kNativeRates[i],
2069 kNumChannels[j],
2070 kNumChannels[j],
2071 kNumChannels[k],
2072 "ref");
2073 }
2074 }
2075 }
2076 }
2077
2078 // Runs a process pass on files with the given parameters and dumps the output
2079 // to a file specified with |output_file_prefix|.
2080 static void ProcessFormat(int input_rate,
2081 int output_rate,
2082 int reverse_rate,
2083 int num_input_channels,
2084 int num_output_channels,
2085 int num_reverse_channels,
2086 std::string output_file_prefix) {
2087 scoped_ptr<AudioProcessing> ap(AudioProcessing::Create());
2088 EnableAllAPComponents(ap.get());
2089 ap->Initialize(input_rate,
2090 output_rate,
2091 reverse_rate,
2092 LayoutFromChannels(num_input_channels),
2093 LayoutFromChannels(num_output_channels),
2094 LayoutFromChannels(num_reverse_channels));
2095
2096 FILE* far_file = fopen(ResourceFilePath("far", reverse_rate).c_str(), "rb");
2097 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
2098 FILE* out_file = fopen(OutputFilePath(output_file_prefix,
andrew@webrtc.orgf26c9e82014-04-24 03:46:462099 input_rate,
andrew@webrtc.orgddbb8a22014-04-22 21:00:042100 output_rate,
andrew@webrtc.orgf26c9e82014-04-24 03:46:462101 reverse_rate,
andrew@webrtc.orgddbb8a22014-04-22 21:00:042102 num_input_channels,
2103 num_output_channels,
2104 num_reverse_channels).c_str(), "wb");
2105 ASSERT_TRUE(far_file != NULL);
2106 ASSERT_TRUE(near_file != NULL);
2107 ASSERT_TRUE(out_file != NULL);
2108
2109 ChannelBuffer<float> fwd_cb(SamplesFromRate(input_rate),
2110 num_input_channels);
2111 ChannelBuffer<float> rev_cb(SamplesFromRate(reverse_rate),
2112 num_reverse_channels);
2113 ChannelBuffer<float> out_cb(SamplesFromRate(output_rate),
2114 num_output_channels);
2115
2116 // Temporary buffers.
2117 const int max_length =
2118 2 * std::max(out_cb.samples_per_channel(),
2119 std::max(fwd_cb.samples_per_channel(),
2120 rev_cb.samples_per_channel()));
2121 scoped_ptr<float[]> float_data(new float[max_length]);
2122 scoped_ptr<int16_t[]> int_data(new int16_t[max_length]);
2123
2124 int analog_level = 127;
2125 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) &&
2126 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) {
2127 EXPECT_NOERR(ap->AnalyzeReverseStream(
2128 rev_cb.channels(),
2129 rev_cb.samples_per_channel(),
2130 reverse_rate,
2131 LayoutFromChannels(num_reverse_channels)));
2132
2133 EXPECT_NOERR(ap->set_stream_delay_ms(0));
2134 ap->echo_cancellation()->set_stream_drift_samples(0);
2135 EXPECT_NOERR(ap->gain_control()->set_stream_analog_level(analog_level));
2136
2137 EXPECT_NOERR(ap->ProcessStream(
2138 fwd_cb.channels(),
2139 fwd_cb.samples_per_channel(),
2140 input_rate,
2141 LayoutFromChannels(num_input_channels),
2142 output_rate,
2143 LayoutFromChannels(num_output_channels),
2144 out_cb.channels()));
2145
2146 Interleave(out_cb.channels(),
2147 out_cb.samples_per_channel(),
2148 out_cb.num_channels(),
2149 float_data.get());
2150 // Dump output to file.
2151 ASSERT_EQ(static_cast<size_t>(out_cb.length()),
2152 fwrite(float_data.get(), sizeof(float_data[0]),
2153 out_cb.length(), out_file));
2154
2155 analog_level = ap->gain_control()->stream_analog_level();
2156 }
2157 fclose(far_file);
2158 fclose(near_file);
2159 fclose(out_file);
2160 }
2161
2162 protected:
2163 int input_rate_;
2164 int output_rate_;
2165 int reverse_rate_;
2166 double expected_snr_;
2167};
2168
bjornv@webrtc.org2812b592014-06-02 11:27:292169TEST_P(AudioProcessingTest, Formats) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:042170 struct ChannelFormat {
2171 int num_input;
2172 int num_output;
2173 int num_reverse;
2174 };
2175 ChannelFormat cf[] = {
2176 {1, 1, 1},
2177 {1, 1, 2},
2178 {2, 1, 1},
2179 {2, 1, 2},
2180 {2, 2, 1},
2181 {2, 2, 2},
2182 };
2183 size_t channel_format_size = sizeof(cf) / sizeof(*cf);
2184
2185 for (size_t i = 0; i < channel_format_size; ++i) {
2186 ProcessFormat(input_rate_,
2187 output_rate_,
2188 reverse_rate_,
2189 cf[i].num_input,
2190 cf[i].num_output,
2191 cf[i].num_reverse,
2192 "out");
2193 int min_ref_rate = std::min(input_rate_, output_rate_);
2194 int ref_rate;
2195 if (min_ref_rate > 16000) {
2196 ref_rate = 32000;
2197 } else if (min_ref_rate > 8000) {
2198 ref_rate = 16000;
2199 } else {
2200 ref_rate = 8000;
2201 }
2202#ifdef WEBRTC_AUDIOPROC_FIXED_PROFILE
2203 ref_rate = std::min(ref_rate, 16000);
2204#endif
2205
2206 FILE* out_file = fopen(OutputFilePath("out",
andrew@webrtc.orgf26c9e82014-04-24 03:46:462207 input_rate_,
andrew@webrtc.orgddbb8a22014-04-22 21:00:042208 output_rate_,
andrew@webrtc.orgf26c9e82014-04-24 03:46:462209 reverse_rate_,
andrew@webrtc.orgddbb8a22014-04-22 21:00:042210 cf[i].num_input,
2211 cf[i].num_output,
2212 cf[i].num_reverse).c_str(), "rb");
2213 // The reference files always have matching input and output channels.
2214 FILE* ref_file = fopen(OutputFilePath("ref",
2215 ref_rate,
andrew@webrtc.orgf26c9e82014-04-24 03:46:462216 ref_rate,
2217 ref_rate,
andrew@webrtc.orgddbb8a22014-04-22 21:00:042218 cf[i].num_output,
2219 cf[i].num_output,
2220 cf[i].num_reverse).c_str(), "rb");
2221 ASSERT_TRUE(out_file != NULL);
2222 ASSERT_TRUE(ref_file != NULL);
2223
2224 const int ref_length = SamplesFromRate(ref_rate) * cf[i].num_output;
2225 const int out_length = SamplesFromRate(output_rate_) * cf[i].num_output;
2226 // Data from the reference file.
2227 scoped_ptr<float[]> ref_data(new float[ref_length]);
2228 // Data from the output file.
2229 scoped_ptr<float[]> out_data(new float[out_length]);
2230 // Data from the resampled output, in case the reference and output rates
2231 // don't match.
2232 scoped_ptr<float[]> cmp_data(new float[ref_length]);
2233
2234 PushResampler<float> resampler;
2235 resampler.InitializeIfNeeded(output_rate_, ref_rate, cf[i].num_output);
2236
2237 // Compute the resampling delay of the output relative to the reference,
2238 // to find the region over which we should search for the best SNR.
2239 float expected_delay_sec = 0;
2240 if (input_rate_ != ref_rate) {
2241 // Input resampling delay.
2242 expected_delay_sec +=
2243 PushSincResampler::AlgorithmicDelaySeconds(input_rate_);
2244 }
2245 if (output_rate_ != ref_rate) {
2246 // Output resampling delay.
2247 expected_delay_sec +=
2248 PushSincResampler::AlgorithmicDelaySeconds(ref_rate);
2249 // Delay of converting the output back to its processing rate for testing.
2250 expected_delay_sec +=
2251 PushSincResampler::AlgorithmicDelaySeconds(output_rate_);
2252 }
2253 int expected_delay = floor(expected_delay_sec * ref_rate + 0.5f) *
2254 cf[i].num_output;
2255
2256 double variance = 0;
2257 double sq_error = 0;
2258 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) &&
2259 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) {
2260 float* out_ptr = out_data.get();
2261 if (output_rate_ != ref_rate) {
2262 // Resample the output back to its internal processing rate if necssary.
2263 ASSERT_EQ(ref_length, resampler.Resample(out_ptr,
2264 out_length,
2265 cmp_data.get(),
2266 ref_length));
2267 out_ptr = cmp_data.get();
2268 }
2269
2270 // Update the |sq_error| and |variance| accumulators with the highest SNR
2271 // of reference vs output.
2272 UpdateBestSNR(ref_data.get(),
2273 out_ptr,
2274 ref_length,
2275 expected_delay,
2276 &variance,
2277 &sq_error);
2278 }
2279
2280 std::cout << "(" << input_rate_ << ", "
2281 << output_rate_ << ", "
2282 << reverse_rate_ << ", "
2283 << cf[i].num_input << ", "
2284 << cf[i].num_output << ", "
2285 << cf[i].num_reverse << "): ";
2286 if (sq_error > 0) {
2287 double snr = 10 * log10(variance / sq_error);
2288 EXPECT_GE(snr, expected_snr_);
2289 EXPECT_NE(0, expected_snr_);
2290 std::cout << "SNR=" << snr << " dB" << std::endl;
2291 } else {
2292 EXPECT_EQ(expected_snr_, 0);
2293 std::cout << "SNR=" << "inf dB" << std::endl;
2294 }
2295
2296 fclose(out_file);
2297 fclose(ref_file);
2298 }
2299}
2300
2301#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
2302INSTANTIATE_TEST_CASE_P(
2303 CommonFormats, AudioProcessingTest, testing::Values(
2304 std::tr1::make_tuple(48000, 48000, 48000, 25),
2305 std::tr1::make_tuple(48000, 48000, 32000, 25),
2306 std::tr1::make_tuple(48000, 48000, 16000, 25),
2307 std::tr1::make_tuple(48000, 44100, 48000, 20),
2308 std::tr1::make_tuple(48000, 44100, 32000, 20),
2309 std::tr1::make_tuple(48000, 44100, 16000, 20),
2310 std::tr1::make_tuple(48000, 32000, 48000, 25),
2311 std::tr1::make_tuple(48000, 32000, 32000, 25),
2312 std::tr1::make_tuple(48000, 32000, 16000, 25),
2313 std::tr1::make_tuple(48000, 16000, 48000, 25),
2314 std::tr1::make_tuple(48000, 16000, 32000, 25),
2315 std::tr1::make_tuple(48000, 16000, 16000, 25),
2316
2317 std::tr1::make_tuple(44100, 48000, 48000, 20),
2318 std::tr1::make_tuple(44100, 48000, 32000, 20),
2319 std::tr1::make_tuple(44100, 48000, 16000, 20),
2320 std::tr1::make_tuple(44100, 44100, 48000, 20),
2321 std::tr1::make_tuple(44100, 44100, 32000, 20),
2322 std::tr1::make_tuple(44100, 44100, 16000, 20),
2323 std::tr1::make_tuple(44100, 32000, 48000, 20),
2324 std::tr1::make_tuple(44100, 32000, 32000, 20),
2325 std::tr1::make_tuple(44100, 32000, 16000, 20),
2326 std::tr1::make_tuple(44100, 16000, 48000, 20),
2327 std::tr1::make_tuple(44100, 16000, 32000, 20),
2328 std::tr1::make_tuple(44100, 16000, 16000, 20),
2329
2330 std::tr1::make_tuple(32000, 48000, 48000, 25),
2331 std::tr1::make_tuple(32000, 48000, 32000, 25),
2332 std::tr1::make_tuple(32000, 48000, 16000, 25),
2333 std::tr1::make_tuple(32000, 44100, 48000, 20),
2334 std::tr1::make_tuple(32000, 44100, 32000, 20),
2335 std::tr1::make_tuple(32000, 44100, 16000, 20),
2336 std::tr1::make_tuple(32000, 32000, 48000, 30),
2337 std::tr1::make_tuple(32000, 32000, 32000, 0),
2338 std::tr1::make_tuple(32000, 32000, 16000, 30),
2339 std::tr1::make_tuple(32000, 16000, 48000, 25),
2340 std::tr1::make_tuple(32000, 16000, 32000, 25),
2341 std::tr1::make_tuple(32000, 16000, 16000, 25),
2342
2343 std::tr1::make_tuple(16000, 48000, 48000, 25),
2344 std::tr1::make_tuple(16000, 48000, 32000, 25),
2345 std::tr1::make_tuple(16000, 48000, 16000, 25),
2346 std::tr1::make_tuple(16000, 44100, 48000, 15),
2347 std::tr1::make_tuple(16000, 44100, 32000, 15),
2348 std::tr1::make_tuple(16000, 44100, 16000, 15),
2349 std::tr1::make_tuple(16000, 32000, 48000, 25),
2350 std::tr1::make_tuple(16000, 32000, 32000, 25),
2351 std::tr1::make_tuple(16000, 32000, 16000, 25),
2352 std::tr1::make_tuple(16000, 16000, 48000, 30),
2353 std::tr1::make_tuple(16000, 16000, 32000, 30),
2354 std::tr1::make_tuple(16000, 16000, 16000, 0)));
2355
2356#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
2357INSTANTIATE_TEST_CASE_P(
2358 CommonFormats, AudioProcessingTest, testing::Values(
2359 std::tr1::make_tuple(48000, 48000, 48000, 20),
2360 std::tr1::make_tuple(48000, 48000, 32000, 20),
2361 std::tr1::make_tuple(48000, 48000, 16000, 20),
2362 std::tr1::make_tuple(48000, 44100, 48000, 15),
2363 std::tr1::make_tuple(48000, 44100, 32000, 15),
2364 std::tr1::make_tuple(48000, 44100, 16000, 15),
2365 std::tr1::make_tuple(48000, 32000, 48000, 20),
2366 std::tr1::make_tuple(48000, 32000, 32000, 20),
2367 std::tr1::make_tuple(48000, 32000, 16000, 20),
2368 std::tr1::make_tuple(48000, 16000, 48000, 20),
2369 std::tr1::make_tuple(48000, 16000, 32000, 20),
2370 std::tr1::make_tuple(48000, 16000, 16000, 20),
2371
2372 std::tr1::make_tuple(44100, 48000, 48000, 19),
2373 std::tr1::make_tuple(44100, 48000, 32000, 19),
2374 std::tr1::make_tuple(44100, 48000, 16000, 19),
2375 std::tr1::make_tuple(44100, 44100, 48000, 15),
2376 std::tr1::make_tuple(44100, 44100, 32000, 15),
2377 std::tr1::make_tuple(44100, 44100, 16000, 15),
2378 std::tr1::make_tuple(44100, 32000, 48000, 19),
2379 std::tr1::make_tuple(44100, 32000, 32000, 19),
2380 std::tr1::make_tuple(44100, 32000, 16000, 19),
2381 std::tr1::make_tuple(44100, 16000, 48000, 19),
2382 std::tr1::make_tuple(44100, 16000, 32000, 19),
2383 std::tr1::make_tuple(44100, 16000, 16000, 19),
2384
2385 std::tr1::make_tuple(32000, 48000, 48000, 19),
2386 std::tr1::make_tuple(32000, 48000, 32000, 19),
2387 std::tr1::make_tuple(32000, 48000, 16000, 19),
2388 std::tr1::make_tuple(32000, 44100, 48000, 15),
2389 std::tr1::make_tuple(32000, 44100, 32000, 15),
2390 std::tr1::make_tuple(32000, 44100, 16000, 15),
2391 std::tr1::make_tuple(32000, 32000, 48000, 19),
2392 std::tr1::make_tuple(32000, 32000, 32000, 19),
2393 std::tr1::make_tuple(32000, 32000, 16000, 19),
2394 std::tr1::make_tuple(32000, 16000, 48000, 19),
2395 std::tr1::make_tuple(32000, 16000, 32000, 19),
2396 std::tr1::make_tuple(32000, 16000, 16000, 19),
2397
2398 std::tr1::make_tuple(16000, 48000, 48000, 25),
2399 std::tr1::make_tuple(16000, 48000, 32000, 25),
2400 std::tr1::make_tuple(16000, 48000, 16000, 25),
2401 std::tr1::make_tuple(16000, 44100, 48000, 15),
2402 std::tr1::make_tuple(16000, 44100, 32000, 15),
2403 std::tr1::make_tuple(16000, 44100, 16000, 15),
2404 std::tr1::make_tuple(16000, 32000, 48000, 25),
2405 std::tr1::make_tuple(16000, 32000, 32000, 25),
2406 std::tr1::make_tuple(16000, 32000, 16000, 25),
2407 std::tr1::make_tuple(16000, 16000, 48000, 30),
2408 std::tr1::make_tuple(16000, 16000, 32000, 30),
2409 std::tr1::make_tuple(16000, 16000, 16000, 0)));
2410#endif
2411
henrike@webrtc.org83cebb22013-06-27 18:31:132412// TODO(henrike): re-implement functionality lost when removing the old main
2413// function. See
2414// https://code.google.com/p/webrtc/issues/detail?id=1981
2415
niklase@google.com470e71d2011-07-07 08:21:252416} // namespace
andrew@webrtc.org27c69802014-02-18 20:24:562417} // namespace webrtc