WebRTC Opus C interface: Add support for non-48 kHz decode sample rate

Plus tests for 16 kHz.

Bug: webrtc:10631
Change-Id: I2d89bc6d0d9548f0ad7bb1e36d6dfde6b6b31f83
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/138072
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Minyue Li <minyue@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28099}
diff --git a/modules/audio_coding/codecs/opus/audio_decoder_multi_channel_opus_impl.cc b/modules/audio_coding/codecs/opus/audio_decoder_multi_channel_opus_impl.cc
index df0f448..c8fd176 100644
--- a/modules/audio_coding/codecs/opus/audio_decoder_multi_channel_opus_impl.cc
+++ b/modules/audio_coding/codecs/opus/audio_decoder_multi_channel_opus_impl.cc
@@ -157,7 +157,7 @@
     return PacketDuration(encoded, encoded_len);
   }
 
-  return WebRtcOpus_FecDurationEst(encoded, encoded_len);
+  return WebRtcOpus_FecDurationEst(encoded, encoded_len, 48000);
 }
 
 bool AudioDecoderMultiChannelOpusImpl::PacketHasFec(const uint8_t* encoded,
diff --git a/modules/audio_coding/codecs/opus/audio_decoder_opus.cc b/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
index 77e1535..0369549 100644
--- a/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
+++ b/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
@@ -23,7 +23,7 @@
 AudioDecoderOpusImpl::AudioDecoderOpusImpl(size_t num_channels)
     : channels_(num_channels) {
   RTC_DCHECK(num_channels == 1 || num_channels == 2);
-  const int error = WebRtcOpus_DecoderCreate(&dec_state_, channels_);
+  const int error = WebRtcOpus_DecoderCreate(&dec_state_, channels_, 48000);
   RTC_DCHECK(error == 0);
   WebRtcOpus_DecoderInit(dec_state_);
 }
@@ -104,7 +104,7 @@
     return PacketDuration(encoded, encoded_len);
   }
 
-  return WebRtcOpus_FecDurationEst(encoded, encoded_len);
+  return WebRtcOpus_FecDurationEst(encoded, encoded_len, 48000);
 }
 
 bool AudioDecoderOpusImpl::PacketHasFec(const uint8_t* encoded,
diff --git a/modules/audio_coding/codecs/opus/opus_fec_test.cc b/modules/audio_coding/codecs/opus/opus_fec_test.cc
index 0af90fe..287213c 100644
--- a/modules/audio_coding/codecs/opus/opus_fec_test.cc
+++ b/modules/audio_coding/codecs/opus/opus_fec_test.cc
@@ -110,7 +110,7 @@
 
   // Create encoder memory.
   EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, app, 48000));
-  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
+  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_, 48000));
   // Set bitrate.
   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, bit_rate_));
 }
diff --git a/modules/audio_coding/codecs/opus/opus_inst.h b/modules/audio_coding/codecs/opus/opus_inst.h
index 08c1e0f..9c3acb3 100644
--- a/modules/audio_coding/codecs/opus/opus_inst.h
+++ b/modules/audio_coding/codecs/opus/opus_inst.h
@@ -33,6 +33,7 @@
   int prev_decoded_samples;
   size_t channels;
   int in_dtx_mode;
+  int sample_rate_hz;
 };
 
 #endif  // MODULES_AUDIO_CODING_CODECS_OPUS_OPUS_INST_H_
diff --git a/modules/audio_coding/codecs/opus/opus_interface.c b/modules/audio_coding/codecs/opus/opus_interface.c
index 817caac..eb426c3 100644
--- a/modules/audio_coding/codecs/opus/opus_interface.c
+++ b/modules/audio_coding/codecs/opus/opus_interface.c
@@ -28,15 +28,26 @@
    * side, we must allow for packets of that size. NetEq is currently limited
    * to 60 ms on the receive side. */
   kWebRtcOpusMaxDecodeFrameSizeMs = 120,
