diff --git a/audio/utility/BUILD.gn b/audio/utility/BUILD.gn index 721b4501cf..f06a6b3e7b 100644 --- a/audio/utility/BUILD.gn +++ b/audio/utility/BUILD.gn @@ -30,6 +30,7 @@ rtc_library("audio_frame_operations") { "../../rtc_base:checks", "../../rtc_base:deprecation", "../../rtc_base:rtc_base_approved", + "../../system_wrappers:field_trial", ] } @@ -46,6 +47,7 @@ if (rtc_include_tests) { "../../api/audio:audio_frame_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../test:field_trial", "../../test:test_support", "//testing/gtest", ] diff --git a/audio/utility/channel_mixing_matrix.cc b/audio/utility/channel_mixing_matrix.cc index c617844b18..4baff8bfba 100644 --- a/audio/utility/channel_mixing_matrix.cc +++ b/audio/utility/channel_mixing_matrix.cc @@ -17,9 +17,20 @@ #include "audio/utility/channel_mixer.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" +#include "system_wrappers/include/field_trial.h" namespace webrtc { +namespace { + +// Selects the default usage of VoIP channel mapping adjustments. +bool UseChannelMappingAdjustmentsByDefault() { + return !field_trial::IsEnabled( + "WebRTC-VoIPChannelRemixingAdjustmentKillSwitch"); +} + +} // namespace + static void ValidateLayout(ChannelLayout layout) { RTC_CHECK_NE(layout, CHANNEL_LAYOUT_NONE); RTC_CHECK_LE(layout, CHANNEL_LAYOUT_MAX); @@ -55,7 +66,9 @@ ChannelMixingMatrix::ChannelMixingMatrix(ChannelLayout input_layout, int input_channels, ChannelLayout output_layout, int output_channels) - : input_layout_(input_layout), + : use_voip_channel_mapping_adjustments_( + UseChannelMappingAdjustmentsByDefault()), + input_layout_(input_layout), input_channels_(input_channels), output_layout_(output_layout), output_channels_(output_channels) { @@ -104,6 +117,20 @@ bool ChannelMixingMatrix::CreateTransformationMatrix( return true; } + // If specified, use adjusted channel mapping for the VoIP scenario. + if (use_voip_channel_mapping_adjustments_ && + input_layout_ == CHANNEL_LAYOUT_MONO && + ChannelLayoutToChannelCount(output_layout_) >= 2) { + // Only place the mono input in the front left and right channels. + (*matrix_)[0][0] = 1.f; + (*matrix_)[1][0] = 1.f; + + for (size_t output_ch = 2; output_ch < matrix_->size(); ++output_ch) { + (*matrix_)[output_ch][0] = 0.f; + } + return true; + } + // Route matching channels and figure out which ones aren't accounted for. for (Channels ch = LEFT; ch < CHANNELS_MAX + 1; ch = static_cast(ch + 1)) { diff --git a/audio/utility/channel_mixing_matrix.h b/audio/utility/channel_mixing_matrix.h index e9cbb245b5..7aef47b3b2 100644 --- a/audio/utility/channel_mixing_matrix.h +++ b/audio/utility/channel_mixing_matrix.h @@ -36,6 +36,8 @@ class ChannelMixingMatrix { bool CreateTransformationMatrix(std::vector>* matrix); private: + const bool use_voip_channel_mapping_adjustments_; + // Result transformation of input channels to output channels std::vector>* matrix_; diff --git a/audio/utility/channel_mixing_matrix_unittest.cc b/audio/utility/channel_mixing_matrix_unittest.cc index 4c4f8ac10c..a4efb4fd38 100644 --- a/audio/utility/channel_mixing_matrix_unittest.cc +++ b/audio/utility/channel_mixing_matrix_unittest.cc @@ -16,6 +16,7 @@ #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 { @@ -124,7 +125,9 @@ TEST(ChannelMixingMatrixTest, MonoToStereo) { EXPECT_EQ(1.0f, matrix[1][0]); } -TEST(ChannelMixingMatrixTest, MonoToTwoOne) { +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( @@ -147,6 +150,157 @@ TEST(ChannelMixingMatrixTest, MonoToTwoOne) { 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> 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> 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(output_channels), matrix.size()); + for (int n = 0; n < output_channels; n++) { + EXPECT_EQ(static_cast(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> 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(output_channels), matrix.size()); + for (int n = 0; n < output_channels; n++) { + EXPECT_EQ(static_cast(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> 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(output_channels), matrix.size()); + for (int n = 0; n < output_channels; n++) { + EXPECT_EQ(static_cast(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> 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(output_channels), matrix.size()); + for (int n = 0; n < output_channels; n++) { + EXPECT_EQ(static_cast(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;