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
diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn
index 30460ba..1aa4031 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -829,6 +829,7 @@
     ":audio_network_adaptor",
     "../..:webrtc_common",
     "../../api/audio_codecs:audio_codecs_api",
+    "../../api/audio_codecs/opus:audio_encoder_opus_config",
     "../../base:protobuf_utils",
     "../../base:rtc_base_approved",
     "../../base:rtc_numerics",
@@ -840,11 +841,6 @@
   ]
 
   defines = audio_codec_defines
-  if (rtc_opus_variable_complexity) {
-    defines += [ "WEBRTC_OPUS_VARIABLE_COMPLEXITY=1" ]
-  } else {
-    defines += [ "WEBRTC_OPUS_VARIABLE_COMPLEXITY=0" ]
-  }
 
   if (rtc_build_opus) {
     public_deps += [ rtc_opus_dir ]
@@ -1485,6 +1481,7 @@
       ":neteq",
       ":neteq_tools",
       "../../api/audio_codecs:audio_codecs_api",
+      "../../api/audio_codecs/opus:audio_encoder_opus",
       "../../base:protobuf_utils",
       "../../common_audio",
       "../../test:test_main",
diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
index be32aef..9ebb63d 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
@@ -19,6 +19,7 @@
 #include "webrtc/base/logging.h"
 #include "webrtc/base/numerics/exp_filter.h"
 #include "webrtc/base/protobuf_utils.h"
+#include "webrtc/base/ptr_util.h"
 #include "webrtc/base/safe_conversions.h"
 #include "webrtc/base/safe_minmax.h"
 #include "webrtc/base/string_to_number.h"
@@ -48,11 +49,6 @@
 constexpr int kOpusBitrateWbBps = 20000;
 constexpr int kOpusBitrateFbBps = 32000;
 
-// Opus API allows a min bitrate of 500bps, but Opus documentation suggests
-// bitrate should be in the range of 6000 to 510000, inclusive.
-constexpr int kOpusMinBitrateBps = 6000;
-constexpr int kOpusMaxBitrateBps = 510000;
-
 constexpr int kSampleRateHz = 48000;
 constexpr int kDefaultMaxPlaybackRate = 48000;
 
@@ -133,8 +129,8 @@
       return kOpusBitrateFbBps * rtc::dchecked_cast<int>(num_channels);
     }
   }();
-  RTC_DCHECK_GE(bitrate, kOpusMinBitrateBps);
-  RTC_DCHECK_LE(bitrate, kOpusMaxBitrateBps);
+  RTC_DCHECK_GE(bitrate, AudioEncoderOpusConfig::kMinBitrateBps);
+  RTC_DCHECK_LE(bitrate, AudioEncoderOpusConfig::kMaxBitrateBps);
   return bitrate;
 }
 
@@ -150,7 +146,8 @@
     const auto bitrate = rtc::StringToNumber<int>(*bitrate_param);
     if (bitrate) {
       const int chosen_bitrate =
-          std::max(kOpusMinBitrateBps, std::min(*bitrate, kOpusMaxBitrateBps));
+          std::max(AudioEncoderOpusConfig::kMinBitrateBps,
+                   std::min(*bitrate, AudioEncoderOpusConfig::kMaxBitrateBps));
       if (bitrate != chosen_bitrate) {
         LOG(LS_WARNING) << "Invalid maxaveragebitrate " << *bitrate
                         << " clamped to " << chosen_bitrate;
@@ -195,7 +192,7 @@
     return *(std::end(kOpusSupportedFrameLengths) - 1);
   }
 
-  return AudioEncoderOpus::Config::kDefaultFrameSizeMs;
+  return AudioEncoderOpusConfig::kDefaultFrameSizeMs;
 }
 
 void FindSupportedFrameLengths(int min_frame_length_ms,
@@ -211,8 +208,39 @@
   RTC_DCHECK(std::is_sorted(out->begin(), out->end()));
 }
 
+int GetBitrateBps(const AudioEncoderOpusConfig& config) {
+  RTC_DCHECK(config.IsOk());
+  return *config.bitrate_bps;
+}
+
 }  // namespace
 