-
-  /* Maximum sample count per channel is 48 kHz * maximum frame size in
-   * milliseconds. */
-  kWebRtcOpusMaxFrameSizePerChannel = 48 * kWebRtcOpusMaxDecodeFrameSizeMs,
-
-  /* Default frame size, 20 ms @ 48 kHz, in samples (for one channel). */
-  kWebRtcOpusDefaultFrameSize = 960,
 };
 
+static int FrameSizePerChannel(int frame_size_ms, int sample_rate_hz) {
+  RTC_DCHECK_GT(frame_size_ms, 0);
+  RTC_DCHECK_EQ(frame_size_ms % 10, 0);
+  RTC_DCHECK_GT(sample_rate_hz, 0);
+  RTC_DCHECK_EQ(sample_rate_hz % 1000, 0);
+  return frame_size_ms * (sample_rate_hz / 1000);
+}
+
+// Maximum sample count per channel.
+static int MaxFrameSizePerChannel(int sample_rate_hz) {
+  return FrameSizePerChannel(kWebRtcOpusMaxDecodeFrameSizeMs, sample_rate_hz);
+}
+
+// Default sample count per channel.
+static int DefaultFrameSizePerChannel(int sample_rate_hz) {
+  return FrameSizePerChannel(20, sample_rate_hz);
+}
+
 int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst,
                                  size_t channels,
                                  int32_t application,
@@ -374,7 +385,9 @@
   }
 }
 
-int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, size_t channels) {
+int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst,
+                                 size_t channels,
+                                 int sample_rate_hz) {
   int error;
   OpusDecInst* state;
 
@@ -385,14 +398,13 @@
       return -1;
     }
 
-    // Create new memory, always at 48000 Hz.
-    state->decoder = opus_decoder_create(48000,
-                                                 (int)channels, &error);
+    state->decoder = opus_decoder_create(sample_rate_hz, (int)channels, &error);
     if (error == OPUS_OK && state->decoder) {
       // Creation of memory all ok.
       state->channels = channels;
-      state->prev_decoded_samples = kWebRtcOpusDefaultFrameSize;
+      state->prev_decoded_samples = DefaultFrameSizePerChannel(sample_rate_hz);
       state->in_dtx_mode = 0;
+      state->sample_rate_hz = sample_rate_hz;
       *inst = state;
       return 0;
     }
@@ -432,8 +444,9 @@
     if (error == OPUS_OK && state->multistream_decoder) {
       // Creation of memory all ok.
       state->channels = channels;
-      state->prev_decoded_samples = kWebRtcOpusDefaultFrameSize;
+      state->prev_decoded_samples = DefaultFrameSizePerChannel(48000);
       state->in_dtx_mode = 0;
+      state->sample_rate_hz = 48000;
       *inst = state;
       return 0;
     }
@@ -529,13 +542,9 @@
     *audio_type = DetermineAudioType(inst, encoded_bytes);
     decoded_samples = WebRtcOpus_DecodePlc(inst, decoded, 1);
   } else {
-    decoded_samples = DecodeNative(inst,
-                                   encoded,
-                                   encoded_bytes,
-                                   kWebRtcOpusMaxFrameSizePerChannel,
-                                   decoded,
-                                   audio_type,
-                                   0);
+    decoded_samples = DecodeNative(inst, encoded, encoded_bytes,
+                                   MaxFrameSizePerChannel(inst->sample_rate_hz),
+                                   decoded, audio_type, 0);
   }
   if (decoded_samples < 0) {
     return -1;
@@ -555,10 +564,13 @@
 
   /* The number of samples we ask for is |number_of_lost_frames| times
    * |prev_decoded_samples_|. Limit the number of samples to maximum
-   * |kWebRtcOpusMaxFrameSizePerChannel|. */
+   * |MaxFrameSizePerChannel()|. */
   plc_samples = number_of_lost_frames * inst->prev_decoded_samples;
-  plc_samples = (plc_samples <= kWebRtcOpusMaxFrameSizePerChannel) ?
-      plc_samples : kWebRtcOpusMaxFrameSizePerChannel;
+  const int max_samples_per_channel =
+      MaxFrameSizePerChannel(inst->sample_rate_hz);
+  plc_samples = plc_samples <= max_samples_per_channel
+                    ? plc_samples
+                    : max_samples_per_channel;
   decoded_samples = DecodeNative(inst, NULL, 0, plc_samples,
                                  decoded, &audio_type, 0);
   if (decoded_samples < 0) {
@@ -578,7 +590,8 @@
     return 0;
   }
 
-  fec_samples = opus_packet_get_samples_per_frame(encoded, 48000);
+  fec_samples =
+      opus_packet_get_samples_per_frame(encoded, inst->sample_rate_hz);
 
   decoded_samples = DecodeNative(inst, encoded, encoded_bytes,
                                  fec_samples, decoded, audio_type, 1);
@@ -604,9 +617,10 @@
     /* Invalid payload data. */
     return 0;
   }
