diff --git a/webrtc/api/audio_codecs/opus/BUILD.gn b/webrtc/api/audio_codecs/opus/BUILD.gn index b82f496a4a..c7f7ac8201 100644 --- a/webrtc/api/audio_codecs/opus/BUILD.gn +++ b/webrtc/api/audio_codecs/opus/BUILD.gn @@ -40,3 +40,16 @@ rtc_source_set("audio_encoder_opus") { "../../../modules/audio_coding:webrtc_opus", ] } + +rtc_static_library("audio_decoder_opus") { + sources = [ + "audio_decoder_opus.cc", + "audio_decoder_opus.h", + ] + deps = [ + "..:audio_codecs_api", + "../../..:webrtc_common", + "../../../base:rtc_base_approved", + "../../../modules/audio_coding:webrtc_opus", + ] +} diff --git a/webrtc/api/audio_codecs/opus/audio_decoder_opus.cc b/webrtc/api/audio_codecs/opus/audio_decoder_opus.cc new file mode 100644 index 0000000000..98f4c0ed27 --- /dev/null +++ b/webrtc/api/audio_codecs/opus/audio_decoder_opus.cc @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/api/audio_codecs/opus/audio_decoder_opus.h" + +#include +#include +#include + +#include "webrtc/base/ptr_util.h" +#include "webrtc/common_types.h" +#include "webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h" + +namespace webrtc { + +rtc::Optional AudioDecoderOpus::SdpToConfig( + const SdpAudioFormat& format) { + const rtc::Optional num_channels = [&] { + auto stereo = format.parameters.find("stereo"); + if (stereo != format.parameters.end()) { + if (stereo->second == "0") { + return rtc::Optional(1); + } else if (stereo->second == "1") { + return rtc::Optional(2); + } else { + return rtc::Optional(); // Bad stereo parameter. + } + } + return rtc::Optional(1); // Default to mono. + }(); + if (STR_CASE_CMP(format.name.c_str(), "opus") == 0 && + format.clockrate_hz == 48000 && format.num_channels == 2 && + num_channels) { + return rtc::Optional(Config{*num_channels}); + } else { + return rtc::Optional(); + } +} + +void AudioDecoderOpus::AppendSupportedDecoders( + std::vector* specs) { + AudioCodecInfo opus_info{48000, 1, 64000, 6000, 510000}; + opus_info.allow_comfort_noise = false; + opus_info.supports_network_adaption = true; + SdpAudioFormat opus_format( + {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}}); + specs->push_back({std::move(opus_format), std::move(opus_info)}); +} + +std::unique_ptr AudioDecoderOpus::MakeAudioDecoder( + Config config) { + return rtc::MakeUnique(config.num_channels); +} + +} // namespace webrtc diff --git a/webrtc/api/audio_codecs/opus/audio_decoder_opus.h b/webrtc/api/audio_codecs/opus/audio_decoder_opus.h new file mode 100644 index 0000000000..c2868bd935 --- /dev/null +++ b/webrtc/api/audio_codecs/opus/audio_decoder_opus.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_DECODER_OPUS_H_ +#define WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_DECODER_OPUS_H_ + +#include +#include + +#include "webrtc/api/audio_codecs/audio_decoder.h" +#include "webrtc/api/audio_codecs/audio_format.h" +#include "webrtc/base/optional.h" + +namespace webrtc { + +// Opus decoder API for use as a template parameter to +// CreateAudioDecoderFactory<...>(). +// +// NOTE: This struct is still under development and may change without notice. +struct AudioDecoderOpus { + struct Config { + int num_channels; + }; + static rtc::Optional SdpToConfig(const SdpAudioFormat& audio_format); + static void AppendSupportedDecoders(std::vector* specs); + static std::unique_ptr MakeAudioDecoder(Config config); +}; + +} // namespace webrtc + +#endif // WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_DECODER_OPUS_H_ diff --git a/webrtc/api/audio_codecs/test/BUILD.gn b/webrtc/api/audio_codecs/test/BUILD.gn index 685726fde8..32cef2d5cb 100644 --- a/webrtc/api/audio_codecs/test/BUILD.gn +++ b/webrtc/api/audio_codecs/test/BUILD.gn @@ -29,6 +29,7 @@ if (rtc_include_tests) { "../g722:audio_encoder_g722", "../ilbc:audio_decoder_ilbc", "../ilbc:audio_encoder_ilbc", + "../opus:audio_decoder_opus", "../opus:audio_encoder_opus", "//testing/gmock", ] diff --git a/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc b/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc index 283a5f5e67..04eef27fc8 100644 --- a/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc +++ b/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc @@ -11,6 +11,7 @@ #include "webrtc/api/audio_codecs/audio_decoder_factory_template.h" #include "webrtc/api/audio_codecs/g722/audio_decoder_g722.h" #include "webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.h" +#include "webrtc/api/audio_codecs/opus/audio_decoder_opus.h" #include "webrtc/base/ptr_util.h" #include "webrtc/test/gmock.h" #include "webrtc/test/gtest.h" @@ -145,4 +146,21 @@ TEST(AudioDecoderFactoryTemplateTest, Ilbc) { EXPECT_EQ(8000, dec->SampleRateHz()); } +TEST(AudioDecoderFactoryTemplateTest, Opus) { + auto factory = CreateAudioDecoderFactory(); + AudioCodecInfo opus_info{48000, 1, 64000, 6000, 510000}; + opus_info.allow_comfort_noise = false; + opus_info.supports_network_adaption = true; + const SdpAudioFormat opus_format( + {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}}); + EXPECT_THAT(factory->GetSupportedDecoders(), + testing::ElementsAre(AudioCodecSpec{opus_format, opus_info})); + EXPECT_FALSE(factory->IsSupportedDecoder({"opus", 48000, 1})); + EXPECT_TRUE(factory->IsSupportedDecoder({"opus", 48000, 2})); + EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"bar", 16000, 1})); + auto dec = factory->MakeAudioDecoder({"opus", 48000, 2}); + ASSERT_NE(nullptr, dec); + EXPECT_EQ(48000, dec->SampleRateHz()); +} + } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_internal.cc b/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_internal.cc index ce7ec3d8f5..8d8025718a 100644 --- a/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_internal.cc +++ b/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_internal.cc @@ -162,7 +162,7 @@ NamedDecoderConstructor decoder_constructors[] = { if (format.clockrate_hz == 48000 && format.num_channels == 2 && num_channels) { if (out) { - out->reset(new AudioDecoderOpus(*num_channels)); + out->reset(new AudioDecoderOpusImpl(*num_channels)); } return true; } else { 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 b6d8a3a1db..28a7b1090a 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.cc +++ b/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.cc @@ -19,7 +19,7 @@ namespace webrtc { namespace { class OpusFrame : public AudioDecoder::EncodedAudioFrame { public: - OpusFrame(AudioDecoderOpus* decoder, + OpusFrame(AudioDecoderOpusImpl* decoder, rtc::Buffer&& payload, bool is_primary_payload) : decoder_(decoder), @@ -57,25 +57,25 @@ class OpusFrame : public AudioDecoder::EncodedAudioFrame { } private: - AudioDecoderOpus* const decoder_; + AudioDecoderOpusImpl* const decoder_; const rtc::Buffer payload_; const bool is_primary_payload_; }; } // namespace -AudioDecoderOpus::AudioDecoderOpus(size_t num_channels) +AudioDecoderOpusImpl::AudioDecoderOpusImpl(size_t num_channels) : channels_(num_channels) { RTC_DCHECK(num_channels == 1 || num_channels == 2); WebRtcOpus_DecoderCreate(&dec_state_, channels_); WebRtcOpus_DecoderInit(dec_state_); } -AudioDecoderOpus::~AudioDecoderOpus() { +AudioDecoderOpusImpl::~AudioDecoderOpusImpl() { WebRtcOpus_DecoderFree(dec_state_); } -std::vector AudioDecoderOpus::ParsePayload( +std::vector AudioDecoderOpusImpl::ParsePayload( rtc::Buffer&& payload, uint32_t timestamp) { std::vector results; @@ -95,11 +95,11 @@ std::vector AudioDecoderOpus::ParsePayload( return results; } -int AudioDecoderOpus::DecodeInternal(const uint8_t* encoded, - size_t encoded_len, - int sample_rate_hz, - int16_t* decoded, - SpeechType* speech_type) { +int AudioDecoderOpusImpl::DecodeInternal(const uint8_t* encoded, + size_t encoded_len, + int sample_rate_hz, + int16_t* decoded, + SpeechType* speech_type) { RTC_DCHECK_EQ(sample_rate_hz, 48000); int16_t temp_type = 1; // Default is speech. int ret = @@ -110,11 +110,11 @@ int AudioDecoderOpus::DecodeInternal(const uint8_t* encoded, return ret; } -int AudioDecoderOpus::DecodeRedundantInternal(const uint8_t* encoded, - size_t encoded_len, - int sample_rate_hz, - int16_t* decoded, - SpeechType* speech_type) { +int AudioDecoderOpusImpl::DecodeRedundantInternal(const uint8_t* encoded, + size_t encoded_len, + int sample_rate_hz, + int16_t* decoded, + SpeechType* speech_type) { if (!PacketHasFec(encoded, encoded_len)) { // This packet is a RED packet. return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded, @@ -131,17 +131,17 @@ int AudioDecoderOpus::DecodeRedundantInternal(const uint8_t* encoded, return ret; } -void AudioDecoderOpus::Reset() { +void AudioDecoderOpusImpl::Reset() { WebRtcOpus_DecoderInit(dec_state_); } -int AudioDecoderOpus::PacketDuration(const uint8_t* encoded, - size_t encoded_len) const { +int AudioDecoderOpusImpl::PacketDuration(const uint8_t* encoded, + size_t encoded_len) const { return WebRtcOpus_DurationEst(dec_state_, encoded, encoded_len); } -int AudioDecoderOpus::PacketDurationRedundant(const uint8_t* encoded, - size_t encoded_len) const { +int AudioDecoderOpusImpl::PacketDurationRedundant(const uint8_t* encoded, + size_t encoded_len) const { if (!PacketHasFec(encoded, encoded_len)) { // This packet is a RED packet. return PacketDuration(encoded, encoded_len); @@ -150,18 +150,18 @@ int AudioDecoderOpus::PacketDurationRedundant(const uint8_t* encoded, return WebRtcOpus_FecDurationEst(encoded, encoded_len); } -bool AudioDecoderOpus::PacketHasFec(const uint8_t* encoded, - size_t encoded_len) const { +bool AudioDecoderOpusImpl::PacketHasFec(const uint8_t* encoded, + size_t encoded_len) const { int fec; fec = WebRtcOpus_PacketHasFec(encoded, encoded_len); return (fec == 1); } -int AudioDecoderOpus::SampleRateHz() const { +int AudioDecoderOpusImpl::SampleRateHz() const { return 48000; } -size_t AudioDecoderOpus::Channels() const { +size_t AudioDecoderOpusImpl::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 e848f37466..dcdaf9281e 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h +++ b/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h @@ -17,10 +17,10 @@ namespace webrtc { -class AudioDecoderOpus final : public AudioDecoder { +class AudioDecoderOpusImpl final : public AudioDecoder { public: - explicit AudioDecoderOpus(size_t num_channels); - ~AudioDecoderOpus() override; + explicit AudioDecoderOpusImpl(size_t num_channels); + ~AudioDecoderOpusImpl() override; std::vector ParsePayload(rtc::Buffer&& payload, uint32_t timestamp) override; @@ -47,7 +47,7 @@ class AudioDecoderOpus final : public AudioDecoder { private: OpusDecInst* dec_state_; const size_t channels_; - RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoderOpus); + RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoderOpusImpl); }; } // namespace webrtc diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc index 1294f23b45..a34594a004 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc @@ -432,7 +432,7 @@ class AudioDecoderOpusTest : public AudioDecoderTest { codec_input_rate_hz_ = 48000; frame_size_ = 480; data_length_ = 10 * frame_size_; - decoder_ = new AudioDecoderOpus(1); + decoder_ = new AudioDecoderOpusImpl(1); AudioEncoderOpusConfig config; config.frame_size_ms = static_cast(frame_size_) / 48; config.application = AudioEncoderOpusConfig::ApplicationMode::kVoip; @@ -445,7 +445,7 @@ class AudioDecoderOpusStereoTest : public AudioDecoderOpusTest { AudioDecoderOpusStereoTest() : AudioDecoderOpusTest() { channels_ = 2; delete decoder_; - decoder_ = new AudioDecoderOpus(2); + decoder_ = new AudioDecoderOpusImpl(2); AudioEncoderOpusConfig config; config.frame_size_ms = static_cast(frame_size_) / 48; config.num_channels = 2; diff --git a/webrtc/test/fuzzers/audio_decoder_opus_fuzzer.cc b/webrtc/test/fuzzers/audio_decoder_opus_fuzzer.cc index ee9f591aca..23b65a6462 100644 --- a/webrtc/test/fuzzers/audio_decoder_opus_fuzzer.cc +++ b/webrtc/test/fuzzers/audio_decoder_opus_fuzzer.cc @@ -14,7 +14,7 @@ namespace webrtc { void FuzzOneInput(const uint8_t* data, size_t size) { const size_t channels = (size % 2) + 1; // 1 or 2 channels. - AudioDecoderOpus dec(channels); + AudioDecoderOpusImpl dec(channels); const int kSampleRateHz = 48000; const size_t kAllocatedOuputSizeSamples = kSampleRateHz / 10; // 100 ms. int16_t output[kAllocatedOuputSizeSamples]; diff --git a/webrtc/test/fuzzers/audio_decoder_opus_redundant_fuzzer.cc b/webrtc/test/fuzzers/audio_decoder_opus_redundant_fuzzer.cc index 48b8b25da3..e623301a7a 100644 --- a/webrtc/test/fuzzers/audio_decoder_opus_redundant_fuzzer.cc +++ b/webrtc/test/fuzzers/audio_decoder_opus_redundant_fuzzer.cc @@ -14,7 +14,7 @@ namespace webrtc { void FuzzOneInput(const uint8_t* data, size_t size) { const size_t channels = (size % 2) + 1; // 1 or 2 channels. - AudioDecoderOpus dec(channels); + AudioDecoderOpusImpl dec(channels); const int kSampleRateHz = 48000; const size_t kAllocatedOuputSizeSamples = kSampleRateHz / 10; // 100 ms. int16_t output[kAllocatedOuputSizeSamples];