Make AudioFrame::channel_layout_ private and check for valid values

Bug: chromium:335805780
Change-Id: Ida671d317c07983cc51faa1a498642747dbb810c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/349322
Reviewed-by: Per Ã…hgren <peah@webrtc.org>
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42199}
diff --git a/api/audio/audio_frame.cc b/api/audio/audio_frame.cc
index 3e12006..4ddaaf6 100644
--- a/api/audio/audio_frame.cc
+++ b/api/audio/audio_frame.cc
@@ -131,6 +131,21 @@
   return muted_;
 }
 
+void AudioFrame::SetLayoutAndNumChannels(ChannelLayout layout,
+                                         size_t num_channels) {
+  channel_layout_ = layout;
+  num_channels_ = num_channels;
+#if RTC_DCHECK_IS_ON
+  // Do a sanity check that the layout and num_channels match.
+  // If this lookup yield 0u, then the layout is likely CHANNEL_LAYOUT_DISCRETE.
+  auto expected_num_channels = ChannelLayoutToChannelCount(layout);
+  if (expected_num_channels) {  // If expected_num_channels is 0
+    RTC_DCHECK_EQ(expected_num_channels, num_channels_);
+  }
+#endif
+  RTC_CHECK_LE(samples_per_channel_ * num_channels_, kMaxDataSizeSamples);
+}
+
 // static
 const int16_t* AudioFrame::empty_data() {
   static int16_t* null_data = new int16_t[kMaxDataSizeSamples]();
diff --git a/api/audio/audio_frame.h b/api/audio/audio_frame.h
index d5dcb5f..81d1255 100644
--- a/api/audio/audio_frame.h
+++ b/api/audio/audio_frame.h
@@ -103,7 +103,11 @@
   size_t max_16bit_samples() const { return kMaxDataSizeSamples; }
   size_t samples_per_channel() const { return samples_per_channel_; }
   size_t num_channels() const { return num_channels_; }
+
   ChannelLayout channel_layout() const { return channel_layout_; }
+  // Sets the `channel_layout` property as well as `num_channels`.
+  void SetLayoutAndNumChannels(ChannelLayout layout, size_t num_channels);
+
   int sample_rate_hz() const { return sample_rate_hz_; }
 
   void set_absolute_capture_timestamp_ms(
@@ -126,7 +130,6 @@
   size_t samples_per_channel_ = 0;
   int sample_rate_hz_ = 0;
   size_t num_channels_ = 0;
-  ChannelLayout channel_layout_ = CHANNEL_LAYOUT_NONE;
   SpeechType speech_type_ = kUndefined;
   VADActivity vad_activity_ = kVadUnknown;
   // Monotonically increasing timestamp intended for profiling of audio frames.
@@ -160,6 +163,7 @@
 
   int16_t data_[kMaxDataSizeSamples];
   bool muted_ = true;
+  ChannelLayout channel_layout_ = CHANNEL_LAYOUT_NONE;
 
   // Absolute capture timestamp when this audio frame was originally captured.
   // This is only valid for audio frames captured on this machine. The absolute
diff --git a/audio/utility/channel_mixer.cc b/audio/utility/channel_mixer.cc
index 0f1e663..98b484f 100644
--- a/audio/utility/channel_mixer.cc
+++ b/audio/utility/channel_mixer.cc
@@ -18,17 +18,26 @@
 namespace webrtc {
 
 ChannelMixer::ChannelMixer(ChannelLayout input_layout,
-                           ChannelLayout output_layout)
+                           size_t input_channels,
+                           ChannelLayout output_layout,
+                           size_t output_channels)
     : input_layout_(input_layout),
       output_layout_(output_layout),
-      input_channels_(ChannelLayoutToChannelCount(input_layout)),
-      output_channels_(ChannelLayoutToChannelCount(output_layout)) {
+      input_channels_(input_channels),
+      output_channels_(output_channels) {
   // Create the transformation matrix.
   ChannelMixingMatrix matrix_builder(input_layout_, input_channels_,
                                      output_layout_, output_channels_);
   remapping_ = matrix_builder.CreateTransformationMatrix(&matrix_);
 }
 
+ChannelMixer::ChannelMixer(ChannelLayout input_layout,
+                           ChannelLayout output_layout)
+    : ChannelMixer(input_layout,
+                   ChannelLayoutToChannelCount(input_layout),
+                   output_layout,
+                   ChannelLayoutToChannelCount(output_layout)) {}
+
 ChannelMixer::~ChannelMixer() = default;
 
 void ChannelMixer::Transform(AudioFrame* frame) {
@@ -49,8 +58,7 @@
 
   // Only change the number of output channels if the audio frame is muted.
   if (frame->muted()) {
-    frame->num_channels_ = output_channels_;
-    frame->channel_layout_ = output_layout_;
+    frame->SetLayoutAndNumChannels(output_layout_, output_channels_);
     return;
   }
 
@@ -87,8 +95,7 @@
   }
 
   // Update channel information.
-  frame->num_channels_ = output_channels_;
-  frame->channel_layout_ = output_layout_;
+  frame->SetLayoutAndNumChannels(output_layout_, output_channels_);
 
   // Copy the output result to the audio frame in `frame`.
   memcpy(
diff --git a/audio/utility/channel_mixer.h b/audio/utility/channel_mixer.h
index 2dea8eb..d8a0d3a 100644
--- a/audio/utility/channel_mixer.h
+++ b/audio/utility/channel_mixer.h
@@ -35,6 +35,10 @@
   // (1 / sqrt(2)) gain to each.
   static constexpr float kHalfPower = 0.707106781186547524401f;
 
+  ChannelMixer(ChannelLayout input_layout,
+               size_t input_channels,
+               ChannelLayout output_layout,
+               size_t output_channels);
   ChannelMixer(ChannelLayout input_layout, ChannelLayout output_layout);
   ~ChannelMixer();
 
diff --git a/audio/utility/channel_mixing_matrix.cc b/audio/utility/channel_mixing_matrix.cc
index 1244653..fa2c5de 100644
--- a/audio/utility/channel_mixing_matrix.cc
+++ b/audio/utility/channel_mixing_matrix.cc
@@ -29,6 +29,21 @@
       "WebRTC-VoIPChannelRemixingAdjustmentKillSwitch");
 }
 
+ChannelLayout CheckInputLayout(ChannelLayout input_layout,
+                               ChannelLayout output_layout) {
+  // Special case for 5.0, 5.1 with back channels when upmixed to 7.0, 7.1,
+  // which should map the back LR to side LR.
+  if (input_layout == CHANNEL_LAYOUT_5_0_BACK &&
+      output_layout == CHANNEL_LAYOUT_7_0) {
+    return CHANNEL_LAYOUT_5_0;
+  } else if (input_layout == CHANNEL_LAYOUT_5_1_BACK &&
+             output_layout == CHANNEL_LAYOUT_7_1) {
+    return CHANNEL_LAYOUT_5_1;
+  }
+
+  return input_layout;
+}
+
 }  // namespace
 
 static void ValidateLayout(ChannelLayout layout) {
@@ -68,7 +83,7 @@
                                          int output_channels)
     : use_voip_channel_mapping_adjustments_(
           UseChannelMappingAdjustmentsByDefault()),
-      input_layout_(input_layout),
+      input_layout_(CheckInputLayout(input_layout, output_layout)),
       input_channels_(input_channels),
       output_layout_(output_layout),
       output_channels_(output_channels) {
@@ -80,16 +95,6 @@
     ValidateLayout(input_layout);
   if (output_layout != CHANNEL_LAYOUT_DISCRETE)
     ValidateLayout(output_layout);
-
-  // Special case for 5.0, 5.1 with back channels when upmixed to 7.0, 7.1,
-  // which should map the back LR to side LR.
-  if (input_layout_ == CHANNEL_LAYOUT_5_0_BACK &&
-      output_layout_ == CHANNEL_LAYOUT_7_0) {
-    input_layout_ = CHANNEL_LAYOUT_5_0;
-  } else if (input_layout_ == CHANNEL_LAYOUT_5_1_BACK &&
-             output_layout_ == CHANNEL_LAYOUT_7_1) {
-    input_layout_ = CHANNEL_LAYOUT_5_1;
-  }
 }
 
 ChannelMixingMatrix::~ChannelMixingMatrix() = default;
diff --git a/audio/utility/channel_mixing_matrix.h b/audio/utility/channel_mixing_matrix.h
index ee00860..58d7c70 100644
--- a/audio/utility/channel_mixing_matrix.h
+++ b/audio/utility/channel_mixing_matrix.h
@@ -42,10 +42,10 @@
   std::vector<std::vector<float>>* matrix_;
 
   // Input and output channel layout provided during construction.
-  ChannelLayout input_layout_;
-  int input_channels_;
-  ChannelLayout output_layout_;
-  int output_channels_;
+  const ChannelLayout input_layout_;
+  const int input_channels_;
+  const ChannelLayout output_layout_;
+  const int output_channels_;
 
   // Helper variable for tracking which inputs are currently unaccounted,
   // should be empty after construction completes.
diff --git a/modules/audio_mixer/audio_frame_manipulator.cc b/modules/audio_mixer/audio_frame_manipulator.cc
index 3100271..94f03b2 100644
--- a/modules/audio_mixer/audio_frame_manipulator.cc
+++ b/modules/audio_mixer/audio_frame_manipulator.cc
@@ -79,8 +79,9 @@
     // instead of guessing based on number of channels.
     const ChannelLayout output_layout(
         GuessChannelLayout(target_number_of_channels));
-    ChannelMixer mixer(GuessChannelLayout(frame->num_channels()),
-                       output_layout);
+    const ChannelLayout input_layout(GuessChannelLayout(frame->num_channels()));
+    ChannelMixer mixer(input_layout, frame->num_channels(), output_layout,
+                       target_number_of_channels);
     mixer.Transform(frame);
     RTC_DCHECK_EQ(frame->channel_layout(), output_layout);
   }