-  samples = frames * opus_packet_get_samples_per_frame(payload, 48000);
-  if (samples < 120 || samples > 5760) {
-    /* Invalid payload duration. */
+  samples =
+      frames * opus_packet_get_samples_per_frame(payload, inst->sample_rate_hz);
+  if (samples > 120 * inst->sample_rate_hz / 1000) {
+    // More than 120 ms' worth of samples.
     return 0;
   }
   return samples;
@@ -615,21 +629,24 @@
 int WebRtcOpus_PlcDuration(OpusDecInst* inst) {
   /* The number of samples we ask for is |number_of_lost_frames| times
    * |prev_decoded_samples_|. Limit the number of samples to maximum
-   * |kWebRtcOpusMaxFrameSizePerChannel|. */
+   * |MaxFrameSizePerChannel()|. */
   const int plc_samples = inst->prev_decoded_samples;
-  return (plc_samples <= kWebRtcOpusMaxFrameSizePerChannel) ?
-      plc_samples : kWebRtcOpusMaxFrameSizePerChannel;
+  const int max_samples_per_channel =
+      MaxFrameSizePerChannel(inst->sample_rate_hz);
+  return plc_samples <= max_samples_per_channel ? plc_samples
+                                                : max_samples_per_channel;
 }
 
 int WebRtcOpus_FecDurationEst(const uint8_t* payload,
-                              size_t payload_length_bytes) {
-  int samples;
+                              size_t payload_length_bytes,
+                              int sample_rate_hz) {
   if (WebRtcOpus_PacketHasFec(payload, payload_length_bytes) != 1) {
     return 0;
   }
-
-  samples = opus_packet_get_samples_per_frame(payload, 48000);
-  if (samples < 480 || samples > 5760) {
+  const int samples =
+      opus_packet_get_samples_per_frame(payload, sample_rate_hz);
+  const int samples_per_ms = sample_rate_hz / 1000;
+  if (samples < 10 * samples_per_ms || samples > 120 * samples_per_ms) {
     /* Invalid payload duration. */
     return 0;
   }
@@ -650,6 +667,8 @@
   if (payload[0] & 0x80)
     return 0;
 
+  // For computing the payload length in ms, the sample rate is not important
+  // since it cancels out. We use 48 kHz, but any valid sample rate would work.
   payload_length_ms = opus_packet_get_samples_per_frame(payload, 48000) / 48;
   if (10 > payload_length_ms)
     payload_length_ms = 10;
diff --git a/modules/audio_coding/codecs/opus/opus_interface.h b/modules/audio_coding/codecs/opus/opus_interface.h
index 54ecadd..cf95a69 100644
--- a/modules/audio_coding/codecs/opus/opus_interface.h
+++ b/modules/audio_coding/codecs/opus/opus_interface.h
@@ -328,7 +328,9 @@
  */
 int16_t WebRtcOpus_SetForceChannels(OpusEncInst* inst, size_t num_channels);
 
-int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, size_t channels);
+int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst,
+                                 size_t channels,
+                                 int sample_rate_hz);
 
 /****************************************************************************
  * WebRtcOpus_MultistreamDecoderCreate(...)
@@ -488,13 +490,15 @@
  * Input:
  *        - payload              : Encoded data pointer
  *        - payload_length_bytes : Bytes of encoded data
+ *        - sample_rate_hz       : Sample rate of output audio
  *
  * Return value                  : >0 - The duration of the FEC data in the
  *                                 packet in samples per channel.
  *                                  0 - No FEC data in the packet.
  */
 int WebRtcOpus_FecDurationEst(const uint8_t* payload,
-                              size_t payload_length_bytes);
+                              size_t payload_length_bytes,
+                              int sample_rate_hz);
 
 /****************************************************************************
  * WebRtcOpus_PacketHasFec(...)
diff --git a/modules/audio_coding/codecs/opus/opus_speed_test.cc b/modules/audio_coding/codecs/opus/opus_speed_test.cc
index 52cb14b..4477e8a 100644
--- a/modules/audio_coding/codecs/opus/opus_speed_test.cc
+++ b/modules/audio_coding/codecs/opus/opus_speed_test.cc
@@ -47,7 +47,7 @@
   int app = channels_ == 1 ? 0 : 1;
   /* Create encoder memory. */
   EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, app, 48000));
