diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn index b7db3d019d..1cd97f3b97 100644 --- a/webrtc/modules/BUILD.gn +++ b/webrtc/modules/BUILD.gn @@ -609,6 +609,7 @@ if (rtc_include_tests) { "audio_processing/low_cut_filter_unittest.cc", "audio_processing/noise_suppression_unittest.cc", "audio_processing/residual_echo_detector_unittest.cc", + "audio_processing/rms_level_unittest.cc", "audio_processing/test/bitexactness_tools.cc", "audio_processing/test/bitexactness_tools.h", "audio_processing/test/debug_dump_replayer.cc", diff --git a/webrtc/modules/audio_processing/rms_level_unittest.cc b/webrtc/modules/audio_processing/rms_level_unittest.cc new file mode 100644 index 0000000000..7b15717ca0 --- /dev/null +++ b/webrtc/modules/audio_processing/rms_level_unittest.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016 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 +#include +#include + +#include "webrtc/base/array_view.h" +#include "webrtc/base/mathutils.h" +#include "webrtc/base/safe_conversions.h" +#include "webrtc/modules/audio_processing/rms_level.h" +#include "webrtc/test/gtest.h" + +namespace webrtc { +namespace { +constexpr int kSampleRateHz = 48000; +constexpr size_t kBlockSizeSamples = kSampleRateHz / 100; + +std::unique_ptr RunTest(rtc::ArrayView input) { + std::unique_ptr level(new RMSLevel); + for (size_t n = 0; n + kBlockSizeSamples <= input.size(); + n += kBlockSizeSamples) { + level->Process(input.subview(n, kBlockSizeSamples).data(), + kBlockSizeSamples); + } + return level; +} + +std::vector CreateSinusoid(int frequency_hz, + int amplitude, + size_t num_samples) { + std::vector x(num_samples); + for (size_t n = 0; n < num_samples; ++n) { + x[n] = rtc::saturated_cast( + amplitude * std::sin(2 * M_PI * n * frequency_hz / kSampleRateHz)); + } + return x; +} +} // namespace + +TEST(RmsLevelTest, Run1000HzFullScale) { + auto x = CreateSinusoid(1000, INT16_MAX, kSampleRateHz); + auto level = RunTest(x); + EXPECT_EQ(3, level->RMS()); // -3 dBFS +} + +TEST(RmsLevelTest, Run1000HzHalfScale) { + auto x = CreateSinusoid(1000, INT16_MAX / 2, kSampleRateHz); + auto level = RunTest(x); + EXPECT_EQ(9, level->RMS()); // -9 dBFS +} + +TEST(RmsLevelTest, RunZeros) { + std::vector x(kSampleRateHz, 0); // 1 second of pure silence. + auto level = RunTest(x); + EXPECT_EQ(127, level->RMS()); +} + +TEST(RmsLevelTest, NoSamples) { + RMSLevel level; + EXPECT_EQ(127, level.RMS()); // Return minimum if no samples are given. +} + +TEST(RmsLevelTest, PollTwice) { + auto x = CreateSinusoid(1000, INT16_MAX, kSampleRateHz); + auto level = RunTest(x); + level->RMS(); + EXPECT_EQ(127, level->RMS()); // Stats should be reset at this point. +} + +TEST(RmsLevelTest, Reset) { + auto x = CreateSinusoid(1000, INT16_MAX, kSampleRateHz); + auto level = RunTest(x); + level->Reset(); + EXPECT_EQ(127, level->RMS()); // Stats should be reset at this point. +} + +// Inserts 1 second of full-scale sinusoid, followed by 1 second of muted. +TEST(RmsLevelTest, ProcessMuted) { + auto x = CreateSinusoid(1000, INT16_MAX, kSampleRateHz); + auto level = RunTest(x); + level->ProcessMuted(kSampleRateHz); + EXPECT_EQ(6, level->RMS()); // Average RMS halved due to the silence. +} + +} // namespace webrtc