+void AudioEncoderOpus::AppendSupportedEncoders(
+    std::vector<AudioCodecSpec>* specs) {
+  const SdpAudioFormat fmt = {
+      "opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}};
+  const AudioCodecInfo info = QueryAudioEncoder(*SdpToConfig(fmt));
+  specs->push_back({fmt, info});
+}
+
+AudioCodecInfo AudioEncoderOpus::QueryAudioEncoder(
+    const AudioEncoderOpusConfig& config) {
+  RTC_DCHECK(config.IsOk());
+  AudioCodecInfo info(48000, config.num_channels, *config.bitrate_bps,
+                      AudioEncoderOpusConfig::kMinBitrateBps,
+                      AudioEncoderOpusConfig::kMaxBitrateBps);
+  info.allow_comfort_noise = false;
+  info.supports_network_adaption = true;
+  return info;
+}
+
+std::unique_ptr<AudioEncoder> AudioEncoderOpus::MakeAudioEncoder(
+    const AudioEncoderOpusConfig& config,
+    int payload_type) {
+  RTC_DCHECK(config.IsOk());
+  return rtc::MakeUnique<AudioEncoderOpus>(config, payload_type);
+}
+
 rtc::Optional<AudioCodecInfo> AudioEncoderOpus::QueryAudioEncoder(
     const SdpAudioFormat& format) {
   if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0 &&
@@ -221,8 +249,9 @@
     const int bitrate =
         CalculateBitrate(GetMaxPlaybackRate(format), num_channels,
                          GetFormatParameter(format, "maxaveragebitrate"));
-    AudioCodecInfo info(48000, num_channels, bitrate, kOpusMinBitrateBps,
-                        kOpusMaxBitrateBps);
+    AudioCodecInfo info(48000, num_channels, bitrate,
+                        AudioEncoderOpusConfig::kMinBitrateBps,
+                        AudioEncoderOpusConfig::kMaxBitrateBps);
     info.allow_comfort_noise = false;
     info.supports_network_adaption = true;
 
@@ -231,27 +260,36 @@
   return rtc::Optional<AudioCodecInfo>();
 }
 
-AudioEncoderOpus::Config AudioEncoderOpus::CreateConfig(
+AudioEncoderOpusConfig AudioEncoderOpus::CreateConfig(
+    int payload_type,
+    const SdpAudioFormat& format) {
+  auto opt_config = SdpToConfig(format);
+  RTC_CHECK(opt_config);
+  opt_config->payload_type = payload_type;
+  return *opt_config;
+}
+
+AudioEncoderOpusConfig AudioEncoderOpus::CreateConfig(
     const CodecInst& codec_inst) {
-  AudioEncoderOpus::Config config;
+  AudioEncoderOpusConfig config;
   config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48);
   config.num_channels = codec_inst.channels;
   config.bitrate_bps = rtc::Optional<int>(codec_inst.rate);
-  config.payload_type = codec_inst.pltype;
-  config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip
-                                                : AudioEncoderOpus::kAudio;
+  config.application = config.num_channels == 1
+                           ? AudioEncoderOpusConfig::ApplicationMode::kVoip
+                           : AudioEncoderOpusConfig::ApplicationMode::kAudio;
   config.supported_frame_lengths_ms.push_back(config.frame_size_ms);
-#if WEBRTC_OPUS_VARIABLE_COMPLEXITY
-  config.low_rate_complexity = 9;
-#endif
   return config;
 }
 
-AudioEncoderOpus::Config AudioEncoderOpus::CreateConfig(
-    int payload_type,
+rtc::Optional<AudioEncoderOpusConfig> AudioEncoderOpus::SdpToConfig(
     const SdpAudioFormat& format) {
-  AudioEncoderOpus::Config config;
+  if (STR_CASE_CMP(format.name.c_str(), "opus") != 0 ||
+      format.clockrate_hz != 48000 || format.num_channels != 2) {
+    return rtc::Optional<AudioEncoderOpusConfig>();
+  }
 
+  AudioEncoderOpusConfig config;
   config.num_channels = GetChannelCount(format);
   config.frame_size_ms = GetFrameSizeMs(format);
   config.max_playback_rate_hz = GetMaxPlaybackRate(format);
@@ -261,16 +299,14 @@
   config.bitrate_bps = rtc::Optional<int>(
       CalculateBitrate(config.max_playback_rate_hz, config.num_channels,
                        GetFormatParameter(format, "maxaveragebitrate")));
-  config.payload_type = payload_type;
-  config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip
-                                                : AudioEncoderOpus::kAudio;
-#if WEBRTC_OPUS_VARIABLE_COMPLEXITY
-  config.low_rate_complexity = 9;
-#endif
+  config.application = config.num_channels == 1
+                           ? AudioEncoderOpusConfig::ApplicationMode::kVoip
+                           : AudioEncoderOpusConfig::ApplicationMode::kAudio;
 
   constexpr int kMinANAFrameLength = kANASupportedFrameLengths[0];
   constexpr int kMaxANAFrameLength =
       kANASupportedFrameLengths[arraysize(kANASupportedFrameLengths) - 1];
+
   // For now, minptime and maxptime are only used with ANA. If ptime is outside
   // of this range, it will get adjusted once ANA takes hold. Ideally, we'd know
   // if ANA was to be used when setting up the config, and adjust accordingly.
@@ -281,7 +317,25 @@
 
   FindSupportedFrameLengths(min_frame_length_ms, max_frame_length_ms,
                             &config.supported_frame_lengths_ms);
-  return config;
+  RTC_DCHECK(config.IsOk());
+  return rtc::Optional<AudioEncoderOpusConfig>(config);
+}
+
+rtc::Optional<int> AudioEncoderOpus::GetNewComplexity(
+    const AudioEncoderOpusConfig& config) {
+  RTC_DCHECK(config.IsOk());
+  const int bitrate_bps = GetBitrateBps(config);
+  if (bitrate_bps >= config.complexity_threshold_bps -
+                         config.complexity_threshold_window_bps &&
+      bitrate_bps <= config.complexity_threshold_bps +
+                         config.complexity_threshold_window_bps) {
+    // Within the hysteresis window; make no change.
+    return rtc::Optional<int>();
+  } else {
+    return rtc::Optional<int>(bitrate_bps <= config.complexity_threshold_bps
+                                  ? config.low_rate_complexity
+                                  : config.complexity);
+  }
 }
 
 class AudioEncoderOpus::PacketLossFractionSmoother {
@@ -311,58 +365,16 @@
   rtc::ExpFilter smoother_;
 };
 
-AudioEncoderOpus::Config::Config() {
-#if WEBRTC_OPUS_VARIABLE_COMPLEXITY
-  low_rate_complexity = 9;
-#endif
-}
-AudioEncoderOpus::Config::Config(const Config&) = default;
-AudioEncoderOpus::Config::~Config() = default;
-auto AudioEncoderOpus::Config::operator=(const Config&) -> Config& = default;
-
-bool AudioEncoderOpus::Config::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 &&
-      (*bitrate_bps < kOpusMinBitrateBps || *bitrate_bps > kOpusMaxBitrateBps))
-    return false;
-  if (complexity < 0 || complexity > 10)
-    return false;
-  if (low_rate_complexity < 0 || low_rate_complexity > 10)
-    return false;
-  return true;
-}
-
-int AudioEncoderOpus::Config::GetBitrateBps() const {
-  RTC_DCHECK(IsOk());
-  if (bitrate_bps)
-    return *bitrate_bps;  // Explicitly set value.
-  else
-    return num_channels == 1 ? 32000 : 64000;  // Default value.
-}
-
-rtc::Optional<int> AudioEncoderOpus::Config::GetNewComplexity() const {
-  RTC_DCHECK(IsOk());
-  const int bitrate_bps = GetBitrateBps();
-  if (bitrate_bps >=
-          complexity_threshold_bps - complexity_threshold_window_bps &&
-      bitrate_bps <=
-          complexity_threshold_bps + complexity_threshold_window_bps) {
-    // Within the hysteresis window; make no change.
-    return rtc::Optional<int>();
-  }
-  return bitrate_bps <= complexity_threshold_bps
-             ? rtc::Optional<int>(low_rate_complexity)
-             : rtc::Optional<int>(complexity);
-}
+AudioEncoderOpus::AudioEncoderOpus(const AudioEncoderOpusConfig& config)
+    : AudioEncoderOpus(config, config.payload_type) {}
 
 AudioEncoderOpus::AudioEncoderOpus(
-    const Config& config,
+    const AudioEncoderOpusConfig& config,
+    int payload_type,
     AudioNetworkAdaptorCreator&& audio_network_adaptor_creator,
     std::unique_ptr<SmoothingFilter> bitrate_smoother)
