| Index: webrtc/modules/audio_processing/test/fake_recording_device_unittest.cc
|
| diff --git a/webrtc/modules/audio_processing/test/fake_recording_device_unittest.cc b/webrtc/modules/audio_processing/test/fake_recording_device_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cc60cbb3dd2cb43c2cffe42ea68ae3808ff83d82
|
| --- /dev/null
|
| +++ b/webrtc/modules/audio_processing/test/fake_recording_device_unittest.cc
|
| @@ -0,0 +1,187 @@
|
| +/*
|
| + * 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 <sstream>
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "webrtc/base/array_view.h"
|
| +#include "webrtc/modules/audio_processing/test/fake_recording_device.h"
|
| +#include "webrtc/test/gtest.h"
|
| +
|
| +namespace webrtc {
|
| +
|
| +namespace {
|
| +
|
| +using MappingKind = FakeRecordingDevice::LevelToScalingMappingKind;
|
| +
|
| +// TODO(...): Add new mapping kinds here as they are added to
|
| +// LevelToScalingMappingKind.
|
| +const std::vector<MappingKind> kMappingKindsToTest =
|
| + {MappingKind::kIdentity, MappingKind::kLinear};
|
| +
|
| +const std::vector<std::vector<float>> kTestMultiChannelSamples{
|
| + std::vector<float>{-10.0, -1.0, -0.1, 0.0, 0.1, 1.0, 10.0}};
|
| +
|
| +// Returns a vector of ArrayView items of const floats.
|
| +std::vector<rtc::ArrayView<const float>> VecVecToVecArrayViewOfConst(
|
| + const std::vector<std::vector<float>>& vectorOfVectors) {
|
| + std::vector<rtc::ArrayView<const float>> vectorOfArrayViews;
|
| + for (const auto& v : vectorOfVectors) { vectorOfArrayViews.emplace_back(v); }
|
| + return vectorOfArrayViews;
|
| +}
|
| +
|
| +// Returns a vector of ArrayView items of non-const floats.
|
| +std::vector<rtc::ArrayView<float>> VecVecToVecArrayView(
|
| + std::vector<std::vector<float>>* vectorOfVectors) {
|
| + std::vector<rtc::ArrayView<float>> vectorOfArrayViews;
|
| + for (auto& v : *vectorOfVectors) { vectorOfArrayViews.emplace_back(v); }
|
| + return vectorOfArrayViews;
|
| +}
|
| +
|
| +// Checks that the samples modified using monotonic level values are also
|
| +// monotonic.
|
| +void CheckIfMonotoneSamplesModules(
|
| + const std::vector<rtc::ArrayView<float>>& prev,
|
| + const std::vector<rtc::ArrayView<float>>& curr) {
|
| + bool valid = true;
|
| + for (size_t i = 0; i < prev.size(); ++i) {
|
| + for (size_t j = 0; j < prev[i].size(); ++j) {
|
| + valid = std::fabs(prev[i][j]) <= std::fabs(curr[i][j]);
|
| + if (!valid) { break; }
|
| + }
|
| + if (!valid) { break; }
|
| + }
|
| + EXPECT_TRUE(valid);
|
| +}
|
| +
|
| +// Checks that the samples in each pair have the same sign unless the sample in
|
| +// |dst| is zero (because of zero gain).
|
| +void CheckSameSign(
|
| + const std::vector<rtc::ArrayView<const float>>& src,
|
| + const std::vector<rtc::ArrayView<float>>& dst) {
|
| + const auto fsgn = [](float x) { return ((x < 0) ? -1 : (x > 0) ? 1 : 0); };
|
| + bool valid = true;
|
| + for (size_t i = 0; i < src.size(); ++i) {
|
| + for (size_t j = 0; j < src[i].size(); ++j) {
|
| + valid = dst[i][j] == 0.0f || fsgn(src[i][j]) == fsgn(dst[i][j]);
|
| + if (!valid) { break; }
|
| + }
|
| + if (!valid) { break; }
|
| + }
|
| + EXPECT_TRUE(valid);
|
| +}
|
| +
|
| +std::string MappingKindToString(MappingKind kind) {
|
| + std::ostringstream ss;
|
| + ss << "simulated microphone kind code: " << static_cast<size_t>(kind);
|
| + return ss.str();
|
| +}
|
| +
|
| +std::string AnalogLevelToString(int level) {
|
| + std::ostringstream ss;
|
| + ss << "analog level: " << level;
|
| + return ss.str();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +TEST(AnalogVolumeMapper, CheckHelperFunctions) {
|
| + // Check read.
|
| + const auto src_multichannel_samples_view = VecVecToVecArrayViewOfConst(
|
| + kTestMultiChannelSamples);
|
| + EXPECT_EQ(kTestMultiChannelSamples[0][0],
|
| + src_multichannel_samples_view[0][0]);
|
| +
|
| + // Check sizes.
|
| + auto dst_multichannel_samples = kTestMultiChannelSamples;
|
| + auto dst_multichannel_samples_view = VecVecToVecArrayView(
|
| + &dst_multichannel_samples);
|
| + EXPECT_EQ(kTestMultiChannelSamples.size(), // Same number of channels.
|
| + dst_multichannel_samples_view.size());
|
| + EXPECT_EQ(kTestMultiChannelSamples[0].size(), // Same number of samples.
|
| + dst_multichannel_samples_view[0].size());
|
| +
|
| + // Check write.
|
| + dst_multichannel_samples[0][1] = -5.0f;
|
| + EXPECT_EQ(dst_multichannel_samples[0][0],
|
| + dst_multichannel_samples_view[0][0]);
|
| +}
|
| +
|
| +TEST(AnalogVolumeMapper, GainCurveShouldBeMonotone) {
|
| + // Create test samples.
|
| + const auto src_multichannel_samples_view = VecVecToVecArrayViewOfConst(
|
| + kTestMultiChannelSamples);
|
| +
|
| + // Create output buffers.
|
| + auto dst_multichannel_samples_prev = kTestMultiChannelSamples;
|
| + auto dst_multichannel_samples_prev_view = VecVecToVecArrayView(
|
| + &dst_multichannel_samples_prev);
|
| + auto dst_multichannel_samples = kTestMultiChannelSamples;
|
| + auto dst_multichannel_samples_view = VecVecToVecArrayView(
|
| + &dst_multichannel_samples);
|
| +
|
| + // Test different mappings.
|
| + for (const auto& kind : kMappingKindsToTest) {
|
| + SCOPED_TRACE(MappingKindToString(kind));
|
| + webrtc::FakeRecordingDevice level_mapper(kind);
|
| +
|
| + // Apply lowest analog level.
|
| + level_mapper.SimulateAnalogGain(
|
| + src_multichannel_samples_view, dst_multichannel_samples_prev_view, 0);
|
| +
|
| + // Increment analog level to check monotonicity.
|
| + for (int i = 1; i <= 255; ++i) {
|
| + SCOPED_TRACE(AnalogLevelToString(i));
|
| + level_mapper.SimulateAnalogGain(
|
| + src_multichannel_samples_view, dst_multichannel_samples_view, i);
|
| + // TODO(alessiob): The test below is designed for state-less recording
|
| + // devices. If, for instance, soft-clipping is used, the test might need
|
| + // to be redesigned.
|
| + CheckIfMonotoneSamplesModules(
|
| + dst_multichannel_samples_prev_view, dst_multichannel_samples_view);
|
| +
|
| + // Update prev.
|
| + dst_multichannel_samples_prev = dst_multichannel_samples;
|
| + dst_multichannel_samples_prev_view = VecVecToVecArrayView(
|
| + &dst_multichannel_samples_prev);
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST(AnalogVolumeMapper, GainCurveShouldNotChangeSign) {
|
| + // Create test samples.
|
| + const auto src_multichannel_samples_view = VecVecToVecArrayViewOfConst(
|
| + kTestMultiChannelSamples);
|
| +
|
| + // Create output buffer.
|
| + auto dst_multichannel_samples = kTestMultiChannelSamples;
|
| + auto dst_multichannel_samples_view = VecVecToVecArrayView(
|
| + &dst_multichannel_samples);
|
| +
|
| + // Test different mappings.
|
| + for (const auto& kind : kMappingKindsToTest) {
|
| + SCOPED_TRACE(MappingKindToString(kind));
|
| + webrtc::FakeRecordingDevice level_mapper(kind);
|
| +
|
| + for (int i = 0; i <= 255; ++i) {
|
| + SCOPED_TRACE(AnalogLevelToString(i));
|
| + level_mapper.SimulateAnalogGain(
|
| + src_multichannel_samples_view, dst_multichannel_samples_view, i);
|
| + // TODO(alessiob): The test below is designed for state-less recording
|
| + // devices. If, for instance, soft-clipping is used, the test might need
|
| + // to be redesigned.
|
| + CheckSameSign(
|
| + src_multichannel_samples_view, dst_multichannel_samples_view);
|
| + }
|
| + }
|
| +}
|
| +
|
| +} // namespace webrtc
|
|
|