Injectable audio encoders: BuiltinAudioEncoderFactory

This CL contains all the changes made to audio_coding while making
audio encoders injectable. Apart from some small changes to
webrtcvoiceengine, nothing here is hooked up to the outside
world. Those changes will be added to a follow-up CL.

BUG=webrtc:5806

Review-Url: https://codereview.webrtc.org/2695243005
Cr-Commit-Position: refs/heads/master@{#17569}
diff --git a/webrtc/api/DEPS b/webrtc/api/DEPS
index 0b3778b..245c31c 100644
--- a/webrtc/api/DEPS
+++ b/webrtc/api/DEPS
@@ -12,6 +12,13 @@
     "+webrtc/voice_engine",
   ],
 
+  # TODO(ossu): Remove this exception when {builtin_,}audio_encoder_factory.h
+  # has moved to api/.
+  "peerconnectioninterface\.h": [
+    "+webrtc/modules/audio_coding/codecs/audio_encoder_factory.h",
+    "+webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.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/audio_format.cc b/webrtc/api/audio_codecs/audio_format.cc
index b0a86e2..3a1d0a9 100644
--- a/webrtc/api/audio_codecs/audio_format.cc
+++ b/webrtc/api/audio_codecs/audio_format.cc
@@ -19,17 +19,17 @@
 
 SdpAudioFormat::SdpAudioFormat(const char* name,
                                int clockrate_hz,
-                               int num_channels)
+                               size_t num_channels)
     : name(name), clockrate_hz(clockrate_hz), num_channels(num_channels) {}
 
 SdpAudioFormat::SdpAudioFormat(const std::string& name,
                                int clockrate_hz,
-                               int num_channels)
+                               size_t num_channels)
     : name(name), clockrate_hz(clockrate_hz), num_channels(num_channels) {}
 
 SdpAudioFormat::SdpAudioFormat(const char* name,
                                int clockrate_hz,
-                               int num_channels,
+                               size_t num_channels,
                                const Parameters& param)
     : name(name),
       clockrate_hz(clockrate_hz),
@@ -38,7 +38,7 @@
 
 SdpAudioFormat::SdpAudioFormat(const std::string& name,
                                int clockrate_hz,
-                               int num_channels,
+                               size_t num_channels,
                                const Parameters& param)
     : name(name),
       clockrate_hz(clockrate_hz),
@@ -77,9 +77,30 @@
   return os;
 }
 
-AudioCodecSpec::AudioCodecSpec(const SdpAudioFormat& format) : format(format) {}
+AudioCodecInfo::AudioCodecInfo(int sample_rate_hz,
+                               size_t num_channels,
+                               int bitrate_bps)
+    : AudioCodecInfo(sample_rate_hz,
+                     num_channels,
+                     bitrate_bps,
+                     bitrate_bps,
+                     bitrate_bps) {}
 
-AudioCodecSpec::AudioCodecSpec(SdpAudioFormat&& format)
-    : format(std::move(format)) {}
+AudioCodecInfo::AudioCodecInfo(int sample_rate_hz,
+                               size_t num_channels,
+                               int default_bitrate_bps,
+                               int min_bitrate_bps,
+                               int max_bitrate_bps)
+    : sample_rate_hz(sample_rate_hz),
+      num_channels(num_channels),
+      default_bitrate_bps(default_bitrate_bps),
+      min_bitrate_bps(min_bitrate_bps),
+      max_bitrate_bps(max_bitrate_bps) {
+  RTC_DCHECK_GT(sample_rate_hz, 0);
+  RTC_DCHECK_GT(num_channels, 0);
+  RTC_DCHECK_GE(min_bitrate_bps, 0);
+  RTC_DCHECK_LE(min_bitrate_bps, default_bitrate_bps);
+  RTC_DCHECK_GE(max_bitrate_bps, default_bitrate_bps);
+}
 
 }  // namespace webrtc
diff --git a/webrtc/api/audio_codecs/audio_format.h b/webrtc/api/audio_codecs/audio_format.h
index db3990f..8814a3d 100644
--- a/webrtc/api/audio_codecs/audio_format.h
+++ b/webrtc/api/audio_codecs/audio_format.h
@@ -16,6 +16,8 @@
 #include <string>
 #include <utility>
 
+#include "webrtc/base/optional.h"
+
 namespace webrtc {
 
 // SDP specification for a single audio codec.
@@ -25,15 +27,17 @@
 
   SdpAudioFormat(const SdpAudioFormat&);
   SdpAudioFormat(SdpAudioFormat&&);
-  SdpAudioFormat(const char* name, int clockrate_hz, int num_channels);
-  SdpAudioFormat(const std::string& name, int clockrate_hz, int num_channels);
+  SdpAudioFormat(const char* name, int clockrate_hz, size_t num_channels);
+  SdpAudioFormat(const std::string& name,
+                 int clockrate_hz,
+                 size_t num_channels);
   SdpAudioFormat(const char* name,
                  int clockrate_hz,
-                 int num_channels,
+                 size_t num_channels,
                  const Parameters& param);
   SdpAudioFormat(const std::string& name,
                  int clockrate_hz,
-                 int num_channels,
+                 size_t num_channels,
                  const Parameters& param);
   ~SdpAudioFormat();
 
@@ -47,35 +51,83 @@
 
   std::string name;
   int clockrate_hz;
-  int num_channels;
+  size_t num_channels;
   Parameters parameters;
 };
 
 void swap(SdpAudioFormat& a, SdpAudioFormat& b);
 std::ostream& operator<<(std::ostream& os, const SdpAudioFormat& saf);
 
-// To avoid API breakage, and make the code clearer, AudioCodecSpec should not
+// Information about how an audio format is treated by the codec implementation.
+// Contains basic information, such as sample rate and number of channels, which
+// isn't uniformly presented by SDP. Also contains flags indicating support for
+// integrating with other parts of WebRTC, like external VAD and comfort noise
+// level calculation.
+//
+// To avoid API breakage, and make the code clearer, AudioCodecInfo should not
 // be directly initializable with any flags indicating optional support. If it
 // were, these initializers would break any time a new flag was added. It's also
 // more difficult to understand:
-//   AudioCodecSpec spec{{"format", 8000, 1}, true, false, false, true, true};
+//   AudioCodecInfo info{16000, 1, 32000, true, false, false, true, true};
 // than
-//   AudioCodecSpec spec({"format", 8000, 1});
-//   spec.allow_comfort_noise = true;
-//   spec.future_flag_b = true;
-//   spec.future_flag_c = true;
-struct AudioCodecSpec {
-  explicit AudioCodecSpec(const SdpAudioFormat& format);
-  explicit AudioCodecSpec(SdpAudioFormat&& format);
-  ~AudioCodecSpec() = default;
+//   AudioCodecInfo info(16000, 1, 32000);
+//   info.allow_comfort_noise = true;
+//   info.future_flag_b = true;
+//   info.future_flag_c = true;
+struct AudioCodecInfo {
+  AudioCodecInfo(int sample_rate_hz, size_t num_channels, int bitrate_bps);
+  AudioCodecInfo(int sample_rate_hz,
+                 size_t num_channels,
+                 int default_bitrate_bps,
+                 int min_bitrate_bps,
+                 int max_bitrate_bps);
+  AudioCodecInfo(const AudioCodecInfo& b) = default;
+  ~AudioCodecInfo() = default;
 
-  SdpAudioFormat format;
+  bool operator==(const AudioCodecInfo& b) const {
+    return sample_rate_hz == b.sample_rate_hz &&
+           num_channels == b.num_channels &&
+           default_bitrate_bps == b.default_bitrate_bps &&
+           min_bitrate_bps == b.min_bitrate_bps &&
+           max_bitrate_bps == b.max_bitrate_bps &&
+           allow_comfort_noise == b.allow_comfort_noise &&
+           supports_network_adaption == b.supports_network_adaption;
+  }
+
+  bool operator!=(const AudioCodecInfo& b) const { return !(*this == b); }
+
+  bool HasFixedBitrate() const {
+    RTC_DCHECK_GE(min_bitrate_bps, 0);
+    RTC_DCHECK_LE(min_bitrate_bps, default_bitrate_bps);
+    RTC_DCHECK_GE(max_bitrate_bps, default_bitrate_bps);
+    return min_bitrate_bps == max_bitrate_bps;
+  }
+
+  int sample_rate_hz;
+  size_t num_channels;
+  int default_bitrate_bps;
+  int min_bitrate_bps;
+  int max_bitrate_bps;
+
   bool allow_comfort_noise = true;  // This codec can be used with an external
                                     // comfort noise generator.
   bool supports_network_adaption = false;  // This codec can adapt to varying
                                            // network conditions.
 };
 
+// AudioCodecSpec ties an audio format to specific information about the codec
+// and its implementation.
+struct AudioCodecSpec {
+  bool operator==(const AudioCodecSpec& b) const {
+    return format == b.format && info == b.info;
+  }
+
+  bool operator!=(const AudioCodecSpec& b) const { return !(*this == b); }
+
+  SdpAudioFormat format;
+  AudioCodecInfo info;
+};
+
 }  // namespace webrtc
 
 #endif  // WEBRTC_API_AUDIO_CODECS_AUDIO_FORMAT_H_
diff --git a/webrtc/api/peerconnectioninterface.h b/webrtc/api/peerconnectioninterface.h
index e965457..d30834d 100644
--- a/webrtc/api/peerconnectioninterface.h
+++ b/webrtc/api/peerconnectioninterface.h
@@ -91,6 +91,9 @@
 #include "webrtc/base/sslstreamadapter.h"
 #include "webrtc/media/base/mediachannel.h"
 #include "webrtc/media/base/videocapturer.h"
+#include "webrtc/modules/audio_coding/codecs/audio_encoder_factory.h"
+// TODO(ossu): Remove this once downstream projects have been updated.
+#include "webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h"
 #include "webrtc/p2p/base/portallocator.h"
 
 namespace rtc {
@@ -986,14 +989,6 @@
   ~PeerConnectionFactoryInterface() {} // NOLINT
 };
 
-// TODO(ossu): Remove these and define a real builtin audio encoder factory
-// instead.
-class AudioEncoderFactory : public rtc::RefCountInterface {};
-inline rtc::scoped_refptr<AudioEncoderFactory>
-CreateBuiltinAudioEncoderFactory() {
-  return nullptr;
-}
-
 // Create a new instance of PeerConnectionFactoryInterface.
 //
 // This method relies on the thread it's called on as the "signaling thread"
diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc
index 8fcda89..d3a928b 100644
--- a/webrtc/media/engine/webrtcvoiceengine.cc
+++ b/webrtc/media/engine/webrtcvoiceengine.cc
@@ -1091,12 +1091,12 @@
     rtc::Optional<AudioCodec> opt_codec = map_format(spec.format, nullptr);
     if (opt_codec) {
       AudioCodec& codec = *opt_codec;
-      if (spec.supports_network_adaption) {
+      if (spec.info.supports_network_adaption) {
         codec.AddFeedbackParam(
             FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty));
       }
 
-      if (spec.allow_comfort_noise) {
+      if (spec.info.allow_comfort_noise) {
         // Generate a CN entry if the decoder allows it and we support the
         // clockrate.
         auto cn = generate_cn.find(spec.format.clockrate_hz);
diff --git a/webrtc/media/engine/webrtcvoiceengine_unittest.cc b/webrtc/media/engine/webrtcvoiceengine_unittest.cc
index 44003ec..5da1d8a 100644
--- a/webrtc/media/engine/webrtcvoiceengine_unittest.cc
+++ b/webrtc/media/engine/webrtcvoiceengine_unittest.cc
@@ -3781,18 +3781,21 @@
 
 TEST(WebRtcVoiceEngineTest, CollectRecvCodecs) {
   std::vector<webrtc::AudioCodecSpec> specs;
-  webrtc::AudioCodecSpec spec1({"codec1", 48000, 2, {{"param1", "value1"}}});
-  spec1.allow_comfort_noise = false;
-  spec1.supports_network_adaption = true;
+  webrtc::AudioCodecSpec spec1{{"codec1", 48000, 2, {{"param1", "value1"}}},
+                               {48000, 2, 16000, 10000, 20000}};
+  spec1.info.allow_comfort_noise = false;
+  spec1.info.supports_network_adaption = true;
   specs.push_back(spec1);
-  webrtc::AudioCodecSpec spec2({"codec2", 32000, 1});
-  spec2.allow_comfort_noise = false;
+  webrtc::AudioCodecSpec spec2{{"codec2", 32000, 1}, {32000, 1, 32000}};
+  spec2.info.allow_comfort_noise = false;
   specs.push_back(spec2);
-  specs.push_back(webrtc::AudioCodecSpec({"codec3", 16000, 1,
-                                          {{"param1", "value1b"},
-                                           {"param2", "value2"}}}));
-  specs.push_back(webrtc::AudioCodecSpec({"codec4", 8000, 1}));
-  specs.push_back(webrtc::AudioCodecSpec({"codec5", 8000, 2}));
+  specs.push_back(webrtc::AudioCodecSpec{
+      {"codec3", 16000, 1, {{"param1", "value1b"}, {"param2", "value2"}}},
+      {16000, 1, 13300}});
+  specs.push_back(
+      webrtc::AudioCodecSpec{{"codec4", 8000, 1}, {8000, 1, 64000}});
+  specs.push_back(
+      webrtc::AudioCodecSpec{{"codec5", 8000, 2}, {8000, 1, 64000}});
 
   rtc::scoped_refptr<webrtc::MockAudioDecoderFactory> mock_factory =
       new rtc::RefCountedObject<webrtc::MockAudioDecoderFactory>;
diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn
index ea3a1b7..5ae3164 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -51,6 +51,33 @@
   ]
 }
 
+rtc_source_set("audio_encoder_factory_interface") {
+  sources = [
+    "codecs/audio_encoder_factory.h",
+  ]
+  deps = [
+    ":audio_encoder_interface",
+    "../../api/audio_codecs:audio_codecs_api",
+    "../../base:rtc_base_approved",
+  ]
+}
+
+rtc_static_library("builtin_audio_encoder_factory") {
+  # TODO(kjellander): Remove (bugs.webrtc.org/6828)
+  # Errors on cyclic dependency with :isac_fix if enabled.
+  check_includes = false
+  sources = [
+    "codecs/builtin_audio_encoder_factory.cc",
+    "codecs/builtin_audio_encoder_factory.h",
+  ]
+  deps = [
+           "../..:webrtc_common",
+           "../../base:rtc_base_approved",
+           ":audio_encoder_factory_interface",
+         ] + audio_codec_deps
+  defines = audio_codec_defines
+}
+
 rtc_static_library("builtin_audio_decoder_factory_internal") {
   sources = [
     "codecs/builtin_audio_decoder_factory_internal.cc",
@@ -491,6 +518,7 @@
   deps = [
     ":audio_encoder_interface",
     "../..:webrtc_common",
+    "../../api/audio_codecs:audio_codecs_api",
     "../../base:rtc_base_approved",
   ]
 }
@@ -1998,6 +2026,7 @@
       "audio_network_adaptor/mock/mock_controller_manager.h",
       "audio_network_adaptor/util/threshold_curve_unittest.cc",
       "codecs/builtin_audio_decoder_factory_unittest.cc",
+      "codecs/builtin_audio_encoder_factory_unittest.cc",
       "codecs/cng/audio_encoder_cng_unittest.cc",
       "codecs/cng/cng_unittest.cc",
       "codecs/ilbc/ilbc_unittest.cc",
@@ -2065,6 +2094,7 @@
       ":audio_encoder_interface",
       ":audio_format_conversion",
       ":audio_network_adaptor",
+      ":builtin_audio_encoder_factory",
       ":cng",
       ":g711",
       ":ilbc",
diff --git a/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc b/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc
index 7515903..98569a6 100644
--- a/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc
+++ b/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc
@@ -26,6 +26,7 @@
 #include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
 #include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
 #include "webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h"
+#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h"
 #include "webrtc/modules/audio_coding/include/audio_coding_module.h"
 #include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
 #include "webrtc/modules/audio_coding/neteq/audio_decoder_impl.h"
@@ -1266,6 +1267,8 @@
   rtc::Md5Digest payload_checksum_;
 };
 
+class AcmSenderBitExactnessNewApi : public AcmSenderBitExactnessOldApi {};
+
 #if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
 TEST_F(AcmSenderBitExactnessOldApi, IsacWb30ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 16000, 1, 103, 480, 480));
@@ -1460,8 +1463,10 @@
 
 #if WEBRTC_OPUS_SUPPORT_120MS_PTIME
 #define MAYBE_Opus_stereo_20ms DISABLED_Opus_stereo_20ms
+#define MAYBE_OpusFromFormat_stereo_20ms DISABLED_OpusFromFormat_stereo_20ms
 #else
 #define MAYBE_Opus_stereo_20ms Opus_stereo_20ms
+#define MAYBE_OpusFromFormat_stereo_20ms OpusFromFormat_stereo_20ms
 #endif
 TEST_F(AcmSenderBitExactnessOldApi, MAYBE_Opus_stereo_20ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 2, 120, 960, 960));
@@ -1478,10 +1483,30 @@
       50, test::AcmReceiveTestOldApi::kStereoOutput);
 }
 
+TEST_F(AcmSenderBitExactnessNewApi, MAYBE_OpusFromFormat_stereo_20ms) {
+  const SdpAudioFormat kOpusFormat("opus", 48000, 2, {{"stereo", "1"}});
+  AudioEncoderOpus encoder(120, kOpusFormat);
+  ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder(&encoder, 120));
+  Run(AcmReceiverBitExactnessOldApi::PlatformChecksum(
+          "855041f2490b887302bce9d544731849",
+          "855041f2490b887302bce9d544731849",
+          "9692eede45638eb425e0daf9c75b5c7a",
+          "86d3552bb3492247f965cdd0e88a1c82"),
+      AcmReceiverBitExactnessOldApi::PlatformChecksum(
+          "d781cce1ab986b618d0da87226cdde30",
+          "d781cce1ab986b618d0da87226cdde30",
+          "8d6782b905c3230d4b0e3e83e1fc3439",
+          "798347a685fac7d0c2d8f748ffe66881"),
+      50, test::AcmReceiveTestOldApi::kStereoOutput);
+}
+
 #if WEBRTC_OPUS_SUPPORT_120MS_PTIME
 #define MAYBE_Opus_stereo_20ms_voip DISABLED_Opus_stereo_20ms_voip
+#define MAYBE_OpusFromFormat_stereo_20ms_voip \
+  DISABLED_OpusFromFormat_stereo_20ms_voip
 #else
 #define MAYBE_Opus_stereo_20ms_voip Opus_stereo_20ms_voip
+#define MAYBE_OpusFromFormat_stereo_20ms_voip OpusFromFormat_stereo_20ms_voip
 #endif
 TEST_F(AcmSenderBitExactnessOldApi, MAYBE_Opus_stereo_20ms_voip) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 2, 120, 960, 960));
@@ -1500,9 +1525,28 @@
       50, test::AcmReceiveTestOldApi::kStereoOutput);
 }
 
+TEST_F(AcmSenderBitExactnessNewApi, MAYBE_OpusFromFormat_stereo_20ms_voip) {
+  const SdpAudioFormat kOpusFormat("opus", 48000, 2, {{"stereo", "1"}});
+  AudioEncoderOpus encoder(120, kOpusFormat);
+  ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder(&encoder, 120));
+  // If not set, default will be kAudio in case of stereo.
+  EXPECT_EQ(0, send_test_->acm()->SetOpusApplication(kVoip));
+  Run(AcmReceiverBitExactnessOldApi::PlatformChecksum(
+          "9b9e12bc3cc793740966e11cbfa8b35b",
+          "9b9e12bc3cc793740966e11cbfa8b35b",
+          "0de6249018fdd316c21086db84e10610",
+          "9c4cb69db77b85841a5f8225bb8f508b"),
+      AcmReceiverBitExactnessOldApi::PlatformChecksum(
+          "c7340b1189652ab6b5e80dade7390cb4",
+          "c7340b1189652ab6b5e80dade7390cb4",
+          "95612864c954ee63e28cc6eebad56626",
+          "ae33ea2e43407cf9ebdabbbd6ca912a3"),
+      50, test::AcmReceiveTestOldApi::kStereoOutput);
+}
+
 // This test is for verifying the SetBitRate function. The bitrate is changed at
 // the beginning, and the number of generated bytes are checked.
-class AcmSetBitRateOldApi : public ::testing::Test {
+class AcmSetBitRateTest : public ::testing::Test {
  protected:
   static const int kTestDurationMs = 1000;
 
@@ -1532,11 +1576,12 @@
                                      payload_type, frame_size_samples);
   }
 
-  // Runs the test. SetUpSender() and RegisterSendCodec() must have been called
-  // before calling this method.
-  void Run(int target_bitrate_bps, int expected_total_bits) {
-    ASSERT_TRUE(send_test_->acm());
-    send_test_->acm()->SetBitRate(target_bitrate_bps);
+  bool RegisterExternalSendCodec(AudioEncoder* external_speech_encoder,
+                                 int payload_type) {
+    return send_test_->RegisterExternalCodec(external_speech_encoder);
+  }
+
+  void RunInner(int expected_total_bits) {
     int nr_bytes = 0;
     while (std::unique_ptr<test::Packet> next_packet =
                send_test_->NextPacket()) {
@@ -1561,10 +1606,31 @@
   std::unique_ptr<test::InputAudioFile> audio_source_;
 };
 
+class AcmSetBitRateOldApi : public AcmSetBitRateTest {
+ protected:
+  // Runs the test. SetUpSender() must have been called and a codec must be set
+  // up before calling this method.
+  void Run(int target_bitrate_bps, int expected_total_bits) {
+    ASSERT_TRUE(send_test_->acm());
+    send_test_->acm()->SetBitRate(target_bitrate_bps);
+    RunInner(expected_total_bits);
+  }
+};
+
+class AcmSetBitRateNewApi : public AcmSetBitRateTest {
+ protected:
+  // Runs the test. SetUpSender() must have been called and a codec must be set
+  // up before calling this method.
+  void Run(int expected_total_bits) { RunInner(expected_total_bits); }
+};
+
 #if WEBRTC_OPUS_SUPPORT_120MS_PTIME
 #define MAYBE_Opus_48khz_20ms_10kbps DISABLED_Opus_48khz_20ms_10kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_10kbps \
+  DISABLED_OpusFromFormat_48khz_20ms_10kbps
 #else
 #define MAYBE_Opus_48khz_20ms_10kbps Opus_48khz_20ms_10kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_10kbps OpusFromFormat_48khz_20ms_10kbps
 #endif
 TEST_F(AcmSetBitRateOldApi, MAYBE_Opus_48khz_20ms_10kbps) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
@@ -1575,10 +1641,25 @@
 #endif  // WEBRTC_ANDROID
 }
 
+TEST_F(AcmSetBitRateNewApi, MAYBE_OpusFromFormat_48khz_20ms_10kbps) {
+  AudioEncoderOpus encoder(
+      107, SdpAudioFormat("opus", 48000, 2, {{"maxaveragebitrate", "10000"}}));
+  ASSERT_TRUE(SetUpSender());
+  ASSERT_TRUE(RegisterExternalSendCodec(&encoder, 107));
+#if defined(WEBRTC_ANDROID)
+  RunInner(9288);
+#else
+  RunInner(9024);
+#endif  // WEBRTC_ANDROID
+}
+
 #if WEBRTC_OPUS_SUPPORT_120MS_PTIME
 #define MAYBE_Opus_48khz_20ms_50kbps DISABLED_Opus_48khz_20ms_50kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_50kbps \
+  DISABLED_OpusFromFormat_48khz_20ms_50kbps
 #else
 #define MAYBE_Opus_48khz_20ms_50kbps Opus_48khz_20ms_50kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_50kbps OpusFromFormat_48khz_20ms_50kbps
 #endif
 TEST_F(AcmSetBitRateOldApi, MAYBE_Opus_48khz_20ms_50kbps) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
@@ -1589,18 +1670,42 @@
 #endif  // WEBRTC_ANDROID
 }
 