-    : send_side_bwe_with_overhead_(webrtc::field_trial::IsEnabled(
+    : payload_type_(payload_type),
+      send_side_bwe_with_overhead_(webrtc::field_trial::IsEnabled(
           "WebRTC-SendSideBwe-WithOverhead")),
       packet_loss_rate_(0.0),
       inst_(nullptr),
@@ -379,15 +391,21 @@
           ? std::move(bitrate_smoother) : std::unique_ptr<SmoothingFilter>(
               // We choose 5sec as initial time constant due to empirical data.
               new SmoothingFilterImpl(5000))) {
+  RTC_DCHECK(0 <= payload_type && payload_type <= 127);
+
+  // Sanity check of the redundant payload type field that we want to get rid
+  // of. See https://bugs.chromium.org/p/webrtc/issues/detail?id=7847
+  RTC_CHECK(config.payload_type == -1 || config.payload_type == payload_type);
+
   RTC_CHECK(RecreateEncoderInstance(config));
 }
 
 AudioEncoderOpus::AudioEncoderOpus(const CodecInst& codec_inst)
-    : AudioEncoderOpus(CreateConfig(codec_inst), nullptr) {}
+    : AudioEncoderOpus(CreateConfig(codec_inst), codec_inst.pltype) {}
 
 AudioEncoderOpus::AudioEncoderOpus(int payload_type,
                                    const SdpAudioFormat& format)
-    : AudioEncoderOpus(CreateConfig(payload_type, format), nullptr) {}
+    : AudioEncoderOpus(*SdpToConfig(format), payload_type) {}
 
 AudioEncoderOpus::~AudioEncoderOpus() {
   RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
@@ -410,7 +428,7 @@
 }
 
 int AudioEncoderOpus::GetTargetBitrate() const {
-  return config_.GetBitrateBps();
+  return GetBitrateBps(config_);
 }
 
 void AudioEncoderOpus::Reset() {
@@ -445,10 +463,10 @@
   auto conf = config_;
   switch (application) {
     case Application::kSpeech:
-      conf.application = AudioEncoderOpus::kVoip;
+      conf.application = AudioEncoderOpusConfig::ApplicationMode::kVoip;
       break;
     case Application::kAudio:
-      conf.application = AudioEncoderOpus::kAudio;
+      conf.application = AudioEncoderOpusConfig::ApplicationMode::kAudio;
       break;
   }
   return RecreateEncoderInstance(conf);
@@ -523,9 +541,10 @@
     }
     const int overhead_bps = static_cast<int>(
         *overhead_bytes_per_packet_ * 8 * 100 / Num10MsFramesInNextPacket());
-    SetTargetBitrate(std::min(
-        kOpusMaxBitrateBps,
-        std::max(kOpusMinBitrateBps, target_audio_bitrate_bps - overhead_bps)));
+    SetTargetBitrate(
+        std::min(AudioEncoderOpusConfig::kMaxBitrateBps,
+                 std::max(AudioEncoderOpusConfig::kMinBitrateBps,
+                          target_audio_bitrate_bps - overhead_bps)));
   } else {
     SetTargetBitrate(target_audio_bitrate_bps);
   }
@@ -597,7 +616,7 @@
   config_.frame_size_ms = next_frame_length_ms_;
 
   info.encoded_timestamp = first_timestamp_in_buffer_;
-  info.payload_type = config_.payload_type;
+  info.payload_type = payload_type_;
   info.send_even_if_empty = true;  // Allows Opus to send empty packets.
   info.speech = (info.encoded_bytes > 0);
   info.encoder_type = CodecType::kOpus;
@@ -616,7 +635,7 @@
   // Calculate the number of bytes we expect the encoder to produce,
   // then multiply by two to give a wide margin for error.
   const size_t bytes_per_millisecond =
