alignment_mixer_unittest.cc (7221B)
1 /* 2 * Copyright (c) 2019 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 11 #include "modules/audio_processing/aec3/alignment_mixer.h" 12 13 #include <algorithm> 14 #include <array> 15 #include <cstddef> 16 #include <string> 17 18 #include "api/array_view.h" 19 #include "modules/audio_processing/aec3/aec3_common.h" 20 #include "modules/audio_processing/aec3/block.h" 21 #include "rtc_base/checks.h" 22 #include "rtc_base/strings/string_builder.h" 23 #include "test/gmock.h" 24 #include "test/gtest.h" 25 26 using ::testing::AllOf; 27 using ::testing::Each; 28 29 namespace webrtc { 30 namespace { 31 std::string ProduceDebugText(bool initial_silence, 32 bool huge_activity_threshold, 33 bool prefer_first_two_channels, 34 int num_channels, 35 int strongest_ch) { 36 StringBuilder ss; 37 ss << ", Initial silence: " << initial_silence; 38 ss << ", Huge activity threshold: " << huge_activity_threshold; 39 ss << ", Prefer first two channels: " << prefer_first_two_channels; 40 ss << ", Number of channels: " << num_channels; 41 ss << ", Strongest channel: " << strongest_ch; 42 return ss.Release(); 43 } 44 45 } // namespace 46 47 TEST(AlignmentMixer, GeneralAdaptiveMode) { 48 constexpr int kChannelOffset = 100; 49 constexpr int kMaxChannelsToTest = 8; 50 constexpr float kStrongestSignalScaling = 51 kMaxChannelsToTest * kChannelOffset * 100; 52 53 for (bool initial_silence : {false, true}) { 54 for (bool huge_activity_threshold : {false, true}) { 55 for (bool prefer_first_two_channels : {false, true}) { 56 for (int num_channels = 2; num_channels < 8; ++num_channels) { 57 for (int strongest_ch = 0; strongest_ch < num_channels; 58 ++strongest_ch) { 59 SCOPED_TRACE(ProduceDebugText( 60 initial_silence, huge_activity_threshold, 61 prefer_first_two_channels, num_channels, strongest_ch)); 62 const float excitation_limit = 63 huge_activity_threshold ? 1000000000.f : 0.001f; 64 AlignmentMixer am(num_channels, /*downmix*/ false, 65 /*adaptive_selection*/ true, excitation_limit, 66 prefer_first_two_channels); 67 68 Block x( 69 /*num_bands=*/1, num_channels); 70 if (initial_silence) { 71 std::array<float, kBlockSize> y; 72 for (int frame = 0; frame < 10 * kNumBlocksPerSecond; ++frame) { 73 am.ProduceOutput(x, y); 74 } 75 } 76 77 for (int frame = 0; frame < 2 * kNumBlocksPerSecond; ++frame) { 78 const auto channel_value = [&](int frame_index, 79 int channel_index) { 80 return static_cast<float>(frame_index + 81 channel_index * kChannelOffset); 82 }; 83 84 for (int ch = 0; ch < num_channels; ++ch) { 85 float scaling = 86 ch == strongest_ch ? kStrongestSignalScaling : 1.f; 87 auto x_ch = x.View(/*band=*/0, ch); 88 std::fill(x_ch.begin(), x_ch.end(), 89 channel_value(frame, ch) * scaling); 90 } 91 92 std::array<float, kBlockSize> y; 93 y.fill(-1.f); 94 am.ProduceOutput(x, y); 95 96 if (frame > 1 * kNumBlocksPerSecond) { 97 if (!prefer_first_two_channels || huge_activity_threshold) { 98 EXPECT_THAT(y, 99 AllOf(Each(x.View(/*band=*/0, strongest_ch)[0]))); 100 } else { 101 bool left_or_right_chosen; 102 for (int ch = 0; ch < 2; ++ch) { 103 left_or_right_chosen = true; 104 const auto x_ch = x.View(/*band=*/0, ch); 105 for (size_t k = 0; k < kBlockSize; ++k) { 106 if (y[k] != x_ch[k]) { 107 left_or_right_chosen = false; 108 break; 109 } 110 } 111 if (left_or_right_chosen) { 112 break; 113 } 114 } 115 EXPECT_TRUE(left_or_right_chosen); 116 } 117 } 118 } 119 } 120 } 121 } 122 } 123 } 124 } 125 126 TEST(AlignmentMixer, DownmixMode) { 127 for (int num_channels = 1; num_channels < 8; ++num_channels) { 128 AlignmentMixer am(num_channels, /*downmix*/ true, 129 /*adaptive_selection*/ false, /*excitation_limit*/ 1.f, 130 /*prefer_first_two_channels*/ false); 131 132 Block x(/*num_bands=*/1, num_channels); 133 const auto channel_value = [](int frame_index, int channel_index) { 134 return static_cast<float>(frame_index + channel_index); 135 }; 136 for (int frame = 0; frame < 10; ++frame) { 137 for (int ch = 0; ch < num_channels; ++ch) { 138 auto x_ch = x.View(/*band=*/0, ch); 139 std::fill(x_ch.begin(), x_ch.end(), channel_value(frame, ch)); 140 } 141 142 std::array<float, kBlockSize> y; 143 y.fill(-1.f); 144 am.ProduceOutput(x, y); 145 146 float expected_mixed_value = 0.f; 147 for (int ch = 0; ch < num_channels; ++ch) { 148 expected_mixed_value += channel_value(frame, ch); 149 } 150 expected_mixed_value *= 1.f / num_channels; 151 152 EXPECT_THAT(y, AllOf(Each(expected_mixed_value))); 153 } 154 } 155 } 156 157 TEST(AlignmentMixer, FixedMode) { 158 for (int num_channels = 1; num_channels < 8; ++num_channels) { 159 AlignmentMixer am(num_channels, /*downmix*/ false, 160 /*adaptive_selection*/ false, /*excitation_limit*/ 1.f, 161 /*prefer_first_two_channels*/ false); 162 163 Block x(/*num_bands=*/1, num_channels); 164 const auto channel_value = [](int frame_index, int channel_index) { 165 return static_cast<float>(frame_index + channel_index); 166 }; 167 for (int frame = 0; frame < 10; ++frame) { 168 for (int ch = 0; ch < num_channels; ++ch) { 169 auto x_ch = x.View(/*band=*/0, ch); 170 std::fill(x_ch.begin(), x_ch.end(), channel_value(frame, ch)); 171 } 172 173 std::array<float, kBlockSize> y; 174 y.fill(-1.f); 175 am.ProduceOutput(x, y); 176 EXPECT_THAT(y, AllOf(Each(x.View(/*band=*/0, /*channel=*/0)[0]))); 177 } 178 } 179 } 180 181 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) 182 183 TEST(AlignmentMixerDeathTest, ZeroNumChannels) { 184 EXPECT_DEATH( 185 AlignmentMixer(/*num_channels*/ 0, /*downmix*/ false, 186 /*adaptive_selection*/ false, /*excitation_limit*/ 1.f, 187 /*prefer_first_two_channels*/ false); 188 , ""); 189 } 190 191 TEST(AlignmentMixerDeathTest, IncorrectVariant) { 192 EXPECT_DEATH( 193 AlignmentMixer(/*num_channels*/ 1, /*downmix*/ true, 194 /*adaptive_selection*/ true, /*excitation_limit*/ 1.f, 195 /*prefer_first_two_channels*/ false); 196 , ""); 197 } 198 199 #endif 200 201 } // namespace webrtc