+TEST_F(AcmSetBitRateNewApi, MAYBE_OpusFromFormat_48khz_20ms_50kbps) {
+  AudioEncoderOpus encoder(
+      107, SdpAudioFormat("opus", 48000, 2, {{"maxaveragebitrate", "50000"}}));
+  ASSERT_TRUE(SetUpSender());
+  ASSERT_TRUE(RegisterExternalSendCodec(&encoder, 107));
+#if defined(WEBRTC_ANDROID)
+  RunInner(47960);
+#else
+  RunInner(49544);
+#endif  // WEBRTC_ANDROID
+}
+
 // The result on the Android platforms is inconsistent for this test case.
 // On android_rel the result is different from android and android arm64 rel.
 #if defined(WEBRTC_ANDROID) || WEBRTC_OPUS_SUPPORT_120MS_PTIME
 #define MAYBE_Opus_48khz_20ms_100kbps DISABLED_Opus_48khz_20ms_100kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_100kbps \
+  DISABLED_OpusFromFormat_48khz_20ms_100kbps
 #else
 #define MAYBE_Opus_48khz_20ms_100kbps Opus_48khz_20ms_100kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_100kbps \
+  OpusFromFormat_48khz_20ms_100kbps
 #endif
 TEST_F(AcmSetBitRateOldApi, MAYBE_Opus_48khz_20ms_100kbps) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
   Run(100000, 100888);
 }
 