-      static_cast<size_t>(config_.GetBitrateBps() / (1000 * 8) + 1);
+      static_cast<size_t>(GetBitrateBps(config_) / (1000 * 8) + 1);
   const size_t approx_encoded_bytes =
       Num10msFramesPerPacket() * 10 * bytes_per_millisecond;
   return 2 * approx_encoded_bytes;
@@ -625,7 +644,8 @@
 // If the given config is OK, recreate the Opus encoder instance with those
 // settings, save the config, and return true. Otherwise, do nothing and return
 // false.
-bool AudioEncoderOpus::RecreateEncoderInstance(const Config& config) {
+bool AudioEncoderOpus::RecreateEncoderInstance(
+    const AudioEncoderOpusConfig& config) {
   if (!config.IsOk())
     return false;
   config_ = config;
@@ -633,9 +653,13 @@
     RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
   input_buffer_.clear();
   input_buffer_.reserve(Num10msFramesPerPacket() * SamplesPer10msFrame());
-  RTC_CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, config.num_channels,
-                                           config.application));
-  RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config.GetBitrateBps()));
+  RTC_CHECK_EQ(0, WebRtcOpus_EncoderCreate(
+                      &inst_, config.num_channels,
+                      config.application ==
+                              AudioEncoderOpusConfig::ApplicationMode::kVoip
+                          ? 0
+                          : 1));
+  RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, GetBitrateBps(config)));
   if (config.fec_enabled) {
     RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_));
   } else {
@@ -645,7 +669,7 @@
       0, WebRtcOpus_SetMaxPlaybackRate(inst_, config.max_playback_rate_hz));
   // Use the default complexity if the start bitrate is within the hysteresis
   // window.
-  complexity_ = config.GetNewComplexity().value_or(config.complexity);
+  complexity_ = GetNewComplexity(config).value_or(config.complexity);
   RTC_CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, complexity_));
   if (config.dtx_enabled) {
     RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_));
@@ -692,10 +716,11 @@
 
 void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) {
   config_.bitrate_bps = rtc::Optional<int>(rtc::SafeClamp<int>(
-      bits_per_second, kOpusMinBitrateBps, kOpusMaxBitrateBps));
+      bits_per_second, AudioEncoderOpusConfig::kMinBitrateBps,
+      AudioEncoderOpusConfig::kMaxBitrateBps));
   RTC_DCHECK(config_.IsOk());
-  RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.GetBitrateBps()));
-  const auto new_complexity = config_.GetNewComplexity();
+  RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, GetBitrateBps(config_)));
+  const auto new_complexity = GetNewComplexity(config_);
   if (new_complexity && complexity_ != *new_complexity) {
     complexity_ = *new_complexity;
     RTC_CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, complexity_));