-  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
+  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_, 48000));
   /* Set bitrate. */
   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, bit_rate_));
 }
diff --git a/modules/audio_coding/codecs/opus/opus_unittest.cc b/modules/audio_coding/codecs/opus/opus_unittest.cc
index d0b240d..8a5bb6a 100644
--- a/modules/audio_coding/codecs/opus/opus_unittest.cc
+++ b/modules/audio_coding/codecs/opus/opus_unittest.cc
@@ -67,9 +67,11 @@
 
 void CreateSingleOrMultiStreamDecoder(WebRtcOpusDecInst** opus_decoder,
                                       int channels,
-                                      bool use_multistream) {
+                                      bool use_multistream,
+                                      int decoder_sample_rate_hz) {
   EXPECT_TRUE(channels == 1 || channels == 2 || use_multistream);
   if (use_multistream) {
+    EXPECT_EQ(decoder_sample_rate_hz, 48000);
     if (channels == 1) {
       EXPECT_EQ(0, WebRtcOpus_MultistreamDecoderCreate(
                        opus_decoder, channels, kMonoTotalStreams,
@@ -86,10 +88,16 @@
       EXPECT_TRUE(false) << channels;
     }
   } else {
-    EXPECT_EQ(0, WebRtcOpus_DecoderCreate(opus_decoder, channels));
+    EXPECT_EQ(0, WebRtcOpus_DecoderCreate(opus_decoder, channels,
+                                          decoder_sample_rate_hz));
   }
 }
 
+int SamplesPerChannel(int sample_rate_hz, int duration_ms) {
+  const int samples_per_ms = rtc::CheckedDivExact(sample_rate_hz, 1000);
+  return samples_per_ms * duration_ms;
+}
+
 }  // namespace
 
 using test::AudioLoop;
@@ -99,16 +107,11 @@
 
 // Maximum number of bytes in output bitstream.
 const size_t kMaxBytes = 2000;
-// Sample rate of Opus.
-const size_t kOpusDecodeRateKhz = 48;
-// Number of samples-per-channel in a 20 ms frame, sampled at 48 kHz.
-const size_t kOpus20msFrameDecodeSamples = kOpusDecodeRateKhz * 20;
-// Number of samples-per-channel in a 10 ms frame, sampled at 48 kHz.
-const size_t kOpus10msFrameDecodeSamples = kOpusDecodeRateKhz * 10;
 
-class OpusTest : public TestWithParam<::testing::tuple<int, int, bool, int>> {
+class OpusTest
+    : public TestWithParam<::testing::tuple<size_t, int, bool, int, int>> {
  protected:
-  OpusTest();
+  OpusTest() = default;
 
   void TestDtxEffect(bool dtx, int block_length_ms);
 
@@ -135,26 +138,35 @@
                          size_t channels,
                          uint16_t bound) const;
 
-  WebRtcOpusEncInst* opus_encoder_;
-  WebRtcOpusDecInst* opus_decoder_;
-
+  WebRtcOpusEncInst* opus_encoder_ = nullptr;
+  WebRtcOpusDecInst* opus_decoder_ = nullptr;
   AudioLoop speech_data_;
   uint8_t bitstream_[kMaxBytes];
-  size_t encoded_bytes_;
-  const size_t channels_;
-  const int application_;
-  const bool use_multistream_;
-  const int encoder_sample_rate_hz_;
+  size_t encoded_bytes_ = 0;
+  const size_t channels_{std::get<0>(GetParam())};
+  const int application_{std::get<1>(GetParam())};
+  const bool use_multistream_{std::get<2>(GetParam())};
+  const int encoder_sample_rate_hz_{std::get<3>(GetParam())};
+  const int decoder_sample_rate_hz_{std::get<4>(GetParam())};
 };
 
-OpusTest::OpusTest()
-    : opus_encoder_(NULL),
-      opus_decoder_(NULL),
-      encoded_bytes_(0),
-      channels_(static_cast<size_t>(::testing::get<0>(GetParam()))),
-      application_(::testing::get<1>(GetParam())),
-      use_multistream_(::testing::get<2>(GetParam())),
-      encoder_sample_rate_hz_(::testing::get<3>(GetParam())) {}
+// Singlestream: Try all combinations.
+INSTANTIATE_TEST_SUITE_P(Singlestream,
+                         OpusTest,
+                         testing::Combine(testing::Values(1, 2),
+                                          testing::Values(0, 1),
+                                          testing::Values(false),
+                                          testing::Values(16000, 48000),
+                                          testing::Values(16000, 48000)));
+
+// Multistream: Some representative cases (only 48 kHz for now).
+INSTANTIATE_TEST_SUITE_P(
+    Multistream,
+    OpusTest,
+    testing::Values(std::make_tuple(1, 0, true, 48000, 48000),
+                    std::make_tuple(2, 1, true, 48000, 48000),
+                    std::make_tuple(4, 0, true, 48000, 48000),
+                    std::make_tuple(4, 1, true, 48000, 48000)));
 
 void OpusTest::PrepareSpeechData(int block_length_ms, int loop_length_ms) {
   std::map<int, std::string> channel_to_basename = {
@@ -220,12 +232,14 @@
   PrepareSpeechData(block_length_ms, 2000);
   const size_t input_samples =
       rtc::CheckedDivExact(encoder_sample_rate_hz_, 1000) * block_length_ms;
-  const size_t output_samples = kOpusDecodeRateKhz * block_length_ms;
+  const size_t output_samples =
+      rtc::CheckedDivExact(decoder_sample_rate_hz_, 1000) * block_length_ms;
 
   // Create encoder memory.
   CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
                                    use_multistream_, encoder_sample_rate_hz_);
-  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_,
+                                   decoder_sample_rate_hz_);
 
   // Set bitrate.
   EXPECT_EQ(
@@ -385,7 +399,8 @@
 // Test if CBR does what we expect.
 void OpusTest::TestCbrEffect(bool cbr, int block_length_ms) {
   PrepareSpeechData(block_length_ms, 2000);
-  const size_t output_samples = kOpusDecodeRateKhz * block_length_ms;
+  const size_t output_samples =
+      rtc::CheckedDivExact(decoder_sample_rate_hz_, 1000) * block_length_ms;
 
   int32_t max_pkt_size_diff = 0;
   int32_t prev_pkt_size = 0;
@@ -393,7 +408,8 @@
   // Create encoder memory.
   CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
                                    use_multistream_, encoder_sample_rate_hz_);
-  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_,
+                                   decoder_sample_rate_hz_);
 
   // Set bitrate.
   EXPECT_EQ(
@@ -443,9 +459,11 @@
   // Invalid sample rate.
   EXPECT_EQ(-1, WebRtcOpus_EncoderCreate(&opus_encoder, 1, 0, 12345));
 
-  EXPECT_EQ(-1, WebRtcOpus_DecoderCreate(NULL, 1));
+  EXPECT_EQ(-1, WebRtcOpus_DecoderCreate(NULL, 1, 48000));
   // Invalid channel number.
-  EXPECT_EQ(-1, WebRtcOpus_DecoderCreate(&opus_decoder, 257));
+  EXPECT_EQ(-1, WebRtcOpus_DecoderCreate(&opus_decoder, 257, 48000));
+  // Invalid sample rate.
+  EXPECT_EQ(-1, WebRtcOpus_DecoderCreate(&opus_decoder, 1, 12345));
 }
 
 // Test failing Free.
@@ -459,7 +477,8 @@
 TEST_P(OpusTest, OpusCreateFree) {
   CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
                                    use_multistream_, encoder_sample_rate_hz_);
-  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_,
+                                   decoder_sample_rate_hz_);
   EXPECT_TRUE(opus_encoder_ != NULL);
   EXPECT_TRUE(opus_decoder_ != NULL);
   // Free encoder and decoder memory.