+TEST_F(AcmSetBitRateNewApi, MAYBE_OpusFromFormat_48khz_20ms_100kbps) {
+  AudioEncoderOpus encoder(
+      107, SdpAudioFormat("opus", 48000, 2, {{"maxaveragebitrate", "100000"}}));
+  ASSERT_TRUE(SetUpSender());
+  ASSERT_TRUE(RegisterExternalSendCodec(&encoder, 107));
+  RunInner(100888);
+}
+
 // These next 2 tests ensure that the SetBitRate function has no effect on PCM
 TEST_F(AcmSetBitRateOldApi, Pcm16_8khz_10ms_8kbps) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80));
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder_factory.h b/webrtc/modules/audio_coding/codecs/audio_encoder_factory.h
new file mode 100644
index 0000000..eebb615
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/audio_encoder_factory.h
@@ -0,0 +1,46 @@
+/*
+ *  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_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_FACTORY_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_FACTORY_H_
+
+#include <memory>
+#include <vector>
+
+#include "webrtc/api/audio_codecs/audio_format.h"
+#include "webrtc/base/refcount.h"
+#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
+
+namespace webrtc {
+
+// A factory that creates AudioEncoders.
+// NOTE: This class is still under development and may change without notice.
+class AudioEncoderFactory : public rtc::RefCountInterface {
+ public:
+  // Returns a prioritized list of audio codecs, to use for signaling etc.
+  virtual std::vector<AudioCodecSpec> GetSupportedEncoders() = 0;
+
+  // Returns information about how this format would be encoded, provided it's
+  // supported. More format and format variations may be supported than those
+  // returned by GetSupportedEncoders().
+  virtual rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+      const SdpAudioFormat& format) = 0;
+
+  // Creates an AudioEncoder for the specified format. The encoder will tags its
+  // payloads with the specified payload type.
+  // TODO(ossu): Try to avoid audio encoders having to know their payload type.
+  virtual std::unique_ptr<AudioEncoder> MakeAudioEncoder(
+      int payload_type,
+      const SdpAudioFormat& format) = 0;
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_FACTORY_H_
diff --git a/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc b/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc
index 5a69ae4..a858053 100644
--- a/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc
+++ b/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc
@@ -25,7 +25,7 @@
 CodecInst MakeCodecInst(int payload_type,
                         const char* name,
                         int sample_rate,
-                        int num_channels) {
+                        size_t num_channels) {
   // Create a CodecInst with some fields set. The remaining fields are zeroed,
   // but we tell MSan to consider them uninitialized.
   CodecInst ci = {0};
@@ -34,7 +34,7 @@
   strncpy(ci.plname, name, sizeof(ci.plname));
   ci.plname[sizeof(ci.plname) - 1] = '\0';
   ci.plfreq = sample_rate;
-  ci.channels = rtc::dchecked_cast<size_t>(num_channels);
+  ci.channels = num_channels;
   return ci;
 }
 
@@ -44,7 +44,7 @@
   if (STR_CASE_CMP(ci.plname, "g722") == 0) {
     RTC_CHECK_EQ(16000, ci.plfreq);
     RTC_CHECK(ci.channels == 1 || ci.channels == 2);
-    return {"g722", 8000, static_cast<int>(ci.channels)};
+    return {"g722", 8000, ci.channels};
   } else if (STR_CASE_CMP(ci.plname, "opus") == 0) {
     RTC_CHECK_EQ(48000, ci.plfreq);
     RTC_CHECK(ci.channels == 1 || ci.channels == 2);
@@ -52,7 +52,7 @@
                ? SdpAudioFormat("opus", 48000, 2)
                : SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}});
   } else {
-    return {ci.plname, ci.plfreq, rtc::checked_cast<int>(ci.channels)};
+    return {ci.plname, ci.plfreq, ci.channels};
   }
 }
 
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 8ec08e4..549fef4 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
@@ -180,30 +180,37 @@
     static std::vector<AudioCodecSpec> specs = [] {
       std::vector<AudioCodecSpec> specs;
 #ifdef WEBRTC_CODEC_OPUS
+      AudioCodecInfo opus_info{48000, 1, 64000, 6000, 510000};
+      opus_info.allow_comfort_noise = false;
+      opus_info.supports_network_adaption = true;
       // clang-format off
-      AudioCodecSpec opus({"opus", 48000, 2, {
-                             {"minptime", "10"},
-                             {"useinbandfec", "1"}
-                           }});
+      SdpAudioFormat opus_format({"opus", 48000, 2, {
+                                    {"minptime", "10"},
+                                    {"useinbandfec", "1"}
+                                  }});
       // clang-format on
-      opus.allow_comfort_noise = false;
-      opus.supports_network_adaption = true;
-      specs.push_back(opus);
+      specs.push_back({std::move(opus_format), opus_info});
 #endif
 #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
-      specs.push_back(AudioCodecSpec({"isac", 16000, 1}));
+      specs.push_back(AudioCodecSpec{{"isac", 16000, 1},
+                                     {16000, 1, 32000, 10000, 56000}});
 #endif
 #if (defined(WEBRTC_CODEC_ISAC))
-      specs.push_back(AudioCodecSpec({"isac", 32000, 1}));
+      specs.push_back(AudioCodecSpec{{"isac", 32000, 1},
+                                     {32000, 1, 56000, 10000, 56000}});
 #endif
 #ifdef WEBRTC_CODEC_G722
-      specs.push_back(AudioCodecSpec({"G722", 8000, 1}));
+      specs.push_back(AudioCodecSpec{{"G722", 8000, 1},
+                                     {16000, 1, 64000}});
 #endif
 #ifdef WEBRTC_CODEC_ILBC
-      specs.push_back(AudioCodecSpec({"iLBC", 8000, 1}));
+      specs.push_back(AudioCodecSpec{{"iLBC", 8000, 1},
+                                     {8000, 1, 13300}});
 #endif
-      specs.push_back(AudioCodecSpec({"PCMU", 8000, 1}));
-      specs.push_back(AudioCodecSpec({"PCMA", 8000, 1}));
+      specs.push_back(AudioCodecSpec{{"PCMU", 8000, 1},
+                                     {8000, 1, 64000}});
+      specs.push_back(AudioCodecSpec{{"PCMA", 8000, 1},
+                                     {8000, 1, 64000}});
       return specs;
     }();
     return specs;
diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.cc b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.cc
new file mode 100644
index 0000000..54345fd
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.cc
@@ -0,0 +1,143 @@
+/*
+ *  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/modules/audio_coding/codecs/builtin_audio_encoder_factory.h"
+
+#include <memory>
+#include <vector>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/optional.h"
+#include "webrtc/common_types.h"
+#include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
+#ifdef WEBRTC_CODEC_G722
+#include "webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h"
+#endif
+#ifdef WEBRTC_CODEC_ILBC
+#include "webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h"
+#endif
+#ifdef WEBRTC_CODEC_ISACFX
+#include "webrtc/modules/audio_coding/codecs/isac/fix/include/audio_encoder_isacfix.h"
+#endif
+#ifdef WEBRTC_CODEC_ISAC
+#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
+#endif
+#ifdef WEBRTC_CODEC_OPUS
+#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h"
+#endif
+#include "webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
+
+namespace webrtc {
+
+namespace {
+
+struct NamedEncoderFactory {
+  const char* name;
+  rtc::Optional<AudioCodecInfo> (*QueryAudioEncoder)(
+      const SdpAudioFormat& format);
+  std::unique_ptr<AudioEncoder> (
+      *MakeAudioEncoder)(int payload_type, const SdpAudioFormat& format);
+
+  template <typename T>
+  static NamedEncoderFactory ForEncoder() {
+    auto constructor = [](int payload_type, const SdpAudioFormat& format) {
+      auto opt_info = T::QueryAudioEncoder(format);
+      if (opt_info) {
+        return std::unique_ptr<AudioEncoder>(new T(payload_type, format));
+      }
+      return std::unique_ptr<AudioEncoder>();
+    };
+
+    return {T::GetPayloadName(), T::QueryAudioEncoder, constructor};
+  }
+};
+
+NamedEncoderFactory encoder_factories[] = {
+#ifdef WEBRTC_CODEC_G722
+    NamedEncoderFactory::ForEncoder<AudioEncoderG722>(),
+#endif
+#ifdef WEBRTC_CODEC_ILBC
+    NamedEncoderFactory::ForEncoder<AudioEncoderIlbc>(),
+#endif
+#if defined(WEBRTC_CODEC_ISACFX)
+    NamedEncoderFactory::ForEncoder<AudioEncoderIsacFix>(),
+#elif defined(WEBRTC_CODEC_ISAC)
+    NamedEncoderFactory::ForEncoder<AudioEncoderIsac>(),
+#endif
+
+#ifdef WEBRTC_CODEC_OPUS
+    NamedEncoderFactory::ForEncoder<AudioEncoderOpus>(),
+#endif
+    NamedEncoderFactory::ForEncoder<AudioEncoderPcm16B>(),
+    NamedEncoderFactory::ForEncoder<AudioEncoderPcmA>(),
+    NamedEncoderFactory::ForEncoder<AudioEncoderPcmU>(),
+};
+}  // namespace
+
+class BuiltinAudioEncoderFactory : public AudioEncoderFactory {
+ public:
+  std::vector<AudioCodecSpec> GetSupportedEncoders() override {
+    static const SdpAudioFormat desired_encoders[] = {
+        {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}},
+        {"isac", 16000, 1},
+        {"isac", 32000, 1},
+        {"G722", 8000, 1},
+        {"iLBC", 8000, 1},
+        {"PCMU", 8000, 1},
+        {"PCMA", 8000, 1},
+    };
+
+    // Initialize thread-safely, once, on first use.
+    static const std::vector<AudioCodecSpec> specs = [] {
+      std::vector<AudioCodecSpec> specs;
+      for (const auto& format : desired_encoders) {
+        for (const auto& ef : encoder_factories) {
+          if (STR_CASE_CMP(format.name.c_str(), ef.name) == 0) {
+            auto opt_info = ef.QueryAudioEncoder(format);
+            if (opt_info) {
+              specs.push_back({format, *opt_info});
+            }
+          }
+        }
+      }
+      return specs;
+    }();
+    return specs;
+  }
+
+  rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+      const SdpAudioFormat& format) override {
+    for (const auto& ef : encoder_factories) {
+      if (STR_CASE_CMP(format.name.c_str(), ef.name) == 0) {
+        return ef.QueryAudioEncoder(format);
+      }
+    }
+    return rtc::Optional<AudioCodecInfo>();
+  }
+
+  std::unique_ptr<AudioEncoder> MakeAudioEncoder(
+      int payload_type,
+      const SdpAudioFormat& format) override {
+    for (const auto& ef : encoder_factories) {
+      if (STR_CASE_CMP(format.name.c_str(), ef.name) == 0) {
+        return ef.MakeAudioEncoder(payload_type, format);
+      }
+    }
+    return nullptr;
+  }
+};
+
+rtc::scoped_refptr<AudioEncoderFactory> CreateBuiltinAudioEncoderFactory() {
+  return rtc::scoped_refptr<AudioEncoderFactory>(
+      new rtc::RefCountedObject<BuiltinAudioEncoderFactory>());
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h
new file mode 100644
index 0000000..150a76c
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h
@@ -0,0 +1,25 @@
+/*
+ *  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_MODULES_AUDIO_CODING_CODECS_BUILTIN_AUDIO_ENCODER_FACTORY_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_BUILTIN_AUDIO_ENCODER_FACTORY_H_
+
+#include "webrtc/base/scoped_ref_ptr.h"
+#include "webrtc/modules/audio_coding/codecs/audio_encoder_factory.h"
+
+namespace webrtc {
+
+// Creates a new factory that can create the built-in types of audio encoders.
+// NOTE: This function is still under development and may change without notice.
+rtc::scoped_refptr<AudioEncoderFactory> CreateBuiltinAudioEncoderFactory();
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_BUILTIN_AUDIO_ENCODER_FACTORY_H_
diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc
new file mode 100644
index 0000000..0d3ce52
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc
@@ -0,0 +1,145 @@
+/*
+ *  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 <limits>
+#include <memory>
+#include <vector>
+
+#include "webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h"
+#include "webrtc/test/gmock.h"
+#include "webrtc/test/gtest.h"
+
+namespace webrtc {
+
+class AudioEncoderFactoryTest
+    : public ::testing::TestWithParam<rtc::scoped_refptr<AudioEncoderFactory>> {
+};
+
+TEST_P(AudioEncoderFactoryTest, SupportsAtLeastOneFormat) {
+  auto factory = GetParam();
+  auto supported_encoders = factory->GetSupportedEncoders();
+  EXPECT_FALSE(supported_encoders.empty());
+}
+
+TEST_P(AudioEncoderFactoryTest, CanQueryAllSupportedFormats) {
+  auto factory = GetParam();
+  auto supported_encoders = factory->GetSupportedEncoders();
+  for (const auto& spec : supported_encoders) {
+    auto info = factory->QueryAudioEncoder(spec.format);
+    EXPECT_TRUE(info);
+  }
+}
+
+TEST_P(AudioEncoderFactoryTest, CanConstructAllSupportedEncoders) {
+  auto factory = GetParam();
+  auto supported_encoders = factory->GetSupportedEncoders();
+  for (const auto& spec : supported_encoders) {
+    auto info = factory->QueryAudioEncoder(spec.format);
+    auto encoder = factory->MakeAudioEncoder(127, spec.format);
+    EXPECT_TRUE(encoder);
+    EXPECT_EQ(encoder->SampleRateHz(), info->sample_rate_hz);
+    EXPECT_EQ(encoder->NumChannels(), info->num_channels);
+    EXPECT_EQ(encoder->RtpTimestampRateHz(), spec.format.clockrate_hz);
+  }
+}
+
+TEST_P(AudioEncoderFactoryTest, CanRunAllSupportedEncoders) {
+  constexpr int kTestPayloadType = 127;
+  auto factory = GetParam();
+  auto supported_encoders = factory->GetSupportedEncoders();
+  for (const auto& spec : supported_encoders) {
+    auto encoder = factory->MakeAudioEncoder(kTestPayloadType, spec.format);
+    EXPECT_TRUE(encoder);
+    encoder->Reset();
+    const int num_samples =
+        encoder->SampleRateHz() * encoder->NumChannels() / 100;
+    rtc::Buffer out;
+    rtc::BufferT<int16_t> audio;
+    audio.SetData(num_samples, [](rtc::ArrayView<int16_t> audio) {
+      for (size_t i = 0; i != audio.size(); ++i) {
+        // Just put some numbers in there, ensure they're within range.
+        audio[i] =
+            static_cast<int16_t>(i & std::numeric_limits<int16_t>::max());
+      }
+      return audio.size();
+    });
+    // This is here to stop the test going forever with a broken encoder.
+    constexpr int kMaxEncodeCalls = 100;
+    int blocks = 0;
+    for (; blocks < kMaxEncodeCalls; ++blocks) {
+      AudioEncoder::EncodedInfo info = encoder->Encode(
+          blocks * encoder->RtpTimestampRateHz() / 100, audio, &out);
+      EXPECT_EQ(info.encoded_bytes, out.size());
+      if (info.encoded_bytes > 0) {
+        EXPECT_EQ(0u, info.encoded_timestamp);
+        EXPECT_EQ(kTestPayloadType, info.payload_type);
+        break;
+      }
+    }
+    ASSERT_LT(blocks, kMaxEncodeCalls);
+    const unsigned int next_timestamp =
+        blocks * encoder->RtpTimestampRateHz() / 100;
+    out.Clear();
+    for (; blocks < kMaxEncodeCalls; ++blocks) {
+      AudioEncoder::EncodedInfo info = encoder->Encode(
+          blocks * encoder->RtpTimestampRateHz() / 100, audio, &out);
+      EXPECT_EQ(info.encoded_bytes, out.size());
+      if (info.encoded_bytes > 0) {
+        EXPECT_EQ(next_timestamp, info.encoded_timestamp);
+        EXPECT_EQ(kTestPayloadType, info.payload_type);
+        break;
+      }
+    }
+    ASSERT_LT(blocks, kMaxEncodeCalls);
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(BuiltinAudioEncoderFactoryTest,
+                        AudioEncoderFactoryTest,
+                        ::testing::Values(CreateBuiltinAudioEncoderFactory()));
+
+TEST(BuiltinAudioEncoderFactoryTest, SupportsTheExpectedFormats) {
+  using ::testing::ElementsAreArray;
+  // Check that we claim to support the formats we expect from build flags, and
+  // we've ordered them correctly.
+  auto factory = CreateBuiltinAudioEncoderFactory();
+  auto specs = factory->GetSupportedEncoders();
+
+  const std::vector<SdpAudioFormat> supported_formats = [&specs] {
+    std::vector<SdpAudioFormat> formats;
+    for (const auto& spec : specs) {
+      formats.push_back(spec.format);
+    }
+    return formats;
+  }();
+
+  const std::vector<SdpAudioFormat> expected_formats = {
+#ifdef WEBRTC_CODEC_OPUS
+    {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}},
+#endif
+#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
+    {"isac", 16000, 1},
+#endif
+#ifdef WEBRTC_CODEC_ISAC
+    {"isac", 32000, 1},
+#endif
+#ifdef WEBRTC_CODEC_G722
+    {"G722", 8000, 1},
+#endif
+#ifdef WEBRTC_CODEC_ILBC
+    {"ilbc", 8000, 1},
+#endif
+    {"pcmu", 8000, 1},
+    {"pcma", 8000, 1}
+  };
+
+  ASSERT_THAT(supported_formats, ElementsAreArray(expected_formats));
+}
+}  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
index baa5d38..113fb63 100644
--- a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
+++ b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
@@ -10,9 +10,11 @@
 
 #include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
 
+#include <algorithm>
 #include <limits>
 
 #include "webrtc/base/checks.h"
+#include "webrtc/base/string_to_number.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/audio_coding/codecs/g711/g711_interface.h"
 
@@ -29,6 +31,35 @@
   return config;
 }
 
+template <typename T>
+typename T::Config CreateConfig(int payload_type,
+                                const SdpAudioFormat& format) {
+  typename T::Config config;
+  config.frame_size_ms = 20;
+  auto ptime_iter = format.parameters.find("ptime");
+  if (ptime_iter != format.parameters.end()) {
+    auto ptime = rtc::StringToNumber<int>(ptime_iter->second);
+    if (ptime && *ptime > 0) {
+      const int whole_packets = *ptime / 10;
+      config.frame_size_ms = std::max(10, std::min(whole_packets * 10, 60));
+    }
+  }
+  config.num_channels = format.num_channels;
+  config.payload_type = payload_type;
+  return config;
+}
+
+template <typename T>
+rtc::Optional<AudioCodecInfo> QueryAudioEncoderImpl(
+    const SdpAudioFormat& format) {
+  if (STR_CASE_CMP(format.name.c_str(), T::GetPayloadName()) == 0 &&
+      format.clockrate_hz == 8000 && format.num_channels >= 1 &&
+      CreateConfig<T>(0, format).IsOk()) {
+    return rtc::Optional<AudioCodecInfo>({8000, format.num_channels, 64000});
+  }
+  return rtc::Optional<AudioCodecInfo>();
+}
+
 }  // namespace
 
 bool AudioEncoderPcm::Config::IsOk() const {
@@ -107,6 +138,15 @@
 AudioEncoderPcmA::AudioEncoderPcmA(const CodecInst& codec_inst)
     : AudioEncoderPcmA(CreateConfig<AudioEncoderPcmA>(codec_inst)) {}
 
+AudioEncoderPcmA::AudioEncoderPcmA(int payload_type,
+                                   const SdpAudioFormat& format)
+    : AudioEncoderPcmA(CreateConfig<AudioEncoderPcmA>(payload_type, format)) {}
+
+rtc::Optional<AudioCodecInfo> AudioEncoderPcmA::QueryAudioEncoder(
+    const SdpAudioFormat& format) {
+  return QueryAudioEncoderImpl<AudioEncoderPcmA>(format);
+}
+
 size_t AudioEncoderPcmA::EncodeCall(const int16_t* audio,
                                     size_t input_len,
                                     uint8_t* encoded) {
@@ -124,6 +164,15 @@
 AudioEncoderPcmU::AudioEncoderPcmU(const CodecInst& codec_inst)
     : AudioEncoderPcmU(CreateConfig<AudioEncoderPcmU>(codec_inst)) {}
 
+AudioEncoderPcmU::AudioEncoderPcmU(int payload_type,
+                                   const SdpAudioFormat& format)
+    : AudioEncoderPcmU(CreateConfig<AudioEncoderPcmU>(payload_type, format)) {}
+
+rtc::Optional<AudioCodecInfo> AudioEncoderPcmU::QueryAudioEncoder(
+    const SdpAudioFormat& format) {
+  return QueryAudioEncoderImpl<AudioEncoderPcmU>(format);
+}
+
 size_t AudioEncoderPcmU::EncodeCall(const int16_t* audio,
                                     size_t input_len,
                                     uint8_t* encoded) {
diff --git a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h
index 7213445..a98d2da 100644
--- a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h
+++ b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h
@@ -13,6 +13,7 @@
 
 #include <vector>
 
+#include "webrtc/api/audio_codecs/audio_format.h"
 #include "webrtc/base/constructormagic.h"
 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
 
@@ -80,6 +81,11 @@
   explicit AudioEncoderPcmA(const Config& config)
       : AudioEncoderPcm(config, kSampleRateHz) {}
   explicit AudioEncoderPcmA(const CodecInst& codec_inst);
+  AudioEncoderPcmA(int payload_type, const SdpAudioFormat& format);
+
+  static constexpr const char* GetPayloadName() { return "pcma"; }
+  static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+      const SdpAudioFormat& format);
 
  protected:
   size_t EncodeCall(const int16_t* audio,
@@ -104,6 +110,11 @@
   explicit AudioEncoderPcmU(const Config& config)
       : AudioEncoderPcm(config, kSampleRateHz) {}
   explicit AudioEncoderPcmU(const CodecInst& codec_inst);
+  AudioEncoderPcmU(int payload_type, const SdpAudioFormat& format);
+
+  static constexpr const char* GetPayloadName() { return "pcmu"; }
+  static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+      const SdpAudioFormat& format);
 
  protected:
   size_t EncodeCall(const int16_t* audio,
diff --git a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
index 1f3936c..d5cf616 100644
--- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
+++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
@@ -10,8 +10,12 @@
 
 #include "webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h"
 
+#include <algorithm>
+
 #include <limits>
 #include "webrtc/base/checks.h"
+#include "webrtc/base/safe_conversions.h"
+#include "webrtc/base/string_to_number.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/audio_coding/codecs/g722/g722_interface.h"
 
@@ -29,6 +33,22 @@
   return config;
 }
 
+AudioEncoderG722::Config CreateConfig(int payload_type,
+                                      const SdpAudioFormat& format) {
+  AudioEncoderG722::Config config;
+  config.payload_type = payload_type;
+  config.num_channels = format.num_channels;
+  auto ptime_iter = format.parameters.find("ptime");
+  if (ptime_iter != format.parameters.end()) {
+    auto ptime = rtc::StringToNumber<int>(ptime_iter->second);
+    if (ptime && *ptime > 0) {
+      const int whole_packets = *ptime / 10;
+      config.frame_size_ms = std::max(10, std::min(whole_packets * 10, 60));
+    }
+  }
+  return config;
+}
+
 }  // namespace
 
 bool AudioEncoderG722::Config::IsOk() const {
@@ -58,8 +78,24 @@
 AudioEncoderG722::AudioEncoderG722(const CodecInst& codec_inst)
     : AudioEncoderG722(CreateConfig(codec_inst)) {}
 
+AudioEncoderG722::AudioEncoderG722(int payload_type,
+                                   const SdpAudioFormat& format)
+    : AudioEncoderG722(CreateConfig(payload_type, format)) {}
+
 AudioEncoderG722::~AudioEncoderG722() = default;
 
+rtc::Optional<AudioCodecInfo> AudioEncoderG722::QueryAudioEncoder(
+    const SdpAudioFormat& format) {
+  if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0) {
+    Config config = CreateConfig(0, format);
+    if (format.clockrate_hz == 8000 && config.IsOk()) {
+      return rtc::Optional<AudioCodecInfo>(
+          {rtc::dchecked_cast<int>(kSampleRateHz), config.num_channels, 64000});
+    }
+  }
+  return rtc::Optional<AudioCodecInfo>();
+}
+
 int AudioEncoderG722::SampleRateHz() const {
   return kSampleRateHz;
 }
diff --git a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h
index ad49a86..cc3e7e5 100644
--- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h
+++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h
@@ -13,6 +13,7 @@
 
 #include <memory>
 
+#include "webrtc/api/audio_codecs/audio_format.h"
 #include "webrtc/base/buffer.h"
 #include "webrtc/base/constructormagic.h"
 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
@@ -34,8 +35,13 @@
 
   explicit AudioEncoderG722(const Config& config);
   explicit AudioEncoderG722(const CodecInst& codec_inst);
+  AudioEncoderG722(int payload_type, const SdpAudioFormat& format);
   ~AudioEncoderG722() override;
 
+  static constexpr const char* GetPayloadName() { return "G722"; }
+  static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+      const SdpAudioFormat& format);
+
   int SampleRateHz() const override;
   size_t NumChannels() const override;
   int RtpTimestampRateHz() const override;
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
index ca11587..6ed445a 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
+++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
@@ -13,6 +13,8 @@
 #include <algorithm>
 #include <limits>
 #include "webrtc/base/checks.h"
+#include "webrtc/base/safe_conversions.h"
+#include "webrtc/base/string_to_number.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/audio_coding/codecs/ilbc/ilbc.h"
 
@@ -29,6 +31,34 @@
   return config;
 }
 
+AudioEncoderIlbc::Config CreateConfig(int payload_type,
+                                      const SdpAudioFormat& format) {
+  AudioEncoderIlbc::Config config;
+  config.payload_type = payload_type;
+  auto ptime_iter = format.parameters.find("ptime");
+  if (ptime_iter != format.parameters.end()) {
+    auto ptime = rtc::StringToNumber<int>(ptime_iter->second);
+    if (ptime && *ptime > 0) {
+      const int whole_packets = *ptime / 10;
+      config.frame_size_ms = std::max(20, std::min(whole_packets * 10, 60));
+    }
+  }
+  return config;
+}
+
+int GetIlbcBitrate(int ptime) {
+  switch (ptime) {
+    case 20: case 40:
+      // 38 bytes per frame of 20 ms => 15200 bits/s.
+      return 15200;
+    case 30: case 60:
+      // 50 bytes per frame of 30 ms => (approx) 13333 bits/s.
+      return 13333;
+    default:
+      FATAL();
+  }
+}
+
 }  // namespace
 
 // static
@@ -52,6 +82,24 @@
 AudioEncoderIlbc::AudioEncoderIlbc(const CodecInst& codec_inst)
     : AudioEncoderIlbc(CreateConfig(codec_inst)) {}
 
+AudioEncoderIlbc::AudioEncoderIlbc(int payload_type,
+                                   const SdpAudioFormat& format)
+    : AudioEncoderIlbc(CreateConfig(payload_type, format)) {}
+
+rtc::Optional<AudioCodecInfo> AudioEncoderIlbc::QueryAudioEncoder(
+    const SdpAudioFormat& format) {
+  if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0 &&
+      format.clockrate_hz == 8000 && format.num_channels == 1) {
+    Config config = CreateConfig(0, format);
+    if (config.IsOk()) {
+      return rtc::Optional<AudioCodecInfo>(
+          {kSampleRateHz, 1, GetIlbcBitrate(config.frame_size_ms)});
+    }
+  }
+
+  return rtc::Optional<AudioCodecInfo>();
+}
+
 AudioEncoderIlbc::~AudioEncoderIlbc() {
   RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_));
 }
@@ -73,16 +121,8 @@
 }
 
 int AudioEncoderIlbc::GetTargetBitrate() const {
-  switch (num_10ms_frames_per_packet_) {
-    case 2: case 4:
-      // 38 bytes per frame of 20 ms => 15200 bits/s.
-      return 15200;
-    case 3: case 6:
-      // 50 bytes per frame of 30 ms => (approx) 13333 bits/s.
-      return 13333;
-    default:
-      FATAL();
-  }
+  return GetIlbcBitrate(rtc::dchecked_cast<int>(num_10ms_frames_per_packet_) *
+                        10);
 }
 
 AudioEncoder::EncodedInfo AudioEncoderIlbc::EncodeImpl(
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h
index 6363986..467caee 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h
+++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h
@@ -11,6 +11,7 @@
 #ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_AUDIO_ENCODER_ILBC_H_
 #define WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_AUDIO_ENCODER_ILBC_H_
 
+#include "webrtc/api/audio_codecs/audio_format.h"
 #include "webrtc/base/constructormagic.h"
 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
 #include "webrtc/modules/audio_coding/codecs/ilbc/ilbc.h"
@@ -32,8 +33,13 @@
 
   explicit AudioEncoderIlbc(const Config& config);
   explicit AudioEncoderIlbc(const CodecInst& codec_inst);
+  AudioEncoderIlbc(int payload_type, const SdpAudioFormat& format);
   ~AudioEncoderIlbc() override;
 
+  static constexpr const char* GetPayloadName() { return "ilbc"; }
+  static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+      const SdpAudioFormat& format);
+
   int SampleRateHz() const override;
   size_t NumChannels() const override;
   size_t Num10MsFramesInNextPacket() const override;
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
index f1f2714..64d6384 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
@@ -13,6 +13,7 @@
 
 #include <vector>
 
+#include "webrtc/api/audio_codecs/audio_format.h"
 #include "webrtc/base/constructormagic.h"
 #include "webrtc/base/scoped_ref_ptr.h"
 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
@@ -55,8 +56,13 @@
   explicit AudioEncoderIsacT(
       const CodecInst& codec_inst,
       const rtc::scoped_refptr<LockedIsacBandwidthInfo>& bwinfo);
+  AudioEncoderIsacT(int payload_type, const SdpAudioFormat& format);
   ~AudioEncoderIsacT() override;
 
+  static constexpr const char* GetPayloadName() { return "isac"; }
+  static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+      const SdpAudioFormat& format);
+
   int SampleRateHz() const override;
   size_t NumChannels() const override;
   size_t Num10MsFramesInNextPacket() const override;
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
index e4d58ae..ebe4d6a 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
@@ -12,9 +12,15 @@
 #define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
 
 #include "webrtc/base/checks.h"
+#include "webrtc/base/string_to_number.h"
 #include "webrtc/common_types.h"
 
 namespace webrtc {
+namespace {  // NOLINT (not a "regular" header file)
+int GetIsacMaxBitrate(int clockrate_hz) {
+  return (clockrate_hz == 32000) ? 56000 : 32000;
+}
+}  // namespace
 
 template <typename T>
 typename AudioEncoderIsacT<T>::Config CreateIsacConfig(
@@ -33,6 +39,33 @@
 }
 
 template <typename T>
+typename AudioEncoderIsacT<T>::Config CreateIsacConfig(
+    int payload_type,
+    const SdpAudioFormat& format) {
+  typename AudioEncoderIsacT<T>::Config config;
+  config.payload_type = payload_type;
+  config.sample_rate_hz = format.clockrate_hz;
+
+  // We only support different frame sizes at 16000 Hz.
+  if (config.sample_rate_hz == 16000) {
+    auto ptime_iter = format.parameters.find("ptime");
+    if (ptime_iter != format.parameters.end()) {
+      auto ptime = rtc::StringToNumber<int>(ptime_iter->second);
+      if (ptime && *ptime >= 60) {
+        config.frame_size_ms = 60;
+      } else {
+        config.frame_size_ms = 30;
+      }
+    }
+  }
+
+  // Set the default bitrate for ISAC to the maximum bitrate allowed at this
+  // clockrate. At this point, adaptive mode is not used by WebRTC.
+  config.bit_rate = GetIsacMaxBitrate(format.clockrate_hz);
+  return config;
+}
+
+template <typename T>
 bool AudioEncoderIsacT<T>::Config::IsOk() const {
   if (max_bit_rate < 32000 && max_bit_rate != -1)
     return false;
@@ -73,6 +106,25 @@
     : AudioEncoderIsacT(CreateIsacConfig<T>(codec_inst, bwinfo)) {}
 
 template <typename T>
+AudioEncoderIsacT<T>::AudioEncoderIsacT(int payload_type,
+                                        const SdpAudioFormat& format)
+    : AudioEncoderIsacT(CreateIsacConfig<T>(payload_type, format)) {}
+
+template <typename T>
+rtc::Optional<AudioCodecInfo> AudioEncoderIsacT<T>::QueryAudioEncoder(
+    const SdpAudioFormat& format) {
+  if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0) {
+    Config config = CreateIsacConfig<T>(0, format);
+    if (config.IsOk()) {
+      return rtc::Optional<AudioCodecInfo>(
+          {config.sample_rate_hz, 1, config.bit_rate, 10000,
+           GetIsacMaxBitrate(format.clockrate_hz)});
+    }
+  }
+  return rtc::Optional<AudioCodecInfo>();
+}
+
+template <typename T>
 AudioEncoderIsacT<T>::~AudioEncoderIsacT() {
   RTC_CHECK_EQ(0, T::Free(isac_state_));
 }
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 103ec9b..aaf2647 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
@@ -12,11 +12,14 @@
 
 #include <algorithm>
 #include <iterator>
+#include <utility>
 
+#include "webrtc/base/arraysize.h"
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/numerics/exp_filter.h"
 #include "webrtc/base/safe_conversions.h"
+#include "webrtc/base/string_to_number.h"
 #include "webrtc/base/timeutils.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h"
@@ -28,39 +31,42 @@
 
 namespace {
 
-constexpr int kSampleRateHz = 48000;
+// Codec parameters for Opus.
+// draft-spittka-payload-rtp-opus-03
+
+// Recommended bitrates:
+// 8-12 kb/s for NB speech,
+// 16-20 kb/s for WB speech,
+// 28-40 kb/s for FB speech,
+// 48-64 kb/s for FB mono music, and
+// 64-128 kb/s for FB stereo music.
+// The current implementation applies the following values to mono signals,
+// and multiplies them by 2 for stereo.
+constexpr int kOpusBitrateNbBps = 12000;
+constexpr int kOpusBitrateWbBps = 20000;
+constexpr int kOpusBitrateFbBps = 32000;
 
 // Opus API allows a min bitrate of 500bps, but Opus documentation suggests
-// a minimum bitrate of 6kbps.
-constexpr int kMinBitrateBps = 6000;
+// bitrate should be in the range of 6000 to 510000, inclusive.
+constexpr int kOpusMinBitrateBps = 6000;
+constexpr int kOpusMaxBitrateBps = 510000;
 
-constexpr int kMaxBitrateBps = 512000;
+constexpr int kSampleRateHz = 48000;
+constexpr int kDefaultMaxPlaybackRate = 48000;
 
+// These two lists must be sorted from low to high
 #if WEBRTC_OPUS_SUPPORT_120MS_PTIME
-constexpr int kSupportedFrameLengths[] = {20, 60, 120};
+constexpr int kANASupportedFrameLengths[] = {20, 60, 120};
+constexpr int kOpusSupportedFrameLengths[] = {10, 20, 40, 60, 120};
 #else
-constexpr int kSupportedFrameLengths[] = {20, 60};
+constexpr int kANASupportedFrameLengths[] = {20, 60};
+constexpr int kOpusSupportedFrameLengths[] = {10, 20, 40, 60};
 #endif
 
 // PacketLossFractionSmoother uses an exponential filter with a time constant
 // of -1.0 / ln(0.9999) = 10000 ms.
 constexpr float kAlphaForPacketLossFractionSmoother = 0.9999f;
 
-AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) {
-  AudioEncoderOpus::Config 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.supported_frame_lengths_ms.push_back(config.frame_size_ms);
-#if WEBRTC_OPUS_VARIABLE_COMPLEXITY
-  config.low_rate_complexity = 9;
-#endif
-  return config;
-}
-
 // Optimize the loss rate to configure Opus. Basically, optimized loss rate is
 // the input loss rate rounded down to various levels, because a robustly good
 // audio quality is achieved by lowering the packet loss down.
@@ -101,8 +107,180 @@
   }
 }
 
+rtc::Optional<std::string> GetFormatParameter(const SdpAudioFormat& format,
+                                              const std::string& param) {
+  auto it = format.parameters.find(param);
+  return (it == format.parameters.end())
+             ? rtc::Optional<std::string>()
+             : rtc::Optional<std::string>(it->second);
+}
+
+template <typename T>
+rtc::Optional<T> GetFormatParameter(const SdpAudioFormat& format,
+                                    const std::string& param) {
+  return rtc::StringToNumber<T>(GetFormatParameter(format, param).value_or(""));
+}
+
+int CalculateDefaultBitrate(int max_playback_rate, size_t num_channels) {
+  const int bitrate = [&] {
+    if (max_playback_rate <= 8000) {
+      return kOpusBitrateNbBps * rtc::dchecked_cast<int>(num_channels);
+    } else if (max_playback_rate <= 16000) {
+      return kOpusBitrateWbBps * rtc::dchecked_cast<int>(num_channels);
+    } else {
+      return kOpusBitrateFbBps * rtc::dchecked_cast<int>(num_channels);
+    }
+  }();
+  RTC_DCHECK_GE(bitrate, kOpusMinBitrateBps);
+  RTC_DCHECK_LE(bitrate, kOpusMaxBitrateBps);
+  return bitrate;
+}
+
+// Get the maxaveragebitrate parameter in string-form, so we can properly figure
+// out how invalid it is and accurately log invalid values.
+int CalculateBitrate(int max_playback_rate_hz,
+                     size_t num_channels,
+                     rtc::Optional<std::string> bitrate_param) {
+  const int default_bitrate =
+      CalculateDefaultBitrate(max_playback_rate_hz, num_channels);
+
+  if (bitrate_param) {
+    const auto bitrate = rtc::StringToNumber<int>(*bitrate_param);
+    if (bitrate) {
+      const int chosen_bitrate =
+          std::max(kOpusMinBitrateBps, std::min(*bitrate, kOpusMaxBitrateBps));
+      if (bitrate != chosen_bitrate) {
+        LOG(LS_WARNING) << "Invalid maxaveragebitrate " << *bitrate
+                        << " clamped to " << chosen_bitrate;
+      }
+      return chosen_bitrate;
+    }
+    LOG(LS_WARNING) << "Invalid maxaveragebitrate \"" << *bitrate_param
+                    << "\" replaced by default bitrate " << default_bitrate;
+  }
+
+  return default_bitrate;
+}
+
+int GetChannelCount(const SdpAudioFormat& format) {
+  const auto param = GetFormatParameter(format, "stereo");
+  if (param == "1") {
+    return 2;
+  } else {
+    return 1;
+  }
+}
+
+int GetMaxPlaybackRate(const SdpAudioFormat& format) {
+  const auto param = GetFormatParameter<int>(format, "maxplaybackrate");
+  if (param && *param >= 8000) {
+    return std::min(*param, kDefaultMaxPlaybackRate);
+  }
+  return kDefaultMaxPlaybackRate;
+}
+
+int GetFrameSizeMs(const SdpAudioFormat& format) {
+  const auto ptime = GetFormatParameter<int>(format, "ptime");
+  if (ptime) {
+    // Pick the next highest supported frame length from
+    // kOpusSupportedFrameLengths.
+    for (const int supported_frame_length : kOpusSupportedFrameLengths) {
+      if (supported_frame_length >= *ptime) {
+        return supported_frame_length;
+      }
+    }
+    // If none was found, return the largest supported frame length.
+    return *(std::end(kOpusSupportedFrameLengths) - 1);
+  }
+
+  return AudioEncoderOpus::Config::kDefaultFrameSizeMs;
+}
+
+void FindSupportedFrameLengths(int min_frame_length_ms,
+                               int max_frame_length_ms,
+                               std::vector<int>* out) {
+  out->clear();
+  std::copy_if(std::begin(kANASupportedFrameLengths),
+               std::end(kANASupportedFrameLengths), std::back_inserter(*out),
+               [&](int frame_length_ms) {
+                 return frame_length_ms >= min_frame_length_ms &&
+                        frame_length_ms <= max_frame_length_ms;
+               });
+  RTC_DCHECK(std::is_sorted(out->begin(), out->end()));
+}
+
 }  // namespace
 
+rtc::Optional<AudioCodecInfo> AudioEncoderOpus::QueryAudioEncoder(
+    const SdpAudioFormat& format) {
+  if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0 &&
+      format.clockrate_hz == 48000 && format.num_channels == 2) {
+    const size_t num_channels = GetChannelCount(format);
+    const int bitrate =
+        CalculateBitrate(GetMaxPlaybackRate(format), num_channels,
+                         GetFormatParameter(format, "maxaveragebitrate"));
+    AudioCodecInfo info(48000, num_channels, bitrate, kOpusMinBitrateBps,
+                        kOpusMaxBitrateBps);
+    info.allow_comfort_noise = false;
+    info.supports_network_adaption = true;
+
+    return rtc::Optional<AudioCodecInfo>(info);
+  }
+  return rtc::Optional<AudioCodecInfo>();
+}
+
+AudioEncoderOpus::Config AudioEncoderOpus::CreateConfig(
+    const CodecInst& codec_inst) {
+  AudioEncoderOpus::Config 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.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,
+    const SdpAudioFormat& format) {
+  AudioEncoderOpus::Config config;
+
+  config.num_channels = GetChannelCount(format);
+  config.frame_size_ms = GetFrameSizeMs(format);
+  config.max_playback_rate_hz = GetMaxPlaybackRate(format);
+  config.fec_enabled = (GetFormatParameter(format, "useinbandfec") == "1");
+  config.dtx_enabled = (GetFormatParameter(format, "usedtx") == "1");
+  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
+
+  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.
+  const int min_frame_length_ms =
+      GetFormatParameter<int>(format, "minptime").value_or(kMinANAFrameLength);
+  const int max_frame_length_ms =
+      GetFormatParameter<int>(format, "maxptime").value_or(kMaxANAFrameLength);
+
+  FindSupportedFrameLengths(min_frame_length_ms, max_frame_length_ms,
+                            &config.supported_frame_lengths_ms);
+  return config;
+}
+
 class AudioEncoderOpus::PacketLossFractionSmoother {
  public:
   explicit PacketLossFractionSmoother(const Clock* clock)
@@ -147,7 +325,7 @@
   if (num_channels != 1 && num_channels != 2)
     return false;
   if (bitrate_bps &&
-      (*bitrate_bps < kMinBitrateBps || *bitrate_bps > kMaxBitrateBps))
+      (*bitrate_bps < kOpusMinBitrateBps || *bitrate_bps > kOpusMaxBitrateBps))
     return false;
   if (complexity < 0 || complexity > 10)
     return false;
@@ -208,6 +386,10 @@
 AudioEncoderOpus::AudioEncoderOpus(const CodecInst& codec_inst)
     : AudioEncoderOpus(CreateConfig(codec_inst), nullptr) {}
 
+AudioEncoderOpus::AudioEncoderOpus(int payload_type,
+                                   const SdpAudioFormat& format)
+    : AudioEncoderOpus(CreateConfig(payload_type, format), nullptr) {}
+
 AudioEncoderOpus::~AudioEncoderOpus() {
   RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
 }
@@ -344,8 +526,8 @@
     const int overhead_bps = static_cast<int>(
         *overhead_bytes_per_packet_ * 8 * 100 / Num10MsFramesInNextPacket());
     SetTargetBitrate(std::min(
-        kMaxBitrateBps,
-        std::max(kMinBitrateBps, target_audio_bitrate_bps - overhead_bps)));
+        kOpusMaxBitrateBps,
+        std::max(kOpusMinBitrateBps, target_audio_bitrate_bps - overhead_bps)));
   } else {
     SetTargetBitrate(target_audio_bitrate_bps);
   }
@@ -374,17 +556,8 @@
   // |EnableAudioNetworkAdaptor|, otherwise we need to recreate
   // |audio_network_adaptor_|, which is not a needed use case.
   RTC_DCHECK(!audio_network_adaptor_);
-
-  config_.supported_frame_lengths_ms.clear();
-  std::copy_if(std::begin(kSupportedFrameLengths),
-               std::end(kSupportedFrameLengths),
-               std::back_inserter(config_.supported_frame_lengths_ms),
-               [&](int frame_length_ms) {
-                 return frame_length_ms >= min_frame_length_ms &&
-                        frame_length_ms <= max_frame_length_ms;
-               });
-  RTC_DCHECK(std::is_sorted(config_.supported_frame_lengths_ms.begin(),
-                            config_.supported_frame_lengths_ms.end()));
+  FindSupportedFrameLengths(min_frame_length_ms, max_frame_length_ms,
+                            &config_.supported_frame_lengths_ms);
 }
 
 AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeImpl(
@@ -516,8 +689,8 @@
 }
 
 void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) {
-  config_.bitrate_bps = rtc::Optional<int>(
-      std::max(std::min(bits_per_second, kMaxBitrateBps), kMinBitrateBps));
+  config_.bitrate_bps = rtc::Optional<int>(std::max(
+      std::min(bits_per_second, kOpusMaxBitrateBps), kOpusMinBitrateBps));
   RTC_DCHECK(config_.IsOk());
   RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.GetBitrateBps()));
   const auto new_complexity = config_.GetNewComplexity();
@@ -558,7 +731,7 @@
       config,
       ControllerManagerImpl::Create(
           config_string, NumChannels(), supported_frame_lengths_ms(),
-          kMinBitrateBps, num_channels_to_encode_, next_frame_length_ms_,
+          kOpusMinBitrateBps, num_channels_to_encode_, next_frame_length_ms_,
           GetTargetBitrate(), config_.fec_enabled, GetDtx(), clock)));
 }
 
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 8f5bba6..3d3597b 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h
@@ -16,12 +16,13 @@
 #include <string>
 #include <vector>
 
+#include "webrtc/api/audio_codecs/audio_format.h"
 #include "webrtc/base/constructormagic.h"
 #include "webrtc/base/optional.h"
 #include "webrtc/common_audio/smoothing_filter.h"
 #include "webrtc/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
-#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
+#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
 
 namespace webrtc {
 
@@ -50,7 +51,8 @@
     // current bitrate is above or below complexity_threshold_bps.
     rtc::Optional<int> GetNewComplexity() const;
 
-    int frame_size_ms = 20;
+    static constexpr int kDefaultFrameSizeMs = 20;
+    int frame_size_ms = kDefaultFrameSizeMs;
     size_t num_channels = 1;
     int payload_type = 120;
     ApplicationMode application = kVoip;
@@ -79,6 +81,9 @@
 #endif
   };
 
+  static Config CreateConfig(int payload_type, const SdpAudioFormat& format);
+  static Config CreateConfig(const CodecInst& codec_inst);
+
   using AudioNetworkAdaptorCreator =
       std::function<std::unique_ptr<AudioNetworkAdaptor>(const std::string&,
                                                          RtcEventLog*,
@@ -89,9 +94,14 @@
       std::unique_ptr<SmoothingFilter> bitrate_smoother = nullptr);
 
   explicit AudioEncoderOpus(const CodecInst& codec_inst);
-
+  AudioEncoderOpus(int payload_type, const SdpAudioFormat& format);
   ~AudioEncoderOpus() override;
 
+  // Static interface for use by BuiltinAudioEncoderFactory.
+  static constexpr const char* GetPayloadName() { return "opus"; }
+  static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+      const SdpAudioFormat& format);
+
   int SampleRateHz() const override;
   size_t NumChannels() const override;
   size_t Num10MsFramesInNextPacket() const override;
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 04c0cf1..55d3c92 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
@@ -10,6 +10,7 @@
 
 #include <array>
 #include <memory>
+#include <utility>
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/fakeclock.h"
@@ -45,6 +46,12 @@
   return config;
 }
 
+AudioEncoderOpus::Config CreateConfigWithParameters(
+    const SdpAudioFormat::Parameters& params) {
+  SdpAudioFormat format("opus", 48000, 2, params);
+  return AudioEncoderOpus::CreateConfig(0, format);
+}
+
 struct AudioEncoderOpusStates {
   std::shared_ptr<MockAudioNetworkAdaptor*> mock_audio_network_adaptor;
   MockSmoothingFilter* mock_bitrate_smoother;
@@ -186,7 +193,7 @@
   auto states = CreateCodec(1);
   // Constants are replicated from audio_states.encoderopus.cc.
   const int kMinBitrateBps = 6000;
-  const int kMaxBitrateBps = 512000;
+  const int kMaxBitrateBps = 510000;
   // Set a too low bitrate.
   states.encoder->OnReceivedUplinkBandwidth(kMinBitrateBps - 1,
                                             rtc::Optional<int64_t>());
@@ -417,7 +424,7 @@
       "WebRTC-SendSideBwe-WithOverhead/Enabled/");
 
   constexpr int kMinBitrateBps = 6000;
-  constexpr int kMaxBitrateBps = 512000;
+  constexpr int kMaxBitrateBps = 510000;
 
   auto states = CreateCodec(2);
 
@@ -545,4 +552,199 @@
   }
 }
 
+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);
+}
+
+TEST(AudioEncoderOpusTest, TestConfigFromParams) {
+  AudioEncoderOpus::Config config;
+
+  config = CreateConfigWithParameters({{"stereo", "0"}});
+  EXPECT_EQ(1U, config.num_channels);
+
+  config = CreateConfigWithParameters({{"stereo", "1"}});
+  EXPECT_EQ(2U, config.num_channels);
+
+  config = CreateConfigWithParameters({{"useinbandfec", "0"}});
+  EXPECT_FALSE(config.fec_enabled);
+
+  config = CreateConfigWithParameters({{"useinbandfec", "1"}});
+  EXPECT_TRUE(config.fec_enabled);
+
+  config = CreateConfigWithParameters({{"usedtx", "0"}});
+  EXPECT_FALSE(config.dtx_enabled);
+
+  config = CreateConfigWithParameters({{"usedtx", "1"}});
+  EXPECT_TRUE(config.dtx_enabled);
+
+  config = CreateConfigWithParameters({{"maxplaybackrate", "12345"}});
+  EXPECT_EQ(12345, config.max_playback_rate_hz);
+
+  config = CreateConfigWithParameters({{"maxaveragebitrate", "96000"}});
+  EXPECT_EQ(96000, config.bitrate_bps);
+
+  config = CreateConfigWithParameters({{"maxptime", "40"}});
+  for (int frame_length : config.supported_frame_lengths_ms) {
+    EXPECT_LE(frame_length, 40);
+  }
+
+  config = CreateConfigWithParameters({{"minptime", "40"}});
+  for (int frame_length : config.supported_frame_lengths_ms) {
+    EXPECT_GE(frame_length, 40);
+  }
+
+  config = CreateConfigWithParameters({{"ptime", "40"}});
+  EXPECT_EQ(40, config.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);
+
+  config = CreateConfigWithParameters({{"ptime", "2000"}});
+  EXPECT_EQ(kMaxSupportedFrameLength, config.frame_size_ms);
+}
+
+TEST(AudioEncoderOpusTest, TestConfigFromInvalidParams) {
+  const webrtc::SdpAudioFormat format("opus", 48000, 2);
+  const AudioEncoderOpus::Config default_config =
+      AudioEncoderOpus::CreateConfig(0, 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;
+  config = CreateConfigWithParameters({{"stereo", "invalid"}});
+  EXPECT_EQ(default_config.num_channels, config.num_channels);
+
+  config = CreateConfigWithParameters({{"useinbandfec", "invalid"}});
+  EXPECT_EQ(default_config.fec_enabled, config.fec_enabled);
+
+  config = CreateConfigWithParameters({{"usedtx", "invalid"}});
+  EXPECT_EQ(default_config.dtx_enabled, config.dtx_enabled);
+
+  config = CreateConfigWithParameters({{"maxplaybackrate", "0"}});
+  EXPECT_EQ(default_config.max_playback_rate_hz, config.max_playback_rate_hz);
+
+  config = CreateConfigWithParameters({{"maxplaybackrate", "-23"}});
+  EXPECT_EQ(default_config.max_playback_rate_hz, config.max_playback_rate_hz);
+
+  config = CreateConfigWithParameters({{"maxplaybackrate", "not a number!"}});
+  EXPECT_EQ(default_config.max_playback_rate_hz, config.max_playback_rate_hz);
+
+  config = CreateConfigWithParameters({{"maxaveragebitrate", "0"}});
+  EXPECT_EQ(6000, config.bitrate_bps);
+
+  config = CreateConfigWithParameters({{"maxaveragebitrate", "-1000"}});
+  EXPECT_EQ(6000, config.bitrate_bps);
+
+  config = CreateConfigWithParameters({{"maxaveragebitrate", "1024000"}});
+  EXPECT_EQ(510000, config.bitrate_bps);
+
+  config = CreateConfigWithParameters({{"maxaveragebitrate", "not a number!"}});
+  EXPECT_EQ(default_config.bitrate_bps, config.bitrate_bps);
+
+  config = CreateConfigWithParameters({{"maxptime", "invalid"}});
+  EXPECT_EQ(default_supported_frame_lengths_ms,
+            config.supported_frame_lengths_ms);
+
+  config = CreateConfigWithParameters({{"minptime", "invalid"}});
+  EXPECT_EQ(default_supported_frame_lengths_ms,
+            config.supported_frame_lengths_ms);
+
+  config = CreateConfigWithParameters({{"ptime", "invalid"}});
+  EXPECT_EQ(default_supported_frame_lengths_ms,
+            config.supported_frame_lengths_ms);
+}
+
+// Test that bitrate will be overridden by the "maxaveragebitrate" parameter.
+// Also test that the "maxaveragebitrate" can't be set to values outside the
+// 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);
+
+  // Ignore if larger than 510000.
+  const AudioEncoderOpus::Config config2 = AudioEncoderOpus::CreateConfig(
+      0, {"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);
+}
+
+// Test maxplaybackrate <= 8000 triggers Opus narrow band mode.
+TEST(AudioEncoderOpusTest, SetMaxPlaybackRateNb) {
+  auto config = CreateConfigWithParameters({{"maxplaybackrate", "8000"}});
+  EXPECT_EQ(8000, config.max_playback_rate_hz);
+  EXPECT_EQ(12000, config.bitrate_bps);
+
+  config = CreateConfigWithParameters({{"maxplaybackrate", "8000"},
+                                       {"stereo", "1"}});
+  EXPECT_EQ(8000, config.max_playback_rate_hz);
+  EXPECT_EQ(24000, config.bitrate_bps);
+}
+
+// Test 8000 < maxplaybackrate <= 12000 triggers Opus medium band mode.
+TEST(AudioEncoderOpusTest, SetMaxPlaybackRateMb) {
+  auto config = CreateConfigWithParameters({{"maxplaybackrate", "8001"}});
+  EXPECT_EQ(8001, config.max_playback_rate_hz);
+  EXPECT_EQ(20000, config.bitrate_bps);
+
+  config = CreateConfigWithParameters({{"maxplaybackrate", "8001"},
+                                       {"stereo", "1"}});
+  EXPECT_EQ(8001, config.max_playback_rate_hz);
+  EXPECT_EQ(40000, config.bitrate_bps);
+}
+
+// Test 12000 < maxplaybackrate <= 16000 triggers Opus wide band mode.
+TEST(AudioEncoderOpusTest, SetMaxPlaybackRateWb) {
+  auto config = CreateConfigWithParameters({{"maxplaybackrate", "12001"}});
+  EXPECT_EQ(12001, config.max_playback_rate_hz);
+  EXPECT_EQ(20000, config.bitrate_bps);
+
+  config = CreateConfigWithParameters({{"maxplaybackrate", "12001"},
+                                       {"stereo", "1"}});
+  EXPECT_EQ(12001, config.max_playback_rate_hz);
+  EXPECT_EQ(40000, config.bitrate_bps);
+}
+
+// Test 16000 < maxplaybackrate <= 24000 triggers Opus super wide band mode.
+TEST(AudioEncoderOpusTest, SetMaxPlaybackRateSwb) {
+  auto config = CreateConfigWithParameters({{"maxplaybackrate", "16001"}});
+  EXPECT_EQ(16001, config.max_playback_rate_hz);
+  EXPECT_EQ(32000, config.bitrate_bps);
+
+  config = CreateConfigWithParameters({{"maxplaybackrate", "16001"},
+                                       {"stereo", "1"}});
+  EXPECT_EQ(16001, config.max_playback_rate_hz);
+  EXPECT_EQ(64000, config.bitrate_bps);
+}
+
+// Test 24000 < maxplaybackrate triggers Opus full band mode.
+TEST(AudioEncoderOpusTest, SetMaxPlaybackRateFb) {
+  auto config = CreateConfigWithParameters({{"maxplaybackrate", "24001"}});
+  EXPECT_EQ(24001, config.max_playback_rate_hz);
+  EXPECT_EQ(32000, config.bitrate_bps);
+
+  config = CreateConfigWithParameters({{"maxplaybackrate", "24001"},
+                                       {"stereo", "1"}});
+  EXPECT_EQ(24001, config.max_playback_rate_hz);
+  EXPECT_EQ(64000, config.bitrate_bps);
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
index cafd3e8..442ea66 100644
--- a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
+++ b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
@@ -10,7 +10,11 @@
 
 #include "webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
 
+#include <algorithm>
+
 #include "webrtc/base/checks.h"
+#include "webrtc/base/safe_conversions.h"
+#include "webrtc/base/string_to_number.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.h"
 
@@ -40,6 +44,24 @@
   config.payload_type = codec_inst.pltype;
   return config;
 }
+
+AudioEncoderPcm16B::Config CreateConfig(int payload_type,
+                                        const SdpAudioFormat& format) {
+  AudioEncoderPcm16B::Config config;
+  config.num_channels = format.num_channels;
+  config.sample_rate_hz = format.clockrate_hz;
+  config.frame_size_ms = 10;
+  auto ptime_iter = format.parameters.find("ptime");
+  if (ptime_iter != format.parameters.end()) {
+    auto ptime = rtc::StringToNumber<int>(ptime_iter->second);
+    if (ptime && *ptime > 0) {
+      const int whole_packets = *ptime / 10;
+      config.frame_size_ms = std::max(10, std::min(whole_packets * 10, 60));
+    }
+  }
+  config.payload_type = payload_type;
+  return config;
+}
 }  // namespace
 
 bool AudioEncoderPcm16B::Config::IsOk() const {
@@ -52,4 +74,23 @@
 AudioEncoderPcm16B::AudioEncoderPcm16B(const CodecInst& codec_inst)
     : AudioEncoderPcm16B(CreateConfig(codec_inst)) {}
 
+AudioEncoderPcm16B::AudioEncoderPcm16B(int payload_type,
+                                       const SdpAudioFormat& format)
+    : AudioEncoderPcm16B(CreateConfig(payload_type, format)) {}
+
+rtc::Optional<AudioCodecInfo> AudioEncoderPcm16B::QueryAudioEncoder(
+    const SdpAudioFormat& format) {
+  if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0 &&
+      format.num_channels >= 1) {
+    Config config = CreateConfig(0, format);
+    if (config.IsOk()) {
+      return rtc::Optional<AudioCodecInfo>(
+          {config.sample_rate_hz, config.num_channels,
+           config.sample_rate_hz * 2 *
+               rtc::dchecked_cast<int>(config.num_channels)});
+    }
+  }
+  return rtc::Optional<AudioCodecInfo>();
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h
index bdc27a6..deb0e1e 100644
--- a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h
+++ b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h
@@ -31,6 +31,11 @@
   explicit AudioEncoderPcm16B(const Config& config)
       : AudioEncoderPcm(config, config.sample_rate_hz) {}
   explicit AudioEncoderPcm16B(const CodecInst& codec_inst);
+  AudioEncoderPcm16B(int payload_type, const SdpAudioFormat& format);
+
+  static constexpr const char* GetPayloadName() { return "L16"; }
+  static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+      const SdpAudioFormat& format);
 
  protected:
   size_t EncodeCall(const int16_t* audio,
diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
index 1ee92a1..4a4e62b 100644
--- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
@@ -611,8 +611,8 @@
   EXPECT_EQ(6000, SetAndGetTargetBitrate(audio_encoder, 5999));
   EXPECT_EQ(6000, SetAndGetTargetBitrate(audio_encoder, 6000));
   EXPECT_EQ(32000, SetAndGetTargetBitrate(audio_encoder, 32000));
-  EXPECT_EQ(512000, SetAndGetTargetBitrate(audio_encoder, 512000));
-  EXPECT_EQ(512000, SetAndGetTargetBitrate(audio_encoder, 513000));
+  EXPECT_EQ(510000, SetAndGetTargetBitrate(audio_encoder, 510000));
+  EXPECT_EQ(510000, SetAndGetTargetBitrate(audio_encoder, 511000));
 }
 }  // namespace
 
diff --git a/webrtc/pc/DEPS b/webrtc/pc/DEPS
index 5b8f955..4468e6b 100644
--- a/webrtc/pc/DEPS
+++ b/webrtc/pc/DEPS
@@ -24,12 +24,12 @@
     "+crypto",
   ],
 
-  # TODO(kwiberg): Remove these exceptions when audio_decoder_factory.h
+  # TODO(ossu): Remove these exceptions when audio_encoder_factory.h
   # has moved to api/.
   "peerconnectionfactory\.cc": [
-    "+webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h",
+    "+webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h",
   ],
   "peerconnectioninterface_unittest\.cc": [
-    "+webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h",
+    "+webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h",
   ],
 }
diff --git a/webrtc/pc/peerconnectionfactory.cc b/webrtc/pc/peerconnectionfactory.cc
index 74a693d..8269a1a 100644
--- a/webrtc/pc/peerconnectionfactory.cc
+++ b/webrtc/pc/peerconnectionfactory.cc
@@ -24,6 +24,7 @@
 #include "webrtc/media/engine/webrtcmediaengine.h"
 #include "webrtc/media/engine/webrtcvideodecoderfactory.h"
 #include "webrtc/media/engine/webrtcvideoencoderfactory.h"
+#include "webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h"
 #include "webrtc/modules/audio_device/include/audio_device.h"
 #include "webrtc/p2p/base/basicpacketsocketfactory.h"
 #include "webrtc/p2p/client/basicportallocator.h"
diff --git a/webrtc/pc/peerconnectioninterface_unittest.cc b/webrtc/pc/peerconnectioninterface_unittest.cc
index 05d53ad..e7636e0 100644
--- a/webrtc/pc/peerconnectioninterface_unittest.cc
+++ b/webrtc/pc/peerconnectioninterface_unittest.cc
@@ -27,6 +27,7 @@
 #include "webrtc/base/thread.h"
 #include "webrtc/media/base/fakevideocapturer.h"
 #include "webrtc/media/sctp/sctptransportinternal.h"
+#include "webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h"
 #include "webrtc/p2p/base/fakeportallocator.h"
 #include "webrtc/pc/audiotrack.h"
 #include "webrtc/pc/mediasession.h"
diff --git a/webrtc/voice_engine/BUILD.gn b/webrtc/voice_engine/BUILD.gn
index 8d0f249..ba79b2d 100644
--- a/webrtc/voice_engine/BUILD.gn
+++ b/webrtc/voice_engine/BUILD.gn
@@ -17,7 +17,9 @@
     "..:webrtc_common",
     "../api/audio_codecs:builtin_audio_decoder_factory",
     "../modules/audio_coding",
+    "../modules/audio_coding:audio_encoder_factory_interface",
     "../modules/audio_coding:audio_format_conversion",
+    "../modules/audio_coding:builtin_audio_encoder_factory",
     "../modules/audio_coding:rent_a_codec",
   ]