@@ -728,11 +753,11 @@
   AudioNetworkAdaptorImpl::Config config;
   config.event_log = event_log;
   return std::unique_ptr<AudioNetworkAdaptor>(new AudioNetworkAdaptorImpl(
-      config,
-      ControllerManagerImpl::Create(
-          config_string, NumChannels(), supported_frame_lengths_ms(),
-          kOpusMinBitrateBps, num_channels_to_encode_, next_frame_length_ms_,
-          GetTargetBitrate(), config_.fec_enabled, GetDtx())));
+      config, ControllerManagerImpl::Create(
+                  config_string, NumChannels(), supported_frame_lengths_ms(),
+                  AudioEncoderOpusConfig::kMinBitrateBps,
+                  num_channels_to_encode_, next_frame_length_ms_,
+                  GetTargetBitrate(), config_.fec_enabled, GetDtx())));
 }
 
 void AudioEncoderOpus::MaybeUpdateUplinkBandwidth() {
diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h
index a1a4d70..e50441b 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h
@@ -18,6 +18,7 @@
 
 #include "webrtc/api/audio_codecs/audio_encoder.h"
 #include "webrtc/api/audio_codecs/audio_format.h"
+#include "webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h"
 #include "webrtc/base/constructormagic.h"
 #include "webrtc/base/optional.h"
 #include "webrtc/base/protobuf_utils.h"
@@ -33,62 +34,42 @@
 
 class AudioEncoderOpus final : public AudioEncoder {
  public:
-  enum ApplicationMode {
-    kVoip = 0,
-    kAudio = 1,
-  };
+  static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs);
+  static AudioCodecInfo QueryAudioEncoder(const AudioEncoderOpusConfig& config);
+  static std::unique_ptr<AudioEncoder> MakeAudioEncoder(
+      const AudioEncoderOpusConfig&,
+      int payload_type);
 
-  struct Config {
-    Config();
-    Config(const Config&);
-    ~Config();
-    Config& operator=(const Config&);
+  // NOTE: This alias will soon go away. See
+  // https://bugs.chromium.org/p/webrtc/issues/detail?id=7847
+  using Config = AudioEncoderOpusConfig;
 
-    bool IsOk() const;
-    int GetBitrateBps() const;
-    // Returns empty if the current bitrate falls within the hysteresis window,
-    // defined by complexity_threshold_bps +/- complexity_threshold_window_bps.
-    // Otherwise, returns the current complexity depending on whether the
-    // current bitrate is above or below complexity_threshold_bps.
-    rtc::Optional<int> GetNewComplexity() const;
-
-    static constexpr int kDefaultFrameSizeMs = 20;
-    int frame_size_ms = kDefaultFrameSizeMs;
-    size_t num_channels = 1;
-    int payload_type = 120;
-    ApplicationMode application = kVoip;
-    rtc::Optional<int> bitrate_bps;  // Unset means to use default value.
-    bool fec_enabled = false;
-    bool cbr_enabled = false;
-    int max_playback_rate_hz = 48000;
-    int complexity = kDefaultComplexity;
-    // This value may change in the struct's constructor.
-    int low_rate_complexity = kDefaultComplexity;
-    // low_rate_complexity is used when the bitrate is below this threshold.
-    int complexity_threshold_bps = 12500;
-    int complexity_threshold_window_bps = 1500;
-    bool dtx_enabled = false;
-    std::vector<int> supported_frame_lengths_ms;
-    int uplink_bandwidth_update_interval_ms = 200;
-
-   private:
-#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 as
-    // default, to save encoder complexity.
-    static const int kDefaultComplexity = 5;
-#else
-    static const int kDefaultComplexity = 9;
-#endif
-  };
-
+  // NOTE: This function will soon go away. See
+  // https://bugs.chromium.org/p/webrtc/issues/detail?id=7847
   static Config CreateConfig(int payload_type, const SdpAudioFormat& format);
-  static Config CreateConfig(const CodecInst& codec_inst);
+
+  static AudioEncoderOpusConfig CreateConfig(const CodecInst& codec_inst);
+  static rtc::Optional<AudioEncoderOpusConfig> SdpToConfig(
+      const SdpAudioFormat& format);
+
+  // Returns empty if the current bitrate falls within the hysteresis window,
+  // defined by complexity_threshold_bps +/- complexity_threshold_window_bps.
+  // Otherwise, returns the current complexity depending on whether the
+  // current bitrate is above or below complexity_threshold_bps.
+  static rtc::Optional<int> GetNewComplexity(
+      const AudioEncoderOpusConfig& config);
 
   using AudioNetworkAdaptorCreator =
       std::function<std::unique_ptr<AudioNetworkAdaptor>(const std::string&,
                                                          RtcEventLog*)>;
+
+  // NOTE: This constructor will soon go away. See
+  // https://bugs.chromium.org/p/webrtc/issues/detail?id=7847
+  AudioEncoderOpus(const AudioEncoderOpusConfig& config);
+
   AudioEncoderOpus(
-      const Config& config,
+      const AudioEncoderOpusConfig& config,
+      int payload_type,
       AudioNetworkAdaptorCreator&& audio_network_adaptor_creator = nullptr,
       std::unique_ptr<SmoothingFilter> bitrate_smoother = nullptr);
 
@@ -110,9 +91,9 @@
   void Reset() override;
   bool SetFec(bool enable) override;
 
-  // Set Opus DTX. Once enabled, Opus stops transmission, when it detects voice
-  // being inactive. During that, it still sends 2 packets (one for content, one
-  // for signaling) about every 400 ms.
+  // Set Opus DTX. Once enabled, Opus stops transmission, when it detects
+  // voice being inactive. During that, it still sends 2 packets (one for
+  // content, one for signaling) about every 400 ms.
   bool SetDtx(bool enable) override;
   bool GetDtx() const override;
 
@@ -138,7 +119,9 @@
 
   // Getters for testing.
   float packet_loss_rate() const { return packet_loss_rate_; }
-  ApplicationMode application() const { return config_.application; }
+  AudioEncoderOpusConfig::ApplicationMode application() const {
+    return config_.application;
+  }
   bool fec_enabled() const { return config_.fec_enabled; }
   size_t num_channels_to_encode() const { return num_channels_to_encode_; }
   int next_frame_length_ms() const { return next_frame_length_ms_; }
@@ -154,7 +137,7 @@
   size_t Num10msFramesPerPacket() const;
   size_t SamplesPer10msFrame() const;
   size_t SufficientOutputBufferSize() const;
-  bool RecreateEncoderInstance(const Config& config);
+  bool RecreateEncoderInstance(const AudioEncoderOpusConfig& config);
   void SetFrameLength(int frame_length_ms);
   void SetNumChannelsToEncode(size_t num_channels_to_encode);
   void SetProjectedPacketLossRate(float fraction);
@@ -170,7 +153,8 @@
 
   void MaybeUpdateUplinkBandwidth();
 
-  Config config_;
+  AudioEncoderOpusConfig config_;
+  const int payload_type_;
   const bool send_side_bwe_with_overhead_;
   float packet_loss_rate_;
   std::vector<int16_t> input_buffer_;
diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
index 76574d6..ecaea5d 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
@@ -33,22 +33,22 @@
 const CodecInst kDefaultOpusSettings = {105, "opus", 48000, 960, 1, 32000};
 constexpr int64_t kInitialTimeUs = 12345678;
 
-AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) {
-  AudioEncoderOpus::Config config;
+AudioEncoderOpusConfig CreateConfig(const CodecInst& codec_inst) {
+  AudioEncoderOpusConfig config;
   config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48);
   config.num_channels = codec_inst.channels;
   config.bitrate_bps = rtc::Optional<int>(codec_inst.rate);
-  config.payload_type = codec_inst.pltype;
-  config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip
-                                                : AudioEncoderOpus::kAudio;
+  config.application = config.num_channels == 1
+                           ? AudioEncoderOpusConfig::ApplicationMode::kVoip
+                           : AudioEncoderOpusConfig::ApplicationMode::kAudio;
   config.supported_frame_lengths_ms.push_back(config.frame_size_ms);
   return config;
 }
 
