diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.cc b/webrtc/modules/audio_coding/codecs/audio_decoder.cc index 442ddc1e4b..e91161e33c 100644 --- a/webrtc/modules/audio_coding/codecs/audio_decoder.cc +++ b/webrtc/modules/audio_coding/codecs/audio_decoder.cc @@ -82,6 +82,10 @@ bool AudioDecoder::PacketHasFec(const uint8_t* encoded, return false; } +int AudioDecoder::SampleRateHz() const { + return -1; +} + AudioDecoder::SpeechType AudioDecoder::ConvertSpeechType(int16_t type) { switch (type) { case 0: // TODO(hlundin): Both iSAC and Opus return 0 for speech. diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.h b/webrtc/modules/audio_coding/codecs/audio_decoder.h index 580ddbf74f..c77a069fc3 100644 --- a/webrtc/modules/audio_coding/codecs/audio_decoder.h +++ b/webrtc/modules/audio_coding/codecs/audio_decoder.h @@ -93,6 +93,14 @@ class AudioDecoder { // Returns true if the packet has FEC and false otherwise. virtual bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const; + // Returns the actual sample rate of the decoder's output. + // NOTE: For now, this has a default implementation that returns an unusable + // value (-1). That default implementation will go away soon, and at the same + // time callers will start relying on the return value, so make sure you + // override it with something that returns a correct value! + // TODO(kwiberg): Remove the default implementation. + virtual int SampleRateHz() const; + virtual size_t Channels() const = 0; protected: diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.cc b/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.cc index deb1b1f4bd..48b2f5d437 100644 --- a/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.cc +++ b/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.cc @@ -74,7 +74,7 @@ NamedDecoderConstructor decoder_constructors[] = { {"isac", [](const SdpAudioFormat& format) { return format.clockrate_hz == 16000 && format.num_channels == 1 - ? Unique(new AudioDecoderIsacFix) + ? Unique(new AudioDecoderIsacFix(format.clockrate_hz)) : nullptr; }}, #elif defined(WEBRTC_CODEC_ISAC) @@ -82,14 +82,15 @@ NamedDecoderConstructor decoder_constructors[] = { [](const SdpAudioFormat& format) { return (format.clockrate_hz == 16000 || format.clockrate_hz == 32000) && format.num_channels == 1 - ? Unique(new AudioDecoderIsac) + ? Unique(new AudioDecoderIsac(format.clockrate_hz)) : nullptr; }}, #endif {"l16", [](const SdpAudioFormat& format) { return format.num_channels >= 1 - ? Unique(new AudioDecoderPcm16B(format.num_channels)) + ? Unique(new AudioDecoderPcm16B(format.clockrate_hz, + format.num_channels)) : nullptr; }}, #ifdef WEBRTC_CODEC_G722 @@ -136,7 +137,15 @@ class BuiltinAudioDecoderFactory : public AudioDecoderFactory { const SdpAudioFormat& format) override { for (const auto& dc : decoder_constructors) { if (STR_CASE_CMP(format.name.c_str(), dc.name) == 0) { - return std::unique_ptr(dc.constructor(format)); + std::unique_ptr dec = dc.constructor(format); + if (dec) { + const int expected_sample_rate_hz = + STR_CASE_CMP(format.name.c_str(), "g722") == 0 + ? 2 * format.clockrate_hz + : format.clockrate_hz; + RTC_CHECK_EQ(expected_sample_rate_hz, dec->SampleRateHz()); + } + return dec; } } return nullptr; diff --git a/webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.cc b/webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.cc index 9757b4a010..af164c4bb7 100644 --- a/webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.cc +++ b/webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.cc @@ -16,6 +16,10 @@ namespace webrtc { void AudioDecoderPcmU::Reset() {} +int AudioDecoderPcmU::SampleRateHz() const { + return 8000; +} + size_t AudioDecoderPcmU::Channels() const { return num_channels_; } @@ -25,7 +29,7 @@ int AudioDecoderPcmU::DecodeInternal(const uint8_t* encoded, int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) { - RTC_DCHECK_EQ(sample_rate_hz, 8000); + RTC_DCHECK_EQ(SampleRateHz(), sample_rate_hz); int16_t temp_type = 1; // Default is speech. size_t ret = WebRtcG711_DecodeU(encoded, encoded_len, decoded, &temp_type); *speech_type = ConvertSpeechType(temp_type); @@ -40,6 +44,10 @@ int AudioDecoderPcmU::PacketDuration(const uint8_t* encoded, void AudioDecoderPcmA::Reset() {} +int AudioDecoderPcmA::SampleRateHz() const { + return 8000; +} + size_t AudioDecoderPcmA::Channels() const { return num_channels_; } @@ -49,7 +57,7 @@ int AudioDecoderPcmA::DecodeInternal(const uint8_t* encoded, int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) { - RTC_DCHECK_EQ(sample_rate_hz, 8000); + RTC_DCHECK_EQ(SampleRateHz(), sample_rate_hz); int16_t temp_type = 1; // Default is speech. size_t ret = WebRtcG711_DecodeA(encoded, encoded_len, decoded, &temp_type); *speech_type = ConvertSpeechType(temp_type); diff --git a/webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.h b/webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.h index 7a627e757c..7fdc3591b3 100644 --- a/webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.h +++ b/webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.h @@ -24,6 +24,7 @@ class AudioDecoderPcmU final : public AudioDecoder { } void Reset() override; int PacketDuration(const uint8_t* encoded, size_t encoded_len) const override; + int SampleRateHz() const override; size_t Channels() const override; protected: @@ -45,6 +46,7 @@ class AudioDecoderPcmA final : public AudioDecoder { } void Reset() override; int PacketDuration(const uint8_t* encoded, size_t encoded_len) const override; + int SampleRateHz() const override; size_t Channels() const override; protected: diff --git a/webrtc/modules/audio_coding/codecs/g722/audio_decoder_g722.cc b/webrtc/modules/audio_coding/codecs/g722/audio_decoder_g722.cc index 7676e90d9e..379293b748 100644 --- a/webrtc/modules/audio_coding/codecs/g722/audio_decoder_g722.cc +++ b/webrtc/modules/audio_coding/codecs/g722/audio_decoder_g722.cc @@ -35,7 +35,7 @@ int AudioDecoderG722::DecodeInternal(const uint8_t* encoded, int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) { - RTC_DCHECK_EQ(sample_rate_hz, 16000); + RTC_DCHECK_EQ(SampleRateHz(), sample_rate_hz); int16_t temp_type = 1; // Default is speech. size_t ret = WebRtcG722_Decode(dec_state_, encoded, encoded_len, decoded, &temp_type); @@ -53,6 +53,10 @@ int AudioDecoderG722::PacketDuration(const uint8_t* encoded, return static_cast(2 * encoded_len / Channels()); } +int AudioDecoderG722::SampleRateHz() const { + return 16000; +} + size_t AudioDecoderG722::Channels() const { return 1; } @@ -74,7 +78,7 @@ int AudioDecoderG722Stereo::DecodeInternal(const uint8_t* encoded, int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) { - RTC_DCHECK_EQ(sample_rate_hz, 16000); + RTC_DCHECK_EQ(SampleRateHz(), sample_rate_hz); int16_t temp_type = 1; // Default is speech. // De-interleave the bit-stream into two separate payloads. uint8_t* encoded_deinterleaved = new uint8_t[encoded_len]; @@ -100,6 +104,10 @@ int AudioDecoderG722Stereo::DecodeInternal(const uint8_t* encoded, return static_cast(ret); } +int AudioDecoderG722Stereo::SampleRateHz() const { + return 16000; +} + size_t AudioDecoderG722Stereo::Channels() const { return 2; } diff --git a/webrtc/modules/audio_coding/codecs/g722/audio_decoder_g722.h b/webrtc/modules/audio_coding/codecs/g722/audio_decoder_g722.h index 1837ffabe2..ccca73d1a1 100644 --- a/webrtc/modules/audio_coding/codecs/g722/audio_decoder_g722.h +++ b/webrtc/modules/audio_coding/codecs/g722/audio_decoder_g722.h @@ -25,6 +25,7 @@ class AudioDecoderG722 final : public AudioDecoder { bool HasDecodePlc() const override; void Reset() override; int PacketDuration(const uint8_t* encoded, size_t encoded_len) const override; + int SampleRateHz() const override; size_t Channels() const override; protected: @@ -44,6 +45,8 @@ class AudioDecoderG722Stereo final : public AudioDecoder { AudioDecoderG722Stereo(); ~AudioDecoderG722Stereo() override; void Reset() override; + int SampleRateHz() const override; + size_t Channels() const override; protected: int DecodeInternal(const uint8_t* encoded, @@ -51,7 +54,6 @@ class AudioDecoderG722Stereo final : public AudioDecoder { int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) override; - size_t Channels() const override; private: // Splits the stereo-interleaved payload in |encoded| into separate payloads diff --git a/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc b/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc index 9ae0e1a95e..dab5805f98 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc +++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc @@ -49,6 +49,10 @@ void AudioDecoderIlbc::Reset() { WebRtcIlbcfix_Decoderinit30Ms(dec_state_); } +int AudioDecoderIlbc::SampleRateHz() const { + return 8000; +} + size_t AudioDecoderIlbc::Channels() const { return 1; } diff --git a/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h b/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h index 036c11fac4..1083479ad8 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h +++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h @@ -25,6 +25,7 @@ class AudioDecoderIlbc final : public AudioDecoder { bool HasDecodePlc() const override; size_t DecodePlc(size_t num_frames, int16_t* decoded) override; void Reset() override; + int SampleRateHz() const override; size_t Channels() const override; protected: diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h index b1907bbb39..264cca2bf3 100644 --- a/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h +++ b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h @@ -14,18 +14,24 @@ #include #include "webrtc/base/constructormagic.h" +#include "webrtc/base/optional.h" #include "webrtc/base/scoped_ref_ptr.h" #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" #include "webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h" namespace webrtc { +// TODO(kwiberg): Remove the possibility of not specifying the sample rate at +// object creation time. template class AudioDecoderIsacT final : public AudioDecoder { public: AudioDecoderIsacT(); explicit AudioDecoderIsacT( const rtc::scoped_refptr& bwinfo); + explicit AudioDecoderIsacT(int sample_rate_hz); + AudioDecoderIsacT(int sample_rate_hz, + const rtc::scoped_refptr& bwinfo); ~AudioDecoderIsacT() override; bool HasDecodePlc() const override; @@ -37,6 +43,7 @@ class AudioDecoderIsacT final : public AudioDecoder { uint32_t rtp_timestamp, uint32_t arrival_timestamp) override; int ErrorCode() override; + int SampleRateHz() const override; size_t Channels() const override; int DecodeInternal(const uint8_t* encoded, size_t encoded_len, @@ -45,9 +52,12 @@ class AudioDecoderIsacT final : public AudioDecoder { SpeechType* speech_type) override; private: + AudioDecoderIsacT(rtc::Optional sample_rate_hz, + const rtc::scoped_refptr& bwinfo); + typename T::instance_type* isac_state_; + rtc::Optional sample_rate_hz_; rtc::scoped_refptr bwinfo_; - int decoder_sample_rate_hz_; RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacT); }; diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h index 4998feac84..431632112a 100644 --- a/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h +++ b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h @@ -19,12 +19,31 @@ namespace webrtc { template AudioDecoderIsacT::AudioDecoderIsacT() - : AudioDecoderIsacT(nullptr) {} + : AudioDecoderIsacT(rtc::Optional(), nullptr) {} template AudioDecoderIsacT::AudioDecoderIsacT( const rtc::scoped_refptr& bwinfo) - : bwinfo_(bwinfo), decoder_sample_rate_hz_(-1) { + : AudioDecoderIsacT(rtc::Optional(), bwinfo) {} + +template +AudioDecoderIsacT::AudioDecoderIsacT(int sample_rate_hz) + : AudioDecoderIsacT(rtc::Optional(sample_rate_hz), nullptr) {} + +template +AudioDecoderIsacT::AudioDecoderIsacT( + int sample_rate_hz, + const rtc::scoped_refptr& bwinfo) + : AudioDecoderIsacT(rtc::Optional(sample_rate_hz), bwinfo) {} + +template +AudioDecoderIsacT::AudioDecoderIsacT( + rtc::Optional sample_rate_hz, + const rtc::scoped_refptr& bwinfo) + : sample_rate_hz_(sample_rate_hz), bwinfo_(bwinfo) { + RTC_CHECK(!sample_rate_hz || *sample_rate_hz == 16000 || + *sample_rate_hz == 32000) + << "Unsupported sample rate " << *sample_rate_hz; RTC_CHECK_EQ(0, T::Create(&isac_state_)); T::DecoderInit(isac_state_); if (bwinfo_) { @@ -32,6 +51,9 @@ AudioDecoderIsacT::AudioDecoderIsacT( T::GetBandwidthInfo(isac_state_, &bi); bwinfo_->Set(bi); } + if (sample_rate_hz_) { + RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, *sample_rate_hz_)); + } } template @@ -45,11 +67,13 @@ int AudioDecoderIsacT::DecodeInternal(const uint8_t* encoded, int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) { - RTC_CHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000) - << "Unsupported sample rate " << sample_rate_hz; - if (sample_rate_hz != decoder_sample_rate_hz_) { - RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, sample_rate_hz)); - decoder_sample_rate_hz_ = sample_rate_hz; + if (sample_rate_hz_) { + RTC_CHECK_EQ(*sample_rate_hz_, sample_rate_hz); + } else { + RTC_CHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000) + << "Unsupported sample rate " << sample_rate_hz; + sample_rate_hz_ = rtc::Optional(sample_rate_hz); + RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, *sample_rate_hz_)); } int16_t temp_type = 1; // Default is speech. int ret = @@ -95,6 +119,12 @@ int AudioDecoderIsacT::ErrorCode() { return T::GetErrorCode(isac_state_); } +template +int AudioDecoderIsacT::SampleRateHz() const { + RTC_CHECK(sample_rate_hz_) << "Sample rate not set yet!"; + return *sample_rate_hz_; +} + template size_t AudioDecoderIsacT::Channels() const { return 1; diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.cc b/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.cc index f64e811afe..42abd0a0d6 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.cc +++ b/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.cc @@ -87,6 +87,10 @@ bool AudioDecoderOpus::PacketHasFec(const uint8_t* encoded, return (fec == 1); } +int AudioDecoderOpus::SampleRateHz() const { + return 48000; +} + size_t AudioDecoderOpus::Channels() const { return channels_; } diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h b/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h index be48ca988e..c22204156b 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h +++ b/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h @@ -27,6 +27,7 @@ class AudioDecoderOpus final : public AudioDecoder { int PacketDurationRedundant(const uint8_t* encoded, size_t encoded_len) const override; bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const override; + int SampleRateHz() const override; size_t Channels() const override; protected: diff --git a/webrtc/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.cc b/webrtc/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.cc index 834c070073..dce5f4c516 100644 --- a/webrtc/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.cc +++ b/webrtc/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.cc @@ -15,13 +15,20 @@ namespace webrtc { -AudioDecoderPcm16B::AudioDecoderPcm16B(size_t num_channels) - : num_channels_(num_channels) { +AudioDecoderPcm16B::AudioDecoderPcm16B(int sample_rate_hz, size_t num_channels) + : sample_rate_hz_(sample_rate_hz), num_channels_(num_channels) { + RTC_DCHECK(sample_rate_hz == 8000 || sample_rate_hz == 16000 || + sample_rate_hz == 32000 || sample_rate_hz == 48000) + << "Unsupported sample rate " << sample_rate_hz; RTC_DCHECK_GE(num_channels, 1u); } void AudioDecoderPcm16B::Reset() {} +int AudioDecoderPcm16B::SampleRateHz() const { + return sample_rate_hz_; +} + size_t AudioDecoderPcm16B::Channels() const { return num_channels_; } @@ -31,9 +38,7 @@ int AudioDecoderPcm16B::DecodeInternal(const uint8_t* encoded, int sample_rate_hz, int16_t* decoded, SpeechType* speech_type) { - RTC_DCHECK(sample_rate_hz == 8000 || sample_rate_hz == 16000 || - sample_rate_hz == 32000 || sample_rate_hz == 48000) - << "Unsupported sample rate " << sample_rate_hz; + RTC_DCHECK_EQ(sample_rate_hz_, sample_rate_hz); size_t ret = WebRtcPcm16b_Decode(encoded, encoded_len, decoded); *speech_type = ConvertSpeechType(1); return static_cast(ret); diff --git a/webrtc/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h b/webrtc/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h index 692cb94282..df94a6a6bd 100644 --- a/webrtc/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h +++ b/webrtc/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h @@ -18,9 +18,10 @@ namespace webrtc { class AudioDecoderPcm16B final : public AudioDecoder { public: - explicit AudioDecoderPcm16B(size_t num_channels); + AudioDecoderPcm16B(int sample_rate_hz, size_t num_channels); void Reset() override; int PacketDuration(const uint8_t* encoded, size_t encoded_len) const override; + int SampleRateHz() const override; size_t Channels() const override; protected: @@ -31,6 +32,7 @@ class AudioDecoderPcm16B final : public AudioDecoder { SpeechType* speech_type) override; private: + const int sample_rate_hz_; const size_t num_channels_; RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoderPcm16B); }; diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc index 1d0802e441..f83afccdf5 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc @@ -310,7 +310,7 @@ class AudioDecoderPcm16BTest : public AudioDecoderTest { codec_input_rate_hz_ = 16000; frame_size_ = 20 * codec_input_rate_hz_ / 1000; data_length_ = 10 * frame_size_; - decoder_ = new AudioDecoderPcm16B(1); + decoder_ = new AudioDecoderPcm16B(codec_input_rate_hz_, 1); assert(decoder_); AudioEncoderPcm16B::Config config; config.sample_rate_hz = codec_input_rate_hz_; @@ -370,7 +370,7 @@ class AudioDecoderIsacFloatTest : public AudioDecoderTest { config.frame_size_ms = 1000 * static_cast(frame_size_) / codec_input_rate_hz_; audio_encoder_.reset(new AudioEncoderIsac(config)); - decoder_ = new AudioDecoderIsac(); + decoder_ = new AudioDecoderIsac(codec_input_rate_hz_); } }; @@ -387,7 +387,7 @@ class AudioDecoderIsacSwbTest : public AudioDecoderTest { config.frame_size_ms = 1000 * static_cast(frame_size_) / codec_input_rate_hz_; audio_encoder_.reset(new AudioEncoderIsac(config)); - decoder_ = new AudioDecoderIsac(); + decoder_ = new AudioDecoderIsac(codec_input_rate_hz_); } }; @@ -404,7 +404,7 @@ class AudioDecoderIsacFixTest : public AudioDecoderTest { config.frame_size_ms = 1000 * static_cast(frame_size_) / codec_input_rate_hz_; audio_encoder_.reset(new AudioEncoderIsacFix(config)); - decoder_ = new AudioDecoderIsacFix(); + decoder_ = new AudioDecoderIsacFix(codec_input_rate_hz_); } };