Opus implementation of the AudioEncoderFactoryTemplate API

This was previously reverted, because external projects were using the
internal webrtc::AudioEncoderOpus class and broke when it was renamed.
This re-land avoids renaming it immediately, to give those projects
time to adapt. It also has to revert some of the changes I had made to the
Config struct, since that was also used by the same external projects.

BUG=webrtc:7831

Review-Url: https://codereview.webrtc.org/2948483002
Cr-Commit-Position: refs/heads/master@{#18852}
diff --git a/webrtc/api/DEPS b/webrtc/api/DEPS
index e48b568..b0493fa 100644
--- a/webrtc/api/DEPS
+++ b/webrtc/api/DEPS
@@ -21,6 +21,13 @@
     "+webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h",
   ],
 
+  # Needed because AudioEncoderOpus is in the wrong place for
+  # backwards compatibilty reasons. See
+  # https://bugs.chromium.org/p/webrtc/issues/detail?id=7847
+  "audio_encoder_opus\.h": [
+    "+webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h",
+  ],
+
   # We allow .cc files in webrtc/api/ to #include a bunch of stuff
   # that's off-limits for the .h files. That's because .h files leak
   # their #includes to whoever's #including them, but .cc files do not
diff --git a/webrtc/api/audio_codecs/opus/BUILD.gn b/webrtc/api/audio_codecs/opus/BUILD.gn
new file mode 100644
index 0000000..b82f496
--- /dev/null
+++ b/webrtc/api/audio_codecs/opus/BUILD.gn
@@ -0,0 +1,42 @@
+# 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.
+
+import("../../../webrtc.gni")
+if (is_android) {
+  import("//build/config/android/config.gni")
+  import("//build/config/android/rules.gni")
+}
+
+rtc_static_library("audio_encoder_opus_config") {
+  sources = [
+    "audio_encoder_opus_config.cc",
+    "audio_encoder_opus_config.h",
+  ]
+  deps = [
+    "../../../base:rtc_base_approved",
+  ]
+  defines = []
+  if (rtc_opus_variable_complexity) {
+    defines += [ "WEBRTC_OPUS_VARIABLE_COMPLEXITY=1" ]
+  } else {
+    defines += [ "WEBRTC_OPUS_VARIABLE_COMPLEXITY=0" ]
+  }
+}
+
+rtc_source_set("audio_encoder_opus") {
+  sources = [
+    "audio_encoder_opus.h",
+  ]
+  deps = [
+    ":audio_encoder_opus_config",
+    "..:audio_codecs_api",
+    "../../../base:protobuf_utils",  # TODO(kwiberg): Why is this needed?
+    "../../../base:rtc_base_approved",
+    "../../../modules/audio_coding:webrtc_opus",
+  ]
+}
diff --git a/webrtc/api/audio_codecs/opus/audio_encoder_opus.h b/webrtc/api/audio_codecs/opus/audio_encoder_opus.h
new file mode 100644
index 0000000..4763f44
--- /dev/null
+++ b/webrtc/api/audio_codecs/opus/audio_encoder_opus.h
@@ -0,0 +1,40 @@
+/*
+ *  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_ENCODER_OPUS_H_
+#define WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_H_
+
+#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h"
+
+namespace webrtc {
+
+// Opus encoder API for use as a template parameter to
+// CreateAudioEncoderFactory<...>().
+//
+// NOTE: At the moment, this struct actually resides in another file. This is a
+// temporary backwards compatibility hack; see
+// https://bugs.chromium.org/p/webrtc/issues/detail?id=7847
+//
+// NOTE: This struct is still under development and may change without notice.
+/*
+struct AudioEncoderOpus {
+  static rtc::Optional<AudioEncoderOpusConfig> SdpToConfig(
+      const SdpAudioFormat& audio_format);
+  static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs);
+  static AudioCodecInfo QueryAudioEncoder(const AudioEncoderOpusConfig& config);
+  static std::unique_ptr<AudioEncoder> MakeAudioEncoder(
+      const AudioEncoderOpusConfig&,
+      int payload_type);
+};
+*/
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_H_
diff --git a/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.cc b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.cc
new file mode 100644
index 0000000..7d29883
--- /dev/null
+++ b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.cc
@@ -0,0 +1,70 @@
+/*
+ *  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_encoder_opus_config.h"
+
+namespace webrtc {
+
+namespace {
+
+#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM)
+// If we are on Android, iOS and/or ARM, use a lower complexity setting by
+// default, to save encoder complexity.
+constexpr int kDefaultComplexity = 5;
+#else
+constexpr int kDefaultComplexity = 9;
+#endif
+
+constexpr int kDefaultLowRateComplexity =
+    WEBRTC_OPUS_VARIABLE_COMPLEXITY ? 9 : kDefaultComplexity;
+
+}  // namespace
+
+constexpr int AudioEncoderOpusConfig::kDefaultFrameSizeMs;
+constexpr int AudioEncoderOpusConfig::kMinBitrateBps;
+constexpr int AudioEncoderOpusConfig::kMaxBitrateBps;
+
+AudioEncoderOpusConfig::AudioEncoderOpusConfig()
+    : frame_size_ms(kDefaultFrameSizeMs),
+      num_channels(1),
+      application(ApplicationMode::kVoip),
+      bitrate_bps(32000),
+      fec_enabled(false),
+      cbr_enabled(false),
+      max_playback_rate_hz(48000),
+      complexity(kDefaultComplexity),
+      low_rate_complexity(kDefaultLowRateComplexity),
+      complexity_threshold_bps(12500),
+      complexity_threshold_window_bps(1500),
+      dtx_enabled(false),
+      uplink_bandwidth_update_interval_ms(200),
+      payload_type(-1) {}
+AudioEncoderOpusConfig::AudioEncoderOpusConfig(const AudioEncoderOpusConfig&) =
+    default;
+AudioEncoderOpusConfig::~AudioEncoderOpusConfig() = default;
+AudioEncoderOpusConfig& AudioEncoderOpusConfig::operator=(
+    const AudioEncoderOpusConfig&) = default;
+
+bool AudioEncoderOpusConfig::IsOk() const {
+  if (frame_size_ms <= 0 || frame_size_ms % 10 != 0)
+    return false;
+  if (num_channels != 1 && num_channels != 2)
+    return false;
+  if (!bitrate_bps)
+    return false;
+  if (*bitrate_bps < kMinBitrateBps || *bitrate_bps > kMaxBitrateBps)
+    return false;
+  if (complexity < 0 || complexity > 10)
+    return false;
+  if (low_rate_complexity < 0 || low_rate_complexity > 10)
+    return false;
+  return true;
+}
+}  // namespace webrtc
diff --git a/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h
new file mode 100644
index 0000000..bd25b54
--- /dev/null
+++ b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h
@@ -0,0 +1,73 @@
+/*
+ *  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_ENCODER_OPUS_CONFIG_H_
+#define WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_CONFIG_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "webrtc/base/optional.h"
+
+namespace webrtc {
+
+// NOTE: This struct is still under development and may change without notice.
+struct AudioEncoderOpusConfig {
+  static constexpr int kDefaultFrameSizeMs = 20;
+
+  // Opus API allows a min bitrate of 500bps, but Opus documentation suggests
+  // bitrate should be in the range of 6000 to 510000, inclusive.
+  static constexpr int kMinBitrateBps = 6000;
+  static constexpr int kMaxBitrateBps = 510000;
+
+  AudioEncoderOpusConfig();
+  AudioEncoderOpusConfig(const AudioEncoderOpusConfig&);
+  ~AudioEncoderOpusConfig();
+  AudioEncoderOpusConfig& operator=(const AudioEncoderOpusConfig&);
+
+  bool IsOk() const;  // Checks if the values are currently OK.
+
+  int frame_size_ms;
+  size_t num_channels;
+  enum class ApplicationMode { kVoip, kAudio };
+  ApplicationMode application;
+
+  // NOTE: This member must always be set.
+  // TODO(kwiberg): Turn it into just an int.
+  rtc::Optional<int> bitrate_bps;
+
+  bool fec_enabled;
+  bool cbr_enabled;
+  int max_playback_rate_hz;
+
+  // |complexity| is used when the bitrate goes above
+  // |complexity_threshold_bps| + |complexity_threshold_window_bps|;
+  // |low_rate_complexity| is used when the bitrate falls below
+  // |complexity_threshold_bps| - |complexity_threshold_window_bps|. In the
+  // interval in the middle, we keep using the most recent of the two
+  // complexity settings.
+  int complexity;
+  int low_rate_complexity;
+  int complexity_threshold_bps;
+  int complexity_threshold_window_bps;
+
+  bool dtx_enabled;
+  std::vector<int> supported_frame_lengths_ms;
+  int uplink_bandwidth_update_interval_ms;
+
+  // NOTE: This member isn't necessary, and will soon go away. See
+  // https://bugs.chromium.org/p/webrtc/issues/detail?id=7847
+  int payload_type;
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_CONFIG_H_
diff --git a/webrtc/api/audio_codecs/test/BUILD.gn b/webrtc/api/audio_codecs/test/BUILD.gn
index 38ca736..685726f 100644
--- a/webrtc/api/audio_codecs/test/BUILD.gn
+++ b/webrtc/api/audio_codecs/test/BUILD.gn
@@ -21,6 +21,7 @@
     ]
     deps = [
       "..:audio_codecs_api",
+      "../../../base:protobuf_utils",  # TODO(kwiberg): Why is this needed?
       "../../../base:rtc_base_approved",
       "../../../test:audio_codec_mocks",
       "../../../test:test_support",
@@ -28,6 +29,7 @@
       "../g722:audio_encoder_g722",
       "../ilbc:audio_decoder_ilbc",
       "../ilbc:audio_encoder_ilbc",
+      "../opus:audio_encoder_opus",
       "//testing/gmock",
     ]
   }
diff --git a/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc b/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc
index c3c07c6..d08e7aa 100644
--- a/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc
+++ b/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc
@@ -11,6 +11,7 @@
 #include "webrtc/api/audio_codecs/audio_encoder_factory_template.h"
 #include "webrtc/api/audio_codecs/g722/audio_encoder_g722.h"
 #include "webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.h"
+#include "webrtc/api/audio_codecs/opus/audio_encoder_opus.h"
 #include "webrtc/base/ptr_util.h"
 #include "webrtc/test/gmock.h"
 #include "webrtc/test/gtest.h"
@@ -149,4 +150,26 @@
   EXPECT_EQ(8000, enc->SampleRateHz());
 }
 
+TEST(AudioEncoderFactoryTemplateTest, Opus) {
+  auto factory = CreateAudioEncoderFactory<AudioEncoderOpus>();
+  AudioCodecInfo info = {48000, 1, 32000, 6000, 510000};
+  info.allow_comfort_noise = false;
+  info.supports_network_adaption = true;
+  EXPECT_THAT(
+      factory->GetSupportedEncoders(),
+      testing::ElementsAre(AudioCodecSpec{
+          {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}},
+          info}));
+  EXPECT_EQ(rtc::Optional<AudioCodecInfo>(),
+            factory->QueryAudioEncoder({"foo", 8000, 1}));
+  EXPECT_EQ(
+      rtc::Optional<AudioCodecInfo>(info),
+      factory->QueryAudioEncoder(
+          {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}}));
+  EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"bar", 16000, 1}));
+  auto enc = factory->MakeAudioEncoder(17, {"opus", 48000, 2});
+  ASSERT_NE(nullptr, enc);
+  EXPECT_EQ(48000, enc->SampleRateHz());
+}
+
 }  // namespace webrtc