@@ -478,7 +497,8 @@
   // Create encoder memory.
   CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
                                    use_multistream_, encoder_sample_rate_hz_);
-  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_,
+                                   decoder_sample_rate_hz_);
 
   // Set bitrate.
   EXPECT_EQ(
@@ -495,12 +515,13 @@
 
   // Encode & decode.
   int16_t audio_type;
+  const int decode_samples_per_channel =
+      SamplesPerChannel(decoder_sample_rate_hz_, /*ms=*/20);
   int16_t* output_data_decode =
-      new int16_t[kOpus20msFrameDecodeSamples * channels_];
-  EXPECT_EQ(kOpus20msFrameDecodeSamples,
-            static_cast<size_t>(
-                EncodeDecode(opus_encoder_, speech_data_.GetNextBlock(),
-                             opus_decoder_, output_data_decode, &audio_type)));
+      new int16_t[decode_samples_per_channel * channels_];
+  EXPECT_EQ(decode_samples_per_channel,
+            EncodeDecode(opus_encoder_, speech_data_.GetNextBlock(),
+                         opus_decoder_, output_data_decode, &audio_type));
 
   // Free memory.
   delete[] output_data_decode;
@@ -549,8 +570,10 @@
   PrepareSpeechData(20, 20);
 
   int16_t audio_type;
+  const int decode_samples_per_channel =
+      SamplesPerChannel(decoder_sample_rate_hz_, /*ms=*/20);
   std::unique_ptr<int16_t[]> output_data_decode(
-      new int16_t[kOpus20msFrameDecodeSamples * channels_]());
+      new int16_t[decode_samples_per_channel * channels_]());
 
   // Test without creating encoder memory.
   EXPECT_EQ(-1,
@@ -560,7 +583,8 @@
   // Create encoder memory, try with different bandwidths.
   CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
                                    use_multistream_, encoder_sample_rate_hz_);
