Generalize the C-language Opus interface.

Switch to explicit channel mappings (RFC 7845) when creating
multi-stream Opus en/de-coders. The responsibility of setting up the
channel mappings will shift from WebRTC to the WebRTC user.

See https://webrtc-review.googlesource.com/c/src/+/121764 for the
current vision. See also the first child CL
https://webrtc-review.googlesource.com/c/src/+/129768
that sets up the Decoder to use this code.

Bug: webrtc:8649
Change-Id: I55959a293d54bb4c982eff68ec107c5ef8666c5c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/129767
Commit-Queue: Alex Loiko <aleloi@webrtc.org>
Reviewed-by: Oskar Sundbom <ossu@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27452}
diff --git a/modules/audio_coding/codecs/opus/opus_unittest.cc b/modules/audio_coding/codecs/opus/opus_unittest.cc
index 56dfd6a..aa7eee9 100644
--- a/modules/audio_coding/codecs/opus/opus_unittest.cc
+++ b/modules/audio_coding/codecs/opus/opus_unittest.cc
@@ -21,6 +21,64 @@
 
 namespace webrtc {
 
+namespace {
+// Equivalent to SDP params
+// {{"channel_mapping", "0,1,2,3"}, {"coupled_streams", "2"}}.
+constexpr unsigned char kQuadChannelMapping[] = {0, 1, 2, 3};
+constexpr int kQuadCoupledStreams = 2;
+
+constexpr unsigned char kStereoChannelMapping[] = {0, 1};
+constexpr int kStereoCoupledStreams = 1;
+
+constexpr unsigned char kMonoChannelMapping[] = {0};
+constexpr int kMonoCoupledStreams = 0;
+
+void CreateSingleOrMultiStreamEncoder(WebRtcOpusEncInst** opus_encoder,
+                                      int channels,
+                                      int application,
+                                      bool force_multistream = false) {
+  if (!force_multistream && (channels == 1 || channels == 2)) {
+    EXPECT_EQ(0, WebRtcOpus_EncoderCreate(opus_encoder, channels, application));
+  } else if (force_multistream && channels == 1) {
+    EXPECT_EQ(0, WebRtcOpus_MultistreamEncoderCreate(
+                     opus_encoder, channels, application, kMonoCoupledStreams,
+                     kMonoChannelMapping));
+  } else if (force_multistream && channels == 2) {
+    EXPECT_EQ(0, WebRtcOpus_MultistreamEncoderCreate(
+                     opus_encoder, channels, application, kStereoCoupledStreams,
+                     kStereoChannelMapping));
+  } else if (channels == 4) {
+    EXPECT_EQ(0, WebRtcOpus_MultistreamEncoderCreate(
+                     opus_encoder, channels, application, kQuadCoupledStreams,
+                     kQuadChannelMapping));
+  } else {
+    EXPECT_TRUE(false) << channels;
+  }
+}
+
+void CreateSingleOrMultiStreamDecoder(WebRtcOpusDecInst** opus_decoder,
+                                      int channels,
+                                      bool force_multistream = false) {
+  if (!force_multistream && (channels == 1 || channels == 2)) {
+    EXPECT_EQ(0, WebRtcOpus_DecoderCreate(opus_decoder, channels));
+  } else if (channels == 1) {
+    EXPECT_EQ(0, WebRtcOpus_MultistreamDecoderCreate(opus_decoder, channels,
+                                                     kMonoCoupledStreams,
+                                                     kMonoChannelMapping));
+  } else if (channels == 2) {
+    EXPECT_EQ(0, WebRtcOpus_MultistreamDecoderCreate(opus_decoder, channels,
+                                                     kStereoCoupledStreams,
+                                                     kStereoChannelMapping));
+  } else if (channels == 4) {
+    EXPECT_EQ(0, WebRtcOpus_MultistreamDecoderCreate(opus_decoder, channels,
+                                                     kQuadCoupledStreams,
+                                                     kQuadChannelMapping));
+  } else {
+    EXPECT_TRUE(false) << channels;
+  }
+}
+}  // namespace
+
 using test::AudioLoop;
 using ::testing::TestWithParam;
 using ::testing::Values;
@@ -35,7 +93,7 @@
 // Number of samples-per-channel in a 10 ms frame, sampled at 48 kHz.
 const size_t kOpus10msFrameSamples = kOpusRateKhz * 10;
 
-class OpusTest : public TestWithParam<::testing::tuple<int, int>> {
+class OpusTest : public TestWithParam<::testing::tuple<int, int, bool>> {
  protected:
   OpusTest();
 
@@ -74,6 +132,7 @@
   size_t encoded_bytes_;
   size_t channels_;
   int application_;
+  bool force_multistream_;
 };
 
 OpusTest::OpusTest()
@@ -81,7 +140,8 @@
       opus_decoder_(NULL),
       encoded_bytes_(0),
       channels_(static_cast<size_t>(::testing::get<0>(GetParam()))),
-      application_(::testing::get<1>(GetParam())) {}
+      application_(::testing::get<1>(GetParam())),
+      force_multistream_(::testing::get<2>(GetParam())) {}
 
 void OpusTest::PrepareSpeechData(size_t channel,
                                  int block_length_ms,
@@ -148,9 +208,10 @@
   const size_t samples = kOpusRateKhz * block_length_ms;
 
   // Create encoder memory.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
-  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
+                                   force_multistream_);
 
   // Set bitrate.
   EXPECT_EQ(
@@ -313,9 +374,10 @@
   int32_t prev_pkt_size = 0;
 
   // Create encoder memory.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
-  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
+                                   force_multistream_);
 
   // Set bitrate.
   EXPECT_EQ(
@@ -376,9 +438,10 @@
 
 // Test normal Create and Free.
 TEST_P(OpusTest, OpusCreateFree) {
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
-  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
+                                   force_multistream_);
   EXPECT_TRUE(opus_encoder_ != NULL);
   EXPECT_TRUE(opus_decoder_ != NULL);
   // Free encoder and decoder memory.
@@ -386,18 +449,19 @@
   EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
 }
 
-#define ENCODER_CTL(inst, vargs)                       \
-  inst->channels <= 2                                  \
-      ? opus_encoder_ctl(inst->encoder.encoder, vargs) \
-      : opus_multistream_encoder_ctl(inst->encoder.multistream_encoder, vargs)
+#define ENCODER_CTL(inst, vargs)               \
+  inst->encoder                                \
+      ? opus_encoder_ctl(inst->encoder, vargs) \
+      : opus_multistream_encoder_ctl(inst->multistream_encoder, vargs)
 
 TEST_P(OpusTest, OpusEncodeDecode) {
   PrepareSpeechData(channels_, 20, 20);
 
   // Create encoder memory.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
-  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
+                                   force_multistream_);
 
   // Set bitrate.
   EXPECT_EQ(
@@ -431,8 +495,8 @@
   EXPECT_EQ(-1, WebRtcOpus_SetBitRate(opus_encoder_, 60000));
 
   // Create encoder memory, try with different bitrates.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 30000));
   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 60000));
   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 300000));