-AudioEncoderOpus::Config CreateConfigWithParameters(
+AudioEncoderOpusConfig CreateConfigWithParameters(
     const SdpAudioFormat::Parameters& params) {
-  SdpAudioFormat format("opus", 48000, 2, params);
-  return AudioEncoderOpus::CreateConfig(0, format);
+  const SdpAudioFormat format("opus", 48000, 2, params);
+  return *AudioEncoderOpus::SdpToConfig(format);
 }
 
 struct AudioEncoderOpusStates {
@@ -56,7 +56,7 @@
   MockSmoothingFilter* mock_bitrate_smoother;
   std::unique_ptr<AudioEncoderOpus> encoder;
   std::unique_ptr<rtc::ScopedFakeClock> fake_clock;
-  AudioEncoderOpus::Config config;
+  AudioEncoderOpusConfig config;
 };
 
 AudioEncoderOpusStates CreateCodec(size_t num_channels) {
@@ -87,7 +87,8 @@
       new MockSmoothingFilter());
   states.mock_bitrate_smoother = bitrate_smoother.get();
 
-  states.encoder.reset(new AudioEncoderOpus(states.config, std::move(creator),
+  states.encoder.reset(new AudioEncoderOpus(states.config, codec_inst.pltype,
+                                            std::move(creator),
                                             std::move(bitrate_smoother)));
   return states;
 }
@@ -142,19 +143,22 @@
 
 TEST(AudioEncoderOpusTest, DefaultApplicationModeMono) {
   auto states = CreateCodec(1);
-  EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application());
+  EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip,
+            states.encoder->application());
 }
 
 TEST(AudioEncoderOpusTest, DefaultApplicationModeStereo) {
   auto states = CreateCodec(2);
-  EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application());
+  EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kAudio,
+            states.encoder->application());
 }
 
 TEST(AudioEncoderOpusTest, ChangeApplicationMode) {
   auto states = CreateCodec(2);
   EXPECT_TRUE(
       states.encoder->SetApplication(AudioEncoder::Application::kSpeech));
-  EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application());
+  EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip,
+            states.encoder->application());
 }
 
 TEST(AudioEncoderOpusTest, ResetWontChangeApplicationMode) {
@@ -163,17 +167,20 @@
   // Trigger a reset.
   states.encoder->Reset();
   // Verify that the mode is still kAudio.
-  EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application());
+  EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kAudio,
+            states.encoder->application());
 
   // Now change to kVoip.
   EXPECT_TRUE(
       states.encoder->SetApplication(AudioEncoder::Application::kSpeech));
-  EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application());
+  EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip,
+            states.encoder->application());
 
   // Trigger a reset again.
   states.encoder->Reset();
   // Verify that the mode is still kVoip.