-  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_,
+                                   decoder_sample_rate_hz_);
 
   EXPECT_EQ(-1, WebRtcOpus_SetBandwidth(opus_encoder_,
                                         OPUS_BANDWIDTH_NARROWBAND - 1));
@@ -618,23 +642,24 @@
   // Create encoder memory.
   CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
                                    use_multistream_, encoder_sample_rate_hz_);
-  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_,
+                                   decoder_sample_rate_hz_);
 
   // Encode & decode.
   int16_t audio_type;
+  const int decode_samples_per_channel =
+      SamplesPerChannel(decoder_sample_rate_hz_, /*ms=*/20);
   int16_t* output_data_decode =
-      new int16_t[kOpus20msFrameDecodeSamples * channels_];
-  EXPECT_EQ(kOpus20msFrameDecodeSamples,
-            static_cast<size_t>(
-                EncodeDecode(opus_encoder_, speech_data_.GetNextBlock(),
-                             opus_decoder_, output_data_decode, &audio_type)));
+      new int16_t[decode_samples_per_channel * channels_];
+  EXPECT_EQ(decode_samples_per_channel,
+            EncodeDecode(opus_encoder_, speech_data_.GetNextBlock(),
+                         opus_decoder_, output_data_decode, &audio_type));
 
   WebRtcOpus_DecoderInit(opus_decoder_);
 
