audio_processing_unittest.cc (137392B)
1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 #include "api/audio/audio_processing.h" 11 12 #include <stdio.h> 13 14 #include <algorithm> 15 #include <array> 16 #include <cmath> 17 #include <cstdint> 18 #include <cstdio> 19 #include <cstring> 20 #include <iostream> 21 #include <limits> 22 #include <map> 23 #include <memory> 24 #include <numeric> 25 #include <ostream> 26 #include <queue> 27 #include <string> 28 #include <tuple> 29 #include <utility> 30 #include <vector> 31 32 #include "absl/flags/flag.h" 33 #include "absl/strings/string_view.h" 34 #include "api/array_view.h" 35 #include "api/audio/audio_processing_statistics.h" 36 #include "api/audio/audio_view.h" 37 #include "api/audio/builtin_audio_processing_builder.h" 38 #include "api/audio/echo_control.h" 39 #include "api/audio/echo_detector_creator.h" 40 #include "api/audio/neural_residual_echo_estimator.h" 41 #include "api/environment/environment.h" 42 #include "api/environment/environment_factory.h" 43 #include "api/make_ref_counted.h" 44 #include "api/scoped_refptr.h" 45 #include "common_audio/channel_buffer.h" 46 #include "common_audio/include/audio_util.h" 47 #include "common_audio/resampler/include/push_resampler.h" 48 #include "common_audio/resampler/push_sinc_resampler.h" 49 #include "modules/audio_processing/aec_dump/aec_dump_factory.h" 50 #include "modules/audio_processing/include/mock_audio_processing.h" 51 #include "modules/audio_processing/test/protobuf_utils.h" 52 #include "modules/audio_processing/test/test_utils.h" 53 #include "rtc_base/checks.h" 54 #include "rtc_base/cpu_info.h" 55 #include "rtc_base/fake_clock.h" 56 #include "rtc_base/numerics/safe_conversions.h" 57 #include "rtc_base/numerics/safe_minmax.h" 58 #include "rtc_base/protobuf_utils.h" 59 #include "rtc_base/strings/string_builder.h" 60 #include "rtc_base/swap_queue.h" 61 #include "rtc_base/system/file_wrapper.h" 62 #include "rtc_base/task_queue_for_test.h" 63 #include "test/gmock.h" 64 #include "test/gtest.h" 65 #include "test/testsupport/file_utils.h" 66 67 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD 68 #include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h" 69 #include "external/webrtc/webrtc/modules/audio_processing/test/unittest.pb.h" 70 #else 71 #include "modules/audio_processing/debug.pb.h" 72 #include "modules/audio_processing/test/unittest.pb.h" 73 #endif 74 75 ABSL_FLAG(bool, 76 write_apm_ref_data, 77 false, 78 "Write ApmTest.Process results to file, instead of comparing results " 79 "to the existing reference data file."); 80 81 namespace webrtc { 82 namespace { 83 84 using ::testing::_; 85 using ::testing::WithoutArgs; 86 87 // All sample rates used by APM internally during processing. Other input / 88 // output rates are resampled to / from one of these. 89 constexpr int kProcessSampleRates[] = {16000, 32000, 48000}; 90 91 enum StreamDirection { kForward = 0, kReverse }; 92 93 void ConvertToFloat(const int16_t* int_data, ChannelBuffer<float>* cb) { 94 ChannelBuffer<int16_t> cb_int(cb->num_frames(), cb->num_channels()); 95 Deinterleave(int_data, cb->num_frames(), cb->num_channels(), 96 cb_int.channels()); 97 for (size_t i = 0; i < cb->num_channels(); ++i) { 98 S16ToFloat(cb_int.channels()[i], cb->num_frames(), cb->channels()[i]); 99 } 100 } 101 102 void ConvertToFloat(const Int16FrameData& frame, ChannelBuffer<float>* cb) { 103 ConvertToFloat(frame.data.data(), cb); 104 } 105 106 void MixStereoToMono(const float* stereo, 107 float* mono, 108 size_t samples_per_channel) { 109 for (size_t i = 0; i < samples_per_channel; ++i) 110 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) / 2; 111 } 112 113 void MixStereoToMono(const int16_t* stereo, 114 int16_t* mono, 115 size_t samples_per_channel) { 116 for (size_t i = 0; i < samples_per_channel; ++i) 117 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) >> 1; 118 } 119 120 void CopyLeftToRightChannel(int16_t* stereo, size_t samples_per_channel) { 121 for (size_t i = 0; i < samples_per_channel; i++) { 122 stereo[i * 2 + 1] = stereo[i * 2]; 123 } 124 } 125 126 void VerifyChannelsAreEqual(const int16_t* stereo, size_t samples_per_channel) { 127 for (size_t i = 0; i < samples_per_channel; i++) { 128 EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]); 129 } 130 } 131 132 void EnableAllAPComponents(AudioProcessing* ap) { 133 AudioProcessing::Config apm_config = ap->GetConfig(); 134 apm_config.echo_canceller.enabled = true; 135 #if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE) 136 apm_config.echo_canceller.mobile_mode = true; 137 138 apm_config.gain_controller1.enabled = true; 139 apm_config.gain_controller1.mode = 140 AudioProcessing::Config::GainController1::kAdaptiveDigital; 141 #elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE) 142 apm_config.echo_canceller.mobile_mode = false; 143 144 apm_config.gain_controller1.enabled = true; 145 apm_config.gain_controller1.mode = 146 AudioProcessing::Config::GainController1::kAdaptiveAnalog; 147 #endif 148 149 apm_config.noise_suppression.enabled = true; 150 151 apm_config.high_pass_filter.enabled = true; 152 apm_config.pipeline.maximum_internal_processing_rate = 48000; 153 ap->ApplyConfig(apm_config); 154 } 155 156 // These functions are only used by ApmTest.Process. 157 template <class T> 158 T AbsValue(T a) { 159 return a > 0 ? a : -a; 160 } 161 162 int16_t MaxAudioFrame(const Int16FrameData& frame) { 163 int16_t max_data = AbsValue(frame.data[0]); 164 for (size_t i = 1; i < frame.size(); i++) { 165 max_data = std::max(max_data, AbsValue(frame.data[i])); 166 } 167 168 return max_data; 169 } 170 171 void OpenFileAndWriteMessage(absl::string_view filename, 172 const MessageLite& msg) { 173 FILE* file = fopen(std::string(filename).c_str(), "wb"); 174 ASSERT_TRUE(file != nullptr); 175 176 int32_t size = checked_cast<int32_t>(msg.ByteSizeLong()); 177 ASSERT_GT(size, 0); 178 std::unique_ptr<uint8_t[]> array(new uint8_t[size]); 179 ASSERT_TRUE(msg.SerializeToArray(array.get(), size)); 180 181 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file)); 182 ASSERT_EQ(static_cast<size_t>(size), 183 fwrite(array.get(), sizeof(array[0]), size, file)); 184 fclose(file); 185 } 186 187 std::string ResourceFilePath(absl::string_view name, int sample_rate_hz) { 188 StringBuilder ss; 189 // Resource files are all stereo. 190 ss << name << sample_rate_hz / 1000 << "_stereo"; 191 return test::ResourcePath(ss.str(), "pcm"); 192 } 193 194 // Temporary filenames unique to this process. Used to be able to run these 195 // tests in parallel as each process needs to be running in isolation they can't 196 // have competing filenames. 197 std::map<std::string, std::string> temp_filenames; 198 199 std::string OutputFilePath(absl::string_view name, 200 int input_rate, 201 int output_rate, 202 int reverse_input_rate, 203 int reverse_output_rate, 204 size_t num_input_channels, 205 size_t num_output_channels, 206 size_t num_reverse_input_channels, 207 size_t num_reverse_output_channels, 208 StreamDirection file_direction) { 209 StringBuilder ss; 210 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000 << "_ir" 211 << num_reverse_input_channels << "_" << reverse_input_rate / 1000 << "_"; 212 if (num_output_channels == 1) { 213 ss << "mono"; 214 } else if (num_output_channels == 2) { 215 ss << "stereo"; 216 } else { 217 RTC_DCHECK_NOTREACHED(); 218 } 219 ss << output_rate / 1000; 220 if (num_reverse_output_channels == 1) { 221 ss << "_rmono"; 222 } else if (num_reverse_output_channels == 2) { 223 ss << "_rstereo"; 224 } else { 225 RTC_DCHECK_NOTREACHED(); 226 } 227 ss << reverse_output_rate / 1000; 228 ss << "_d" << file_direction << "_pcm"; 229 230 std::string filename = ss.str(); 231 if (temp_filenames[filename].empty()) 232 temp_filenames[filename] = test::TempFilename(test::OutputPath(), filename); 233 return temp_filenames[filename]; 234 } 235 236 void ClearTempFiles() { 237 for (auto& kv : temp_filenames) 238 remove(kv.second.c_str()); 239 } 240 241 // Only remove "out" files. Keep "ref" files. 242 void ClearTempOutFiles() { 243 for (auto it = temp_filenames.begin(); it != temp_filenames.end();) { 244 const std::string& filename = it->first; 245 if (filename.substr(0, 3).compare("out") == 0) { 246 remove(it->second.c_str()); 247 temp_filenames.erase(it++); 248 } else { 249 it++; 250 } 251 } 252 } 253 254 void OpenFileAndReadMessage(absl::string_view filename, MessageLite* msg) { 255 FILE* file = fopen(std::string(filename).c_str(), "rb"); 256 ASSERT_TRUE(file != nullptr); 257 ReadMessageFromFile(file, msg); 258 fclose(file); 259 } 260 261 // Reads a 10 ms chunk (actually AudioProcessing::GetFrameSize() samples per 262 // channel) of int16 interleaved audio from the given (assumed stereo) file, 263 // converts to deinterleaved float (optionally downmixing) and returns the 264 // result in `cb`. Returns false if the file ended (or on error) and true 265 // otherwise. 266 // 267 // `int_data` and `float_data` are just temporary space that must be 268 // sufficiently large to hold the 10 ms chunk. 269 bool ReadChunk(FILE* file, 270 int16_t* int_data, 271 float* float_data, 272 ChannelBuffer<float>* cb) { 273 // The files always contain stereo audio. 274 size_t frame_size = cb->num_frames() * 2; 275 size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file); 276 if (read_count != frame_size) { 277 // Check that the file really ended. 278 RTC_DCHECK(feof(file)); 279 return false; // This is expected. 280 } 281 282 S16ToFloat(int_data, frame_size, float_data); 283 if (cb->num_channels() == 1) { 284 MixStereoToMono(float_data, cb->channels()[0], cb->num_frames()); 285 } else { 286 Deinterleave(float_data, cb->num_frames(), 2, cb->channels()); 287 } 288 289 return true; 290 } 291 292 // Returns the reference file name that matches the current CPU 293 // architecture/optimizations. 294 std::string GetReferenceFilename() { 295 #if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE) 296 return test::ResourcePath("audio_processing/output_data_fixed", "pb"); 297 #elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE) 298 if (cpu_info::Supports(cpu_info::ISA::kAVX2)) { 299 return test::ResourcePath("audio_processing/output_data_float_avx2", "pb"); 300 } 301 return test::ResourcePath("audio_processing/output_data_float", "pb"); 302 #endif 303 } 304 305 // Flag that can temporarily be enabled for local debugging to inspect 306 // `ApmTest.VerifyDebugDump(Int|Float)` failures. Do not upload code changes 307 // with this flag set to true. 308 constexpr bool kDumpWhenExpectMessageEqFails = false; 309 310 // Checks the debug constants values used in this file so that no code change is 311 // submitted with values temporarily used for local debugging. 312 TEST(ApmUnitTests, CheckDebugConstants) { 313 ASSERT_FALSE(kDumpWhenExpectMessageEqFails); 314 } 315 316 // Expects the equality of `actual` and `expected` by inspecting a hard-coded 317 // subset of `audioproc::Stream` fields. 318 void ExpectStreamFieldsEq(const audioproc::Stream& actual, 319 const audioproc::Stream& expected) { 320 EXPECT_EQ(actual.input_data(), expected.input_data()); 321 EXPECT_EQ(actual.output_data(), expected.output_data()); 322 EXPECT_EQ(actual.delay(), expected.delay()); 323 EXPECT_EQ(actual.drift(), expected.drift()); 324 EXPECT_EQ(actual.applied_input_volume(), expected.applied_input_volume()); 325 EXPECT_EQ(actual.keypress(), expected.keypress()); 326 } 327 328 // Expects the equality of `actual` and `expected` by inspecting a hard-coded 329 // subset of `audioproc::Event` fields. 330 void ExpectEventFieldsEq(const audioproc::Event& actual, 331 const audioproc::Event& expected) { 332 EXPECT_EQ(actual.type(), expected.type()); 333 if (actual.type() != expected.type()) { 334 return; 335 } 336 switch (actual.type()) { 337 case audioproc::Event::STREAM: 338 ExpectStreamFieldsEq(actual.stream(), expected.stream()); 339 break; 340 default: 341 // Not implemented. 342 break; 343 } 344 } 345 346 // Returns true if the `actual` and `expected` byte streams share the same size 347 // and contain the same data. If they differ and `kDumpWhenExpectMessageEqFails` 348 // is true, checks the equality of a subset of `audioproc::Event` (nested) 349 // fields. 350 bool ExpectMessageEq(ArrayView<const uint8_t> actual, 351 ArrayView<const uint8_t> expected) { 352 EXPECT_EQ(actual.size(), expected.size()); 353 if (actual.size() != expected.size()) { 354 return false; 355 } 356 if (memcmp(actual.data(), expected.data(), actual.size()) == 0) { 357 // Same message. No need to parse. 358 return true; 359 } 360 if (kDumpWhenExpectMessageEqFails) { 361 // Parse differing messages and expect equality to produce detailed error 362 // messages. 363 audioproc::Event event_actual, event_expected; 364 RTC_DCHECK(event_actual.ParseFromArray(actual.data(), actual.size())); 365 RTC_DCHECK(event_expected.ParseFromArray(expected.data(), expected.size())); 366 ExpectEventFieldsEq(event_actual, event_expected); 367 } 368 return false; 369 } 370 371 class ApmTest : public ::testing::Test { 372 protected: 373 ApmTest(); 374 void SetUp() override; 375 void TearDown() override; 376 377 static void SetUpTestSuite() {} 378 379 static void TearDownTestSuite() { ClearTempFiles(); } 380 381 // Used to select between int and float interface tests. 382 enum Format { kIntFormat, kFloatFormat }; 383 384 void Init(int sample_rate_hz, 385 int output_sample_rate_hz, 386 int reverse_sample_rate_hz, 387 size_t num_input_channels, 388 size_t num_output_channels, 389 size_t num_reverse_channels, 390 bool open_output_file); 391 void Init(AudioProcessing* ap); 392 void EnableAllComponents(); 393 bool ReadFrame(FILE* file, Int16FrameData* frame); 394 bool ReadFrame(FILE* file, Int16FrameData* frame, ChannelBuffer<float>* cb); 395 void ReadFrameWithRewind(FILE* file, Int16FrameData* frame); 396 void ReadFrameWithRewind(FILE* file, 397 Int16FrameData* frame, 398 ChannelBuffer<float>* cb); 399 void ProcessDelayVerificationTest(int delay_ms, 400 int system_delay_ms, 401 int delay_min, 402 int delay_max); 403 void TestChangingChannelsInt16Interface( 404 size_t num_channels, 405 AudioProcessing::Error expected_return); 406 void TestChangingForwardChannels(size_t num_in_channels, 407 size_t num_out_channels, 408 AudioProcessing::Error expected_return); 409 void TestChangingReverseChannels(size_t num_rev_channels, 410 AudioProcessing::Error expected_return); 411 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate); 412 void RunManualVolumeChangeIsPossibleTest(int sample_rate); 413 void StreamParametersTest(Format format); 414 int ProcessStreamChooser(Format format); 415 int AnalyzeReverseStreamChooser(Format format); 416 void ProcessDebugDump(absl::string_view in_filename, 417 absl::string_view out_filename, 418 Format format, 419 int max_size_bytes); 420 void VerifyDebugDumpTest(Format format); 421 422 const std::string output_path_; 423 const std::string ref_filename_; 424 scoped_refptr<AudioProcessing> apm_; 425 Int16FrameData frame_; 426 Int16FrameData revframe_; 427 std::unique_ptr<ChannelBuffer<float>> float_cb_; 428 std::unique_ptr<ChannelBuffer<float>> revfloat_cb_; 429 int output_sample_rate_hz_; 430 size_t num_output_channels_; 431 FILE* far_file_; 432 FILE* near_file_; 433 FILE* out_file_; 434 }; 435 436 ApmTest::ApmTest() 437 : output_path_(test::OutputPath()), 438 ref_filename_(GetReferenceFilename()), 439 output_sample_rate_hz_(0), 440 num_output_channels_(0), 441 far_file_(nullptr), 442 near_file_(nullptr), 443 out_file_(nullptr) { 444 apm_ = BuiltinAudioProcessingBuilder().Build(CreateEnvironment()); 445 AudioProcessing::Config apm_config = apm_->GetConfig(); 446 apm_config.gain_controller1.analog_gain_controller.enabled = false; 447 apm_config.pipeline.maximum_internal_processing_rate = 48000; 448 apm_->ApplyConfig(apm_config); 449 } 450 451 void ApmTest::SetUp() { 452 ASSERT_TRUE(apm_.get() != nullptr); 453 454 Init(32000, 32000, 32000, 2, 2, 2, false); 455 } 456 457 void ApmTest::TearDown() { 458 if (far_file_) { 459 ASSERT_EQ(0, fclose(far_file_)); 460 } 461 far_file_ = nullptr; 462 463 if (near_file_) { 464 ASSERT_EQ(0, fclose(near_file_)); 465 } 466 near_file_ = nullptr; 467 468 if (out_file_) { 469 ASSERT_EQ(0, fclose(out_file_)); 470 } 471 out_file_ = nullptr; 472 } 473 474 void ApmTest::Init(AudioProcessing* ap) { 475 ASSERT_EQ( 476 AudioProcessing::kNoError, 477 ap->Initialize({{{frame_.sample_rate_hz, frame_.num_channels()}, 478 {output_sample_rate_hz_, num_output_channels_}, 479 {revframe_.sample_rate_hz, revframe_.num_channels()}, 480 {revframe_.sample_rate_hz, revframe_.num_channels()}}})); 481 } 482 483 void ApmTest::Init(int sample_rate_hz, 484 int output_sample_rate_hz, 485 int reverse_sample_rate_hz, 486 size_t num_input_channels, 487 size_t num_output_channels, 488 size_t num_reverse_channels, 489 bool open_output_file) { 490 SetContainerFormat(sample_rate_hz, num_input_channels, &frame_, &float_cb_); 491 output_sample_rate_hz_ = output_sample_rate_hz; 492 num_output_channels_ = num_output_channels; 493 494 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, &revframe_, 495 &revfloat_cb_); 496 Init(apm_.get()); 497 498 if (far_file_) { 499 ASSERT_EQ(0, fclose(far_file_)); 500 } 501 std::string filename = ResourceFilePath("far", sample_rate_hz); 502 far_file_ = fopen(filename.c_str(), "rb"); 503 ASSERT_TRUE(far_file_ != nullptr) 504 << "Could not open file " << filename << "\n"; 505 506 if (near_file_) { 507 ASSERT_EQ(0, fclose(near_file_)); 508 } 509 filename = ResourceFilePath("near", sample_rate_hz); 510 near_file_ = fopen(filename.c_str(), "rb"); 511 ASSERT_TRUE(near_file_ != nullptr) 512 << "Could not open file " << filename << "\n"; 513 514 if (open_output_file) { 515 if (out_file_) { 516 ASSERT_EQ(0, fclose(out_file_)); 517 } 518 filename = OutputFilePath( 519 "out", sample_rate_hz, output_sample_rate_hz, reverse_sample_rate_hz, 520 reverse_sample_rate_hz, num_input_channels, num_output_channels, 521 num_reverse_channels, num_reverse_channels, kForward); 522 out_file_ = fopen(filename.c_str(), "wb"); 523 ASSERT_TRUE(out_file_ != nullptr) 524 << "Could not open file " << filename << "\n"; 525 } 526 } 527 528 void ApmTest::EnableAllComponents() { 529 EnableAllAPComponents(apm_.get()); 530 } 531 532 bool ApmTest::ReadFrame(FILE* file, 533 Int16FrameData* frame, 534 ChannelBuffer<float>* cb) { 535 // The files always contain stereo audio. 536 size_t frame_size = frame->samples_per_channel() * 2; 537 size_t read_count = 538 fread(frame->data.data(), sizeof(int16_t), frame_size, file); 539 if (read_count != frame_size) { 540 // Check that the file really ended. 541 EXPECT_NE(0, feof(file)); 542 return false; // This is expected. 543 } 544 545 if (frame->num_channels() == 1) { 546 MixStereoToMono(frame->data.data(), frame->data.data(), 547 frame->samples_per_channel()); 548 } 549 550 if (cb) { 551 ConvertToFloat(*frame, cb); 552 } 553 return true; 554 } 555 556 bool ApmTest::ReadFrame(FILE* file, Int16FrameData* frame) { 557 return ReadFrame(file, frame, nullptr); 558 } 559 560 // If the end of the file has been reached, rewind it and attempt to read the 561 // frame again. 562 void ApmTest::ReadFrameWithRewind(FILE* /* file */, 563 Int16FrameData* /* frame */, 564 ChannelBuffer<float>* cb) { 565 if (!ReadFrame(near_file_, &frame_, cb)) { 566 rewind(near_file_); 567 ASSERT_TRUE(ReadFrame(near_file_, &frame_, cb)); 568 } 569 } 570 571 void ApmTest::ReadFrameWithRewind(FILE* file, Int16FrameData* frame) { 572 ReadFrameWithRewind(file, frame, nullptr); 573 } 574 575 int ApmTest::ProcessStreamChooser(Format format) { 576 if (format == kIntFormat) { 577 return apm_->ProcessStream( 578 frame_.data.data(), 579 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 580 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 581 frame_.data.data()); 582 } 583 return apm_->ProcessStream( 584 float_cb_->channels(), 585 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 586 StreamConfig(output_sample_rate_hz_, num_output_channels_), 587 float_cb_->channels()); 588 } 589 590 int ApmTest::AnalyzeReverseStreamChooser(Format format) { 591 if (format == kIntFormat) { 592 return apm_->ProcessReverseStream( 593 revframe_.data.data(), 594 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels()), 595 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels()), 596 revframe_.data.data()); 597 } 598 return apm_->AnalyzeReverseStream( 599 revfloat_cb_->channels(), 600 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels())); 601 } 602 603 void ApmTest::ProcessDelayVerificationTest(int delay_ms, 604 int system_delay_ms, 605 int delay_min, 606 int delay_max) { 607 // The `revframe_` and `frame_` should include the proper frame information, 608 // hence can be used for extracting information. 609 Int16FrameData tmp_frame; 610 std::queue<Int16FrameData*> frame_queue; 611 bool causal = true; 612 613 tmp_frame.CopyFrom(revframe_); 614 tmp_frame.FillData(0); 615 616 EXPECT_EQ(AudioProcessing::kNoError, apm_->Initialize()); 617 // Initialize the `frame_queue` with empty frames. 618 int frame_delay = delay_ms / 10; 619 while (frame_delay < 0) { 620 Int16FrameData* frame = new Int16FrameData(); 621 frame->CopyFrom(tmp_frame); 622 frame_queue.push(frame); 623 frame_delay++; 624 causal = false; 625 } 626 while (frame_delay > 0) { 627 Int16FrameData* frame = new Int16FrameData(); 628 frame->CopyFrom(tmp_frame); 629 frame_queue.push(frame); 630 frame_delay--; 631 } 632 // Run for 4.5 seconds, skipping statistics from the first 2.5 seconds. We 633 // need enough frames with audio to have reliable estimates, but as few as 634 // possible to keep processing time down. 4.5 seconds seemed to be a good 635 // compromise for this recording. 636 for (int frame_count = 0; frame_count < 450; ++frame_count) { 637 Int16FrameData* frame = new Int16FrameData(); 638 frame->CopyFrom(tmp_frame); 639 // Use the near end recording, since that has more speech in it. 640 ASSERT_TRUE(ReadFrame(near_file_, frame)); 641 frame_queue.push(frame); 642 Int16FrameData* reverse_frame = frame; 643 Int16FrameData* process_frame = frame_queue.front(); 644 if (!causal) { 645 reverse_frame = frame_queue.front(); 646 // When we call ProcessStream() the frame is modified, so we can't use the 647 // pointer directly when things are non-causal. Use an intermediate frame 648 // and copy the data. 649 process_frame = &tmp_frame; 650 process_frame->CopyFrom(*frame); 651 } 652 EXPECT_EQ( 653 AudioProcessing::kNoError, 654 apm_->ProcessReverseStream(reverse_frame->data.data(), 655 StreamConfig(reverse_frame->sample_rate_hz, 656 reverse_frame->num_channels()), 657 StreamConfig(reverse_frame->sample_rate_hz, 658 reverse_frame->num_channels()), 659 reverse_frame->data.data())); 660 EXPECT_EQ(AudioProcessing::kNoError, 661 apm_->set_stream_delay_ms(system_delay_ms)); 662 EXPECT_EQ(AudioProcessing::kNoError, 663 apm_->ProcessStream(process_frame->data.data(), 664 StreamConfig(process_frame->sample_rate_hz, 665 process_frame->num_channels()), 666 StreamConfig(process_frame->sample_rate_hz, 667 process_frame->num_channels()), 668 process_frame->data.data())); 669 frame = frame_queue.front(); 670 frame_queue.pop(); 671 delete frame; 672 673 if (frame_count == 250) { 674 // Discard the first delay metrics to avoid convergence effects. 675 static_cast<void>(apm_->GetStatistics()); 676 } 677 } 678 679 rewind(near_file_); 680 while (!frame_queue.empty()) { 681 Int16FrameData* frame = frame_queue.front(); 682 frame_queue.pop(); 683 delete frame; 684 } 685 // Calculate expected delay estimate and acceptable regions. Further, 686 // limit them w.r.t. AEC delay estimation support. 687 const size_t samples_per_ms = 688 SafeMin<size_t>(16u, frame_.samples_per_channel() / 10); 689 const int expected_median = 690 SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max); 691 const int expected_median_high = 692 SafeClamp<int>(expected_median + dchecked_cast<int>(96 / samples_per_ms), 693 delay_min, delay_max); 694 const int expected_median_low = 695 SafeClamp<int>(expected_median - dchecked_cast<int>(96 / samples_per_ms), 696 delay_min, delay_max); 697 // Verify delay metrics. 698 AudioProcessingStats stats = apm_->GetStatistics(); 699 ASSERT_TRUE(stats.delay_median_ms.has_value()); 700 int32_t median = *stats.delay_median_ms; 701 EXPECT_GE(expected_median_high, median); 702 EXPECT_LE(expected_median_low, median); 703 } 704 705 void ApmTest::StreamParametersTest(Format format) { 706 // No errors when the components are disabled. 707 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(format)); 708 709 // -- Missing AGC level -- 710 AudioProcessing::Config apm_config = apm_->GetConfig(); 711 apm_config.gain_controller1.enabled = true; 712 apm_->ApplyConfig(apm_config); 713 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format)); 714 715 // Resets after successful ProcessStream(). 716 apm_->set_stream_analog_level(127); 717 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(format)); 718 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format)); 719 720 // Other stream parameters set correctly. 721 apm_config.echo_canceller.enabled = true; 722 apm_config.echo_canceller.mobile_mode = false; 723 apm_->ApplyConfig(apm_config); 724 EXPECT_EQ(AudioProcessing::kNoError, apm_->set_stream_delay_ms(100)); 725 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format)); 726 apm_config.gain_controller1.enabled = false; 727 apm_->ApplyConfig(apm_config); 728 729 // -- Missing delay -- 730 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(format)); 731 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(format)); 732 733 // Resets after successful ProcessStream(). 734 EXPECT_EQ(AudioProcessing::kNoError, apm_->set_stream_delay_ms(100)); 735 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(format)); 736 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(format)); 737 738 // Other stream parameters set correctly. 739 apm_config.gain_controller1.enabled = true; 740 apm_->ApplyConfig(apm_config); 741 apm_->set_stream_analog_level(127); 742 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(format)); 743 apm_config.gain_controller1.enabled = false; 744 apm_->ApplyConfig(apm_config); 745 746 // -- No stream parameters -- 747 EXPECT_EQ(AudioProcessing::kNoError, AnalyzeReverseStreamChooser(format)); 748 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(format)); 749 750 // -- All there -- 751 EXPECT_EQ(AudioProcessing::kNoError, apm_->set_stream_delay_ms(100)); 752 apm_->set_stream_analog_level(127); 753 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(format)); 754 } 755 756 TEST_F(ApmTest, StreamParametersInt) { 757 StreamParametersTest(kIntFormat); 758 } 759 760 TEST_F(ApmTest, StreamParametersFloat) { 761 StreamParametersTest(kFloatFormat); 762 } 763 764 void ApmTest::TestChangingChannelsInt16Interface( 765 size_t num_channels, 766 AudioProcessing::Error expected_return) { 767 frame_.set_num_channels(num_channels); 768 769 EXPECT_EQ(expected_return, 770 apm_->ProcessStream( 771 frame_.data.data(), 772 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 773 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 774 frame_.data.data())); 775 EXPECT_EQ(expected_return, 776 apm_->ProcessReverseStream( 777 frame_.data.data(), 778 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 779 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 780 frame_.data.data())); 781 } 782 783 void ApmTest::TestChangingForwardChannels( 784 size_t num_in_channels, 785 size_t num_out_channels, 786 AudioProcessing::Error expected_return) { 787 const StreamConfig input_stream = {frame_.sample_rate_hz, num_in_channels}; 788 const StreamConfig output_stream = {output_sample_rate_hz_, num_out_channels}; 789 790 EXPECT_EQ(expected_return, 791 apm_->ProcessStream(float_cb_->channels(), input_stream, 792 output_stream, float_cb_->channels())); 793 } 794 795 void ApmTest::TestChangingReverseChannels( 796 size_t num_rev_channels, 797 AudioProcessing::Error expected_return) { 798 const ProcessingConfig processing_config = { 799 {{frame_.sample_rate_hz, apm_->num_input_channels()}, 800 {output_sample_rate_hz_, apm_->num_output_channels()}, 801 {frame_.sample_rate_hz, num_rev_channels}, 802 {frame_.sample_rate_hz, num_rev_channels}}}; 803 804 EXPECT_EQ( 805 expected_return, 806 apm_->ProcessReverseStream( 807 float_cb_->channels(), processing_config.reverse_input_stream(), 808 processing_config.reverse_output_stream(), float_cb_->channels())); 809 } 810 811 TEST_F(ApmTest, ChannelsInt16Interface) { 812 // Testing number of invalid and valid channels. 813 Init(16000, 16000, 16000, 4, 4, 4, false); 814 815 TestChangingChannelsInt16Interface(0, 816 AudioProcessing::kBadNumberChannelsError); 817 818 for (size_t i = 1; i < 4; i++) { 819 TestChangingChannelsInt16Interface(i, AudioProcessing::kNoError); 820 EXPECT_EQ(i, apm_->num_input_channels()); 821 } 822 } 823 824 TEST_F(ApmTest, Channels) { 825 // Testing number of invalid and valid channels. 826 Init(16000, 16000, 16000, 4, 4, 4, false); 827 828 TestChangingForwardChannels(0, 1, AudioProcessing::kBadNumberChannelsError); 829 TestChangingReverseChannels(0, AudioProcessing::kBadNumberChannelsError); 830 831 for (size_t i = 1; i < 4; ++i) { 832 for (size_t j = 0; j < 1; ++j) { 833 // Output channels much be one or match input channels. 834 if (j == 1 || i == j) { 835 TestChangingForwardChannels(i, j, AudioProcessing::kNoError); 836 TestChangingReverseChannels(i, AudioProcessing::kNoError); 837 838 EXPECT_EQ(i, apm_->num_input_channels()); 839 EXPECT_EQ(j, apm_->num_output_channels()); 840 // The number of reverse channels used for processing to is always 1. 841 EXPECT_EQ(1u, apm_->num_reverse_channels()); 842 } else { 843 TestChangingForwardChannels(i, j, 844 AudioProcessing::kBadNumberChannelsError); 845 } 846 } 847 } 848 } 849 850 TEST_F(ApmTest, SampleRatesInt) { 851 // Testing some valid sample rates. 852 for (int sample_rate : {8000, 12000, 16000, 32000, 44100, 48000, 96000}) { 853 SetContainerFormat(sample_rate, 2, &frame_, &float_cb_); 854 EXPECT_NOERR(ProcessStreamChooser(kIntFormat)); 855 } 856 } 857 858 // This test repeatedly reconfigures the pre-amplifier in APM, processes a 859 // number of frames, and checks that output signal has the right level. 860 TEST_F(ApmTest, PreAmplifier) { 861 // Fill the audio frame with a sawtooth pattern. 862 InterleavedView<int16_t> frame_data = frame_.view(); 863 const size_t samples_per_channel = frame_.samples_per_channel(); 864 for (size_t i = 0; i < samples_per_channel; i++) { 865 for (size_t ch = 0; ch < frame_.num_channels(); ++ch) { 866 frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1); 867 } 868 } 869 // Cache the frame in tmp_frame. 870 Int16FrameData tmp_frame; 871 tmp_frame.CopyFrom(frame_); 872 873 auto compute_power = [](const Int16FrameData& frame) { 874 ArrayView<const int16_t> data = frame.view().data(); 875 return std::accumulate(data.begin(), data.end(), 0.0f, 876 [](float a, float b) { return a + b * b; }) / 877 data.size() / 32768 / 32768; 878 }; 879 880 const float input_power = compute_power(tmp_frame); 881 // Double-check that the input data is large compared to the error kEpsilon. 882 constexpr float kEpsilon = 1e-4f; 883 RTC_DCHECK_GE(input_power, 10 * kEpsilon); 884 885 // 1. Enable pre-amp with 0 dB gain. 886 AudioProcessing::Config config = apm_->GetConfig(); 887 config.pre_amplifier.enabled = true; 888 config.pre_amplifier.fixed_gain_factor = 1.0f; 889 apm_->ApplyConfig(config); 890 891 for (int i = 0; i < 20; ++i) { 892 frame_.CopyFrom(tmp_frame); 893 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kIntFormat)); 894 } 895 float output_power = compute_power(frame_); 896 EXPECT_NEAR(output_power, input_power, kEpsilon); 897 config = apm_->GetConfig(); 898 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.0f); 899 900 // 2. Change pre-amp gain via ApplyConfig. 901 config.pre_amplifier.fixed_gain_factor = 2.0f; 902 apm_->ApplyConfig(config); 903 904 for (int i = 0; i < 20; ++i) { 905 frame_.CopyFrom(tmp_frame); 906 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kIntFormat)); 907 } 908 output_power = compute_power(frame_); 909 EXPECT_NEAR(output_power, 4 * input_power, kEpsilon); 910 config = apm_->GetConfig(); 911 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 2.0f); 912 913 // 3. Change pre-amp gain via a RuntimeSetting. 914 apm_->SetRuntimeSetting( 915 AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.5f)); 916 917 for (int i = 0; i < 20; ++i) { 918 frame_.CopyFrom(tmp_frame); 919 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kIntFormat)); 920 } 921 output_power = compute_power(frame_); 922 EXPECT_NEAR(output_power, 2.25 * input_power, kEpsilon); 923 config = apm_->GetConfig(); 924 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f); 925 } 926 927 // Ensures that the emulated analog mic gain functionality runs without 928 // crashing. 929 TEST_F(ApmTest, AnalogMicGainEmulation) { 930 // Fill the audio frame with a sawtooth pattern. 931 InterleavedView<int16_t> frame_data = frame_.view(); 932 const size_t samples_per_channel = frame_.samples_per_channel(); 933 for (size_t i = 0; i < samples_per_channel; i++) { 934 for (size_t ch = 0; ch < frame_.num_channels(); ++ch) { 935 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1); 936 } 937 } 938 // Cache the frame in tmp_frame. 939 Int16FrameData tmp_frame; 940 tmp_frame.CopyFrom(frame_); 941 942 // Enable the analog gain emulation. 943 AudioProcessing::Config config = apm_->GetConfig(); 944 config.capture_level_adjustment.enabled = true; 945 config.capture_level_adjustment.analog_mic_gain_emulation.enabled = true; 946 config.capture_level_adjustment.analog_mic_gain_emulation.initial_level = 21; 947 config.gain_controller1.enabled = true; 948 config.gain_controller1.mode = 949 AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog; 950 config.gain_controller1.analog_gain_controller.enabled = true; 951 apm_->ApplyConfig(config); 952 953 // Process a number of frames to ensure that the code runs without crashes. 954 for (int i = 0; i < 20; ++i) { 955 frame_.CopyFrom(tmp_frame); 956 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kIntFormat)); 957 } 958 } 959 960 // This test repeatedly reconfigures the capture level adjustment functionality 961 // in APM, processes a number of frames, and checks that output signal has the 962 // right level. 963 TEST_F(ApmTest, CaptureLevelAdjustment) { 964 // Fill the audio frame with a sawtooth pattern. 965 InterleavedView<int16_t> frame_data = frame_.view(); 966 const size_t samples_per_channel = frame_.samples_per_channel(); 967 for (size_t i = 0; i < samples_per_channel; i++) { 968 for (size_t ch = 0; ch < frame_.num_channels(); ++ch) { 969 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1); 970 } 971 } 972 // Cache the frame in tmp_frame. 973 Int16FrameData tmp_frame; 974 tmp_frame.CopyFrom(frame_); 975 976 auto compute_power = [](const Int16FrameData& frame) { 977 ArrayView<const int16_t> data = frame.view().data(); 978 return std::accumulate(data.begin(), data.end(), 0.0f, 979 [](float a, float b) { return a + b * b; }) / 980 data.size() / 32768 / 32768; 981 }; 982 983 const float input_power = compute_power(tmp_frame); 984 // Double-check that the input data is large compared to the error kEpsilon. 985 constexpr float kEpsilon = 1e-20f; 986 RTC_DCHECK_GE(input_power, 10 * kEpsilon); 987 988 // 1. Enable pre-amp with 0 dB gain. 989 AudioProcessing::Config config = apm_->GetConfig(); 990 config.capture_level_adjustment.enabled = true; 991 config.capture_level_adjustment.pre_gain_factor = 0.5f; 992 config.capture_level_adjustment.post_gain_factor = 4.f; 993 const float expected_output_power1 = 994 config.capture_level_adjustment.pre_gain_factor * 995 config.capture_level_adjustment.pre_gain_factor * 996 config.capture_level_adjustment.post_gain_factor * 997 config.capture_level_adjustment.post_gain_factor * input_power; 998 apm_->ApplyConfig(config); 999 1000 for (int i = 0; i < 20; ++i) { 1001 frame_.CopyFrom(tmp_frame); 1002 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kIntFormat)); 1003 } 1004 float output_power = compute_power(frame_); 1005 EXPECT_NEAR(output_power, expected_output_power1, kEpsilon); 1006 config = apm_->GetConfig(); 1007 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f); 1008 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 4.f); 1009 1010 // 2. Change pre-amp gain via ApplyConfig. 1011 config.capture_level_adjustment.pre_gain_factor = 1.0f; 1012 config.capture_level_adjustment.post_gain_factor = 2.f; 1013 const float expected_output_power2 = 1014 config.capture_level_adjustment.pre_gain_factor * 1015 config.capture_level_adjustment.pre_gain_factor * 1016 config.capture_level_adjustment.post_gain_factor * 1017 config.capture_level_adjustment.post_gain_factor * input_power; 1018 apm_->ApplyConfig(config); 1019 1020 for (int i = 0; i < 20; ++i) { 1021 frame_.CopyFrom(tmp_frame); 1022 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kIntFormat)); 1023 } 1024 output_power = compute_power(frame_); 1025 EXPECT_NEAR(output_power, expected_output_power2, kEpsilon); 1026 config = apm_->GetConfig(); 1027 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 1.0f); 1028 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 2.f); 1029 1030 // 3. Change pre-amp gain via a RuntimeSetting. 1031 constexpr float kPreGain3 = 0.5f; 1032 constexpr float kPostGain3 = 3.f; 1033 const float expected_output_power3 = 1034 kPreGain3 * kPreGain3 * kPostGain3 * kPostGain3 * input_power; 1035 1036 apm_->SetRuntimeSetting( 1037 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kPreGain3)); 1038 apm_->SetRuntimeSetting( 1039 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kPostGain3)); 1040 1041 for (int i = 0; i < 20; ++i) { 1042 frame_.CopyFrom(tmp_frame); 1043 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kIntFormat)); 1044 } 1045 output_power = compute_power(frame_); 1046 EXPECT_NEAR(output_power, expected_output_power3, kEpsilon); 1047 config = apm_->GetConfig(); 1048 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f); 1049 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 3.f); 1050 } 1051 1052 TEST_F(ApmTest, GainControl) { 1053 AudioProcessing::Config config = apm_->GetConfig(); 1054 config.gain_controller1.enabled = false; 1055 apm_->ApplyConfig(config); 1056 config.gain_controller1.enabled = true; 1057 apm_->ApplyConfig(config); 1058 1059 // Testing gain modes 1060 for (auto mode : 1061 {AudioProcessing::Config::GainController1::kAdaptiveDigital, 1062 AudioProcessing::Config::GainController1::kFixedDigital, 1063 AudioProcessing::Config::GainController1::kAdaptiveAnalog}) { 1064 config.gain_controller1.mode = mode; 1065 apm_->ApplyConfig(config); 1066 apm_->set_stream_analog_level(100); 1067 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kFloatFormat)); 1068 } 1069 1070 // Testing target levels 1071 for (int target_level_dbfs : {0, 15, 31}) { 1072 config.gain_controller1.target_level_dbfs = target_level_dbfs; 1073 apm_->ApplyConfig(config); 1074 apm_->set_stream_analog_level(100); 1075 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kFloatFormat)); 1076 } 1077 1078 // Testing compression gains 1079 for (int compression_gain_db : {0, 10, 90}) { 1080 config.gain_controller1.compression_gain_db = compression_gain_db; 1081 apm_->ApplyConfig(config); 1082 apm_->set_stream_analog_level(100); 1083 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kFloatFormat)); 1084 } 1085 1086 // Testing limiter off/on 1087 for (bool enable : {false, true}) { 1088 config.gain_controller1.enable_limiter = enable; 1089 apm_->ApplyConfig(config); 1090 apm_->set_stream_analog_level(100); 1091 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kFloatFormat)); 1092 } 1093 1094 // Testing level limits. 1095 constexpr int kMinLevel = 0; 1096 constexpr int kMaxLevel = 255; 1097 apm_->set_stream_analog_level(kMinLevel); 1098 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kFloatFormat)); 1099 apm_->set_stream_analog_level((kMinLevel + kMaxLevel) / 2); 1100 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kFloatFormat)); 1101 apm_->set_stream_analog_level(kMaxLevel); 1102 EXPECT_EQ(AudioProcessing::kNoError, ProcessStreamChooser(kFloatFormat)); 1103 } 1104 1105 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) 1106 using ApmDeathTest = ApmTest; 1107 1108 TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) { 1109 auto config = apm_->GetConfig(); 1110 config.gain_controller1.enabled = true; 1111 config.gain_controller1.target_level_dbfs = -1; 1112 EXPECT_DEATH(apm_->ApplyConfig(config), ""); 1113 } 1114 1115 TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) { 1116 auto config = apm_->GetConfig(); 1117 config.gain_controller1.enabled = true; 1118 config.gain_controller1.target_level_dbfs = 32; 1119 EXPECT_DEATH(apm_->ApplyConfig(config), ""); 1120 } 1121 1122 TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) { 1123 auto config = apm_->GetConfig(); 1124 config.gain_controller1.enabled = true; 1125 config.gain_controller1.compression_gain_db = -1; 1126 EXPECT_DEATH(apm_->ApplyConfig(config), ""); 1127 } 1128 1129 TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) { 1130 auto config = apm_->GetConfig(); 1131 config.gain_controller1.enabled = true; 1132 config.gain_controller1.compression_gain_db = 91; 1133 EXPECT_DEATH(apm_->ApplyConfig(config), ""); 1134 } 1135 1136 TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) { 1137 auto config = apm_->GetConfig(); 1138 config.gain_controller1.enabled = true; 1139 apm_->ApplyConfig(config); 1140 EXPECT_DEATH(apm_->set_stream_analog_level(-1), ""); 1141 } 1142 1143 TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) { 1144 auto config = apm_->GetConfig(); 1145 config.gain_controller1.enabled = true; 1146 apm_->ApplyConfig(config); 1147 EXPECT_DEATH(apm_->set_stream_analog_level(256), ""); 1148 } 1149 #endif 1150 1151 void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) { 1152 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false); 1153 auto config = apm_->GetConfig(); 1154 config.gain_controller1.enabled = true; 1155 config.gain_controller1.mode = 1156 AudioProcessing::Config::GainController1::kAdaptiveAnalog; 1157 apm_->ApplyConfig(config); 1158 1159 int out_analog_level = 0; 1160 for (int i = 0; i < 2000; ++i) { 1161 ReadFrameWithRewind(near_file_, &frame_); 1162 // Ensure the audio is at a low level, so the AGC will try to increase it. 1163 frame_.Scale(0.25f); 1164 1165 // Always pass in the same volume. 1166 apm_->set_stream_analog_level(100); 1167 EXPECT_EQ(AudioProcessing::kNoError, 1168 apm_->ProcessStream( 1169 frame_.data.data(), 1170 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1171 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1172 frame_.data.data())); 1173 out_analog_level = apm_->recommended_stream_analog_level(); 1174 } 1175 1176 // Ensure the AGC is still able to reach the maximum. 1177 EXPECT_EQ(255, out_analog_level); 1178 } 1179 1180 // Verifies that despite volume slider quantization, the AGC can continue to 1181 // increase its volume. 1182 TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) { 1183 for (size_t sample_rate_hz : kProcessSampleRates) { 1184 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz); 1185 RunQuantizedVolumeDoesNotGetStuckTest(sample_rate_hz); 1186 } 1187 } 1188 1189 void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) { 1190 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false); 1191 auto config = apm_->GetConfig(); 1192 config.gain_controller1.enabled = true; 1193 config.gain_controller1.mode = 1194 AudioProcessing::Config::GainController1::kAdaptiveAnalog; 1195 apm_->ApplyConfig(config); 1196 1197 int out_analog_level = 100; 1198 for (int i = 0; i < 1000; ++i) { 1199 ReadFrameWithRewind(near_file_, &frame_); 1200 // Ensure the audio is at a low level, so the AGC will try to increase it. 1201 frame_.Scale(0.25f); 1202 1203 apm_->set_stream_analog_level(out_analog_level); 1204 EXPECT_EQ(AudioProcessing::kNoError, 1205 apm_->ProcessStream( 1206 frame_.data.data(), 1207 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1208 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1209 frame_.data.data())); 1210 out_analog_level = apm_->recommended_stream_analog_level(); 1211 } 1212 1213 // Ensure the volume was raised. 1214 EXPECT_GT(out_analog_level, 100); 1215 int highest_level_reached = out_analog_level; 1216 // Simulate a user manual volume change. 1217 out_analog_level = 100; 1218 1219 for (int i = 0; i < 300; ++i) { 1220 ReadFrameWithRewind(near_file_, &frame_); 1221 frame_.Scale(0.25f); 1222 1223 apm_->set_stream_analog_level(out_analog_level); 1224 EXPECT_EQ(AudioProcessing::kNoError, 1225 apm_->ProcessStream( 1226 frame_.data.data(), 1227 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1228 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1229 frame_.data.data())); 1230 out_analog_level = apm_->recommended_stream_analog_level(); 1231 // Check that AGC respected the manually adjusted volume. 1232 EXPECT_LT(out_analog_level, highest_level_reached); 1233 } 1234 // Check that the volume was still raised. 1235 EXPECT_GT(out_analog_level, 100); 1236 } 1237 1238 TEST_F(ApmTest, ManualVolumeChangeIsPossible) { 1239 for (size_t sample_rate_hz : kProcessSampleRates) { 1240 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz); 1241 RunManualVolumeChangeIsPossibleTest(sample_rate_hz); 1242 } 1243 } 1244 1245 TEST_F(ApmTest, HighPassFilter) { 1246 // Turn HP filter on/off 1247 AudioProcessing::Config apm_config; 1248 apm_config.high_pass_filter.enabled = true; 1249 apm_->ApplyConfig(apm_config); 1250 apm_config.high_pass_filter.enabled = false; 1251 apm_->ApplyConfig(apm_config); 1252 } 1253 1254 TEST_F(ApmTest, AllProcessingDisabledByDefault) { 1255 AudioProcessing::Config config = apm_->GetConfig(); 1256 EXPECT_FALSE(config.echo_canceller.enabled); 1257 EXPECT_FALSE(config.high_pass_filter.enabled); 1258 EXPECT_FALSE(config.gain_controller1.enabled); 1259 EXPECT_FALSE(config.noise_suppression.enabled); 1260 } 1261 1262 TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledInt) { 1263 // Test that ProcessStream simply copies input to output when all components 1264 // are disabled. 1265 // Runs over all processing rates, and some particularly common or special 1266 // rates. 1267 // - 8000 Hz: lowest sample rate seen in Chrome metrics, 1268 // - 22050 Hz: APM input/output frames are not exactly 10 ms, 1269 // - 44100 Hz: very common desktop sample rate. 1270 constexpr int kSampleRatesHz[] = {8000, 16000, 22050, 32000, 44100, 48000}; 1271 for (size_t sample_rate_hz : kSampleRatesHz) { 1272 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz); 1273 Init(sample_rate_hz, sample_rate_hz, sample_rate_hz, 2, 2, 2, false); 1274 frame_.FillStereoData(1000, 2000); 1275 Int16FrameData frame_copy; 1276 frame_copy.CopyFrom(frame_); 1277 for (int j = 0; j < 1000; j++) { 1278 EXPECT_EQ(AudioProcessing::kNoError, 1279 apm_->ProcessStream( 1280 frame_.data.data(), 1281 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1282 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1283 frame_.data.data())); 1284 EXPECT_TRUE(frame_.IsEqual(frame_copy)); 1285 EXPECT_EQ(AudioProcessing::kNoError, 1286 apm_->ProcessReverseStream( 1287 frame_.data.data(), 1288 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1289 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1290 frame_.data.data())); 1291 EXPECT_TRUE(frame_.IsEqual(frame_copy)); 1292 } 1293 } 1294 } 1295 1296 TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) { 1297 // Test that ProcessStream simply copies input to output when all components 1298 // are disabled. 1299 const size_t kSamples = 160; 1300 const int sample_rate = 16000; 1301 const float src[kSamples] = {-1.0f, 0.0f, 1.0f}; 1302 float dest[kSamples] = {}; 1303 1304 auto src_channels = &src[0]; 1305 auto dest_channels = &dest[0]; 1306 1307 apm_ = BuiltinAudioProcessingBuilder().Build(CreateEnvironment()); 1308 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1), 1309 StreamConfig(sample_rate, 1), 1310 &dest_channels)); 1311 1312 for (size_t i = 0; i < kSamples; ++i) { 1313 EXPECT_EQ(src[i], dest[i]); 1314 } 1315 1316 // Same for ProcessReverseStream. 1317 float rev_dest[kSamples] = {}; 1318 auto rev_dest_channels = &rev_dest[0]; 1319 1320 StreamConfig input_stream = {sample_rate, 1}; 1321 StreamConfig output_stream = {sample_rate, 1}; 1322 EXPECT_NOERR(apm_->ProcessReverseStream(&src_channels, input_stream, 1323 output_stream, &rev_dest_channels)); 1324 1325 for (size_t i = 0; i < kSamples; ++i) { 1326 EXPECT_EQ(src[i], rev_dest[i]); 1327 } 1328 } 1329 1330 TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) { 1331 EnableAllComponents(); 1332 1333 for (int sample_rate_hz : kProcessSampleRates) { 1334 Init(sample_rate_hz, sample_rate_hz, sample_rate_hz, 2, 2, 2, false); 1335 int analog_level = 127; 1336 ASSERT_EQ(0, feof(far_file_)); 1337 ASSERT_EQ(0, feof(near_file_)); 1338 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) { 1339 CopyLeftToRightChannel(revframe_.data.data(), 1340 revframe_.samples_per_channel()); 1341 1342 ASSERT_EQ( 1343 AudioProcessing::kNoError, 1344 apm_->ProcessReverseStream( 1345 revframe_.data.data(), 1346 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels()), 1347 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels()), 1348 revframe_.data.data())); 1349 1350 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel()); 1351 1352 ASSERT_EQ(AudioProcessing::kNoError, apm_->set_stream_delay_ms(0)); 1353 apm_->set_stream_analog_level(analog_level); 1354 ASSERT_EQ(AudioProcessing::kNoError, 1355 apm_->ProcessStream( 1356 frame_.data.data(), 1357 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1358 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1359 frame_.data.data())); 1360 analog_level = apm_->recommended_stream_analog_level(); 1361 1362 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel()); 1363 } 1364 rewind(far_file_); 1365 rewind(near_file_); 1366 } 1367 } 1368 1369 TEST_F(ApmTest, SplittingFilter) { 1370 // Verify the filter is not active through undistorted audio when: 1371 // 1. No components are enabled... 1372 frame_.FillData(1000); 1373 Int16FrameData frame_copy; 1374 frame_copy.CopyFrom(frame_); 1375 EXPECT_EQ(AudioProcessing::kNoError, 1376 apm_->ProcessStream( 1377 frame_.data.data(), 1378 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1379 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1380 frame_.data.data())); 1381 EXPECT_EQ(AudioProcessing::kNoError, 1382 apm_->ProcessStream( 1383 frame_.data.data(), 1384 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1385 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1386 frame_.data.data())); 1387 EXPECT_TRUE(frame_.IsEqual(frame_copy)); 1388 1389 // 2. Only the level estimator is enabled... 1390 auto apm_config = apm_->GetConfig(); 1391 frame_.FillData(1000); 1392 frame_copy.CopyFrom(frame_); 1393 apm_->ApplyConfig(apm_config); 1394 EXPECT_EQ(AudioProcessing::kNoError, 1395 apm_->ProcessStream( 1396 frame_.data.data(), 1397 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1398 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1399 frame_.data.data())); 1400 EXPECT_EQ(AudioProcessing::kNoError, 1401 apm_->ProcessStream( 1402 frame_.data.data(), 1403 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1404 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1405 frame_.data.data())); 1406 EXPECT_TRUE(frame_.IsEqual(frame_copy)); 1407 apm_->ApplyConfig(apm_config); 1408 1409 // Check the test is valid. We should have distortion from the filter 1410 // when AEC is enabled (which won't affect the audio). 1411 apm_config.echo_canceller.enabled = true; 1412 apm_config.echo_canceller.mobile_mode = false; 1413 apm_->ApplyConfig(apm_config); 1414 frame_.SetProperties(/* samples_per_channel=*/320, /* num_channels=*/2); 1415 frame_.FillData(1000); 1416 frame_copy.CopyFrom(frame_); 1417 EXPECT_EQ(AudioProcessing::kNoError, apm_->set_stream_delay_ms(0)); 1418 EXPECT_EQ(AudioProcessing::kNoError, 1419 apm_->ProcessStream( 1420 frame_.data.data(), 1421 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1422 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1423 frame_.data.data())); 1424 EXPECT_FALSE(frame_.IsEqual(frame_copy)); 1425 } 1426 1427 #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP 1428 void ApmTest::ProcessDebugDump(absl::string_view in_filename, 1429 absl::string_view out_filename, 1430 Format format, 1431 int max_size_bytes) { 1432 TaskQueueForTest worker_queue("ApmTest_worker_queue"); 1433 FILE* in_file = fopen(std::string(in_filename).c_str(), "rb"); 1434 ASSERT_TRUE(in_file != nullptr); 1435 audioproc::Event event_msg; 1436 bool first_init = true; 1437 1438 while (ReadMessageFromFile(in_file, &event_msg)) { 1439 if (event_msg.type() == audioproc::Event::INIT) { 1440 const audioproc::Init msg = event_msg.init(); 1441 int reverse_sample_rate = msg.sample_rate(); 1442 if (msg.has_reverse_sample_rate()) { 1443 reverse_sample_rate = msg.reverse_sample_rate(); 1444 } 1445 int output_sample_rate = msg.sample_rate(); 1446 if (msg.has_output_sample_rate()) { 1447 output_sample_rate = msg.output_sample_rate(); 1448 } 1449 1450 Init(msg.sample_rate(), output_sample_rate, reverse_sample_rate, 1451 msg.num_input_channels(), msg.num_output_channels(), 1452 msg.num_reverse_channels(), false); 1453 if (first_init) { 1454 // AttachAecDump() writes an additional init message. Don't start 1455 // recording until after the first init to avoid the extra message. 1456 auto aec_dump = AecDumpFactory::Create(out_filename, max_size_bytes, 1457 worker_queue.Get()); 1458 EXPECT_TRUE(aec_dump); 1459 apm_->AttachAecDump(std::move(aec_dump)); 1460 first_init = false; 1461 } 1462 1463 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) { 1464 const audioproc::ReverseStream msg = event_msg.reverse_stream(); 1465 1466 if (msg.channel_size() > 0) { 1467 ASSERT_EQ(revframe_.num_channels(), 1468 static_cast<size_t>(msg.channel_size())); 1469 for (int i = 0; i < msg.channel_size(); ++i) { 1470 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(), 1471 msg.channel(i).size()); 1472 } 1473 } else { 1474 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size()); 1475 if (format == kFloatFormat) { 1476 // We're using an int16 input file; convert to float. 1477 ConvertToFloat(revframe_, revfloat_cb_.get()); 1478 } 1479 } 1480 AnalyzeReverseStreamChooser(format); 1481 1482 } else if (event_msg.type() == audioproc::Event::STREAM) { 1483 const audioproc::Stream msg = event_msg.stream(); 1484 // ProcessStream could have changed this for the output frame. 1485 frame_.set_num_channels(apm_->num_input_channels()); 1486 1487 apm_->set_stream_analog_level(msg.applied_input_volume()); 1488 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay())); 1489 if (msg.has_keypress()) { 1490 apm_->set_stream_key_pressed(msg.keypress()); 1491 } else { 1492 apm_->set_stream_key_pressed(true); 1493 } 1494 1495 if (msg.input_channel_size() > 0) { 1496 ASSERT_EQ(frame_.num_channels(), 1497 static_cast<size_t>(msg.input_channel_size())); 1498 for (int i = 0; i < msg.input_channel_size(); ++i) { 1499 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(), 1500 msg.input_channel(i).size()); 1501 } 1502 } else { 1503 memcpy(frame_.data.data(), msg.input_data().data(), 1504 msg.input_data().size()); 1505 if (format == kFloatFormat) { 1506 // We're using an int16 input file; convert to float. 1507 ConvertToFloat(frame_, float_cb_.get()); 1508 } 1509 } 1510 ProcessStreamChooser(format); 1511 } 1512 } 1513 apm_->DetachAecDump(); 1514 fclose(in_file); 1515 } 1516 1517 void ApmTest::VerifyDebugDumpTest(Format format) { 1518 ScopedFakeClock fake_clock; 1519 const std::string in_filename = test::ResourcePath("ref03", "aecdump"); 1520 std::string format_string; 1521 switch (format) { 1522 case kIntFormat: 1523 format_string = "_int"; 1524 break; 1525 case kFloatFormat: 1526 format_string = "_float"; 1527 break; 1528 } 1529 const std::string ref_filename = test::TempFilename( 1530 test::OutputPath(), std::string("ref") + format_string + "_aecdump"); 1531 const std::string out_filename = test::TempFilename( 1532 test::OutputPath(), std::string("out") + format_string + "_aecdump"); 1533 const std::string limited_filename = test::TempFilename( 1534 test::OutputPath(), std::string("limited") + format_string + "_aecdump"); 1535 const size_t logging_limit_bytes = 100000; 1536 // We expect at least this many bytes in the created logfile. 1537 const size_t logging_expected_bytes = 95000; 1538 EnableAllComponents(); 1539 ProcessDebugDump(in_filename, ref_filename, format, -1); 1540 ProcessDebugDump(ref_filename, out_filename, format, -1); 1541 ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes); 1542 1543 FILE* ref_file = fopen(ref_filename.c_str(), "rb"); 1544 FILE* out_file = fopen(out_filename.c_str(), "rb"); 1545 FILE* limited_file = fopen(limited_filename.c_str(), "rb"); 1546 ASSERT_TRUE(ref_file != nullptr); 1547 ASSERT_TRUE(out_file != nullptr); 1548 ASSERT_TRUE(limited_file != nullptr); 1549 std::unique_ptr<uint8_t[]> ref_bytes; 1550 std::unique_ptr<uint8_t[]> out_bytes; 1551 std::unique_ptr<uint8_t[]> limited_bytes; 1552 1553 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes); 1554 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes); 1555 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes); 1556 size_t bytes_read = 0; 1557 size_t bytes_read_limited = 0; 1558 while (ref_size > 0 && out_size > 0) { 1559 bytes_read += ref_size; 1560 bytes_read_limited += limited_size; 1561 EXPECT_EQ(ref_size, out_size); 1562 EXPECT_GE(ref_size, limited_size); 1563 EXPECT_TRUE(ExpectMessageEq(/*actual=*/{out_bytes.get(), out_size}, 1564 /*expected=*/{ref_bytes.get(), ref_size})); 1565 if (limited_size > 0) { 1566 EXPECT_TRUE( 1567 ExpectMessageEq(/*actual=*/{limited_bytes.get(), limited_size}, 1568 /*expected=*/{ref_bytes.get(), ref_size})); 1569 } 1570 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes); 1571 out_size = ReadMessageBytesFromFile(out_file, &out_bytes); 1572 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes); 1573 } 1574 EXPECT_GT(bytes_read, 0u); 1575 EXPECT_GT(bytes_read_limited, logging_expected_bytes); 1576 EXPECT_LE(bytes_read_limited, logging_limit_bytes); 1577 EXPECT_NE(0, feof(ref_file)); 1578 EXPECT_NE(0, feof(out_file)); 1579 EXPECT_NE(0, feof(limited_file)); 1580 ASSERT_EQ(0, fclose(ref_file)); 1581 ASSERT_EQ(0, fclose(out_file)); 1582 ASSERT_EQ(0, fclose(limited_file)); 1583 remove(ref_filename.c_str()); 1584 remove(out_filename.c_str()); 1585 remove(limited_filename.c_str()); 1586 } 1587 1588 TEST_F(ApmTest, VerifyDebugDumpInt) { 1589 VerifyDebugDumpTest(kIntFormat); 1590 } 1591 1592 TEST_F(ApmTest, VerifyDebugDumpFloat) { 1593 VerifyDebugDumpTest(kFloatFormat); 1594 } 1595 #endif 1596 1597 // TODO(andrew): expand test to verify output. 1598 TEST_F(ApmTest, DebugDump) { 1599 TaskQueueForTest worker_queue("ApmTest_worker_queue"); 1600 const std::string filename = 1601 test::TempFilename(test::OutputPath(), "debug_aec"); 1602 { 1603 auto aec_dump = AecDumpFactory::Create("", -1, worker_queue.Get()); 1604 EXPECT_FALSE(aec_dump); 1605 } 1606 1607 #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP 1608 // Stopping without having started should be OK. 1609 apm_->DetachAecDump(); 1610 1611 auto aec_dump = AecDumpFactory::Create(filename, -1, worker_queue.Get()); 1612 EXPECT_TRUE(aec_dump); 1613 apm_->AttachAecDump(std::move(aec_dump)); 1614 EXPECT_EQ(AudioProcessing::kNoError, 1615 apm_->ProcessStream( 1616 frame_.data.data(), 1617 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1618 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1619 frame_.data.data())); 1620 EXPECT_EQ( 1621 AudioProcessing::kNoError, 1622 apm_->ProcessReverseStream( 1623 revframe_.data.data(), 1624 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels()), 1625 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels()), 1626 revframe_.data.data())); 1627 apm_->DetachAecDump(); 1628 1629 // Verify the file has been written. 1630 FILE* fid = fopen(filename.c_str(), "r"); 1631 ASSERT_TRUE(fid != nullptr); 1632 1633 // Clean it up. 1634 ASSERT_EQ(0, fclose(fid)); 1635 ASSERT_EQ(0, remove(filename.c_str())); 1636 #else 1637 // Verify the file has NOT been written. 1638 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL); 1639 #endif // WEBRTC_AUDIOPROC_DEBUG_DUMP 1640 } 1641 1642 // TODO(andrew): expand test to verify output. 1643 TEST_F(ApmTest, DebugDumpFromFileHandle) { 1644 TaskQueueForTest worker_queue("ApmTest_worker_queue"); 1645 1646 const std::string filename = 1647 test::TempFilename(test::OutputPath(), "debug_aec"); 1648 FileWrapper f = FileWrapper::OpenWriteOnly(filename); 1649 ASSERT_TRUE(f.is_open()); 1650 1651 #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP 1652 // Stopping without having started should be OK. 1653 apm_->DetachAecDump(); 1654 1655 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, worker_queue.Get()); 1656 EXPECT_TRUE(aec_dump); 1657 apm_->AttachAecDump(std::move(aec_dump)); 1658 EXPECT_EQ( 1659 AudioProcessing::kNoError, 1660 apm_->ProcessReverseStream( 1661 revframe_.data.data(), 1662 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels()), 1663 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels()), 1664 revframe_.data.data())); 1665 EXPECT_EQ(AudioProcessing::kNoError, 1666 apm_->ProcessStream( 1667 frame_.data.data(), 1668 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1669 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1670 frame_.data.data())); 1671 apm_->DetachAecDump(); 1672 1673 // Verify the file has been written. 1674 FILE* fid = fopen(filename.c_str(), "r"); 1675 ASSERT_TRUE(fid != nullptr); 1676 1677 // Clean it up. 1678 ASSERT_EQ(0, fclose(fid)); 1679 ASSERT_EQ(0, remove(filename.c_str())); 1680 #endif // WEBRTC_AUDIOPROC_DEBUG_DUMP 1681 } 1682 1683 // TODO(andrew): Add a test to process a few frames with different combinations 1684 // of enabled components. 1685 1686 TEST_F(ApmTest, Process) { 1687 audioproc::OutputData ref_data; 1688 1689 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) { 1690 OpenFileAndReadMessage(ref_filename_, &ref_data); 1691 } else { 1692 const int kChannels[] = {1, 2}; 1693 // Write the desired tests to the protobuf reference file. 1694 for (int num_reverse_channels : kChannels) { 1695 for (int num_channels : kChannels) { 1696 for (int sample_rate_hz : AudioProcessing::kNativeSampleRatesHz) { 1697 audioproc::Test* test = ref_data.add_test(); 1698 test->set_num_reverse_channels(num_reverse_channels); 1699 test->set_num_input_channels(num_channels); 1700 test->set_num_output_channels(num_channels); 1701 test->set_sample_rate(sample_rate_hz); 1702 test->set_use_aec_extended_filter(false); 1703 } 1704 } 1705 } 1706 #if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE) 1707 // To test the extended filter mode. 1708 audioproc::Test* test = ref_data.add_test(); 1709 test->set_num_reverse_channels(2); 1710 test->set_num_input_channels(2); 1711 test->set_num_output_channels(2); 1712 test->set_sample_rate(AudioProcessing::kSampleRate32kHz); 1713 test->set_use_aec_extended_filter(true); 1714 #endif 1715 } 1716 1717 for (int i = 0; i < ref_data.test_size(); i++) { 1718 printf("Running test %d of %d...\n", i + 1, ref_data.test_size()); 1719 1720 audioproc::Test* test = ref_data.mutable_test(i); 1721 // TODO(ajm): We no longer allow different input and output channels. Skip 1722 // these tests for now, but they should be removed from the set. 1723 if (test->num_input_channels() != test->num_output_channels()) 1724 continue; 1725 1726 apm_ = BuiltinAudioProcessingBuilder() 1727 .SetEchoDetector(CreateEchoDetector()) 1728 .Build(CreateEnvironment()); 1729 AudioProcessing::Config apm_config = apm_->GetConfig(); 1730 apm_config.gain_controller1.analog_gain_controller.enabled = false; 1731 apm_->ApplyConfig(apm_config); 1732 1733 EnableAllComponents(); 1734 1735 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(), 1736 static_cast<size_t>(test->num_input_channels()), 1737 static_cast<size_t>(test->num_output_channels()), 1738 static_cast<size_t>(test->num_reverse_channels()), true); 1739 1740 int frame_count = 0; 1741 int analog_level = 127; 1742 int analog_level_average = 0; 1743 int max_output_average = 0; 1744 #if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE) 1745 int stats_index = 0; 1746 #endif 1747 1748 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) { 1749 EXPECT_EQ( 1750 AudioProcessing::kNoError, 1751 apm_->ProcessReverseStream( 1752 revframe_.data.data(), 1753 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels()), 1754 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels()), 1755 revframe_.data.data())); 1756 1757 EXPECT_EQ(AudioProcessing::kNoError, apm_->set_stream_delay_ms(0)); 1758 apm_->set_stream_analog_level(analog_level); 1759 1760 EXPECT_EQ(AudioProcessing::kNoError, 1761 apm_->ProcessStream( 1762 frame_.data.data(), 1763 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1764 StreamConfig(frame_.sample_rate_hz, frame_.num_channels()), 1765 frame_.data.data())); 1766 1767 // Ensure the frame was downmixed properly. 1768 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()), 1769 frame_.num_channels()); 1770 1771 max_output_average += MaxAudioFrame(frame_); 1772 1773 analog_level = apm_->recommended_stream_analog_level(); 1774 analog_level_average += analog_level; 1775 AudioProcessingStats stats = apm_->GetStatistics(); 1776 1777 size_t write_count = 1778 fwrite(frame_.data.data(), sizeof(int16_t), frame_.size(), out_file_); 1779 ASSERT_EQ(frame_.size(), write_count); 1780 1781 // Reset in case of downmixing. 1782 frame_.set_num_channels(static_cast<size_t>(test->num_input_channels())); 1783 frame_count++; 1784 1785 #if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE) 1786 const int kStatsAggregationFrameNum = 100; // 1 second. 1787 if (frame_count % kStatsAggregationFrameNum == 0) { 1788 // Get echo and delay metrics. 1789 AudioProcessingStats stats2 = apm_->GetStatistics(); 1790 1791 // Echo metrics. 1792 const float echo_return_loss = stats2.echo_return_loss.value_or(-1.0f); 1793 const float echo_return_loss_enhancement = 1794 stats2.echo_return_loss_enhancement.value_or(-1.0f); 1795 const float residual_echo_likelihood = 1796 stats2.residual_echo_likelihood.value_or(-1.0f); 1797 const float residual_echo_likelihood_recent_max = 1798 stats2.residual_echo_likelihood_recent_max.value_or(-1.0f); 1799 1800 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) { 1801 const audioproc::Test::EchoMetrics& reference = 1802 test->echo_metrics(stats_index); 1803 constexpr float kEpsilon = 0.01; 1804 EXPECT_NEAR(echo_return_loss, reference.echo_return_loss(), kEpsilon); 1805 EXPECT_NEAR(echo_return_loss_enhancement, 1806 reference.echo_return_loss_enhancement(), kEpsilon); 1807 EXPECT_NEAR(residual_echo_likelihood, 1808 reference.residual_echo_likelihood(), kEpsilon); 1809 EXPECT_NEAR(residual_echo_likelihood_recent_max, 1810 reference.residual_echo_likelihood_recent_max(), 1811 kEpsilon); 1812 ++stats_index; 1813 } else { 1814 audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics(); 1815 message_echo->set_echo_return_loss(echo_return_loss); 1816 message_echo->set_echo_return_loss_enhancement( 1817 echo_return_loss_enhancement); 1818 message_echo->set_residual_echo_likelihood(residual_echo_likelihood); 1819 message_echo->set_residual_echo_likelihood_recent_max( 1820 residual_echo_likelihood_recent_max); 1821 } 1822 } 1823 #endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE). 1824 } 1825 max_output_average /= frame_count; 1826 analog_level_average /= frame_count; 1827 1828 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) { 1829 const int kIntNear = 1; 1830 // All numbers being consistently higher on N7 compare to the reference 1831 // data. 1832 // TODO(bjornv): If we start getting more of these offsets on Android we 1833 // should consider a different approach. Either using one slack for all, 1834 // or generate a separate android reference. 1835 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) 1836 const int kMaxOutputAverageOffset = 9; 1837 const int kMaxOutputAverageNear = 26; 1838 #else 1839 const int kMaxOutputAverageOffset = 0; 1840 const int kMaxOutputAverageNear = 7; 1841 #endif 1842 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear); 1843 EXPECT_NEAR(test->max_output_average(), 1844 max_output_average - kMaxOutputAverageOffset, 1845 kMaxOutputAverageNear); 1846 } else { 1847 test->set_analog_level_average(analog_level_average); 1848 test->set_max_output_average(max_output_average); 1849 } 1850 1851 rewind(far_file_); 1852 rewind(near_file_); 1853 } 1854 1855 if (absl::GetFlag(FLAGS_write_apm_ref_data)) { 1856 OpenFileAndWriteMessage(ref_filename_, ref_data); 1857 } 1858 } 1859 1860 // Compares the reference and test arrays over a region around the expected 1861 // delay. Finds the highest SNR in that region and adds the variance and squared 1862 // error results to the supplied accumulators. 1863 void UpdateBestSNR(const float* ref, 1864 const float* test, 1865 size_t length, 1866 int expected_delay, 1867 double* variance_acc, 1868 double* sq_error_acc) { 1869 RTC_CHECK_LT(expected_delay, length) 1870 << "delay greater than signal length, cannot compute SNR"; 1871 double best_snr = std::numeric_limits<double>::min(); 1872 double best_variance = 0; 1873 double best_sq_error = 0; 1874 // Search over a region of nine samples around the expected delay. 1875 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4; 1876 ++delay) { 1877 double sq_error = 0; 1878 double variance = 0; 1879 for (size_t i = 0; i < length - delay; ++i) { 1880 double error = test[i + delay] - ref[i]; 1881 sq_error += error * error; 1882 variance += ref[i] * ref[i]; 1883 } 1884 1885 if (sq_error == 0) { 1886 *variance_acc += variance; 1887 return; 1888 } 1889 double snr = variance / sq_error; 1890 if (snr > best_snr) { 1891 best_snr = snr; 1892 best_variance = variance; 1893 best_sq_error = sq_error; 1894 } 1895 } 1896 1897 *variance_acc += best_variance; 1898 *sq_error_acc += best_sq_error; 1899 } 1900 1901 // Used to test a multitude of sample rate and channel combinations. It works 1902 // by first producing a set of reference files (in SetUpTestCase) that are 1903 // assumed to be correct, as the used parameters are verified by other tests 1904 // in this collection. Primarily the reference files are all produced at 1905 // "native" rates which do not involve any resampling. 1906 1907 // Each test pass produces an output file with a particular format. The output 1908 // is matched against the reference file closest to its internal processing 1909 // format. If necessary the output is resampled back to its process format. 1910 // Due to the resampling distortion, we don't expect identical results, but 1911 // enforce SNR thresholds which vary depending on the format. 0 is a special 1912 // case SNR which corresponds to inf, or zero error. 1913 typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData; 1914 class AudioProcessingTest 1915 : public ::testing::TestWithParam<AudioProcessingTestData> { 1916 public: 1917 AudioProcessingTest() 1918 : input_rate_(std::get<0>(GetParam())), 1919 output_rate_(std::get<1>(GetParam())), 1920 reverse_input_rate_(std::get<2>(GetParam())), 1921 reverse_output_rate_(std::get<3>(GetParam())), 1922 expected_snr_(std::get<4>(GetParam())), 1923 expected_reverse_snr_(std::get<5>(GetParam())) {} 1924 1925 ~AudioProcessingTest() override {} 1926 1927 static void SetUpTestSuite() { 1928 // Create all needed output reference files. 1929 const size_t kNumChannels[] = {1, 2}; 1930 for (int sample_rate_hz : kProcessSampleRates) { 1931 for (int num_channels : kNumChannels) { 1932 for (int num_reverse_channels : kNumChannels) { 1933 // The reference files always have matching input and output channels. 1934 ProcessFormat(sample_rate_hz, sample_rate_hz, sample_rate_hz, 1935 sample_rate_hz, num_channels, num_channels, 1936 num_reverse_channels, num_reverse_channels, "ref"); 1937 } 1938 } 1939 } 1940 } 1941 1942 void TearDown() override { 1943 // Remove "out" files after each test. 1944 ClearTempOutFiles(); 1945 } 1946 1947 static void TearDownTestSuite() { ClearTempFiles(); } 1948 1949 // Runs a process pass on files with the given parameters and dumps the output 1950 // to a file specified with `output_file_prefix`. Both forward and reverse 1951 // output streams are dumped. 1952 static void ProcessFormat(int input_rate, 1953 int output_rate, 1954 int reverse_input_rate, 1955 int reverse_output_rate, 1956 size_t num_input_channels, 1957 size_t num_output_channels, 1958 size_t num_reverse_input_channels, 1959 size_t num_reverse_output_channels, 1960 absl::string_view output_file_prefix) { 1961 AudioProcessing::Config apm_config; 1962 apm_config.gain_controller1.analog_gain_controller.enabled = false; 1963 scoped_refptr<AudioProcessing> ap = BuiltinAudioProcessingBuilder() 1964 .SetConfig(apm_config) 1965 .Build(CreateEnvironment()); 1966 1967 EnableAllAPComponents(ap.get()); 1968 1969 ProcessingConfig processing_config = { 1970 {{input_rate, num_input_channels}, 1971 {output_rate, num_output_channels}, 1972 {reverse_input_rate, num_reverse_input_channels}, 1973 {reverse_output_rate, num_reverse_output_channels}}}; 1974 ap->Initialize(processing_config); 1975 1976 FILE* far_file = 1977 fopen(ResourceFilePath("far", reverse_input_rate).c_str(), "rb"); 1978 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb"); 1979 FILE* out_file = fopen( 1980 OutputFilePath( 1981 output_file_prefix, input_rate, output_rate, reverse_input_rate, 1982 reverse_output_rate, num_input_channels, num_output_channels, 1983 num_reverse_input_channels, num_reverse_output_channels, kForward) 1984 .c_str(), 1985 "wb"); 1986 FILE* rev_out_file = fopen( 1987 OutputFilePath( 1988 output_file_prefix, input_rate, output_rate, reverse_input_rate, 1989 reverse_output_rate, num_input_channels, num_output_channels, 1990 num_reverse_input_channels, num_reverse_output_channels, kReverse) 1991 .c_str(), 1992 "wb"); 1993 ASSERT_TRUE(far_file != nullptr); 1994 ASSERT_TRUE(near_file != nullptr); 1995 ASSERT_TRUE(out_file != nullptr); 1996 ASSERT_TRUE(rev_out_file != nullptr); 1997 1998 ChannelBuffer<float> fwd_cb(AudioProcessing::GetFrameSize(input_rate), 1999 num_input_channels); 2000 ChannelBuffer<float> rev_cb( 2001 AudioProcessing::GetFrameSize(reverse_input_rate), 2002 num_reverse_input_channels); 2003 ChannelBuffer<float> out_cb(AudioProcessing::GetFrameSize(output_rate), 2004 num_output_channels); 2005 ChannelBuffer<float> rev_out_cb( 2006 AudioProcessing::GetFrameSize(reverse_output_rate), 2007 num_reverse_output_channels); 2008 2009 // Temporary buffers. 2010 const int max_length = 2011 2 * std::max(std::max(out_cb.num_frames(), rev_out_cb.num_frames()), 2012 std::max(fwd_cb.num_frames(), rev_cb.num_frames())); 2013 std::unique_ptr<float[]> float_data(new float[max_length]); 2014 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]); 2015 2016 int analog_level = 127; 2017 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) && 2018 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) { 2019 EXPECT_NOERR(ap->ProcessReverseStream( 2020 rev_cb.channels(), processing_config.reverse_input_stream(), 2021 processing_config.reverse_output_stream(), rev_out_cb.channels())); 2022 2023 EXPECT_NOERR(ap->set_stream_delay_ms(0)); 2024 ap->set_stream_analog_level(analog_level); 2025 2026 EXPECT_NOERR(ap->ProcessStream( 2027 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels), 2028 StreamConfig(output_rate, num_output_channels), out_cb.channels())); 2029 2030 // Dump forward output to file. 2031 RTC_DCHECK_EQ(out_cb.num_bands(), 1u); // Assumes full frequency band. 2032 DeinterleavedView<const float> deinterleaved_src( 2033 out_cb.channels(), out_cb.num_frames(), out_cb.num_channels()); 2034 InterleavedView<float> interleaved_dst( 2035 float_data.get(), out_cb.num_frames(), out_cb.num_channels()); 2036 Interleave(deinterleaved_src, interleaved_dst); 2037 size_t out_length = out_cb.num_channels() * out_cb.num_frames(); 2038 2039 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]), 2040 out_length, out_file)); 2041 2042 // Dump reverse output to file. 2043 RTC_DCHECK_EQ(rev_out_cb.num_bands(), 1u); 2044 deinterleaved_src = DeinterleavedView<const float>( 2045 rev_out_cb.channels(), rev_out_cb.num_frames(), 2046 rev_out_cb.num_channels()); 2047 interleaved_dst = InterleavedView<float>( 2048 float_data.get(), rev_out_cb.num_frames(), rev_out_cb.num_channels()); 2049 Interleave(deinterleaved_src, interleaved_dst); 2050 size_t rev_out_length = 2051 rev_out_cb.num_channels() * rev_out_cb.num_frames(); 2052 2053 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]), 2054 rev_out_length, rev_out_file)); 2055 2056 analog_level = ap->recommended_stream_analog_level(); 2057 } 2058 fclose(far_file); 2059 fclose(near_file); 2060 fclose(out_file); 2061 fclose(rev_out_file); 2062 } 2063 2064 protected: 2065 int input_rate_; 2066 int output_rate_; 2067 int reverse_input_rate_; 2068 int reverse_output_rate_; 2069 double expected_snr_; 2070 double expected_reverse_snr_; 2071 }; 2072 2073 TEST_P(AudioProcessingTest, Formats) { 2074 struct ChannelFormat { 2075 int num_input; 2076 int num_output; 2077 int num_reverse_input; 2078 int num_reverse_output; 2079 }; 2080 ChannelFormat cf[] = { 2081 {.num_input = 1, 2082 .num_output = 1, 2083 .num_reverse_input = 1, 2084 .num_reverse_output = 1}, 2085 {.num_input = 1, 2086 .num_output = 1, 2087 .num_reverse_input = 2, 2088 .num_reverse_output = 1}, 2089 {.num_input = 2, 2090 .num_output = 1, 2091 .num_reverse_input = 1, 2092 .num_reverse_output = 1}, 2093 {.num_input = 2, 2094 .num_output = 1, 2095 .num_reverse_input = 2, 2096 .num_reverse_output = 1}, 2097 {.num_input = 2, 2098 .num_output = 2, 2099 .num_reverse_input = 1, 2100 .num_reverse_output = 1}, 2101 {.num_input = 2, 2102 .num_output = 2, 2103 .num_reverse_input = 2, 2104 .num_reverse_output = 2}, 2105 }; 2106 2107 for (auto [num_input, num_output, num_reverse_input, num_reverse_output] : 2108 cf) { 2109 ProcessFormat(input_rate_, output_rate_, reverse_input_rate_, 2110 reverse_output_rate_, num_input, num_output, 2111 num_reverse_input, num_reverse_output, "out"); 2112 2113 // Verify output for both directions. 2114 std::vector<StreamDirection> stream_directions; 2115 stream_directions.push_back(kForward); 2116 stream_directions.push_back(kReverse); 2117 for (StreamDirection file_direction : stream_directions) { 2118 const int in_rate = file_direction ? reverse_input_rate_ : input_rate_; 2119 const int out_rate = file_direction ? reverse_output_rate_ : output_rate_; 2120 const int out_num = file_direction ? num_reverse_output : num_output; 2121 const double expected_snr = 2122 file_direction ? expected_reverse_snr_ : expected_snr_; 2123 2124 const int min_ref_rate = std::min(in_rate, out_rate); 2125 int ref_rate; 2126 if (min_ref_rate > 32000) { 2127 ref_rate = 48000; 2128 } else if (min_ref_rate > 16000) { 2129 ref_rate = 32000; 2130 } else { 2131 ref_rate = 16000; 2132 } 2133 2134 FILE* out_file = fopen( 2135 OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_, 2136 reverse_output_rate_, num_input, num_output, 2137 num_reverse_input, num_reverse_output, file_direction) 2138 .c_str(), 2139 "rb"); 2140 // The reference files always have matching input and output channels. 2141 FILE* ref_file = 2142 fopen(OutputFilePath("ref", ref_rate, ref_rate, ref_rate, ref_rate, 2143 num_output, num_output, num_reverse_output, 2144 num_reverse_output, file_direction) 2145 .c_str(), 2146 "rb"); 2147 ASSERT_TRUE(out_file != nullptr); 2148 ASSERT_TRUE(ref_file != nullptr); 2149 2150 const size_t ref_samples_per_channel = 2151 AudioProcessing::GetFrameSize(ref_rate); 2152 const size_t ref_length = ref_samples_per_channel * out_num; 2153 const size_t out_samples_per_channel = 2154 AudioProcessing::GetFrameSize(out_rate); 2155 const size_t out_length = out_samples_per_channel * out_num; 2156 // Data from the reference file. 2157 std::unique_ptr<float[]> ref_data(new float[ref_length]); 2158 // Data from the output file. 2159 std::unique_ptr<float[]> out_data(new float[out_length]); 2160 // Data from the resampled output, in case the reference and output rates 2161 // don't match. 2162 std::unique_ptr<float[]> cmp_data(new float[ref_length]); 2163 2164 PushResampler<float> resampler(out_samples_per_channel, 2165 ref_samples_per_channel, out_num); 2166 2167 // Compute the resampling delay of the output relative to the reference, 2168 // to find the region over which we should search for the best SNR. 2169 float expected_delay_sec = 0; 2170 if (in_rate != ref_rate) { 2171 // Input resampling delay. 2172 expected_delay_sec += 2173 PushSincResampler::AlgorithmicDelaySeconds(in_rate); 2174 } 2175 if (out_rate != ref_rate) { 2176 // Output resampling delay. 2177 expected_delay_sec += 2178 PushSincResampler::AlgorithmicDelaySeconds(ref_rate); 2179 // Delay of converting the output back to its processing rate for 2180 // testing. 2181 expected_delay_sec += 2182 PushSincResampler::AlgorithmicDelaySeconds(out_rate); 2183 } 2184 // The delay is multiplied by the number of channels because 2185 // UpdateBestSNR() computes the SNR over interleaved data without taking 2186 // channels into account. 2187 int expected_delay = 2188 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num; 2189 2190 double variance = 0; 2191 double sq_error = 0; 2192 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) && 2193 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) { 2194 float* out_ptr = out_data.get(); 2195 if (out_rate != ref_rate) { 2196 // Resample the output back to its internal processing rate if 2197 // necessary. 2198 InterleavedView<const float> src(out_ptr, out_samples_per_channel, 2199 out_num); 2200 InterleavedView<float> dst(cmp_data.get(), ref_samples_per_channel, 2201 out_num); 2202 resampler.Resample(src, dst); 2203 out_ptr = cmp_data.get(); 2204 } 2205 2206 // Update the `sq_error` and `variance` accumulators with the highest 2207 // SNR of reference vs output. 2208 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay, 2209 &variance, &sq_error); 2210 } 2211 2212 std::cout << "(" << input_rate_ << ", " << output_rate_ << ", " 2213 << reverse_input_rate_ << ", " << reverse_output_rate_ << ", " 2214 << num_input << ", " << num_output << ", " << num_reverse_input 2215 << ", " << num_reverse_output << ", " << file_direction 2216 << "): "; 2217 if (sq_error > 0) { 2218 double snr = 10 * log10(variance / sq_error); 2219 EXPECT_GE(snr, expected_snr); 2220 EXPECT_NE(0, expected_snr); 2221 std::cout << "SNR=" << snr << " dB" << std::endl; 2222 } else { 2223 std::cout << "SNR=inf dB" << std::endl; 2224 } 2225 2226 fclose(out_file); 2227 fclose(ref_file); 2228 } 2229 } 2230 } 2231 2232 #if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE) 2233 INSTANTIATE_TEST_SUITE_P( 2234 CommonFormats, 2235 AudioProcessingTest, 2236 // Internal processing rates and the particularly common sample rate 44100 2237 // Hz are tested in a grid of combinations (capture in, render in, out). 2238 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0), 2239 std::make_tuple(48000, 48000, 32000, 48000, 40, 30), 2240 std::make_tuple(48000, 48000, 16000, 48000, 40, 20), 2241 std::make_tuple(48000, 44100, 48000, 44100, 20, 20), 2242 std::make_tuple(48000, 44100, 32000, 44100, 20, 15), 2243 std::make_tuple(48000, 44100, 16000, 44100, 20, 15), 2244 std::make_tuple(48000, 32000, 48000, 32000, 30, 35), 2245 std::make_tuple(48000, 32000, 32000, 32000, 30, 0), 2246 std::make_tuple(48000, 32000, 16000, 32000, 30, 20), 2247 std::make_tuple(48000, 16000, 48000, 16000, 25, 20), 2248 std::make_tuple(48000, 16000, 32000, 16000, 25, 20), 2249 std::make_tuple(48000, 16000, 16000, 16000, 25, 0), 2250 2251 std::make_tuple(44100, 48000, 48000, 48000, 30, 0), 2252 std::make_tuple(44100, 48000, 32000, 48000, 30, 30), 2253 std::make_tuple(44100, 48000, 16000, 48000, 30, 20), 2254 std::make_tuple(44100, 44100, 48000, 44100, 20, 20), 2255 std::make_tuple(44100, 44100, 32000, 44100, 20, 15), 2256 std::make_tuple(44100, 44100, 16000, 44100, 20, 15), 2257 std::make_tuple(44100, 32000, 48000, 32000, 30, 35), 2258 std::make_tuple(44100, 32000, 32000, 32000, 30, 0), 2259 std::make_tuple(44100, 32000, 16000, 32000, 30, 20), 2260 std::make_tuple(44100, 16000, 48000, 16000, 25, 20), 2261 std::make_tuple(44100, 16000, 32000, 16000, 25, 20), 2262 std::make_tuple(44100, 16000, 16000, 16000, 25, 0), 2263 2264 std::make_tuple(32000, 48000, 48000, 48000, 15, 0), 2265 std::make_tuple(32000, 48000, 32000, 48000, 15, 30), 2266 std::make_tuple(32000, 48000, 16000, 48000, 15, 20), 2267 std::make_tuple(32000, 44100, 48000, 44100, 19, 20), 2268 std::make_tuple(32000, 44100, 32000, 44100, 19, 15), 2269 std::make_tuple(32000, 44100, 16000, 44100, 19, 15), 2270 std::make_tuple(32000, 32000, 48000, 32000, 40, 35), 2271 std::make_tuple(32000, 32000, 32000, 32000, 0, 0), 2272 std::make_tuple(32000, 32000, 16000, 32000, 39, 20), 2273 std::make_tuple(32000, 16000, 48000, 16000, 25, 20), 2274 std::make_tuple(32000, 16000, 32000, 16000, 25, 20), 2275 std::make_tuple(32000, 16000, 16000, 16000, 25, 0), 2276 2277 std::make_tuple(16000, 48000, 48000, 48000, 9, 0), 2278 std::make_tuple(16000, 48000, 32000, 48000, 9, 30), 2279 std::make_tuple(16000, 48000, 16000, 48000, 9, 20), 2280 std::make_tuple(16000, 44100, 48000, 44100, 15, 20), 2281 std::make_tuple(16000, 44100, 32000, 44100, 15, 15), 2282 std::make_tuple(16000, 44100, 16000, 44100, 15, 15), 2283 std::make_tuple(16000, 32000, 48000, 32000, 25, 35), 2284 std::make_tuple(16000, 32000, 32000, 32000, 25, 0), 2285 std::make_tuple(16000, 32000, 16000, 32000, 25, 20), 2286 std::make_tuple(16000, 16000, 48000, 16000, 39, 20), 2287 std::make_tuple(16000, 16000, 32000, 16000, 39, 20), 2288 std::make_tuple(16000, 16000, 16000, 16000, 0, 0), 2289 2290 // Other sample rates are not tested exhaustively, to keep 2291 // the test runtime manageable. 2292 // 2293 // Testing most other sample rates logged by Chrome UMA: 2294 // - WebRTC.AudioInputSampleRate 2295 // - WebRTC.AudioOutputSampleRate 2296 // ApmConfiguration.HandlingOfRateCombinations covers 2297 // remaining sample rates. 2298 std::make_tuple(192000, 192000, 48000, 192000, 20, 40), 2299 std::make_tuple(176400, 176400, 48000, 176400, 20, 35), 2300 std::make_tuple(96000, 96000, 48000, 96000, 20, 40), 2301 std::make_tuple(88200, 88200, 48000, 88200, 20, 20), 2302 std::make_tuple(44100, 44100, 48000, 44100, 20, 20))); 2303 2304 #elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE) 2305 INSTANTIATE_TEST_SUITE_P( 2306 CommonFormats, 2307 AudioProcessingTest, 2308 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 19, 0), 2309 std::make_tuple(48000, 48000, 32000, 48000, 19, 30), 2310 std::make_tuple(48000, 48000, 16000, 48000, 19, 20), 2311 std::make_tuple(48000, 44100, 48000, 44100, 15, 20), 2312 std::make_tuple(48000, 44100, 32000, 44100, 15, 15), 2313 std::make_tuple(48000, 44100, 16000, 44100, 15, 15), 2314 std::make_tuple(48000, 32000, 48000, 32000, 19, 35), 2315 std::make_tuple(48000, 32000, 32000, 32000, 19, 0), 2316 std::make_tuple(48000, 32000, 16000, 32000, 19, 20), 2317 std::make_tuple(48000, 16000, 48000, 16000, 20, 20), 2318 std::make_tuple(48000, 16000, 32000, 16000, 20, 20), 2319 std::make_tuple(48000, 16000, 16000, 16000, 20, 0), 2320 2321 std::make_tuple(44100, 48000, 48000, 48000, 15, 0), 2322 std::make_tuple(44100, 48000, 32000, 48000, 15, 30), 2323 std::make_tuple(44100, 48000, 16000, 48000, 15, 20), 2324 std::make_tuple(44100, 44100, 48000, 44100, 15, 20), 2325 std::make_tuple(44100, 44100, 32000, 44100, 15, 15), 2326 std::make_tuple(44100, 44100, 16000, 44100, 15, 15), 2327 std::make_tuple(44100, 32000, 48000, 32000, 18, 35), 2328 std::make_tuple(44100, 32000, 32000, 32000, 18, 0), 2329 std::make_tuple(44100, 32000, 16000, 32000, 18, 20), 2330 std::make_tuple(44100, 16000, 48000, 16000, 19, 20), 2331 std::make_tuple(44100, 16000, 32000, 16000, 19, 20), 2332 std::make_tuple(44100, 16000, 16000, 16000, 19, 0), 2333 2334 std::make_tuple(32000, 48000, 48000, 48000, 17, 0), 2335 std::make_tuple(32000, 48000, 32000, 48000, 17, 30), 2336 std::make_tuple(32000, 48000, 16000, 48000, 17, 20), 2337 std::make_tuple(32000, 44100, 48000, 44100, 20, 20), 2338 std::make_tuple(32000, 44100, 32000, 44100, 20, 15), 2339 std::make_tuple(32000, 44100, 16000, 44100, 20, 15), 2340 std::make_tuple(32000, 32000, 48000, 32000, 27, 35), 2341 std::make_tuple(32000, 32000, 32000, 32000, 0, 0), 2342 std::make_tuple(32000, 32000, 16000, 32000, 30, 20), 2343 std::make_tuple(32000, 16000, 48000, 16000, 20, 20), 2344 std::make_tuple(32000, 16000, 32000, 16000, 20, 20), 2345 std::make_tuple(32000, 16000, 16000, 16000, 20, 0), 2346 2347 std::make_tuple(16000, 48000, 48000, 48000, 11, 0), 2348 std::make_tuple(16000, 48000, 32000, 48000, 11, 30), 2349 std::make_tuple(16000, 48000, 16000, 48000, 11, 20), 2350 std::make_tuple(16000, 44100, 48000, 44100, 15, 20), 2351 std::make_tuple(16000, 44100, 32000, 44100, 15, 15), 2352 std::make_tuple(16000, 44100, 16000, 44100, 15, 15), 2353 std::make_tuple(16000, 32000, 48000, 32000, 24, 35), 2354 std::make_tuple(16000, 32000, 32000, 32000, 24, 0), 2355 std::make_tuple(16000, 32000, 16000, 32000, 25, 20), 2356 std::make_tuple(16000, 16000, 48000, 16000, 28, 20), 2357 std::make_tuple(16000, 16000, 32000, 16000, 28, 20), 2358 std::make_tuple(16000, 16000, 16000, 16000, 0, 0), 2359 2360 std::make_tuple(192000, 192000, 48000, 192000, 20, 40), 2361 std::make_tuple(176400, 176400, 48000, 176400, 20, 35), 2362 std::make_tuple(96000, 96000, 48000, 96000, 20, 40), 2363 std::make_tuple(88200, 88200, 48000, 88200, 20, 20), 2364 std::make_tuple(44100, 44100, 48000, 44100, 20, 20))); 2365 #endif 2366 2367 // Produces a scoped trace debug output. 2368 std::string ProduceDebugText(int render_input_sample_rate_hz, 2369 int render_output_sample_rate_hz, 2370 int capture_input_sample_rate_hz, 2371 int capture_output_sample_rate_hz, 2372 size_t render_input_num_channels, 2373 size_t render_output_num_channels, 2374 size_t capture_input_num_channels, 2375 size_t capture_output_num_channels) { 2376 StringBuilder ss; 2377 ss << "Sample rates:" 2378 "\n Render input: " 2379 << render_input_sample_rate_hz 2380 << " Hz" 2381 "\n Render output: " 2382 << render_output_sample_rate_hz 2383 << " Hz" 2384 "\n Capture input: " 2385 << capture_input_sample_rate_hz 2386 << " Hz" 2387 "\n Capture output: " 2388 << capture_output_sample_rate_hz 2389 << " Hz" 2390 "\nNumber of channels:" 2391 "\n Render input: " 2392 << render_input_num_channels 2393 << "\n Render output: " << render_output_num_channels 2394 << "\n Capture input: " << capture_input_num_channels 2395 << "\n Capture output: " << capture_output_num_channels; 2396 return ss.Release(); 2397 } 2398 2399 // Validates that running the audio processing module using various combinations 2400 // of sample rates and number of channels works as intended. 2401 void RunApmRateAndChannelTest(ArrayView<const int> sample_rates_hz, 2402 ArrayView<const int> render_channel_counts, 2403 ArrayView<const int> capture_channel_counts) { 2404 AudioProcessing::Config apm_config; 2405 apm_config.pipeline.multi_channel_render = true; 2406 apm_config.pipeline.multi_channel_capture = true; 2407 apm_config.echo_canceller.enabled = true; 2408 scoped_refptr<AudioProcessing> apm = 2409 BuiltinAudioProcessingBuilder(apm_config).Build(CreateEnvironment()); 2410 2411 StreamConfig render_input_stream_config; 2412 StreamConfig render_output_stream_config; 2413 StreamConfig capture_input_stream_config; 2414 StreamConfig capture_output_stream_config; 2415 2416 std::vector<float> render_input_frame_channels; 2417 std::vector<float*> render_input_frame; 2418 std::vector<float> render_output_frame_channels; 2419 std::vector<float*> render_output_frame; 2420 std::vector<float> capture_input_frame_channels; 2421 std::vector<float*> capture_input_frame; 2422 std::vector<float> capture_output_frame_channels; 2423 std::vector<float*> capture_output_frame; 2424 2425 for (auto render_input_sample_rate_hz : sample_rates_hz) { 2426 for (auto render_output_sample_rate_hz : sample_rates_hz) { 2427 for (auto capture_input_sample_rate_hz : sample_rates_hz) { 2428 for (auto capture_output_sample_rate_hz : sample_rates_hz) { 2429 for (size_t render_input_num_channels : render_channel_counts) { 2430 for (size_t capture_input_num_channels : capture_channel_counts) { 2431 size_t render_output_num_channels = render_input_num_channels; 2432 size_t capture_output_num_channels = capture_input_num_channels; 2433 auto populate_audio_frame = [](int sample_rate_hz, 2434 size_t num_channels, 2435 StreamConfig* cfg, 2436 std::vector<float>* channels_data, 2437 std::vector<float*>* frame_data) { 2438 cfg->set_sample_rate_hz(sample_rate_hz); 2439 cfg->set_num_channels(num_channels); 2440 2441 size_t max_frame_size = 2442 AudioProcessing::GetFrameSize(sample_rate_hz); 2443 channels_data->resize(num_channels * max_frame_size); 2444 std::fill(channels_data->begin(), channels_data->end(), 0.5f); 2445 frame_data->resize(num_channels); 2446 for (size_t channel = 0; channel < num_channels; ++channel) { 2447 (*frame_data)[channel] = 2448 &(*channels_data)[channel * max_frame_size]; 2449 } 2450 }; 2451 2452 populate_audio_frame( 2453 render_input_sample_rate_hz, render_input_num_channels, 2454 &render_input_stream_config, &render_input_frame_channels, 2455 &render_input_frame); 2456 populate_audio_frame( 2457 render_output_sample_rate_hz, render_output_num_channels, 2458 &render_output_stream_config, &render_output_frame_channels, 2459 &render_output_frame); 2460 populate_audio_frame( 2461 capture_input_sample_rate_hz, capture_input_num_channels, 2462 &capture_input_stream_config, &capture_input_frame_channels, 2463 &capture_input_frame); 2464 populate_audio_frame( 2465 capture_output_sample_rate_hz, capture_output_num_channels, 2466 &capture_output_stream_config, &capture_output_frame_channels, 2467 &capture_output_frame); 2468 2469 for (size_t frame = 0; frame < 2; ++frame) { 2470 SCOPED_TRACE(ProduceDebugText( 2471 render_input_sample_rate_hz, render_output_sample_rate_hz, 2472 capture_input_sample_rate_hz, capture_output_sample_rate_hz, 2473 render_input_num_channels, render_output_num_channels, 2474 render_input_num_channels, capture_output_num_channels)); 2475 2476 int result = apm->ProcessReverseStream( 2477 &render_input_frame[0], render_input_stream_config, 2478 render_output_stream_config, &render_output_frame[0]); 2479 EXPECT_EQ(result, AudioProcessing::kNoError); 2480 result = apm->ProcessStream( 2481 &capture_input_frame[0], capture_input_stream_config, 2482 capture_output_stream_config, &capture_output_frame[0]); 2483 EXPECT_EQ(result, AudioProcessing::kNoError); 2484 } 2485 } 2486 } 2487 } 2488 } 2489 } 2490 } 2491 } 2492 2493 constexpr void Toggle(bool& b) { 2494 b ^= true; 2495 } 2496 2497 TEST(RuntimeSettingTest, TestDefaultCtor) { 2498 auto s = AudioProcessing::RuntimeSetting(); 2499 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type()); 2500 } 2501 2502 TEST(RuntimeSettingTest, TestUsageWithSwapQueue) { 2503 SwapQueue<AudioProcessing::RuntimeSetting> q(1); 2504 auto s = AudioProcessing::RuntimeSetting(); 2505 ASSERT_TRUE(q.Insert(&s)); 2506 ASSERT_TRUE(q.Remove(&s)); 2507 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type()); 2508 } 2509 2510 TEST(ApmConfiguration, EnablePostProcessing) { 2511 // Verify that apm uses a capture post processing module if one is provided. 2512 auto mock_post_processor_ptr = 2513 new ::testing::NiceMock<test::MockCustomProcessing>(); 2514 auto mock_post_processor = 2515 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr); 2516 scoped_refptr<AudioProcessing> apm = 2517 BuiltinAudioProcessingBuilder() 2518 .SetCapturePostProcessing(std::move(mock_post_processor)) 2519 .Build(CreateEnvironment()); 2520 2521 Int16FrameData audio; 2522 audio.SetProperties(AudioProcessing::GetFrameSize( 2523 AudioProcessing::NativeRate::kSampleRate16kHz), 2524 /* num_channels=*/1); 2525 2526 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1); 2527 apm->ProcessStream(audio.data.data(), 2528 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2529 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2530 audio.data.data()); 2531 } 2532 2533 TEST(ApmConfiguration, EnablePreProcessing) { 2534 // Verify that apm uses a capture post processing module if one is provided. 2535 auto mock_pre_processor_ptr = 2536 new ::testing::NiceMock<test::MockCustomProcessing>(); 2537 auto mock_pre_processor = 2538 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr); 2539 scoped_refptr<AudioProcessing> apm = 2540 BuiltinAudioProcessingBuilder() 2541 .SetRenderPreProcessing(std::move(mock_pre_processor)) 2542 .Build(CreateEnvironment()); 2543 2544 Int16FrameData audio; 2545 audio.SetProperties(AudioProcessing::GetFrameSize( 2546 AudioProcessing::NativeRate::kSampleRate16kHz), 2547 /* num_channels=*/1); 2548 2549 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1); 2550 apm->ProcessReverseStream( 2551 audio.data.data(), 2552 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2553 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2554 audio.data.data()); 2555 } 2556 2557 TEST(ApmConfiguration, EnableCaptureAnalyzer) { 2558 // Verify that apm uses a capture analyzer if one is provided. 2559 auto mock_capture_analyzer_ptr = 2560 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>(); 2561 auto mock_capture_analyzer = 2562 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr); 2563 scoped_refptr<AudioProcessing> apm = 2564 BuiltinAudioProcessingBuilder() 2565 .SetCaptureAnalyzer(std::move(mock_capture_analyzer)) 2566 .Build(CreateEnvironment()); 2567 2568 Int16FrameData audio; 2569 audio.SetProperties(AudioProcessing::GetFrameSize( 2570 AudioProcessing::NativeRate::kSampleRate16kHz), 2571 /* num_channels=*/1); 2572 2573 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1); 2574 apm->ProcessStream(audio.data.data(), 2575 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2576 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2577 audio.data.data()); 2578 } 2579 2580 TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) { 2581 auto mock_pre_processor_ptr = 2582 new ::testing::NiceMock<test::MockCustomProcessing>(); 2583 auto mock_pre_processor = 2584 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr); 2585 scoped_refptr<AudioProcessing> apm = 2586 BuiltinAudioProcessingBuilder() 2587 .SetRenderPreProcessing(std::move(mock_pre_processor)) 2588 .Build(CreateEnvironment()); 2589 apm->SetRuntimeSetting( 2590 AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0)); 2591 2592 // RuntimeSettings forwarded during 'Process*Stream' calls. 2593 // Therefore we have to make one such call. 2594 Int16FrameData audio; 2595 audio.SetProperties(AudioProcessing::GetFrameSize( 2596 AudioProcessing::NativeRate::kSampleRate16kHz), 2597 /* num_channels=*/1); 2598 2599 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_)) 2600 .Times(1); 2601 apm->ProcessReverseStream( 2602 audio.data.data(), 2603 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2604 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2605 audio.data.data()); 2606 } 2607 2608 class MockEchoControlFactory : public EchoControlFactory { 2609 public: 2610 MOCK_METHOD(std::unique_ptr<EchoControl>, 2611 Create, 2612 (const Environment&, int, int, int), 2613 (override)); 2614 MOCK_METHOD(std::unique_ptr<EchoControl>, 2615 Create, 2616 (const Environment&, int, int, int, NeuralResidualEchoEstimator*), 2617 (override)); 2618 }; 2619 2620 TEST(ApmConfiguration, EchoControlInjection) { 2621 // Verify that apm uses an injected echo controller if one is provided. 2622 auto echo_control_factory = std::make_unique<MockEchoControlFactory>(); 2623 EXPECT_CALL(*echo_control_factory, Create(_, _, _, _, _)) 2624 .WillOnce(WithoutArgs([] { 2625 auto ec = std::make_unique<test::MockEchoControl>(); 2626 EXPECT_CALL(*ec, AnalyzeRender).Times(1); 2627 EXPECT_CALL(*ec, AnalyzeCapture).Times(2); 2628 EXPECT_CALL(*ec, ProcessCapture(_, _, _)).Times(2); 2629 return ec; 2630 })); 2631 2632 scoped_refptr<AudioProcessing> apm = 2633 BuiltinAudioProcessingBuilder() 2634 .SetEchoControlFactory(std::move(echo_control_factory)) 2635 .Build(CreateEnvironment()); 2636 2637 Int16FrameData audio; 2638 audio.SetProperties(AudioProcessing::GetFrameSize( 2639 AudioProcessing::NativeRate::kSampleRate16kHz), 2640 /* num_channels=*/1); 2641 apm->ProcessStream(audio.data.data(), 2642 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2643 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2644 audio.data.data()); 2645 apm->ProcessReverseStream( 2646 audio.data.data(), 2647 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2648 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2649 audio.data.data()); 2650 apm->ProcessStream(audio.data.data(), 2651 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2652 StreamConfig(audio.sample_rate_hz, audio.num_channels()), 2653 audio.data.data()); 2654 } 2655 2656 TEST(ApmConfiguration, EchoDetectorInjection) { 2657 using ::testing::_; 2658 scoped_refptr<test::MockEchoDetector> mock_echo_detector = 2659 make_ref_counted<::testing::StrictMock<test::MockEchoDetector>>(); 2660 EXPECT_CALL(*mock_echo_detector, 2661 Initialize(/*capture_sample_rate_hz=*/16000, _, 2662 /*render_sample_rate_hz=*/16000, _)) 2663 .Times(1); 2664 scoped_refptr<AudioProcessing> apm = BuiltinAudioProcessingBuilder() 2665 .SetEchoDetector(mock_echo_detector) 2666 .Build(CreateEnvironment()); 2667 2668 // The echo detector is included in processing when enabled. 2669 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_)) 2670 .WillOnce([](ArrayView<const float> render_audio) { 2671 EXPECT_EQ(render_audio.size(), 160u); 2672 }); 2673 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_)) 2674 .WillOnce([](ArrayView<const float> capture_audio) { 2675 EXPECT_EQ(capture_audio.size(), 160u); 2676 }); 2677 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(1); 2678 2679 Int16FrameData frame; 2680 frame.SetProperties(AudioProcessing::GetFrameSize( 2681 AudioProcessing::NativeRate::kSampleRate16kHz), 2682 /* num_channels=*/1); 2683 2684 apm->ProcessReverseStream(frame.data.data(), StreamConfig(16000, 1), 2685 StreamConfig(16000, 1), frame.data.data()); 2686 apm->ProcessStream(frame.data.data(), StreamConfig(16000, 1), 2687 StreamConfig(16000, 1), frame.data.data()); 2688 2689 // When processing rates change, the echo detector is also reinitialized to 2690 // match those. 2691 EXPECT_CALL(*mock_echo_detector, 2692 Initialize(/*capture_sample_rate_hz=*/48000, _, 2693 /*render_sample_rate_hz=*/16000, _)) 2694 .Times(1); 2695 EXPECT_CALL(*mock_echo_detector, 2696 Initialize(/*capture_sample_rate_hz=*/48000, _, 2697 /*render_sample_rate_hz=*/48000, _)) 2698 .Times(1); 2699 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_)) 2700 .WillOnce([](ArrayView<const float> render_audio) { 2701 EXPECT_EQ(render_audio.size(), 480u); 2702 }); 2703 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_)) 2704 .Times(2) 2705 .WillRepeatedly([](ArrayView<const float> capture_audio) { 2706 EXPECT_EQ(capture_audio.size(), 480u); 2707 }); 2708 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(2); 2709 2710 frame.SetProperties(AudioProcessing::GetFrameSize( 2711 AudioProcessing::NativeRate::kSampleRate48kHz), 2712 frame.num_channels()); 2713 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1), 2714 StreamConfig(48000, 1), frame.data.data()); 2715 apm->ProcessReverseStream(frame.data.data(), StreamConfig(48000, 1), 2716 StreamConfig(48000, 1), frame.data.data()); 2717 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1), 2718 StreamConfig(48000, 1), frame.data.data()); 2719 } 2720 2721 scoped_refptr<AudioProcessing> CreateApm(bool mobile_aec) { 2722 // Enable residual echo detection, for stats. 2723 scoped_refptr<AudioProcessing> apm = 2724 BuiltinAudioProcessingBuilder() 2725 .SetEchoDetector(CreateEchoDetector()) 2726 .Build(CreateEnvironment()); 2727 if (!apm) { 2728 return apm; 2729 } 2730 2731 ProcessingConfig processing_config = { 2732 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}}; 2733 2734 if (apm->Initialize(processing_config) != 0) { 2735 return nullptr; 2736 } 2737 2738 // Disable all components except for an AEC. 2739 AudioProcessing::Config apm_config; 2740 apm_config.high_pass_filter.enabled = false; 2741 apm_config.gain_controller1.enabled = false; 2742 apm_config.gain_controller2.enabled = false; 2743 apm_config.echo_canceller.enabled = true; 2744 apm_config.echo_canceller.mobile_mode = mobile_aec; 2745 apm_config.noise_suppression.enabled = false; 2746 apm->ApplyConfig(apm_config); 2747 return apm; 2748 } 2749 2750 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_MAC) 2751 #define MAYBE_ApmStatistics DISABLED_ApmStatistics 2752 #else 2753 #define MAYBE_ApmStatistics ApmStatistics 2754 #endif 2755 2756 TEST(MAYBE_ApmStatistics, AECEnabledTest) { 2757 // Set up APM with AEC3 and process some audio. 2758 scoped_refptr<AudioProcessing> apm = CreateApm(false); 2759 ASSERT_TRUE(apm); 2760 AudioProcessing::Config apm_config; 2761 apm_config.echo_canceller.enabled = true; 2762 apm->ApplyConfig(apm_config); 2763 2764 // Set up an audioframe. 2765 Int16FrameData frame; 2766 frame.SetProperties(AudioProcessing::GetFrameSize( 2767 AudioProcessing::NativeRate::kSampleRate32kHz), 2768 /* num_channels=*/1); 2769 2770 // Fill the audio frame with a sawtooth pattern. 2771 int16_t* ptr = frame.data.data(); 2772 for (size_t i = 0; i < Int16FrameData::kMaxDataSizeSamples; i++) { 2773 ptr[i] = 10000 * ((i % 3) - 1); 2774 } 2775 2776 // Do some processing. 2777 for (int i = 0; i < 200; i++) { 2778 EXPECT_EQ(apm->ProcessReverseStream( 2779 frame.data.data(), 2780 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2781 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2782 frame.data.data()), 2783 0); 2784 EXPECT_EQ(apm->set_stream_delay_ms(0), 0); 2785 EXPECT_EQ(apm->ProcessStream( 2786 frame.data.data(), 2787 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2788 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2789 frame.data.data()), 2790 0); 2791 } 2792 2793 // Test statistics interface. 2794 AudioProcessingStats stats = apm->GetStatistics(); 2795 // We expect all statistics to be set and have a sensible value. 2796 ASSERT_TRUE(stats.residual_echo_likelihood.has_value()); 2797 EXPECT_GE(*stats.residual_echo_likelihood, 0.0); 2798 EXPECT_LE(*stats.residual_echo_likelihood, 1.0); 2799 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value()); 2800 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0); 2801 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0); 2802 ASSERT_TRUE(stats.echo_return_loss.has_value()); 2803 EXPECT_NE(*stats.echo_return_loss, -100.0); 2804 ASSERT_TRUE(stats.echo_return_loss_enhancement.has_value()); 2805 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0); 2806 } 2807 2808 TEST(MAYBE_ApmStatistics, AECMEnabledTest) { 2809 // Set up APM with AECM and process some audio. 2810 scoped_refptr<AudioProcessing> apm = CreateApm(true); 2811 ASSERT_TRUE(apm); 2812 2813 // Set up an audioframe. 2814 Int16FrameData frame; 2815 frame.SetProperties(AudioProcessing::GetFrameSize( 2816 AudioProcessing::NativeRate::kSampleRate32kHz), 2817 /* num_channels=*/1); 2818 2819 // Fill the audio frame with a sawtooth pattern. 2820 int16_t* ptr = frame.data.data(); 2821 for (size_t i = 0; i < Int16FrameData::kMaxDataSizeSamples; i++) { 2822 ptr[i] = 10000 * ((i % 3) - 1); 2823 } 2824 2825 // Do some processing. 2826 for (int i = 0; i < 200; i++) { 2827 EXPECT_EQ(apm->ProcessReverseStream( 2828 frame.data.data(), 2829 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2830 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2831 frame.data.data()), 2832 0); 2833 EXPECT_EQ(apm->set_stream_delay_ms(0), 0); 2834 EXPECT_EQ(apm->ProcessStream( 2835 frame.data.data(), 2836 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2837 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2838 frame.data.data()), 2839 0); 2840 } 2841 2842 // Test statistics interface. 2843 AudioProcessingStats stats = apm->GetStatistics(); 2844 // We expect only the residual echo detector statistics to be set and have a 2845 // sensible value. 2846 ASSERT_TRUE(stats.residual_echo_likelihood.has_value()); 2847 EXPECT_GE(*stats.residual_echo_likelihood, 0.0); 2848 EXPECT_LE(*stats.residual_echo_likelihood, 1.0); 2849 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value()); 2850 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0); 2851 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0); 2852 EXPECT_FALSE(stats.echo_return_loss.has_value()); 2853 EXPECT_FALSE(stats.echo_return_loss_enhancement.has_value()); 2854 } 2855 2856 TEST(ApmStatistics, DoNotReportVoiceDetectedStat) { 2857 ProcessingConfig processing_config = { 2858 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}}; 2859 2860 // Set up an audioframe. 2861 Int16FrameData frame; 2862 frame.SetProperties(AudioProcessing::GetFrameSize( 2863 AudioProcessing::NativeRate::kSampleRate32kHz), 2864 /* num_channels=*/1); 2865 2866 // Fill the audio frame with a sawtooth pattern. 2867 int16_t* ptr = frame.data.data(); 2868 for (size_t i = 0; i < Int16FrameData::kMaxDataSizeSamples; i++) { 2869 ptr[i] = 10000 * ((i % 3) - 1); 2870 } 2871 2872 scoped_refptr<AudioProcessing> apm = 2873 BuiltinAudioProcessingBuilder().Build(CreateEnvironment()); 2874 apm->Initialize(processing_config); 2875 2876 // No metric should be reported. 2877 EXPECT_EQ(apm->ProcessStream( 2878 frame.data.data(), 2879 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2880 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2881 frame.data.data()), 2882 0); 2883 #pragma clang diagnostic push 2884 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 2885 EXPECT_FALSE(apm->GetStatistics().voice_detected.has_value()); 2886 #pragma clang diagnostic pop 2887 } 2888 2889 TEST(ApmStatistics, GetStatisticsReportsNoEchoDetectorStatsWhenDisabled) { 2890 scoped_refptr<AudioProcessing> apm = 2891 BuiltinAudioProcessingBuilder().Build(CreateEnvironment()); 2892 Int16FrameData frame; 2893 frame.SetProperties(AudioProcessing::GetFrameSize( 2894 AudioProcessing::NativeRate::kSampleRate32kHz), 2895 /* num_channels=*/1); 2896 ASSERT_EQ(apm->ProcessStream( 2897 frame.data.data(), 2898 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2899 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2900 frame.data.data()), 2901 0); 2902 // Echo detector is disabled by default, no stats reported. 2903 AudioProcessingStats stats = apm->GetStatistics(); 2904 EXPECT_FALSE(stats.residual_echo_likelihood.has_value()); 2905 EXPECT_FALSE(stats.residual_echo_likelihood_recent_max.has_value()); 2906 } 2907 2908 TEST(ApmStatistics, GetStatisticsReportsEchoDetectorStatsWhenEnabled) { 2909 // Create APM with an echo detector injected. 2910 scoped_refptr<AudioProcessing> apm = 2911 BuiltinAudioProcessingBuilder() 2912 .SetEchoDetector(CreateEchoDetector()) 2913 .Build(CreateEnvironment()); 2914 Int16FrameData frame; 2915 frame.SetProperties(AudioProcessing::GetFrameSize( 2916 AudioProcessing::NativeRate::kSampleRate32kHz), 2917 /* num_channels=*/1); 2918 // Echo detector enabled: Report stats. 2919 ASSERT_EQ(apm->ProcessStream( 2920 frame.data.data(), 2921 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2922 StreamConfig(frame.sample_rate_hz, frame.num_channels()), 2923 frame.data.data()), 2924 0); 2925 AudioProcessingStats stats = apm->GetStatistics(); 2926 EXPECT_TRUE(stats.residual_echo_likelihood.has_value()); 2927 EXPECT_TRUE(stats.residual_echo_likelihood_recent_max.has_value()); 2928 } 2929 2930 TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) { 2931 std::array<int, 3> sample_rates_hz = {16000, 32000, 48000}; 2932 std::array<int, 2> render_channel_counts = {1, 7}; 2933 std::array<int, 2> capture_channel_counts = {1, 7}; 2934 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts, 2935 capture_channel_counts); 2936 } 2937 2938 TEST(ApmConfiguration, HandlingOfChannelCombinations) { 2939 std::array<int, 1> sample_rates_hz = {48000}; 2940 std::array<int, 8> render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8}; 2941 std::array<int, 8> capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8}; 2942 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts, 2943 capture_channel_counts); 2944 } 2945 2946 TEST(ApmConfiguration, HandlingOfRateCombinations) { 2947 // Test rates <= 96000 logged by Chrome UMA: 2948 // - WebRTC.AudioInputSampleRate 2949 // - WebRTC.AudioOutputSampleRate 2950 // Higher rates are tested in AudioProcessingTest.Format, to keep the number 2951 // of combinations in this test manageable. 2952 std::array<int, 9> sample_rates_hz = {8000, 11025, 16000, 22050, 32000, 2953 44100, 48000, 88200, 96000}; 2954 std::array<int, 1> render_channel_counts = {2}; 2955 std::array<int, 1> capture_channel_counts = {2}; 2956 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts, 2957 capture_channel_counts); 2958 } 2959 2960 TEST(ApmConfiguration, SelfAssignment) { 2961 // At some point memory sanitizer was complaining about self-assigment. 2962 // Make sure we don't regress. 2963 AudioProcessing::Config config; 2964 AudioProcessing::Config* config2 = &config; 2965 *config2 = *config2; // Workaround -Wself-assign-overloaded 2966 SUCCEED(); // Real success is absence of defects from asan/msan/ubsan. 2967 } 2968 2969 TEST(AudioProcessing, GainController1ConfigEqual) { 2970 AudioProcessing::Config::GainController1 a; 2971 AudioProcessing::Config::GainController1 b; 2972 EXPECT_EQ(a, b); 2973 2974 Toggle(a.enabled); 2975 b.enabled = a.enabled; 2976 EXPECT_EQ(a, b); 2977 2978 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital; 2979 b.mode = a.mode; 2980 EXPECT_EQ(a, b); 2981 2982 a.target_level_dbfs++; 2983 b.target_level_dbfs = a.target_level_dbfs; 2984 EXPECT_EQ(a, b); 2985 2986 a.compression_gain_db++; 2987 b.compression_gain_db = a.compression_gain_db; 2988 EXPECT_EQ(a, b); 2989 2990 Toggle(a.enable_limiter); 2991 b.enable_limiter = a.enable_limiter; 2992 EXPECT_EQ(a, b); 2993 2994 auto& a_analog = a.analog_gain_controller; 2995 auto& b_analog = b.analog_gain_controller; 2996 2997 Toggle(a_analog.enabled); 2998 b_analog.enabled = a_analog.enabled; 2999 EXPECT_EQ(a, b); 3000 3001 a_analog.startup_min_volume++; 3002 b_analog.startup_min_volume = a_analog.startup_min_volume; 3003 EXPECT_EQ(a, b); 3004 3005 a_analog.clipped_level_min++; 3006 b_analog.clipped_level_min = a_analog.clipped_level_min; 3007 EXPECT_EQ(a, b); 3008 3009 Toggle(a_analog.enable_digital_adaptive); 3010 b_analog.enable_digital_adaptive = a_analog.enable_digital_adaptive; 3011 EXPECT_EQ(a, b); 3012 } 3013 3014 // Checks that one differing parameter is sufficient to make two configs 3015 // different. 3016 TEST(AudioProcessing, GainController1ConfigNotEqual) { 3017 AudioProcessing::Config::GainController1 a; 3018 const AudioProcessing::Config::GainController1 b; 3019 3020 Toggle(a.enabled); 3021 EXPECT_NE(a, b); 3022 a = b; 3023 3024 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital; 3025 EXPECT_NE(a, b); 3026 a = b; 3027 3028 a.target_level_dbfs++; 3029 EXPECT_NE(a, b); 3030 a = b; 3031 3032 a.compression_gain_db++; 3033 EXPECT_NE(a, b); 3034 a = b; 3035 3036 Toggle(a.enable_limiter); 3037 EXPECT_NE(a, b); 3038 a = b; 3039 3040 auto& a_analog = a.analog_gain_controller; 3041 const auto& b_analog = b.analog_gain_controller; 3042 3043 Toggle(a_analog.enabled); 3044 EXPECT_NE(a, b); 3045 a_analog = b_analog; 3046 3047 a_analog.startup_min_volume++; 3048 EXPECT_NE(a, b); 3049 a_analog = b_analog; 3050 3051 a_analog.clipped_level_min++; 3052 EXPECT_NE(a, b); 3053 a_analog = b_analog; 3054 3055 Toggle(a_analog.enable_digital_adaptive); 3056 EXPECT_NE(a, b); 3057 a_analog = b_analog; 3058 } 3059 3060 TEST(AudioProcessing, GainController2ConfigEqual) { 3061 AudioProcessing::Config::GainController2 a; 3062 AudioProcessing::Config::GainController2 b; 3063 EXPECT_EQ(a, b); 3064 3065 Toggle(a.enabled); 3066 b.enabled = a.enabled; 3067 EXPECT_EQ(a, b); 3068 3069 a.fixed_digital.gain_db += 1.0f; 3070 b.fixed_digital.gain_db = a.fixed_digital.gain_db; 3071 EXPECT_EQ(a, b); 3072 3073 auto& a_adaptive = a.adaptive_digital; 3074 auto& b_adaptive = b.adaptive_digital; 3075 3076 Toggle(a_adaptive.enabled); 3077 b_adaptive.enabled = a_adaptive.enabled; 3078 EXPECT_EQ(a, b); 3079 3080 a_adaptive.headroom_db += 1.0f; 3081 b_adaptive.headroom_db = a_adaptive.headroom_db; 3082 EXPECT_EQ(a, b); 3083 3084 a_adaptive.max_gain_db += 1.0f; 3085 b_adaptive.max_gain_db = a_adaptive.max_gain_db; 3086 EXPECT_EQ(a, b); 3087 3088 a_adaptive.initial_gain_db += 1.0f; 3089 b_adaptive.initial_gain_db = a_adaptive.initial_gain_db; 3090 EXPECT_EQ(a, b); 3091 3092 a_adaptive.max_gain_change_db_per_second += 1.0f; 3093 b_adaptive.max_gain_change_db_per_second = 3094 a_adaptive.max_gain_change_db_per_second; 3095 EXPECT_EQ(a, b); 3096 3097 a_adaptive.max_output_noise_level_dbfs += 1.0f; 3098 b_adaptive.max_output_noise_level_dbfs = 3099 a_adaptive.max_output_noise_level_dbfs; 3100 EXPECT_EQ(a, b); 3101 } 3102 3103 // Checks that one differing parameter is sufficient to make two configs 3104 // different. 3105 TEST(AudioProcessing, GainController2ConfigNotEqual) { 3106 AudioProcessing::Config::GainController2 a; 3107 const AudioProcessing::Config::GainController2 b; 3108 3109 Toggle(a.enabled); 3110 EXPECT_NE(a, b); 3111 a = b; 3112 3113 a.fixed_digital.gain_db += 1.0f; 3114 EXPECT_NE(a, b); 3115 a.fixed_digital = b.fixed_digital; 3116 3117 auto& a_adaptive = a.adaptive_digital; 3118 const auto& b_adaptive = b.adaptive_digital; 3119 3120 Toggle(a_adaptive.enabled); 3121 EXPECT_NE(a, b); 3122 a_adaptive = b_adaptive; 3123 3124 a_adaptive.headroom_db += 1.0f; 3125 EXPECT_NE(a, b); 3126 a_adaptive = b_adaptive; 3127 3128 a_adaptive.max_gain_db += 1.0f; 3129 EXPECT_NE(a, b); 3130 a_adaptive = b_adaptive; 3131 3132 a_adaptive.initial_gain_db += 1.0f; 3133 EXPECT_NE(a, b); 3134 a_adaptive = b_adaptive; 3135 3136 a_adaptive.max_gain_change_db_per_second += 1.0f; 3137 EXPECT_NE(a, b); 3138 a_adaptive = b_adaptive; 3139 3140 a_adaptive.max_output_noise_level_dbfs += 1.0f; 3141 EXPECT_NE(a, b); 3142 a_adaptive = b_adaptive; 3143 } 3144 3145 struct ApmFormatHandlingTestParams { 3146 enum class ExpectedOutput { 3147 kErrorAndUnmodified, 3148 kErrorAndSilence, 3149 kErrorAndCopyOfFirstChannel, 3150 kErrorAndExactCopy, 3151 kNoError 3152 }; 3153 3154 StreamConfig input_config; 3155 StreamConfig output_config; 3156 ExpectedOutput expected_output; 3157 }; 3158 3159 class ApmFormatHandlingTest 3160 : public ::testing::TestWithParam< 3161 std::tuple<StreamDirection, ApmFormatHandlingTestParams>> { 3162 public: 3163 ApmFormatHandlingTest() 3164 : stream_direction_(std::get<0>(GetParam())), 3165 test_params_(std::get<1>(GetParam())) {} 3166 3167 protected: 3168 ::testing::Message ProduceDebugMessage() { 3169 return ::testing::Message() 3170 << "input sample_rate_hz=" 3171 << test_params_.input_config.sample_rate_hz() 3172 << " num_channels=" << test_params_.input_config.num_channels() 3173 << ", output sample_rate_hz=" 3174 << test_params_.output_config.sample_rate_hz() 3175 << " num_channels=" << test_params_.output_config.num_channels() 3176 << ", stream_direction=" << stream_direction_ << ", expected_output=" 3177 << static_cast<int>(test_params_.expected_output); 3178 } 3179 3180 StreamDirection stream_direction_; 3181 ApmFormatHandlingTestParams test_params_; 3182 }; 3183 3184 INSTANTIATE_TEST_SUITE_P( 3185 FormatValidation, 3186 ApmFormatHandlingTest, 3187 testing::Combine( 3188 ::testing::Values(kForward, kReverse), 3189 ::testing::Values( 3190 // Test cases with values on the boundary of legal ranges. 3191 ApmFormatHandlingTestParams{ 3192 StreamConfig(16000, 1), StreamConfig(8000, 1), 3193 ApmFormatHandlingTestParams::ExpectedOutput::kNoError}, 3194 ApmFormatHandlingTestParams{ 3195 StreamConfig(8000, 1), StreamConfig(16000, 1), 3196 ApmFormatHandlingTestParams::ExpectedOutput::kNoError}, 3197 ApmFormatHandlingTestParams{ 3198 StreamConfig(384000, 1), StreamConfig(16000, 1), 3199 ApmFormatHandlingTestParams::ExpectedOutput::kNoError}, 3200 ApmFormatHandlingTestParams{ 3201 StreamConfig(16000, 1), StreamConfig(384000, 1), 3202 ApmFormatHandlingTestParams::ExpectedOutput::kNoError}, 3203 ApmFormatHandlingTestParams{ 3204 StreamConfig(16000, 2), StreamConfig(16000, 1), 3205 ApmFormatHandlingTestParams::ExpectedOutput::kNoError}, 3206 ApmFormatHandlingTestParams{ 3207 StreamConfig(16000, 3), StreamConfig(16000, 3), 3208 ApmFormatHandlingTestParams::ExpectedOutput::kNoError}, 3209 3210 // Supported but incompatible formats. 3211 ApmFormatHandlingTestParams{ 3212 StreamConfig(16000, 3), StreamConfig(16000, 2), 3213 ApmFormatHandlingTestParams::ExpectedOutput:: 3214 kErrorAndCopyOfFirstChannel}, 3215 ApmFormatHandlingTestParams{ 3216 StreamConfig(16000, 3), StreamConfig(16000, 4), 3217 ApmFormatHandlingTestParams::ExpectedOutput:: 3218 kErrorAndCopyOfFirstChannel}, 3219 3220 // Unsupported format and input / output mismatch. 3221 ApmFormatHandlingTestParams{ 3222 StreamConfig(7900, 1), StreamConfig(16000, 1), 3223 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence}, 3224 ApmFormatHandlingTestParams{ 3225 StreamConfig(16000, 1), StreamConfig(7900, 1), 3226 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence}, 3227 ApmFormatHandlingTestParams{ 3228 StreamConfig(390000, 1), StreamConfig(16000, 1), 3229 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence}, 3230 ApmFormatHandlingTestParams{ 3231 StreamConfig(16000, 1), StreamConfig(390000, 1), 3232 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence}, 3233 ApmFormatHandlingTestParams{ 3234 StreamConfig(-16000, 1), StreamConfig(16000, 1), 3235 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence}, 3236 3237 // Unsupported format but input / output formats match. 3238 ApmFormatHandlingTestParams{StreamConfig(7900, 1), 3239 StreamConfig(7900, 1), 3240 ApmFormatHandlingTestParams:: 3241 ExpectedOutput::kErrorAndExactCopy}, 3242 ApmFormatHandlingTestParams{StreamConfig(390000, 1), 3243 StreamConfig(390000, 1), 3244 ApmFormatHandlingTestParams:: 3245 ExpectedOutput::kErrorAndExactCopy}, 3246 3247 // Unsupported but identical sample rate, channel mismatch. 3248 ApmFormatHandlingTestParams{ 3249 StreamConfig(7900, 1), StreamConfig(7900, 2), 3250 ApmFormatHandlingTestParams::ExpectedOutput:: 3251 kErrorAndCopyOfFirstChannel}, 3252 ApmFormatHandlingTestParams{ 3253 StreamConfig(7900, 2), StreamConfig(7900, 1), 3254 ApmFormatHandlingTestParams::ExpectedOutput:: 3255 kErrorAndCopyOfFirstChannel}, 3256 3257 // Test cases with meaningless output format. 3258 ApmFormatHandlingTestParams{ 3259 StreamConfig(16000, 1), StreamConfig(-16000, 1), 3260 ApmFormatHandlingTestParams::ExpectedOutput:: 3261 kErrorAndUnmodified}, 3262 ApmFormatHandlingTestParams{ 3263 StreamConfig(-16000, 1), StreamConfig(-16000, 1), 3264 ApmFormatHandlingTestParams::ExpectedOutput:: 3265 kErrorAndUnmodified}))); 3266 3267 TEST_P(ApmFormatHandlingTest, IntApi) { 3268 SCOPED_TRACE(ProduceDebugMessage()); 3269 3270 // Set up input and output data. 3271 const size_t num_input_samples = 3272 test_params_.input_config.num_channels() * 3273 std::abs(test_params_.input_config.sample_rate_hz() / 100); 3274 const size_t num_output_samples = 3275 test_params_.output_config.num_channels() * 3276 std::abs(test_params_.output_config.sample_rate_hz() / 100); 3277 std::vector<int16_t> input_block(num_input_samples); 3278 for (int i = 0; i < static_cast<int>(input_block.size()); ++i) { 3279 input_block[i] = i; 3280 } 3281 std::vector<int16_t> output_block(num_output_samples); 3282 constexpr int kUnlikelyOffset = 37; 3283 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) { 3284 output_block[i] = i - kUnlikelyOffset; 3285 } 3286 3287 // Call APM. 3288 scoped_refptr<AudioProcessing> ap = 3289 BuiltinAudioProcessingBuilder().Build(CreateEnvironment()); 3290 int error; 3291 if (stream_direction_ == kForward) { 3292 error = ap->ProcessStream(input_block.data(), test_params_.input_config, 3293 test_params_.output_config, output_block.data()); 3294 } else { 3295 error = ap->ProcessReverseStream( 3296 input_block.data(), test_params_.input_config, 3297 test_params_.output_config, output_block.data()); 3298 } 3299 3300 // Check output. 3301 switch (test_params_.expected_output) { 3302 case ApmFormatHandlingTestParams::ExpectedOutput::kNoError: 3303 EXPECT_EQ(error, AudioProcessing::kNoError); 3304 break; 3305 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndUnmodified: 3306 EXPECT_NE(error, AudioProcessing::kNoError); 3307 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) { 3308 EXPECT_EQ(output_block[i], i - kUnlikelyOffset); 3309 } 3310 break; 3311 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence: 3312 EXPECT_NE(error, AudioProcessing::kNoError); 3313 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) { 3314 EXPECT_EQ(output_block[i], 0); 3315 } 3316 break; 3317 case ApmFormatHandlingTestParams::ExpectedOutput:: 3318 kErrorAndCopyOfFirstChannel: 3319 EXPECT_NE(error, AudioProcessing::kNoError); 3320 for (size_t ch = 0; ch < test_params_.output_config.num_channels(); 3321 ++ch) { 3322 for (size_t i = 0; i < test_params_.output_config.num_frames(); ++i) { 3323 EXPECT_EQ( 3324 output_block[ch + i * test_params_.output_config.num_channels()], 3325 static_cast<int16_t>(i * 3326 test_params_.input_config.num_channels())); 3327 } 3328 } 3329 break; 3330 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndExactCopy: 3331 EXPECT_NE(error, AudioProcessing::kNoError); 3332 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) { 3333 EXPECT_EQ(output_block[i], i); 3334 } 3335 break; 3336 } 3337 } 3338 3339 TEST_P(ApmFormatHandlingTest, FloatApi) { 3340 SCOPED_TRACE(ProduceDebugMessage()); 3341 3342 // Set up input and output data. 3343 const size_t input_samples_per_channel = 3344 std::abs(test_params_.input_config.sample_rate_hz()) / 100; 3345 const size_t output_samples_per_channel = 3346 std::abs(test_params_.output_config.sample_rate_hz()) / 100; 3347 const size_t input_num_channels = test_params_.input_config.num_channels(); 3348 const size_t output_num_channels = test_params_.output_config.num_channels(); 3349 ChannelBuffer<float> input_block(input_samples_per_channel, 3350 input_num_channels); 3351 ChannelBuffer<float> output_block(output_samples_per_channel, 3352 output_num_channels); 3353 for (size_t ch = 0; ch < input_num_channels; ++ch) { 3354 for (size_t i = 0; i < input_samples_per_channel; ++i) { 3355 input_block.channels()[ch][i] = ch + i * input_num_channels; 3356 } 3357 } 3358 constexpr int kUnlikelyOffset = 37; 3359 for (size_t ch = 0; ch < output_num_channels; ++ch) { 3360 for (size_t i = 0; i < output_samples_per_channel; ++i) { 3361 output_block.channels()[ch][i] = 3362 ch + i * output_num_channels - kUnlikelyOffset; 3363 } 3364 } 3365 3366 // Call APM. 3367 scoped_refptr<AudioProcessing> ap = 3368 BuiltinAudioProcessingBuilder().Build(CreateEnvironment()); 3369 int error; 3370 if (stream_direction_ == kForward) { 3371 error = 3372 ap->ProcessStream(input_block.channels(), test_params_.input_config, 3373 test_params_.output_config, output_block.channels()); 3374 } else { 3375 error = ap->ProcessReverseStream( 3376 input_block.channels(), test_params_.input_config, 3377 test_params_.output_config, output_block.channels()); 3378 } 3379 3380 // Check output. 3381 switch (test_params_.expected_output) { 3382 case ApmFormatHandlingTestParams::ExpectedOutput::kNoError: 3383 EXPECT_EQ(error, AudioProcessing::kNoError); 3384 break; 3385 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndUnmodified: 3386 EXPECT_NE(error, AudioProcessing::kNoError); 3387 for (size_t ch = 0; ch < output_num_channels; ++ch) { 3388 for (size_t i = 0; i < output_samples_per_channel; ++i) { 3389 EXPECT_EQ(output_block.channels()[ch][i], 3390 ch + i * output_num_channels - kUnlikelyOffset); 3391 } 3392 } 3393 break; 3394 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence: 3395 EXPECT_NE(error, AudioProcessing::kNoError); 3396 for (size_t ch = 0; ch < output_num_channels; ++ch) { 3397 for (size_t i = 0; i < output_samples_per_channel; ++i) { 3398 EXPECT_EQ(output_block.channels()[ch][i], 0); 3399 } 3400 } 3401 break; 3402 case ApmFormatHandlingTestParams::ExpectedOutput:: 3403 kErrorAndCopyOfFirstChannel: 3404 EXPECT_NE(error, AudioProcessing::kNoError); 3405 for (size_t ch = 0; ch < output_num_channels; ++ch) { 3406 for (size_t i = 0; i < output_samples_per_channel; ++i) { 3407 EXPECT_EQ(output_block.channels()[ch][i], 3408 input_block.channels()[0][i]); 3409 } 3410 } 3411 break; 3412 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndExactCopy: 3413 EXPECT_NE(error, AudioProcessing::kNoError); 3414 for (size_t ch = 0; ch < output_num_channels; ++ch) { 3415 for (size_t i = 0; i < output_samples_per_channel; ++i) { 3416 EXPECT_EQ(output_block.channels()[ch][i], 3417 input_block.channels()[ch][i]); 3418 } 3419 } 3420 break; 3421 } 3422 } 3423 3424 TEST(ApmAnalyzeReverseStreamFormatTest, AnalyzeReverseStream) { 3425 for (auto&& [input_config, expect_error] : 3426 {std::tuple(StreamConfig(16000, 2), /*expect_error=*/false), 3427 std::tuple(StreamConfig(8000, 1), /*expect_error=*/false), 3428 std::tuple(StreamConfig(384000, 1), /*expect_error=*/false), 3429 std::tuple(StreamConfig(7900, 1), /*expect_error=*/true), 3430 std::tuple(StreamConfig(390000, 1), /*expect_error=*/true), 3431 std::tuple(StreamConfig(16000, 0), /*expect_error=*/true), 3432 std::tuple(StreamConfig(-16000, 0), /*expect_error=*/true)}) { 3433 SCOPED_TRACE(::testing::Message() 3434 << "sample_rate_hz=" << input_config.sample_rate_hz() 3435 << " num_channels=" << input_config.num_channels()); 3436 3437 // Set up input data. 3438 ChannelBuffer<float> input_block( 3439 std::abs(input_config.sample_rate_hz()) / 100, 3440 input_config.num_channels()); 3441 3442 // Call APM. 3443 scoped_refptr<AudioProcessing> ap = 3444 BuiltinAudioProcessingBuilder().Build(CreateEnvironment()); 3445 int error = ap->AnalyzeReverseStream(input_block.channels(), input_config); 3446 3447 // Check output. 3448 if (expect_error) { 3449 EXPECT_NE(error, AudioProcessing::kNoError); 3450 } else { 3451 EXPECT_EQ(error, AudioProcessing::kNoError); 3452 } 3453 } 3454 } 3455 3456 } // namespace 3457 } // namespace webrtc