Opus implementation of the AudioDecoderFactoryTemplate API
(This got reverted because of a problem with the Opus encoder parts.
Re-landing without changes.)
BUG=webrtc:7837
Review-Url: https://codereview.webrtc.org/2950453002
Cr-Commit-Position: refs/heads/master@{#18855}
diff --git a/webrtc/api/audio_codecs/opus/BUILD.gn b/webrtc/api/audio_codecs/opus/BUILD.gn
index b82f496..c7f7ac8 100644
--- a/webrtc/api/audio_codecs/opus/BUILD.gn
+++ b/webrtc/api/audio_codecs/opus/BUILD.gn
@@ -40,3 +40,16 @@
"../../../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 0000000..98f4c0e
--- /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 <memory>
+#include <utility>
+#include <vector>
+
+#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::Config> AudioDecoderOpus::SdpToConfig(
+ const SdpAudioFormat& format) {
+ const rtc::Optional<int> num_channels = [&] {
+ auto stereo = format.parameters.find("stereo");
+ if (stereo != format.parameters.end()) {
+ if (stereo->second == "0") {
+ return rtc::Optional<int>(1);
+ } else if (stereo->second == "1") {
+ return rtc::Optional<int>(2);
+ } else {
+ return rtc::Optional<int>(); // Bad stereo parameter.
+ }
+ }
+ return rtc::Optional<int>(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>(Config{*num_channels});
+ } else {
+ return rtc::Optional<Config>();
+ }
+}
+
+void AudioDecoderOpus::AppendSupportedDecoders(
+ std::vector<AudioCodecSpec>* 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<AudioDecoder> AudioDecoderOpus::MakeAudioDecoder(
+ Config config) {
+ return rtc::MakeUnique<AudioDecoderOpusImpl>(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 0000000..c2868bd
--- /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 <memory>
+#include <vector>
+
+#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<Config> SdpToConfig(const SdpAudioFormat& audio_format);
+ static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs);
+ static std::unique_ptr<AudioDecoder> 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 685726f..32cef2d 100644
--- a/webrtc/api/audio_codecs/test/BUILD.gn
+++ b/webrtc/api/audio_codecs/test/BUILD.gn
@@ -29,6 +29,7 @@
"../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 283a5f5..04eef27 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 @@
EXPECT_EQ(8000, dec->SampleRateHz());
}
+TEST(AudioDecoderFactoryTemplateTest, Opus) {
+ auto factory = CreateAudioDecoderFactory<AudioDecoderOpus>();
+ 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 ce7ec3d..8d80257 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 @@
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 b6d8a3a..28a7b10 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 {
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 @@
}
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<AudioDecoder::ParseResult> AudioDecoderOpus::ParsePayload(
+std::vector<AudioDecoder::ParseResult> AudioDecoderOpusImpl::ParsePayload(
rtc::Buffer&& payload,
uint32_t timestamp) {
std::vector<ParseResult> results;
@@ -95,11 +95,11 @@
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 @@
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 @@
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 @@
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 e848f37..dcdaf92 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<ParseResult> ParsePayload(rtc::Buffer&& payload,
uint32_t timestamp) override;
@@ -47,7 +47,7 @@
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 1294f23..a34594a 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 @@
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<int>(frame_size_) / 48;
config.application = AudioEncoderOpusConfig::ApplicationMode::kVoip;
@@ -445,7 +445,7 @@
AudioDecoderOpusStereoTest() : AudioDecoderOpusTest() {
channels_ = 2;
delete decoder_;
- decoder_ = new AudioDecoderOpus(2);
+ decoder_ = new AudioDecoderOpusImpl(2);
AudioEncoderOpusConfig config;
config.frame_size_ms = static_cast<int>(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 ee9f591..23b65a6 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 48b8b25..e623301 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];