-  EXPECT_EQ(kOpus20msFrameDecodeSamples,
-            static_cast<size_t>(
-                WebRtcOpus_Decode(opus_decoder_, bitstream_, encoded_bytes_,
-                                  output_data_decode, &audio_type)));
+  EXPECT_EQ(decode_samples_per_channel,
+            WebRtcOpus_Decode(opus_decoder_, bitstream_, encoded_bytes_,
+                              output_data_decode, &audio_type));
 
   // Free memory.
   delete[] output_data_decode;
@@ -762,7 +787,8 @@
   // Create encoder memory.
   CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
                                    use_multistream_, encoder_sample_rate_hz_);
-  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_,
+                                   decoder_sample_rate_hz_);
 
   // Set bitrate.
   EXPECT_EQ(
@@ -773,18 +799,18 @@
 
   // Encode & decode.
   int16_t audio_type;
+  const int decode_samples_per_channel =
+      SamplesPerChannel(decoder_sample_rate_hz_, /*ms=*/20);
   int16_t* output_data_decode =
-      new int16_t[kOpus20msFrameDecodeSamples * channels_];
-  EXPECT_EQ(kOpus20msFrameDecodeSamples,
-            static_cast<size_t>(
-                EncodeDecode(opus_encoder_, speech_data_.GetNextBlock(),
-                             opus_decoder_, output_data_decode, &audio_type)));
+      new int16_t[decode_samples_per_channel * channels_];
+  EXPECT_EQ(decode_samples_per_channel,
+            EncodeDecode(opus_encoder_, speech_data_.GetNextBlock(),
+                         opus_decoder_, output_data_decode, &audio_type));
 
   // Call decoder PLC.
-  int16_t* plc_buffer = new int16_t[kOpus20msFrameDecodeSamples * channels_];
-  EXPECT_EQ(
-      kOpus20msFrameDecodeSamples,
-      static_cast<size_t>(WebRtcOpus_DecodePlc(opus_decoder_, plc_buffer, 1)));
+  int16_t* plc_buffer = new int16_t[decode_samples_per_channel * channels_];
+  EXPECT_EQ(decode_samples_per_channel,
+            WebRtcOpus_DecodePlc(opus_decoder_, plc_buffer, 1));
 
   // Free memory.
   delete[] plc_buffer;
@@ -800,7 +826,8 @@
   // Create.
   CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
                                    use_multistream_, encoder_sample_rate_hz_);
-  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_,
+                                   decoder_sample_rate_hz_);
 
   // 10 ms. We use only first 10 ms of a 20 ms block.
   auto speech_block = speech_data_.GetNextBlock();
@@ -809,10 +836,9 @@
       rtc::CheckedDivExact(speech_block.size(), 2 * channels_), kMaxBytes,
       bitstream_);
   EXPECT_GE(encoded_bytes_int, 0);
-  EXPECT_EQ(
-      kOpus10msFrameDecodeSamples,
-      static_cast<size_t>(WebRtcOpus_DurationEst(
-          opus_decoder_, bitstream_, static_cast<size_t>(encoded_bytes_int))));
+  EXPECT_EQ(SamplesPerChannel(decoder_sample_rate_hz_, /*ms=*/10),
+            WebRtcOpus_DurationEst(opus_decoder_, bitstream_,
+                                   static_cast<size_t>(encoded_bytes_int)));
 
   // 20 ms
   speech_block = speech_data_.GetNextBlock();
@@ -821,10 +847,9 @@
                         rtc::CheckedDivExact(speech_block.size(), channels_),
                         kMaxBytes, bitstream_);
   EXPECT_GE(encoded_bytes_int, 0);