@@ -447,8 +511,8 @@
   EXPECT_EQ(-1, WebRtcOpus_SetComplexity(opus_encoder_, 9));
 
   // Create encoder memory, try with different complexities.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
 
   EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, 0));
   EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, 10));
@@ -476,9 +540,10 @@
   EXPECT_EQ(-1, WebRtcOpus_GetBandwidth(opus_encoder_));
 
   // Create encoder memory, try with different bandwidths.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
-  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
+                                   force_multistream_);
 
   EXPECT_EQ(-1, WebRtcOpus_SetBandwidth(opus_encoder_,
                                         OPUS_BANDWIDTH_NARROWBAND - 1));
@@ -506,8 +571,9 @@
   // Test without creating encoder memory.
   EXPECT_EQ(-1, WebRtcOpus_SetForceChannels(opus_encoder_, 1));
 
-  ASSERT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
+  ASSERT_NE(nullptr, opus_encoder_);
 
   if (channels_ >= 2) {
     EXPECT_EQ(-1, WebRtcOpus_SetForceChannels(opus_encoder_, 3));
@@ -529,9 +595,10 @@
   PrepareSpeechData(channels_, 20, 20);
 
   // Create encoder memory.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
-  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
+                                   force_multistream_);
 
   // Encode & decode.
   int16_t audio_type;
@@ -560,8 +627,8 @@
   EXPECT_EQ(-1, WebRtcOpus_DisableFec(opus_encoder_));
 
   // Create encoder memory.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
 
   EXPECT_EQ(0, WebRtcOpus_EnableFec(opus_encoder_));
   EXPECT_EQ(0, WebRtcOpus_DisableFec(opus_encoder_));
@@ -576,8 +643,8 @@
   EXPECT_EQ(-1, WebRtcOpus_DisableDtx(opus_encoder_));
 
   // Create encoder memory.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
 
   opus_int32 dtx;
 
@@ -633,8 +700,8 @@
   EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50));
 
   // Create encoder memory.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
 
   EXPECT_EQ(0, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50));
   EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, -1));
@@ -649,8 +716,8 @@
   EXPECT_EQ(-1, WebRtcOpus_SetMaxPlaybackRate(opus_encoder_, 20000));
 
   // Create encoder memory.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
 
   SetMaxPlaybackRate(opus_encoder_, OPUS_BANDWIDTH_FULLBAND, 48000);
   SetMaxPlaybackRate(opus_encoder_, OPUS_BANDWIDTH_FULLBAND, 24001);
@@ -672,9 +739,10 @@
   PrepareSpeechData(channels_, 20, 20);
 
   // Create encoder memory.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
-  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
+                                   force_multistream_);
 
   // Set bitrate.
   EXPECT_EQ(
@@ -708,9 +776,10 @@
   PrepareSpeechData(channels_, 20, 20);
 
   // Create.
-  EXPECT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
-  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
+                                   force_multistream_);
 
   // 10 ms. We use only first 10 ms of a 20 ms block.
   auto speech_block = speech_data_.GetNextBlock();
@@ -753,9 +822,12 @@
   PrepareSpeechData(channels_, 20, 20 * kPackets);
 
   // Create encoder memory.
-  ASSERT_EQ(0,
-            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
-  ASSERT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
+  CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
+                                   force_multistream_);
+  ASSERT_NE(nullptr, opus_encoder_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
+                                   force_multistream_);
+  ASSERT_NE(nullptr, opus_decoder_);
 
   // Set bitrate.
   EXPECT_EQ(
@@ -812,6 +884,13 @@
 
 INSTANTIATE_TEST_SUITE_P(VariousMode,
                          OpusTest,
-                         Combine(Values(1, 2, 4), Values(0, 1)));
+                         ::testing::ValuesIn({
+                             std::make_tuple(1, 0, true),
+                             std::make_tuple(1, 1, true),
+                             std::make_tuple(2, 0, false),
+                             std::make_tuple(4, 0, false),
+                             std::make_tuple(1, 1, false),
+                             std::make_tuple(4, 1, false),
+                         }));
 
 }  // namespace webrtc