summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/audio/utility/channel_mixing_matrix_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/audio/utility/channel_mixing_matrix_unittest.cc')
-rw-r--r--third_party/libwebrtc/audio/utility/channel_mixing_matrix_unittest.cc476
1 files changed, 476 insertions, 0 deletions
diff --git a/third_party/libwebrtc/audio/utility/channel_mixing_matrix_unittest.cc b/third_party/libwebrtc/audio/utility/channel_mixing_matrix_unittest.cc
new file mode 100644
index 0000000000..a4efb4fd38
--- /dev/null
+++ b/third_party/libwebrtc/audio/utility/channel_mixing_matrix_unittest.cc
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2019 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 "audio/utility/channel_mixing_matrix.h"
+
+#include <stddef.h>
+
+#include "audio/utility/channel_mixer.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/strings/string_builder.h"
+#include "test/field_trial.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+// Test all possible layout conversions can be constructed and mixed.
+// Also ensure that the channel matrix fulfill certain conditions when remapping
+// is supported.
+TEST(ChannelMixingMatrixTest, ConstructAllPossibleLayouts) {
+ for (ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
+ input_layout <= CHANNEL_LAYOUT_MAX;
+ input_layout = static_cast<ChannelLayout>(input_layout + 1)) {
+ for (ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
+ output_layout <= CHANNEL_LAYOUT_MAX;
+ output_layout = static_cast<ChannelLayout>(output_layout + 1)) {
+ // DISCRETE, BITSTREAM can't be tested here based on the current approach.
+ // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC is not mixable.
+ // Stereo down mix should never be the output layout.
+ if (input_layout == CHANNEL_LAYOUT_BITSTREAM ||
+ input_layout == CHANNEL_LAYOUT_DISCRETE ||
+ input_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC ||
+ output_layout == CHANNEL_LAYOUT_BITSTREAM ||
+ output_layout == CHANNEL_LAYOUT_DISCRETE ||
+ output_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC ||
+ output_layout == CHANNEL_LAYOUT_STEREO_DOWNMIX) {
+ continue;
+ }
+
+ rtc::StringBuilder ss;
+ ss << "Input Layout: " << input_layout
+ << ", Output Layout: " << output_layout;
+ SCOPED_TRACE(ss.str());
+ ChannelMixingMatrix matrix_builder(
+ input_layout, ChannelLayoutToChannelCount(input_layout),
+ output_layout, ChannelLayoutToChannelCount(output_layout));
+ const int input_channels = ChannelLayoutToChannelCount(input_layout);
+ const int output_channels = ChannelLayoutToChannelCount(output_layout);
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+
+ if (remapping) {
+ // Also ensure that (when remapping can take place), a maximum of one
+ // input channel is included per output. This knowledge will simplify
+ // the channel mixing algorithm since it allows us to find the only
+ // scale factor which equals 1.0 and copy that input to its
+ // corresponding output. If no such factor can be found, the
+ // corresponding output can be set to zero.
+ for (int i = 0; i < output_channels; i++) {
+ EXPECT_EQ(static_cast<size_t>(input_channels), matrix[i].size());
+ int num_input_channels_accounted_for_per_output = 0;
+ for (int j = 0; j < input_channels; j++) {
+ float scale = matrix[i][j];
+ if (scale > 0) {
+ EXPECT_EQ(scale, 1.0f);
+ num_input_channels_accounted_for_per_output++;
+ }
+ }
+ // Each output channel shall contain contribution from one or less
+ // input channels.
+ EXPECT_LE(num_input_channels_accounted_for_per_output, 1);
+ }
+ }
+ }
+ }
+}
+
+// Verify channels are mixed and scaled correctly.
+TEST(ChannelMixingMatrixTest, StereoToMono) {
+ ChannelLayout input_layout = CHANNEL_LAYOUT_STEREO;
+ ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
+ ChannelMixingMatrix matrix_builder(
+ input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
+ ChannelLayoutToChannelCount(output_layout));
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+
+ // Input: stereo
+ // LEFT RIGHT
+ // Output: mono CENTER 0.5 0.5
+ //
+ EXPECT_FALSE(remapping);
+ EXPECT_EQ(1u, matrix.size());
+ EXPECT_EQ(2u, matrix[0].size());
+ EXPECT_EQ(0.5f, matrix[0][0]);
+ EXPECT_EQ(0.5f, matrix[0][1]);
+}
+
+TEST(ChannelMixingMatrixTest, MonoToStereo) {
+ ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
+ ChannelLayout output_layout = CHANNEL_LAYOUT_STEREO;
+ ChannelMixingMatrix matrix_builder(
+ input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
+ ChannelLayoutToChannelCount(output_layout));
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+
+ // Input: mono
+ // CENTER
+ // Output: stereo LEFT 1
+ // RIGHT 1
+ //
+ EXPECT_TRUE(remapping);
+ EXPECT_EQ(2u, matrix.size());
+ EXPECT_EQ(1u, matrix[0].size());
+ EXPECT_EQ(1.0f, matrix[0][0]);
+ EXPECT_EQ(1u, matrix[1].size());
+ EXPECT_EQ(1.0f, matrix[1][0]);
+}
+
+TEST(ChannelMixingMatrixTest, MonoToTwoOneWithoutVoIPAdjustments) {
+ test::ScopedFieldTrials field_trials(
+ "WebRTC-VoIPChannelRemixingAdjustmentKillSwitch/Enabled/");
+ ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
+ ChannelLayout output_layout = CHANNEL_LAYOUT_2_1;
+ ChannelMixingMatrix matrix_builder(
+ input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
+ ChannelLayoutToChannelCount(output_layout));
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+
+ // Input: mono
+ // CENTER
+ // Output: 2.1 FRONT_LEFT 1
+ // FRONT_RIGHT 1
+ // BACK_CENTER 0
+ //
+ EXPECT_FALSE(remapping);
+ EXPECT_EQ(3u, matrix.size());
+ EXPECT_EQ(1u, matrix[0].size());
+ EXPECT_EQ(1.0f, matrix[0][0]);
+ EXPECT_EQ(1.0f, matrix[1][0]);
+ EXPECT_EQ(0.0f, matrix[2][0]);
+}
+
+TEST(ChannelMixingMatrixTest, MonoToTwoOneWithVoIPAdjustments) {
+ ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
+ ChannelLayout output_layout = CHANNEL_LAYOUT_2_1;
+ ChannelMixingMatrix matrix_builder(
+ input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
+ ChannelLayoutToChannelCount(output_layout));
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+
+ // Input: mono
+ // CENTER
+ // Output: 2.1 FRONT_LEFT 1
+ // FRONT_RIGHT 1
+ // BACK_CENTER 0
+ //
+ EXPECT_TRUE(remapping);
+ EXPECT_EQ(3u, matrix.size());
+ EXPECT_EQ(1u, matrix[0].size());
+ EXPECT_EQ(1.0f, matrix[0][0]);
+ EXPECT_EQ(1.0f, matrix[1][0]);
+ EXPECT_EQ(0.0f, matrix[2][0]);
+}
+
+TEST(ChannelMixingMatrixTest, MonoToFiveOneWithoutVoIPAdjustments) {
+ test::ScopedFieldTrials field_trials(
+ "WebRTC-VoIPChannelRemixingAdjustmentKillSwitch/Enabled/");
+ ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
+ ChannelLayout output_layout = CHANNEL_LAYOUT_5_1;
+ const int input_channels = ChannelLayoutToChannelCount(input_layout);
+ const int output_channels = ChannelLayoutToChannelCount(output_layout);
+ ChannelMixingMatrix matrix_builder(input_layout, input_channels,
+ output_layout, output_channels);
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+ // Input: mono
+ // CENTER
+ // Output: 5.1 LEFT 0
+ // RIGHT 0
+ // CENTER 1
+ // LFE 0
+ // SIDE_LEFT 0
+ // SIDE_RIGHT 0
+ //
+ EXPECT_TRUE(remapping);
+ EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
+ for (int n = 0; n < output_channels; n++) {
+ EXPECT_EQ(static_cast<size_t>(input_channels), matrix[n].size());
+ if (n == CENTER) {
+ EXPECT_EQ(1.0f, matrix[CENTER][0]);
+ } else {
+ EXPECT_EQ(0.0f, matrix[n][0]);
+ }
+ }
+}
+
+TEST(ChannelMixingMatrixTest, MonoToFiveOneWithVoIPAdjustments) {
+ ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
+ ChannelLayout output_layout = CHANNEL_LAYOUT_5_1;
+ const int input_channels = ChannelLayoutToChannelCount(input_layout);
+ const int output_channels = ChannelLayoutToChannelCount(output_layout);
+ ChannelMixingMatrix matrix_builder(input_layout, input_channels,
+ output_layout, output_channels);
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+ // Input: mono
+ // CENTER
+ // Output: 5.1 LEFT 1
+ // RIGHT 1
+ // CENTER 0
+ // LFE 0
+ // SIDE_LEFT 0
+ // SIDE_RIGHT 0
+ //
+ EXPECT_TRUE(remapping);
+ EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
+ for (int n = 0; n < output_channels; n++) {
+ EXPECT_EQ(static_cast<size_t>(input_channels), matrix[n].size());
+ if (n == LEFT || n == RIGHT) {
+ EXPECT_EQ(1.0f, matrix[n][0]);
+ } else {
+ EXPECT_EQ(0.0f, matrix[n][0]);
+ }
+ }
+}
+
+TEST(ChannelMixingMatrixTest, MonoToSevenOneWithoutVoIPAdjustments) {
+ test::ScopedFieldTrials field_trials(
+ "WebRTC-VoIPChannelRemixingAdjustmentKillSwitch/Enabled/");
+ ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
+ ChannelLayout output_layout = CHANNEL_LAYOUT_7_1;
+ const int input_channels = ChannelLayoutToChannelCount(input_layout);
+ const int output_channels = ChannelLayoutToChannelCount(output_layout);
+ ChannelMixingMatrix matrix_builder(input_layout, input_channels,
+ output_layout, output_channels);
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+ // Input: mono
+ // CENTER
+ // Output: 7.1 LEFT 0
+ // RIGHT 0
+ // CENTER 1
+ // LFE 0
+ // SIDE_LEFT 0
+ // SIDE_RIGHT 0
+ // BACK_LEFT 0
+ // BACK_RIGHT 0
+ //
+ EXPECT_TRUE(remapping);
+ EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
+ for (int n = 0; n < output_channels; n++) {
+ EXPECT_EQ(static_cast<size_t>(input_channels), matrix[n].size());
+ if (n == CENTER) {
+ EXPECT_EQ(1.0f, matrix[CENTER][0]);
+ } else {
+ EXPECT_EQ(0.0f, matrix[n][0]);
+ }
+ }
+}
+
+TEST(ChannelMixingMatrixTest, MonoToSevenOneWithVoIPAdjustments) {
+ ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
+ ChannelLayout output_layout = CHANNEL_LAYOUT_7_1;
+ const int input_channels = ChannelLayoutToChannelCount(input_layout);
+ const int output_channels = ChannelLayoutToChannelCount(output_layout);
+ ChannelMixingMatrix matrix_builder(input_layout, input_channels,
+ output_layout, output_channels);
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+ // Input: mono
+ // CENTER
+ // Output: 7.1 LEFT 1
+ // RIGHT 1
+ // CENTER 0
+ // LFE 0
+ // SIDE_LEFT 0
+ // SIDE_RIGHT 0
+ // BACK_LEFT 0
+ // BACK_RIGHT 0
+ //
+ EXPECT_TRUE(remapping);
+ EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
+ for (int n = 0; n < output_channels; n++) {
+ EXPECT_EQ(static_cast<size_t>(input_channels), matrix[n].size());
+ if (n == LEFT || n == RIGHT) {
+ EXPECT_EQ(1.0f, matrix[n][0]);
+ } else {
+ EXPECT_EQ(0.0f, matrix[n][0]);
+ }
+ }
+}
+
+TEST(ChannelMixingMatrixTest, FiveOneToMono) {
+ ChannelLayout input_layout = CHANNEL_LAYOUT_5_1;
+ ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
+ ChannelMixingMatrix matrix_builder(
+ input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
+ ChannelLayoutToChannelCount(output_layout));
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+
+ // Note: 1/sqrt(2) is shown as 0.707.
+ //
+ // Input: 5.1
+ // LEFT RIGHT CENTER LFE SIDE_LEFT SIDE_RIGHT
+ // Output: mono CENTER 0.707 0.707 1 0.707 0.707 0.707
+ //
+ EXPECT_FALSE(remapping);
+ EXPECT_EQ(1u, matrix.size());
+ EXPECT_EQ(6u, matrix[0].size());
+ EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][0]);
+ EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][1]);
+ // The center channel will be mixed at scale 1.
+ EXPECT_EQ(1.0f, matrix[0][2]);
+ EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][3]);
+ EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][4]);
+ EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][5]);
+}
+
+TEST(ChannelMixingMatrixTest, FiveOneBackToStereo) {
+ // Front L, Front R, Front C, LFE, Back L, Back R
+ ChannelLayout input_layout = CHANNEL_LAYOUT_5_1_BACK;
+ ChannelLayout output_layout = CHANNEL_LAYOUT_STEREO;
+ const int input_channels = ChannelLayoutToChannelCount(input_layout);
+ const int output_channels = ChannelLayoutToChannelCount(output_layout);
+ ChannelMixingMatrix matrix_builder(input_layout, input_channels,
+ output_layout, output_channels);
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+
+ // Note: 1/sqrt(2) is shown as 0.707.
+ // Note: The Channels enumerator is given by {LEFT = 0, RIGHT, CENTER, LFE,
+ // BACK_LEFT, BACK_RIGHT,...}, hence we can use the enumerator values as
+ // indexes in the matrix when verifying the scaling factors.
+ //
+ // Input: 5.1
+ // LEFT RIGHT CENTER LFE BACK_LEFT BACK_RIGHT
+ // Output: stereo LEFT 1 0 0.707 0.707 0.707 0
+ // RIGHT 0 1 0.707 0.707 0 0.707
+ //
+ EXPECT_FALSE(remapping);
+ EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
+ EXPECT_EQ(static_cast<size_t>(input_channels), matrix[LEFT].size());
+ EXPECT_EQ(static_cast<size_t>(input_channels), matrix[RIGHT].size());
+ EXPECT_EQ(1.0f, matrix[LEFT][LEFT]);
+ EXPECT_EQ(1.0f, matrix[RIGHT][RIGHT]);
+ EXPECT_EQ(0.0f, matrix[LEFT][RIGHT]);
+ EXPECT_EQ(0.0f, matrix[RIGHT][LEFT]);
+ EXPECT_EQ(0.0f, matrix[LEFT][BACK_RIGHT]);
+ EXPECT_EQ(0.0f, matrix[RIGHT][BACK_LEFT]);
+ EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[LEFT][CENTER]);
+ EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[LEFT][LFE]);
+ EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[LEFT][BACK_LEFT]);
+ EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[RIGHT][CENTER]);
+ EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[RIGHT][LFE]);
+ EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[RIGHT][BACK_RIGHT]);
+}
+
+TEST(ChannelMixingMatrixTest, FiveOneToSevenOne) {
+ // Front L, Front R, Front C, LFE, Side L, Side R
+ ChannelLayout input_layout = CHANNEL_LAYOUT_5_1;
+ // Front L, Front R, Front C, LFE, Side L, Side R, Back L, Back R
+ ChannelLayout output_layout = CHANNEL_LAYOUT_7_1;
+ const int input_channels = ChannelLayoutToChannelCount(input_layout);
+ const int output_channels = ChannelLayoutToChannelCount(output_layout);
+ ChannelMixingMatrix matrix_builder(input_layout, input_channels,
+ output_layout, output_channels);
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+
+ // Input: 5.1
+ // LEFT RIGHT CENTER LFE SIDE_LEFT SIDE_RIGHT
+ // Output: 7.1 LEFT 1 0 0 0 0 0
+ // RIGHT 0 1 0 0 0 0
+ // CENTER 0 0 1 0 0 0
+ // LFE 0 0 0 1 0 0
+ // SIDE_LEFT 0 0 0 0 1 0
+ // SIDE_RIGHT 0 0 0 0 0 1
+ // BACK_LEFT 0 0 0 0 0 0
+ // BACK_RIGHT 0 0 0 0 0 0
+ //
+ EXPECT_TRUE(remapping);
+ EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
+ for (int i = 0; i < output_channels; i++) {
+ EXPECT_EQ(static_cast<size_t>(input_channels), matrix[i].size());
+ for (int j = 0; j < input_channels; j++) {
+ if (i == j) {
+ EXPECT_EQ(1.0f, matrix[i][j]);
+ } else {
+ EXPECT_EQ(0.0f, matrix[i][j]);
+ }
+ }
+ }
+}
+
+TEST(ChannelMixingMatrixTest, StereoToFiveOne) {
+ ChannelLayout input_layout = CHANNEL_LAYOUT_STEREO;
+ ChannelLayout output_layout = CHANNEL_LAYOUT_5_1;
+ const int input_channels = ChannelLayoutToChannelCount(input_layout);
+ const int output_channels = ChannelLayoutToChannelCount(output_layout);
+ ChannelMixingMatrix matrix_builder(input_layout, input_channels,
+ output_layout, output_channels);
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+
+ // Input: Stereo
+ // LEFT RIGHT
+ // Output: 5.1 LEFT 1 0
+ // RIGHT 0 1
+ // CENTER 0 0
+ // LFE 0 0
+ // SIDE_LEFT 0 0
+ // SIDE_RIGHT 0 0
+ //
+ EXPECT_TRUE(remapping);
+ EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
+ for (int n = 0; n < output_channels; n++) {
+ EXPECT_EQ(static_cast<size_t>(input_channels), matrix[n].size());
+ if (n == LEFT) {
+ EXPECT_EQ(1.0f, matrix[LEFT][LEFT]);
+ EXPECT_EQ(0.0f, matrix[LEFT][RIGHT]);
+ } else if (n == RIGHT) {
+ EXPECT_EQ(0.0f, matrix[RIGHT][LEFT]);
+ EXPECT_EQ(1.0f, matrix[RIGHT][RIGHT]);
+ } else {
+ EXPECT_EQ(0.0f, matrix[n][LEFT]);
+ EXPECT_EQ(0.0f, matrix[n][RIGHT]);
+ }
+ }
+}
+
+TEST(ChannelMixingMatrixTest, DiscreteToDiscrete) {
+ const struct {
+ int input_channels;
+ int output_channels;
+ } test_case[] = {
+ {2, 2},
+ {2, 5},
+ {5, 2},
+ };
+
+ for (size_t n = 0; n < arraysize(test_case); n++) {
+ int input_channels = test_case[n].input_channels;
+ int output_channels = test_case[n].output_channels;
+ ChannelMixingMatrix matrix_builder(CHANNEL_LAYOUT_DISCRETE, input_channels,
+ CHANNEL_LAYOUT_DISCRETE,
+ output_channels);
+ std::vector<std::vector<float>> matrix;
+ bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
+ EXPECT_TRUE(remapping);
+ EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
+ for (int i = 0; i < output_channels; i++) {
+ EXPECT_EQ(static_cast<size_t>(input_channels), matrix[i].size());
+ for (int j = 0; j < input_channels; j++) {
+ if (i == j) {
+ EXPECT_EQ(1.0f, matrix[i][j]);
+ } else {
+ EXPECT_EQ(0.0f, matrix[i][j]);
+ }
+ }
+ }
+ }
+}
+
+} // namespace webrtc