-  EXPECT_EQ(
-      kOpus20msFrameDecodeSamples,
-      static_cast<size_t>(WebRtcOpus_DurationEst(
-          opus_decoder_, bitstream_, static_cast<size_t>(encoded_bytes_int))));
+  EXPECT_EQ(SamplesPerChannel(decoder_sample_rate_hz_, /*ms=*/20),
+            WebRtcOpus_DurationEst(opus_decoder_, bitstream_,
+                                   static_cast<size_t>(encoded_bytes_int)));
 
   // Free memory.
   EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_encoder_));
@@ -846,7 +871,8 @@
   CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
                                    use_multistream_, encoder_sample_rate_hz_);
   ASSERT_NE(nullptr, opus_encoder_);
-  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_);
+  CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_, use_multistream_,
+                                   decoder_sample_rate_hz_);
   ASSERT_NE(nullptr, opus_decoder_);
 
   // Set bitrate.
@@ -858,8 +884,10 @@
 
   // Encode & decode.
   int16_t audio_type;
+  const int decode_samples_per_channel =
+      SamplesPerChannel(decoder_sample_rate_hz_, /*ms=*/20);
   std::unique_ptr<int16_t[]> output_data_decode(
-      new int16_t[kPackets * kOpus20msFrameDecodeSamples * channels_]);
+      new int16_t[kPackets * decode_samples_per_channel * channels_]);
   OpusRepacketizer* rp = opus_repacketizer_create();
 
   size_t num_packets = 0;
@@ -887,11 +915,11 @@
 
   encoded_bytes_ = opus_repacketizer_out(rp, bitstream_, kMaxBytes);
 
-  EXPECT_EQ(kOpus20msFrameDecodeSamples * kPackets,
+  EXPECT_EQ(decode_samples_per_channel * kPackets,
             static_cast<size_t>(WebRtcOpus_DurationEst(
                 opus_decoder_, bitstream_, encoded_bytes_)));
 
-  EXPECT_EQ(kOpus20msFrameDecodeSamples * kPackets,
+  EXPECT_EQ(decode_samples_per_channel * kPackets,
             static_cast<size_t>(
                 WebRtcOpus_Decode(opus_decoder_, bitstream_, encoded_bytes_,
                                   output_data_decode.get(), &audio_type)));
@@ -902,21 +930,4 @@
   EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
 }
 
-INSTANTIATE_TEST_SUITE_P(VariousMode,
-                         OpusTest,
-                         ::testing::ValuesIn({
-                             std::make_tuple(1, 0, false, 16000),
-                             std::make_tuple(1, 1, false, 16000),
-                             std::make_tuple(2, 0, false, 16000),
-                             std::make_tuple(2, 1, false, 16000),
-                             std::make_tuple(1, 0, false, 48000),
-                             std::make_tuple(1, 1, false, 48000),
-                             std::make_tuple(2, 0, false, 48000),
-                             std::make_tuple(2, 1, false, 48000),
-                             std::make_tuple(1, 0, true, 48000),
-                             std::make_tuple(2, 1, true, 48000),
-                             std::make_tuple(4, 0, true, 48000),
-                             std::make_tuple(4, 1, true, 48000),
-                         }));
-
 }  // namespace webrtc
diff --git a/modules/audio_coding/test/opus_test.cc b/modules/audio_coding/test/opus_test.cc
index 38d97a7..7f0bdd2 100644
--- a/modules/audio_coding/test/opus_test.cc
+++ b/modules/audio_coding/test/opus_test.cc
@@ -77,8 +77,8 @@
   ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_stereo_encoder_, 2, 1, 48000), -1);
 
   // Create Opus decoders for mono and stereo for stand-alone testing of Opus.
-  ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_mono_decoder_, 1), -1);
-  ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_stereo_decoder_, 2), -1);
+  ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_mono_decoder_, 1, 48000), -1);
+  ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_stereo_decoder_, 2, 48000), -1);
   WebRtcOpus_DecoderInit(opus_mono_decoder_);
   WebRtcOpus_DecoderInit(opus_stereo_decoder_);