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];