From a1d1a1e976049d006d0b1eea2f0cbf2d0e709186 Mon Sep 17 00:00:00 2001 From: Karl Wiberg Date: Tue, 28 May 2019 14:41:07 +0200 Subject: [PATCH] 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 Reviewed-by: Minyue Li Cr-Commit-Position: refs/heads/master@{#28099} --- .../audio_decoder_multi_channel_opus_impl.cc | 2 +- .../codecs/opus/audio_decoder_opus.cc | 4 +- .../audio_coding/codecs/opus/opus_fec_test.cc | 2 +- modules/audio_coding/codecs/opus/opus_inst.h | 1 + .../audio_coding/codecs/opus/opus_interface.c | 89 ++++---- .../audio_coding/codecs/opus/opus_interface.h | 8 +- .../codecs/opus/opus_speed_test.cc | 2 +- .../audio_coding/codecs/opus/opus_unittest.cc | 193 +++++++++--------- modules/audio_coding/test/opus_test.cc | 4 +- 9 files changed, 170 insertions(+), 135 deletions(-) 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 df0f4482c8..c8fd176fbb 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 @@ int AudioDecoderMultiChannelOpusImpl::PacketDurationRedundant( 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 77e1535927..03695490ce 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 @@ namespace webrtc { 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 @@ int AudioDecoderOpusImpl::PacketDurationRedundant(const uint8_t* encoded, 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 0af90fef5e..287213c45d 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 @@ void OpusFecTest::SetUp() { // 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 08c1e0f361..9c3acb3b21 100644 --- a/modules/audio_coding/codecs/opus/opus_inst.h +++ b/modules/audio_coding/codecs/opus/opus_inst.h @@ -33,6 +33,7 @@ struct WebRtcOpusDecInst { 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 817caac117..eb426c3980 100644 --- a/modules/audio_coding/codecs/opus/opus_interface.c +++ b/modules/audio_coding/codecs/opus/opus_interface.c @@ -28,15 +28,26 @@ enum { * 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_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) { int error; OpusDecInst* state; @@ -385,14 +398,13 @@ int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, size_t channels) { 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 @@ int16_t WebRtcOpus_MultistreamDecoderCreate( 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 @@ int WebRtcOpus_Decode(OpusDecInst* inst, const uint8_t* encoded, *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 @@ int WebRtcOpus_DecodePlc(OpusDecInst* inst, int16_t* decoded, /* 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 @@ int WebRtcOpus_DecodeFec(OpusDecInst* inst, const uint8_t* encoded, 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 @@ int WebRtcOpus_DurationEst(OpusDecInst* inst, /* 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_DurationEst(OpusDecInst* inst, 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 @@ int WebRtcOpus_PacketHasFec(const uint8_t* payload, 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 54ecadde30..cf95a6912d 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_SetBandwidth(OpusEncInst* inst, int32_t bandwidth); */ 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 @@ int WebRtcOpus_PlcDuration(OpusDecInst* inst); * 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 52cb14beca..4477e8a5f8 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 @@ void OpusSpeedTest::SetUp() { 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 d0b240dfc6..8a5bb6a2a3 100644 --- a/modules/audio_coding/codecs/opus/opus_unittest.cc +++ b/modules/audio_coding/codecs/opus/opus_unittest.cc @@ -67,9 +67,11 @@ void CreateSingleOrMultiStreamEncoder(WebRtcOpusEncInst** opus_encoder, 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 @@ void CreateSingleOrMultiStreamDecoder(WebRtcOpusDecInst** opus_decoder, 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 @@ using ::testing::Combine; // 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> { +class OpusTest + : public TestWithParam<::testing::tuple> { protected: - OpusTest(); + OpusTest() = default; void TestDtxEffect(bool dtx, int block_length_ms); @@ -135,26 +138,35 @@ class OpusTest : public TestWithParam<::testing::tuple> { 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(::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 channel_to_basename = { @@ -220,12 +232,14 @@ void OpusTest::TestDtxEffect(bool dtx, int block_length_ms) { 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 @@ void OpusTest::TestDtxEffect(bool dtx, int block_length_ms) { // 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 @@ void OpusTest::TestCbrEffect(bool cbr, int 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( @@ -443,9 +459,11 @@ TEST(OpusTest, OpusCreateFail) { // 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(OpusTest, OpusFreeFail) { 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 @@ TEST_P(OpusTest, OpusEncodeDecode) { // 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 @@ TEST_P(OpusTest, OpusEncodeDecode) { // 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( - 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 @@ TEST_P(OpusTest, OpusSetBandwidth) { PrepareSpeechData(20, 20); int16_t audio_type; + const int decode_samples_per_channel = + SamplesPerChannel(decoder_sample_rate_hz_, /*ms=*/20); std::unique_ptr 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 @@ TEST_P(OpusTest, OpusSetBandwidth) { // 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 @@ TEST_P(OpusTest, OpusDecodeInit) { // 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( - 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( - 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 @@ TEST_P(OpusTest, OpusDecodePlc) { // 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 @@ TEST_P(OpusTest, OpusDecodePlc) { // 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( - 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(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 @@ TEST_P(OpusTest, OpusDurationEstimation) { // 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 @@ TEST_P(OpusTest, OpusDurationEstimation) { rtc::CheckedDivExact(speech_block.size(), 2 * channels_), kMaxBytes, bitstream_); EXPECT_GE(encoded_bytes_int, 0); - EXPECT_EQ( - kOpus10msFrameDecodeSamples, - static_cast(WebRtcOpus_DurationEst( - opus_decoder_, bitstream_, static_cast(encoded_bytes_int)))); + EXPECT_EQ(SamplesPerChannel(decoder_sample_rate_hz_, /*ms=*/10), + WebRtcOpus_DurationEst(opus_decoder_, bitstream_, + static_cast(encoded_bytes_int))); // 20 ms speech_block = speech_data_.GetNextBlock(); @@ -821,10 +847,9 @@ TEST_P(OpusTest, OpusDurationEstimation) { rtc::CheckedDivExact(speech_block.size(), channels_), kMaxBytes, bitstream_); EXPECT_GE(encoded_bytes_int, 0); - EXPECT_EQ( - kOpus20msFrameDecodeSamples, - static_cast(WebRtcOpus_DurationEst( - opus_decoder_, bitstream_, static_cast(encoded_bytes_int)))); + EXPECT_EQ(SamplesPerChannel(decoder_sample_rate_hz_, /*ms=*/20), + WebRtcOpus_DurationEst(opus_decoder_, bitstream_, + static_cast(encoded_bytes_int))); // Free memory. EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_encoder_)); @@ -846,7 +871,8 @@ TEST_P(OpusTest, OpusDecodeRepacketized) { 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 @@ TEST_P(OpusTest, OpusDecodeRepacketized) { // Encode & decode. int16_t audio_type; + const int decode_samples_per_channel = + SamplesPerChannel(decoder_sample_rate_hz_, /*ms=*/20); std::unique_ptr 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 @@ TEST_P(OpusTest, OpusDecodeRepacketized) { encoded_bytes_ = opus_repacketizer_out(rp, bitstream_, kMaxBytes); - EXPECT_EQ(kOpus20msFrameDecodeSamples * kPackets, + EXPECT_EQ(decode_samples_per_channel * kPackets, static_cast(WebRtcOpus_DurationEst( opus_decoder_, bitstream_, encoded_bytes_))); - EXPECT_EQ(kOpus20msFrameDecodeSamples * kPackets, + EXPECT_EQ(decode_samples_per_channel * kPackets, static_cast( WebRtcOpus_Decode(opus_decoder_, bitstream_, encoded_bytes_, output_data_decode.get(), &audio_type))); @@ -902,21 +930,4 @@ TEST_P(OpusTest, OpusDecodeRepacketized) { 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 38d97a71a2..7f0bdd2974 100644 --- a/modules/audio_coding/test/opus_test.cc +++ b/modules/audio_coding/test/opus_test.cc @@ -77,8 +77,8 @@ void OpusTest::Perform() { 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_);