-  EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application());
+  EXPECT_EQ(AudioEncoderOpusConfig::ApplicationMode::kVoip,
+            states.encoder->application());
 }
 
 TEST(AudioEncoderOpusTest, ToggleDtx) {
@@ -452,25 +459,25 @@
 
 // Verifies that the complexity adaptation in the config works as intended.
 TEST(AudioEncoderOpusTest, ConfigComplexityAdaptation) {
-  AudioEncoderOpus::Config config;
+  AudioEncoderOpusConfig config;
   config.low_rate_complexity = 8;
   config.complexity = 6;
 
   // Bitrate within hysteresis window. Expect empty output.
   config.bitrate_bps = rtc::Optional<int>(12500);
-  EXPECT_EQ(rtc::Optional<int>(), config.GetNewComplexity());
+  EXPECT_EQ(rtc::Optional<int>(), AudioEncoderOpus::GetNewComplexity(config));
 
   // Bitrate below hysteresis window. Expect higher complexity.
   config.bitrate_bps = rtc::Optional<int>(10999);
-  EXPECT_EQ(rtc::Optional<int>(8), config.GetNewComplexity());
+  EXPECT_EQ(rtc::Optional<int>(8), AudioEncoderOpus::GetNewComplexity(config));
 
   // Bitrate within hysteresis window. Expect empty output.
   config.bitrate_bps = rtc::Optional<int>(12500);
-  EXPECT_EQ(rtc::Optional<int>(), config.GetNewComplexity());
+  EXPECT_EQ(rtc::Optional<int>(), AudioEncoderOpus::GetNewComplexity(config));
 
   // Bitrate above hysteresis window. Expect lower complexity.
   config.bitrate_bps = rtc::Optional<int>(14001);
-  EXPECT_EQ(rtc::Optional<int>(6), config.GetNewComplexity());
+  EXPECT_EQ(rtc::Optional<int>(6), AudioEncoderOpus::GetNewComplexity(config));
 }
 
 TEST(AudioEncoderOpusTest, EmptyConfigDoesNotAffectEncoderSettings) {
@@ -552,84 +559,82 @@
 }
 
 TEST(AudioEncoderOpusTest, TestConfigDefaults) {
-  const AudioEncoderOpus::Config config =
-      AudioEncoderOpus::CreateConfig(0, {"opus", 48000, 2});
-
-  EXPECT_EQ(48000, config.max_playback_rate_hz);
-  EXPECT_EQ(1u, config.num_channels);
-  EXPECT_FALSE(config.fec_enabled);
-  EXPECT_FALSE(config.dtx_enabled);
-  EXPECT_EQ(20, config.frame_size_ms);
+  const auto config_opt = AudioEncoderOpus::SdpToConfig({"opus", 48000, 2});
+  ASSERT_TRUE(config_opt);
+  EXPECT_EQ(48000, config_opt->max_playback_rate_hz);
+  EXPECT_EQ(1u, config_opt->num_channels);
+  EXPECT_FALSE(config_opt->fec_enabled);
+  EXPECT_FALSE(config_opt->dtx_enabled);
+  EXPECT_EQ(20, config_opt->frame_size_ms);
 }
 
 TEST(AudioEncoderOpusTest, TestConfigFromParams) {
-  AudioEncoderOpus::Config config;
+  const auto config1 = CreateConfigWithParameters({{"stereo", "0"}});
+  EXPECT_EQ(1U, config1.num_channels);
 
-  config = CreateConfigWithParameters({{"stereo", "0"}});
-  EXPECT_EQ(1U, config.num_channels);
+  const auto config2 = CreateConfigWithParameters({{"stereo", "1"}});
+  EXPECT_EQ(2U, config2.num_channels);
 
-  config = CreateConfigWithParameters({{"stereo", "1"}});
-  EXPECT_EQ(2U, config.num_channels);
+  const auto config3 = CreateConfigWithParameters({{"useinbandfec", "0"}});
+  EXPECT_FALSE(config3.fec_enabled);
 
-  config = CreateConfigWithParameters({{"useinbandfec", "0"}});
-  EXPECT_FALSE(config.fec_enabled);
+  const auto config4 = CreateConfigWithParameters({{"useinbandfec", "1"}});
+  EXPECT_TRUE(config4.fec_enabled);
 
-  config = CreateConfigWithParameters({{"useinbandfec", "1"}});
-  EXPECT_TRUE(config.fec_enabled);
+  const auto config5 = CreateConfigWithParameters({{"usedtx", "0"}});
+  EXPECT_FALSE(config5.dtx_enabled);
 
-  config = CreateConfigWithParameters({{"usedtx", "0"}});
-  EXPECT_FALSE(config.dtx_enabled);
+  const auto config6 = CreateConfigWithParameters({{"usedtx", "1"}});
+  EXPECT_TRUE(config6.dtx_enabled);
 
-  config = CreateConfigWithParameters({{"usedtx", "1"}});
-  EXPECT_TRUE(config.dtx_enabled);
+  const auto config7 = CreateConfigWithParameters({{"cbr", "0"}});
+  EXPECT_FALSE(config7.cbr_enabled);
 
-  config = CreateConfigWithParameters({{"cbr", "0"}});
-  EXPECT_FALSE(config.cbr_enabled);
+  const auto config8 = CreateConfigWithParameters({{"cbr", "1"}});
+  EXPECT_TRUE(config8.cbr_enabled);
 
-  config = CreateConfigWithParameters({{"cbr", "1"}});
-  EXPECT_TRUE(config.cbr_enabled);
+  const auto config9 =
+      CreateConfigWithParameters({{"maxplaybackrate", "12345"}});
+  EXPECT_EQ(12345, config9.max_playback_rate_hz);
 
-  config = CreateConfigWithParameters({{"maxplaybackrate", "12345"}});
-  EXPECT_EQ(12345, config.max_playback_rate_hz);
+  const auto config10 =
+      CreateConfigWithParameters({{"maxaveragebitrate", "96000"}});
+  EXPECT_EQ(96000, config10.bitrate_bps);
 
-  config = CreateConfigWithParameters({{"maxaveragebitrate", "96000"}});
-  EXPECT_EQ(96000, config.bitrate_bps);
-
-  config = CreateConfigWithParameters({{"maxptime", "40"}});
-  for (int frame_length : config.supported_frame_lengths_ms) {
+  const auto config11 = CreateConfigWithParameters({{"maxptime", "40"}});
+  for (int frame_length : config11.supported_frame_lengths_ms) {
     EXPECT_LE(frame_length, 40);
   }
 
-  config = CreateConfigWithParameters({{"minptime", "40"}});
-  for (int frame_length : config.supported_frame_lengths_ms) {
+  const auto config12 = CreateConfigWithParameters({{"minptime", "40"}});
+  for (int frame_length : config12.supported_frame_lengths_ms) {
     EXPECT_GE(frame_length, 40);
   }
 
-  config = CreateConfigWithParameters({{"ptime", "40"}});
-  EXPECT_EQ(40, config.frame_size_ms);
+  const auto config13 = CreateConfigWithParameters({{"ptime", "40"}});
+  EXPECT_EQ(40, config13.frame_size_ms);
 
   constexpr int kMinSupportedFrameLength = 10;
   constexpr int kMaxSupportedFrameLength =
       WEBRTC_OPUS_SUPPORT_120MS_PTIME ? 120 : 60;
 
-  config = CreateConfigWithParameters({{"ptime", "1"}});
-  EXPECT_EQ(kMinSupportedFrameLength, config.frame_size_ms);
+  const auto config14 = CreateConfigWithParameters({{"ptime", "1"}});
+  EXPECT_EQ(kMinSupportedFrameLength, config14.frame_size_ms);
 
-  config = CreateConfigWithParameters({{"ptime", "2000"}});
-  EXPECT_EQ(kMaxSupportedFrameLength, config.frame_size_ms);
+  const auto config15 = CreateConfigWithParameters({{"ptime", "2000"}});
+  EXPECT_EQ(kMaxSupportedFrameLength, config15.frame_size_ms);
 }
 
 TEST(AudioEncoderOpusTest, TestConfigFromInvalidParams) {
   const webrtc::SdpAudioFormat format("opus", 48000, 2);
-  const AudioEncoderOpus::Config default_config =
-      AudioEncoderOpus::CreateConfig(0, format);
+  const auto default_config = *AudioEncoderOpus::SdpToConfig(format);
 #if WEBRTC_OPUS_SUPPORT_120MS_PTIME
   const std::vector<int> default_supported_frame_lengths_ms({20, 60, 120});
 #else
   const std::vector<int> default_supported_frame_lengths_ms({20, 60});
 #endif
 
-  AudioEncoderOpus::Config config;
+  AudioEncoderOpusConfig config;
   config = CreateConfigWithParameters({{"stereo", "invalid"}});
   EXPECT_EQ(default_config.num_channels, config.num_channels);
 
@@ -681,18 +686,18 @@
 // range of 6000 and 510000
 TEST(AudioEncoderOpusTest, SetSendCodecOpusMaxAverageBitrate) {
   // Ignore if less than 6000.
-  const AudioEncoderOpus::Config config1 = AudioEncoderOpus::CreateConfig(
-      0, {"opus", 48000, 2, {{"maxaveragebitrate", "5999"}}});
-  EXPECT_EQ(6000, config1.bitrate_bps);
+  const auto config1 = AudioEncoderOpus::SdpToConfig(
+      {"opus", 48000, 2, {{"maxaveragebitrate", "5999"}}});
+  EXPECT_EQ(6000, config1->bitrate_bps);
 
   // Ignore if larger than 510000.
-  const AudioEncoderOpus::Config config2 = AudioEncoderOpus::CreateConfig(
-      0, {"opus", 48000, 2, {{"maxaveragebitrate", "510001"}}});
-  EXPECT_EQ(510000, config2.bitrate_bps);
+  const auto config2 = AudioEncoderOpus::SdpToConfig(
+      {"opus", 48000, 2, {{"maxaveragebitrate", "510001"}}});
+  EXPECT_EQ(510000, config2->bitrate_bps);
 
-  const AudioEncoderOpus::Config config3 = AudioEncoderOpus::CreateConfig(
-      0, {"opus", 48000, 2, {{"maxaveragebitrate", "200000"}}});
-  EXPECT_EQ(200000, config3.bitrate_bps);
+  const auto config3 = AudioEncoderOpus::SdpToConfig(
+      {"opus", 48000, 2, {{"maxaveragebitrate", "200000"}}});
+  EXPECT_EQ(200000, config3->bitrate_bps);
 }
 
 // Test maxplaybackrate <= 8000 triggers Opus narrow band mode.
diff --git a/webrtc/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc b/webrtc/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc
index b199912..8b8f9a1 100644
--- a/webrtc/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc
@@ -19,9 +19,10 @@
 namespace webrtc {
 
 namespace {
-int64_t RunComplexityTest(const AudioEncoderOpus::Config& config) {
+int64_t RunComplexityTest(const AudioEncoderOpusConfig& config) {
   // Create encoder.
-  AudioEncoderOpus encoder(config);
+  constexpr int payload_type = 17;
+  AudioEncoderOpus encoder(config, payload_type);
   // Open speech file.
   const std::string kInputFileName =
       webrtc::test::ResourcePath("audio_coding/speech_mono_32_48kHz", "pcm");
@@ -60,7 +61,7 @@
 // the lower rate.
 TEST(AudioEncoderOpusComplexityAdaptationTest, AdaptationOn) {
   // Create config.
-  AudioEncoderOpus::Config config;
+  AudioEncoderOpusConfig config;
   // The limit -- including the hysteresis window -- at which the complexity
   // shuold be increased.
   config.bitrate_bps = rtc::Optional<int>(11000 - 1);
@@ -80,7 +81,7 @@
 // that the resulting ratio is less than 100% at all times.
 TEST(AudioEncoderOpusComplexityAdaptationTest, AdaptationOff) {
   // Create config.
-  AudioEncoderOpus::Config config;
+  AudioEncoderOpusConfig config;
   // The limit -- including the hysteresis window -- at which the complexity
   // shuold be increased (but not in this test since complexity adaptation is
   // disabled).
diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
index 15a89e9..1294f23 100644
--- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
@@ -17,6 +17,7 @@
 #include <string>
 #include <vector>
 
+#include "webrtc/api/audio_codecs/opus/audio_encoder_opus.h"
 #include "webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.h"
 #include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
 #include "webrtc/modules/audio_coding/codecs/g722/audio_decoder_g722.h"
@@ -28,7 +29,6 @@
 #include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h"
 #include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
 #include "webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h"
-#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h"
 #include "webrtc/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h"
 #include "webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
 #include "webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.h"
@@ -433,11 +433,10 @@
     frame_size_ = 480;
     data_length_ = 10 * frame_size_;
     decoder_ = new AudioDecoderOpus(1);
-    AudioEncoderOpus::Config config;
+    AudioEncoderOpusConfig config;
     config.frame_size_ms = static_cast<int>(frame_size_) / 48;
-    config.payload_type = payload_type_;
-    config.application = AudioEncoderOpus::kVoip;
-    audio_encoder_.reset(new AudioEncoderOpus(config));
+    config.application = AudioEncoderOpusConfig::ApplicationMode::kVoip;
+    audio_encoder_ = AudioEncoderOpus::MakeAudioEncoder(config, payload_type_);
   }
 };
 
@@ -447,12 +446,11 @@
     channels_ = 2;
     delete decoder_;
     decoder_ = new AudioDecoderOpus(2);
-    AudioEncoderOpus::Config config;
+    AudioEncoderOpusConfig config;
     config.frame_size_ms = static_cast<int>(frame_size_) / 48;
     config.num_channels = 2;
-    config.payload_type = payload_type_;
-    config.application = AudioEncoderOpus::kAudio;
-    audio_encoder_.reset(new AudioEncoderOpus(config));
+    config.application = AudioEncoderOpusConfig::ApplicationMode::kAudio;
+    audio_encoder_ = AudioEncoderOpus::MakeAudioEncoder(config, payload_type_);
   }
 };