/* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/aec3/decimator.h" #include #include #include #include #include #include #include #include #include "modules/audio_processing/aec3/aec3_common.h" #include "rtc_base/strings/string_builder.h" #include "test/gtest.h" namespace webrtc { namespace { std::string ProduceDebugText(int sample_rate_hz) { rtc::StringBuilder ss; ss << "Sample rate: " << sample_rate_hz; return ss.Release(); } constexpr size_t kDownSamplingFactors[] = {2, 4, 8}; constexpr float kPi = 3.141592f; constexpr size_t kNumStartupBlocks = 50; constexpr size_t kNumBlocks = 1000; void ProduceDecimatedSinusoidalOutputPower(int sample_rate_hz, size_t down_sampling_factor, float sinusoidal_frequency_hz, float* input_power, float* output_power) { float input[kBlockSize * kNumBlocks]; const size_t sub_block_size = kBlockSize / down_sampling_factor; // Produce a sinusoid of the specified frequency. for (size_t k = 0; k < kBlockSize * kNumBlocks; ++k) { input[k] = 32767.f * std::sin(2.f * kPi * sinusoidal_frequency_hz * k / sample_rate_hz); } Decimator decimator(down_sampling_factor); std::vector output(sub_block_size * kNumBlocks); for (size_t k = 0; k < kNumBlocks; ++k) { std::vector sub_block(sub_block_size); decimator.Decimate( rtc::ArrayView(&input[k * kBlockSize], kBlockSize), sub_block); std::copy(sub_block.begin(), sub_block.end(), output.begin() + k * sub_block_size); } ASSERT_GT(kNumBlocks, kNumStartupBlocks); rtc::ArrayView input_to_evaluate( &input[kNumStartupBlocks * kBlockSize], (kNumBlocks - kNumStartupBlocks) * kBlockSize); rtc::ArrayView output_to_evaluate( &output[kNumStartupBlocks * sub_block_size], (kNumBlocks - kNumStartupBlocks) * sub_block_size); *input_power = std::inner_product(input_to_evaluate.begin(), input_to_evaluate.end(), input_to_evaluate.begin(), 0.f) / input_to_evaluate.size(); *output_power = std::inner_product(output_to_evaluate.begin(), output_to_evaluate.end(), output_to_evaluate.begin(), 0.f) / output_to_evaluate.size(); } } // namespace // Verifies that there is little aliasing from upper frequencies in the // downsampling. TEST(Decimator, NoLeakageFromUpperFrequencies) { float input_power; float output_power; for (auto rate : {16000, 32000, 48000}) { for (auto down_sampling_factor : kDownSamplingFactors) { ProduceDebugText(rate); ProduceDecimatedSinusoidalOutputPower(rate, down_sampling_factor, 3.f / 8.f * rate, &input_power, &output_power); EXPECT_GT(0.0001f * input_power, output_power); } } } #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) // Verifies the check for the input size. TEST(DecimatorDeathTest, WrongInputSize) { Decimator decimator(4); std::vector x(kBlockSize - 1, 0.f); std::array x_downsampled; EXPECT_DEATH(decimator.Decimate(x, x_downsampled), ""); } // Verifies the check for non-null output parameter. TEST(DecimatorDeathTest, NullOutput) { Decimator decimator(4); std::vector x(kBlockSize, 0.f); EXPECT_DEATH(decimator.Decimate(x, nullptr), ""); } // Verifies the check for the output size. TEST(DecimatorDeathTest, WrongOutputSize) { Decimator decimator(4); std::vector x(kBlockSize, 0.f); std::array x_downsampled; EXPECT_DEATH(decimator.Decimate(x, x_downsampled), ""); } // Verifies the check for the correct downsampling factor. TEST(DecimatorDeathTest, CorrectDownSamplingFactor) { EXPECT_DEATH(Decimator(3), ""); } #endif } // namespace webrtc