Fold AudioEncoderMutable into AudioEncoder

It makes more sense to combine the two interfaces, since there wasn't
a clear line separating them. The result is a combined interface with
just over a dozen methods, half of which need to be implemented by
every subclass, while the other half have sensible (and trivial)
default implementations and are implemented only by the few subclasses
that need non-default behavior.

Review URL: https://codereview.webrtc.org/1322973004

Cr-Commit-Position: refs/heads/master@{#9894}
diff --git a/webrtc/common_audio/vad/include/vad.h b/webrtc/common_audio/vad/include/vad.h
index 1944f9d..72c0949 100644
--- a/webrtc/common_audio/vad/include/vad.h
+++ b/webrtc/common_audio/vad/include/vad.h
@@ -37,8 +37,12 @@
                                  size_t num_samples,
                                  int sample_rate_hz);
 
+  // Reset VAD state.
+  virtual void Reset();
+
  private:
   VadInst* handle_;
+  Aggressiveness aggressiveness_;
 };
 
 }  // namespace webrtc
diff --git a/webrtc/common_audio/vad/mock/mock_vad.h b/webrtc/common_audio/vad/mock/mock_vad.h
index 7a7de0f..916480a 100644
--- a/webrtc/common_audio/vad/mock/mock_vad.h
+++ b/webrtc/common_audio/vad/mock/mock_vad.h
@@ -27,6 +27,7 @@
                enum Activity(const int16_t* audio,
                              size_t num_samples,
                              int sample_rate_hz));
+  MOCK_METHOD0(Reset, void());
 };
 
 }  // namespace webrtc
diff --git a/webrtc/common_audio/vad/vad.cc b/webrtc/common_audio/vad/vad.cc
index 764d024..dc4eb6d 100644
--- a/webrtc/common_audio/vad/vad.cc
+++ b/webrtc/common_audio/vad/vad.cc
@@ -14,11 +14,8 @@
 
 namespace webrtc {
 
-Vad::Vad(enum Aggressiveness mode) {
-  handle_ = WebRtcVad_Create();
-  CHECK(handle_);
-  CHECK_EQ(WebRtcVad_Init(handle_), 0);
-  CHECK_EQ(WebRtcVad_set_mode(handle_, mode), 0);
+Vad::Vad(enum Aggressiveness mode) : handle_(nullptr), aggressiveness_(mode) {
+  Reset();
 }
 
 Vad::~Vad() {
@@ -40,4 +37,13 @@
   }
 }
 
+void Vad::Reset() {
+  if (handle_)
+    WebRtcVad_Free(handle_);
+  handle_ = WebRtcVad_Create();
+  CHECK(handle_);
+  CHECK_EQ(WebRtcVad_Init(handle_), 0);
+  CHECK_EQ(WebRtcVad_set_mode(handle_, aggressiveness_), 0);
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.cc b/webrtc/modules/audio_coding/codecs/audio_encoder.cc
index 72e4265..eb553a7 100644
--- a/webrtc/modules/audio_coding/codecs/audio_encoder.cc
+++ b/webrtc/modules/audio_coding/codecs/audio_encoder.cc
@@ -13,10 +13,12 @@
 
 namespace webrtc {
 
-AudioEncoder::EncodedInfo::EncodedInfo() : EncodedInfoLeaf() {
-}
+AudioEncoder::EncodedInfo::EncodedInfo() = default;
 
-AudioEncoder::EncodedInfo::~EncodedInfo() {
+AudioEncoder::EncodedInfo::~EncodedInfo() = default;
+
+int AudioEncoder::RtpTimestampRateHz() const {
+  return SampleRateHz();
 }
 
 AudioEncoder::EncodedInfo AudioEncoder::Encode(uint32_t rtp_timestamp,
@@ -32,8 +34,28 @@
   return info;
 }
 
-int AudioEncoder::RtpTimestampRateHz() const {
-  return SampleRateHz();
+bool AudioEncoder::SetFec(bool enable) {
+  return !enable;
 }
 
+bool AudioEncoder::SetDtx(bool enable) {
+  return !enable;
+}
+
+bool AudioEncoder::SetApplication(Application application) {
+  return false;
+}
+
+bool AudioEncoder::SetMaxPlaybackRate(int frequency_hz) {
+  return true;
+}
+
+void AudioEncoder::SetProjectedPacketLossRate(double fraction) {}
+
+void AudioEncoder::SetTargetBitrate(int target_bps) {}
+
+void AudioEncoder::SetMaxBitrate(int max_bps) {}
+
+void AudioEncoder::SetMaxPayloadSize(int max_payload_size_bytes) {}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.h b/webrtc/modules/audio_coding/codecs/audio_encoder.h
index 0a40316..73b4468 100644
--- a/webrtc/modules/audio_coding/codecs/audio_encoder.h
+++ b/webrtc/modules/audio_coding/codecs/audio_encoder.h
@@ -23,18 +23,11 @@
 class AudioEncoder {
  public:
   struct EncodedInfoLeaf {
-    EncodedInfoLeaf()
-        : encoded_bytes(0),
-          encoded_timestamp(0),
-          payload_type(0),
-          send_even_if_empty(false),
-          speech(true) {}
-
-    size_t encoded_bytes;
-    uint32_t encoded_timestamp;
-    int payload_type;
-    bool send_even_if_empty;
-    bool speech;
+    size_t encoded_bytes = 0;
+    uint32_t encoded_timestamp = 0;
+    int payload_type = 0;
+    bool send_even_if_empty = false;
+    bool speech = true;
   };
 
   // This is the main struct for auxiliary encoding information. Each encoded
@@ -54,26 +47,9 @@
     std::vector<EncodedInfoLeaf> redundant;
   };
 
-  virtual ~AudioEncoder() {}
+  virtual ~AudioEncoder() = default;
 
-  // Accepts one 10 ms block of input audio (i.e., sample_rate_hz() / 100 *
-  // num_channels() samples). Multi-channel audio must be sample-interleaved.
-  // The encoder produces zero or more bytes of output in |encoded| and
-  // returns additional encoding information.
-  // The caller is responsible for making sure that |max_encoded_bytes| is
-  // not smaller than the number of bytes actually produced by the encoder.
-  EncodedInfo Encode(uint32_t rtp_timestamp,
-                     const int16_t* audio,
-                     size_t num_samples_per_channel,
-                     size_t max_encoded_bytes,
-                     uint8_t* encoded);
-
-  // Return the input sample rate in Hz and the number of input channels.
-  // These are constants set at instantiation time.
-  virtual int SampleRateHz() const = 0;
-  virtual int NumChannels() const = 0;
-
-  // Return the maximum number of bytes that can be produced by the encoder
+  // Returns the maximum number of bytes that can be produced by the encoder
   // at each Encode() call. The caller can use the return value to determine
   // the size of the buffer that needs to be allocated. This value is allowed
   // to depend on encoder parameters like bitrate, frame size etc., so if
@@ -81,8 +57,13 @@
   // that the buffer is large enough by calling MaxEncodedBytes() again.
   virtual size_t MaxEncodedBytes() const = 0;
 
-  // Returns the rate with which the RTP timestamps are updated. By default,
-  // this is the same as sample_rate_hz().
+  // Returns the input sample rate in Hz and the number of input channels.
+  // These are constants set at instantiation time.
+  virtual int SampleRateHz() const = 0;
+  virtual int NumChannels() const = 0;
+
+  // Returns the rate at which the RTP timestamps are updated. The default
+  // implementation returns SampleRateHz().
   virtual int RtpTimestampRateHz() const;
 
   // Returns the number of 10 ms frames the encoder will put in the next
@@ -101,52 +82,74 @@
   // provided.
   virtual int GetTargetBitrate() const = 0;
 
-  // Changes the target bitrate. The implementation is free to alter this value,
-  // e.g., if the desired value is outside the valid range.
-  virtual void SetTargetBitrate(int bits_per_second) {}
+  // Accepts one 10 ms block of input audio (i.e., SampleRateHz() / 100 *
+  // NumChannels() samples). Multi-channel audio must be sample-interleaved.
+  // The encoder produces zero or more bytes of output in |encoded| and
+  // returns additional encoding information.
+  // The caller is responsible for making sure that |max_encoded_bytes| is
+  // not smaller than the number of bytes actually produced by the encoder.
+  // Encode() checks some preconditions, calls EncodeInternal() which does the
+  // actual work, and then checks some postconditions.
+  EncodedInfo Encode(uint32_t rtp_timestamp,
+                     const int16_t* audio,
+                     size_t num_samples_per_channel,
+                     size_t max_encoded_bytes,
+                     uint8_t* encoded);
 
-  // Tells the implementation what the projected packet loss rate is. The rate
-  // is in the range [0.0, 1.0]. This rate is typically used to adjust channel
-  // coding efforts, such as FEC.
-  virtual void SetProjectedPacketLossRate(double fraction) {}
-
-  // This is the encode function that the inherited classes must implement. It
-  // is called from Encode in the base class.
   virtual EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
                                      const int16_t* audio,
                                      size_t max_encoded_bytes,
                                      uint8_t* encoded) = 0;
-};
 
-class AudioEncoderMutable : public AudioEncoder {
- public:
-  enum Application { kApplicationSpeech, kApplicationAudio };
-
-  // Discards unprocessed audio data.
+  // Resets the encoder to its starting state, discarding any input that has
+  // been fed to the encoder but not yet emitted in a packet.
   virtual void Reset() = 0;
 
-  // Enables codec-internal FEC, if the implementation supports it.
-  virtual bool SetFec(bool enable) = 0;
+  // Enables or disables codec-internal FEC (forward error correction). Returns
+  // true if the codec was able to comply. The default implementation returns
+  // true when asked to disable FEC and false when asked to enable it (meaning
+  // that FEC isn't supported).
+  virtual bool SetFec(bool enable);
 
-  // Enables or disables codec-internal VAD/DTX, if the implementation supports
-  // it.
-  virtual bool SetDtx(bool enable) = 0;
+  // Enables or disables codec-internal VAD/DTX. Returns true if the codec was
+  // able to comply. The default implementation returns true when asked to
+  // disable DTX and false when asked to enable it (meaning that DTX isn't
+  // supported).
+  virtual bool SetDtx(bool enable);
 
-  // Sets the application mode. The implementation is free to disregard this
-  // setting.
-  virtual bool SetApplication(Application application) = 0;
+  // Sets the application mode. Returns true if the codec was able to comply.
+  // The default implementation just returns false.
+  enum class Application { kSpeech, kAudio };
+  virtual bool SetApplication(Application application);
 
-  // Sets an upper limit on the payload size produced by the encoder. The
-  // implementation is free to disregard this setting.
-  virtual void SetMaxPayloadSize(int max_payload_size_bytes) = 0;
+  // Tells the encoder about the highest sample rate the decoder is expected to
+  // use when decoding the bitstream. The encoder would typically use this
+  // information to adjust the quality of the encoding. The default
+  // implementation just returns true.
+  // TODO(kwiberg): Change return value to void, since it doesn't matter
+  // whether the encoder approved of the max playback rate or not.
+  virtual bool SetMaxPlaybackRate(int frequency_hz);
 
-  // Sets the maximum rate which the codec may not exceed for any packet.
-  virtual void SetMaxRate(int max_rate_bps) = 0;
+  // Tells the encoder what the projected packet loss rate is. The rate is in
+  // the range [0.0, 1.0]. The encoder would typically use this information to
+  // adjust channel coding efforts, such as FEC. The default implementation
+  // does nothing.
+  virtual void SetProjectedPacketLossRate(double fraction);
 
-  // Informs the encoder about the maximum sample rate which the decoder will
-  // use when decoding the bitstream. The implementation is free to disregard
-  // this hint.
-  virtual bool SetMaxPlaybackRate(int frequency_hz) = 0;
+  // Tells the encoder what average bitrate we'd like it to produce. The
+  // encoder is free to adjust or disregard the given bitrate (the default
+  // implementation does the latter).
+  virtual void SetTargetBitrate(int target_bps);
+
+  // Sets the maximum bitrate which must not be exceeded for any packet. The
+  // encoder is free to adjust or disregard this value (the default
+  // implementation does the latter).
+  virtual void SetMaxBitrate(int max_bps);
+
+  // Sets an upper limit on the size of packet payloads produced by the
+  // encoder. The encoder is free to adjust or disregard this value (the
+  // default implementation does the latter).
+  virtual void SetMaxPayloadSize(int max_payload_size_bytes);
 };
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h b/webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h
deleted file mode 100644
index c1184e1..0000000
--- a/webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- *  Copyright (c) 2015 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_MUTABLE_IMPL_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_MUTABLE_IMPL_H_
-
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/base/thread_annotations.h"
-#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
-#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
-#include "webrtc/system_wrappers/interface/thread_wrapper.h"
-
-namespace webrtc {
-
-// This is a convenient base class for implementations of AudioEncoderMutable.
-// T is the type of the encoder state; it has to look like an AudioEncoder
-// subclass whose constructor takes a single T::Config parameter. If P is
-// given, this class will inherit from it instead of directly from
-// AudioEncoderMutable.
-template <typename T, typename P = AudioEncoderMutable>
-class AudioEncoderMutableImpl : public P {
- public:
-  void Reset() override {
-    typename T::Config config;
-    {
-      CriticalSectionScoped cs(encoder_lock_.get());
-      config = config_;
-    }
-    Reconstruct(config);
-  }
-
-  bool SetFec(bool enable) override { return false; }
-
-  bool SetDtx(bool enable) override { return false; }
-
-  bool SetApplication(AudioEncoderMutable::Application application) override {
-    return false;
-  }
-
-  void SetMaxPayloadSize(int max_payload_size_bytes) override {}
-
-  void SetMaxRate(int max_rate_bps) override {}
-
-  bool SetMaxPlaybackRate(int frequency_hz) override { return false; }
-
-  AudioEncoderMutable::EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
-                                                  const int16_t* audio,
-                                                  size_t max_encoded_bytes,
-                                                  uint8_t* encoded) override {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return encoder_->EncodeInternal(rtp_timestamp, audio, max_encoded_bytes,
-                                    encoded);
-  }
-  int SampleRateHz() const override {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return encoder_->SampleRateHz();
-  }
-  int NumChannels() const override {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return encoder_->NumChannels();
-  }
-  size_t MaxEncodedBytes() const override {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return encoder_->MaxEncodedBytes();
-  }
-  int RtpTimestampRateHz() const override {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return encoder_->RtpTimestampRateHz();
-  }
-  size_t Num10MsFramesInNextPacket() const override {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return encoder_->Num10MsFramesInNextPacket();
-  }
-  size_t Max10MsFramesInAPacket() const override {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return encoder_->Max10MsFramesInAPacket();
-  }
-  int GetTargetBitrate() const override {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return encoder_->GetTargetBitrate();
-  }
-  void SetTargetBitrate(int bits_per_second) override {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    encoder_->SetTargetBitrate(bits_per_second);
-  }
-  void SetProjectedPacketLossRate(double fraction) override {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    encoder_->SetProjectedPacketLossRate(fraction);
-  }
-
- protected:
-  explicit AudioEncoderMutableImpl(const typename T::Config& config)
-      : encoder_lock_(CriticalSectionWrapper::CreateCriticalSection()) {
-    Reconstruct(config);
-  }
-
-  bool Reconstruct(const typename T::Config& config) {
-    if (!config.IsOk())
-      return false;
-    CriticalSectionScoped cs(encoder_lock_.get());
-    config_ = config;
-    encoder_.reset(new T(config_));
-    return true;
-  }
-
-  typename T::Config config() const {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return config_;
-  }
-  T* encoder() EXCLUSIVE_LOCKS_REQUIRED(encoder_lock_) {
-    return encoder_.get();
-  }
-  const T* encoder() const EXCLUSIVE_LOCKS_REQUIRED(encoder_lock_) {
-    return encoder_.get();
-  }
-
-  const rtc::scoped_ptr<CriticalSectionWrapper> encoder_lock_;
-
- private:
-  rtc::scoped_ptr<T> encoder_ GUARDED_BY(encoder_lock_);
-  typename T::Config config_ GUARDED_BY(encoder_lock_);
-};
-
-}  // namespace webrtc
-
-#endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_MUTABLE_IMPL_H_
diff --git a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc
index 279616e..171198b 100644
--- a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc
+++ b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc
@@ -19,18 +19,19 @@
 
 const int kMaxFrameSizeMs = 60;
 
-}  // namespace
-
-AudioEncoderCng::Config::Config()
-    : num_channels(1),
-      payload_type(13),
-      speech_encoder(NULL),
-      vad_mode(Vad::kVadNormal),
-      sid_frame_interval_ms(100),
-      num_cng_coefficients(8),
-      vad(NULL) {
+rtc::scoped_ptr<CNG_enc_inst, CngInstDeleter> CreateCngInst(
+    int sample_rate_hz,
+    int sid_frame_interval_ms,
+    int num_cng_coefficients) {
+  rtc::scoped_ptr<CNG_enc_inst, CngInstDeleter> cng_inst;
+  CHECK_EQ(0, WebRtcCng_CreateEnc(cng_inst.accept()));
+  CHECK_EQ(0, WebRtcCng_InitEnc(cng_inst.get(), sample_rate_hz,
+                                sid_frame_interval_ms, num_cng_coefficients));
+  return cng_inst;
 }
 
+}  // namespace
+
 bool AudioEncoderCng::Config::IsOk() const {
   if (num_channels != 1)
     return false;
@@ -51,37 +52,15 @@
     : speech_encoder_(config.speech_encoder),
       cng_payload_type_(config.payload_type),
       num_cng_coefficients_(config.num_cng_coefficients),
+      sid_frame_interval_ms_(config.sid_frame_interval_ms),
       last_frame_active_(true),
-      vad_(new Vad(config.vad_mode)) {
-  if (config.vad) {
-    // Replace default Vad object with user-provided one.
-    vad_.reset(config.vad);
-  }
+      vad_(config.vad ? config.vad : new Vad(config.vad_mode)) {
   CHECK(config.IsOk()) << "Invalid configuration.";
-  CNG_enc_inst* cng_inst;
-  CHECK_EQ(WebRtcCng_CreateEnc(&cng_inst), 0) << "WebRtcCng_CreateEnc failed.";
-  cng_inst_.reset(cng_inst);  // Transfer ownership to scoped_ptr.
-  CHECK_EQ(WebRtcCng_InitEnc(cng_inst_.get(), SampleRateHz(),
-                             config.sid_frame_interval_ms,
-                             config.num_cng_coefficients),
-           0)
-      << "WebRtcCng_InitEnc failed";
+  cng_inst_ = CreateCngInst(SampleRateHz(), sid_frame_interval_ms_,
+                            num_cng_coefficients_);
 }
 
-AudioEncoderCng::~AudioEncoderCng() {
-}
-
-int AudioEncoderCng::SampleRateHz() const {
-  return speech_encoder_->SampleRateHz();
-}
-
-int AudioEncoderCng::RtpTimestampRateHz() const {
-  return speech_encoder_->RtpTimestampRateHz();
-}
-
-int AudioEncoderCng::NumChannels() const {
-  return 1;
-}
+AudioEncoderCng::~AudioEncoderCng() = default;
 
 size_t AudioEncoderCng::MaxEncodedBytes() const {
   const size_t max_encoded_bytes_active = speech_encoder_->MaxEncodedBytes();
@@ -90,6 +69,18 @@
   return std::max(max_encoded_bytes_active, max_encoded_bytes_passive);
 }
 
+int AudioEncoderCng::SampleRateHz() const {
+  return speech_encoder_->SampleRateHz();
+}
+
+int AudioEncoderCng::NumChannels() const {
+  return 1;
+}
+
+int AudioEncoderCng::RtpTimestampRateHz() const {
+  return speech_encoder_->RtpTimestampRateHz();
+}
+
 size_t AudioEncoderCng::Num10MsFramesInNextPacket() const {
   return speech_encoder_->Num10MsFramesInNextPacket();
 }
@@ -102,16 +93,6 @@
   return speech_encoder_->GetTargetBitrate();
 }
 
-void AudioEncoderCng::SetTargetBitrate(int bits_per_second) {
-  speech_encoder_->SetTargetBitrate(bits_per_second);
-}
-
-void AudioEncoderCng::SetProjectedPacketLossRate(double fraction) {
-  DCHECK_GE(fraction, 0.0);
-  DCHECK_LE(fraction, 1.0);
-  speech_encoder_->SetProjectedPacketLossRate(fraction);
-}
-
 AudioEncoder::EncodedInfo AudioEncoderCng::EncodeInternal(
     uint32_t rtp_timestamp,
     const int16_t* audio,
@@ -183,6 +164,48 @@
   return info;
 }
 
+void AudioEncoderCng::Reset() {
+  speech_encoder_->Reset();
+  speech_buffer_.clear();
+  rtp_timestamps_.clear();
+  last_frame_active_ = true;
+  vad_->Reset();
+  cng_inst_ = CreateCngInst(SampleRateHz(), sid_frame_interval_ms_,
+                            num_cng_coefficients_);
+}
+
+bool AudioEncoderCng::SetFec(bool enable) {
+  return speech_encoder_->SetFec(enable);
+}
+
+bool AudioEncoderCng::SetDtx(bool enable) {
+  return speech_encoder_->SetDtx(enable);
+}
+
+bool AudioEncoderCng::SetApplication(Application application) {
+  return speech_encoder_->SetApplication(application);
+}
+
+bool AudioEncoderCng::SetMaxPlaybackRate(int frequency_hz) {
+  return speech_encoder_->SetMaxPlaybackRate(frequency_hz);
+}
+
+void AudioEncoderCng::SetProjectedPacketLossRate(double fraction) {
+  speech_encoder_->SetProjectedPacketLossRate(fraction);
+}
+
+void AudioEncoderCng::SetTargetBitrate(int bits_per_second) {
+  speech_encoder_->SetTargetBitrate(bits_per_second);
+}
+
+void AudioEncoderCng::SetMaxBitrate(int max_bps) {
+  speech_encoder_->SetMaxBitrate(max_bps);
+}
+
+void AudioEncoderCng::SetMaxPayloadSize(int max_payload_size_bytes) {
+  speech_encoder_->SetMaxPayloadSize(max_payload_size_bytes);
+}
+
 AudioEncoder::EncodedInfo AudioEncoderCng::EncodePassive(
     size_t frames_to_encode,
     size_t max_encoded_bytes,
diff --git a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
index a2ab6e8..d7bc474 100644
--- a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
@@ -386,6 +386,14 @@
             encoded_info_.encoded_bytes);
 }
 
+// Resetting the CNG should reset both the VAD and the encoder.
+TEST_F(AudioEncoderCngTest, Reset) {
+  CreateCng();
+  EXPECT_CALL(mock_encoder_, Reset()).Times(1);
+  EXPECT_CALL(*mock_vad_, Reset()).Times(1);
+  cng_->Reset();
+}
+
 #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
 
 // This test fixture tests various error conditions that makes the
diff --git a/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h b/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h
index 6a11366..2ac1f95 100644
--- a/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h
+++ b/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h
@@ -20,53 +20,57 @@
 
 namespace webrtc {
 
+// Deleter for use with scoped_ptr.
+struct CngInstDeleter {
+  void operator()(CNG_enc_inst* ptr) const { WebRtcCng_FreeEnc(ptr); }
+};
+
 class Vad;
 
 class AudioEncoderCng final : public AudioEncoder {
  public:
   struct Config {
-    Config();
     bool IsOk() const;
 
-    int num_channels;
-    int payload_type;
+    int num_channels = 1;
+    int payload_type = 13;
     // Caller keeps ownership of the AudioEncoder object.
-    AudioEncoder* speech_encoder;
-    Vad::Aggressiveness vad_mode;
-    int sid_frame_interval_ms;
-    int num_cng_coefficients;
+    AudioEncoder* speech_encoder = nullptr;
+    Vad::Aggressiveness vad_mode = Vad::kVadNormal;
+    int sid_frame_interval_ms = 100;
+    int num_cng_coefficients = 8;
     // The Vad pointer is mainly for testing. If a NULL pointer is passed, the
     // AudioEncoderCng creates (and destroys) a Vad object internally. If an
     // object is passed, the AudioEncoderCng assumes ownership of the Vad
     // object.
-    Vad* vad;
+    Vad* vad = nullptr;
   };
 
   explicit AudioEncoderCng(const Config& config);
-
   ~AudioEncoderCng() override;
 
+  size_t MaxEncodedBytes() const override;
   int SampleRateHz() const override;
   int NumChannels() const override;
-  size_t MaxEncodedBytes() const override;
   int RtpTimestampRateHz() const override;
   size_t Num10MsFramesInNextPacket() const override;
   size_t Max10MsFramesInAPacket() const override;
   int GetTargetBitrate() const override;
-  void SetTargetBitrate(int bits_per_second) override;
-  void SetProjectedPacketLossRate(double fraction) override;
   EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
                              const int16_t* audio,
                              size_t max_encoded_bytes,
                              uint8_t* encoded) override;
+  void Reset() override;
+  bool SetFec(bool enable) override;
+  bool SetDtx(bool enable) override;
+  bool SetApplication(Application application) override;
+  bool SetMaxPlaybackRate(int frequency_hz) override;
+  void SetProjectedPacketLossRate(double fraction) override;
+  void SetTargetBitrate(int target_bps) override;
+  void SetMaxBitrate(int max_bps) override;
+  void SetMaxPayloadSize(int max_payload_size_bytes) override;
 
  private:
-  // Deleter for use with scoped_ptr. E.g., use as
-  //   rtc::scoped_ptr<CNG_enc_inst, CngInstDeleter> cng_inst_;
-  struct CngInstDeleter {
-    inline void operator()(CNG_enc_inst* ptr) const { WebRtcCng_FreeEnc(ptr); }
-  };
-
   EncodedInfo EncodePassive(size_t frames_to_encode,
                             size_t max_encoded_bytes,
                             uint8_t* encoded);
@@ -78,6 +82,7 @@
   AudioEncoder* speech_encoder_;
   const int cng_payload_type_;
   const int num_cng_coefficients_;
+  const int sid_frame_interval_ms_;
   std::vector<int16_t> speech_buffer_;
   std::vector<uint32_t> rtp_timestamps_;
   bool last_frame_active_;
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 ba5959d..f7812b3 100644
--- a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
+++ b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
@@ -19,6 +19,7 @@
 namespace webrtc {
 
 namespace {
+
 int16_t NumSamplesPerFrame(int num_channels,
                            int frame_size_ms,
                            int sample_rate_hz) {
@@ -27,6 +28,16 @@
       << "Frame size too large.";
   return static_cast<int16_t>(samples_per_frame);
 }
+
+template <typename T>
+typename T::Config CreateConfig(const CodecInst& codec_inst) {
+  typename T::Config config;
+  config.frame_size_ms = codec_inst.pacsize / 8;
+  config.num_channels = codec_inst.channels;
+  config.payload_type = codec_inst.pltype;
+  return config;
+}
+
 }  // namespace
 
 bool AudioEncoderPcm::Config::IsOk() const {
@@ -49,7 +60,10 @@
   speech_buffer_.reserve(full_frame_samples_);
 }
 
-AudioEncoderPcm::~AudioEncoderPcm() {
+AudioEncoderPcm::~AudioEncoderPcm() = default;
+
+size_t AudioEncoderPcm::MaxEncodedBytes() const {
+  return full_frame_samples_ * BytesPerSample();
 }
 
 int AudioEncoderPcm::SampleRateHz() const {
@@ -60,10 +74,6 @@
   return num_channels_;
 }
 
-size_t AudioEncoderPcm::MaxEncodedBytes() const {
-  return full_frame_samples_ * BytesPerSample();
-}
-
 size_t AudioEncoderPcm::Num10MsFramesInNextPacket() const {
   return num_10ms_frames_per_packet_;
 }
@@ -102,6 +112,13 @@
   return info;
 }
 
+void AudioEncoderPcm::Reset() {
+  speech_buffer_.clear();
+}
+
+AudioEncoderPcmA::AudioEncoderPcmA(const CodecInst& codec_inst)
+    : AudioEncoderPcmA(CreateConfig<AudioEncoderPcmA>(codec_inst)) {}
+
 size_t AudioEncoderPcmA::EncodeCall(const int16_t* audio,
                                     size_t input_len,
                                     uint8_t* encoded) {
@@ -112,6 +129,9 @@
   return 1;
 }
 
+AudioEncoderPcmU::AudioEncoderPcmU(const CodecInst& codec_inst)
+    : AudioEncoderPcmU(CreateConfig<AudioEncoderPcmU>(codec_inst)) {}
+
 size_t AudioEncoderPcmU::EncodeCall(const int16_t* audio,
                                     size_t input_len,
                                     uint8_t* encoded) {
@@ -122,25 +142,4 @@
   return 1;
 }
 
-namespace {
-template <typename T>
-typename T::Config CreateConfig(const CodecInst& codec_inst) {
-  typename T::Config config;
-  config.frame_size_ms = codec_inst.pacsize / 8;
-  config.num_channels = codec_inst.channels;
-  config.payload_type = codec_inst.pltype;
-  return config;
-}
-}  // namespace
-
-AudioEncoderMutablePcmU::AudioEncoderMutablePcmU(const CodecInst& codec_inst)
-    : AudioEncoderMutableImpl<AudioEncoderPcmU>(
-          CreateConfig<AudioEncoderPcmU>(codec_inst)) {
-}
-
-AudioEncoderMutablePcmA::AudioEncoderMutablePcmA(const CodecInst& codec_inst)
-    : AudioEncoderMutableImpl<AudioEncoderPcmA>(
-          CreateConfig<AudioEncoderPcmA>(codec_inst)) {
-}
-
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h b/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h
index 7d45f3f..c2788f1 100644
--- a/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h
+++ b/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h
@@ -15,7 +15,6 @@
 
 #include "webrtc/base/scoped_ptr.h"
 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
-#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h"
 
 namespace webrtc {
 
@@ -36,9 +35,9 @@
 
   ~AudioEncoderPcm() override;
 
+  size_t MaxEncodedBytes() const override;
   int SampleRateHz() const override;
   int NumChannels() const override;
-  size_t MaxEncodedBytes() const override;
   size_t Num10MsFramesInNextPacket() const override;
   size_t Max10MsFramesInAPacket() const override;
   int GetTargetBitrate() const override;
@@ -46,6 +45,7 @@
                              const int16_t* audio,
                              size_t max_encoded_bytes,
                              uint8_t* encoded) override;
+  void Reset() override;
 
  protected:
   AudioEncoderPcm(const Config& config, int sample_rate_hz);
@@ -66,6 +66,8 @@
   uint32_t first_timestamp_in_buffer_;
 };
 
+struct CodecInst;
+
 class AudioEncoderPcmA final : public AudioEncoderPcm {
  public:
   struct Config : public AudioEncoderPcm::Config {
@@ -74,6 +76,7 @@
 
   explicit AudioEncoderPcmA(const Config& config)
       : AudioEncoderPcm(config, kSampleRateHz) {}
+  explicit AudioEncoderPcmA(const CodecInst& codec_inst);
 
  protected:
   size_t EncodeCall(const int16_t* audio,
@@ -94,6 +97,7 @@
 
   explicit AudioEncoderPcmU(const Config& config)
       : AudioEncoderPcm(config, kSampleRateHz) {}
+  explicit AudioEncoderPcmU(const CodecInst& codec_inst);
 
  protected:
   size_t EncodeCall(const int16_t* audio,
@@ -106,19 +110,5 @@
   static const int kSampleRateHz = 8000;
 };
 
-struct CodecInst;
-
-class AudioEncoderMutablePcmU
-    : public AudioEncoderMutableImpl<AudioEncoderPcmU> {
- public:
-  explicit AudioEncoderMutablePcmU(const CodecInst& codec_inst);
-};
-
-class AudioEncoderMutablePcmA
-    : public AudioEncoderMutableImpl<AudioEncoderPcmA> {
- public:
-  explicit AudioEncoderMutablePcmA(const CodecInst& codec_inst);
-};
-
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_G711_INCLUDE_AUDIO_ENCODER_PCM_H_
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 9eb7a11..6df5430 100644
--- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
+++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
@@ -21,6 +21,14 @@
 
 const size_t kSampleRateHz = 16000;
 
+AudioEncoderG722::Config CreateConfig(const CodecInst& codec_inst) {
+  AudioEncoderG722::Config config;
+  config.num_channels = codec_inst.channels;
+  config.frame_size_ms = codec_inst.pacsize / 16;
+  config.payload_type = codec_inst.pltype;
+  return config;
+}
+
 }  // namespace
 
 bool AudioEncoderG722::Config::IsOk() const {
@@ -28,15 +36,6 @@
       (num_channels >= 1);
 }
 
-AudioEncoderG722::EncoderState::EncoderState() {
-  CHECK_EQ(0, WebRtcG722_CreateEncoder(&encoder));
-  CHECK_EQ(0, WebRtcG722_EncoderInit(encoder));
-}
-
-AudioEncoderG722::EncoderState::~EncoderState() {
-  CHECK_EQ(0, WebRtcG722_FreeEncoder(encoder));
-}
-
 AudioEncoderG722::AudioEncoderG722(const Config& config)
     : num_channels_(config.num_channels),
       payload_type_(config.payload_type),
@@ -53,26 +52,30 @@
     encoders_[i].speech_buffer.reset(new int16_t[samples_per_channel]);
     encoders_[i].encoded_buffer.SetSize(samples_per_channel / 2);
   }
+  Reset();
 }
 
-AudioEncoderG722::~AudioEncoderG722() {}
+AudioEncoderG722::AudioEncoderG722(const CodecInst& codec_inst)
+    : AudioEncoderG722(CreateConfig(codec_inst)) {}
+
+AudioEncoderG722::~AudioEncoderG722() = default;
+
+size_t AudioEncoderG722::MaxEncodedBytes() const {
+  return SamplesPerChannel() / 2 * num_channels_;
+}
 
 int AudioEncoderG722::SampleRateHz() const {
   return kSampleRateHz;
 }
 
-int AudioEncoderG722::RtpTimestampRateHz() const {
-  // The RTP timestamp rate for G.722 is 8000 Hz, even though it is a 16 kHz
-  // codec.
-  return kSampleRateHz / 2;
-}
-
 int AudioEncoderG722::NumChannels() const {
   return num_channels_;
 }
 
-size_t AudioEncoderG722::MaxEncodedBytes() const {
-  return SamplesPerChannel() / 2 * num_channels_;
+int AudioEncoderG722::RtpTimestampRateHz() const {
+  // The RTP timestamp rate for G.722 is 8000 Hz, even though it is a 16 kHz
+  // codec.
+  return kSampleRateHz / 2;
 }
 
 size_t AudioEncoderG722::Num10MsFramesInNextPacket() const {
@@ -116,7 +119,7 @@
   for (int i = 0; i < num_channels_; ++i) {
     const size_t encoded = WebRtcG722_Encode(
         encoders_[i].encoder, encoders_[i].speech_buffer.get(),
-        samples_per_channel, encoders_[i].encoded_buffer.data<uint8_t>());
+        samples_per_channel, encoders_[i].encoded_buffer.data());
     CHECK_EQ(encoded, samples_per_channel / 2);
   }
 
@@ -140,22 +143,22 @@
   return info;
 }
 
+void AudioEncoderG722::Reset() {
+  num_10ms_frames_buffered_ = 0;
+  for (int i = 0; i < num_channels_; ++i)
+    CHECK_EQ(0, WebRtcG722_EncoderInit(encoders_[i].encoder));
+}
+
+AudioEncoderG722::EncoderState::EncoderState() {
+  CHECK_EQ(0, WebRtcG722_CreateEncoder(&encoder));
+}
+
+AudioEncoderG722::EncoderState::~EncoderState() {
+  CHECK_EQ(0, WebRtcG722_FreeEncoder(encoder));
+}
+
 size_t AudioEncoderG722::SamplesPerChannel() const {
   return kSampleRateHz / 100 * num_10ms_frames_per_packet_;
 }
 
-namespace {
-AudioEncoderG722::Config CreateConfig(const CodecInst& codec_inst) {
-  AudioEncoderG722::Config config;
-  config.num_channels = codec_inst.channels;
-  config.frame_size_ms = codec_inst.pacsize / 16;
-  config.payload_type = codec_inst.pltype;
-  return config;
-}
-}  // namespace
-
-AudioEncoderMutableG722::AudioEncoderMutableG722(const CodecInst& codec_inst)
-    : AudioEncoderMutableImpl<AudioEncoderG722>(CreateConfig(codec_inst)) {
-}
-
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h b/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h
index 1f36fac..36f809a 100644
--- a/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h
+++ b/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h
@@ -14,28 +14,29 @@
 #include "webrtc/base/buffer.h"
 #include "webrtc/base/scoped_ptr.h"
 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
-#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h"
 #include "webrtc/modules/audio_coding/codecs/g722/include/g722_interface.h"
 
 namespace webrtc {
 
+struct CodecInst;
+
 class AudioEncoderG722 final : public AudioEncoder {
  public:
   struct Config {
-    Config() : payload_type(9), frame_size_ms(20), num_channels(1) {}
     bool IsOk() const;
 
-    int payload_type;
-    int frame_size_ms;
-    int num_channels;
+    int payload_type = 9;
+    int frame_size_ms = 20;
+    int num_channels = 1;
   };
 
   explicit AudioEncoderG722(const Config& config);
+  explicit AudioEncoderG722(const CodecInst& codec_inst);
   ~AudioEncoderG722() override;
 
+  size_t MaxEncodedBytes() const override;
   int SampleRateHz() const override;
   int NumChannels() const override;
-  size_t MaxEncodedBytes() const override;
   int RtpTimestampRateHz() const override;
   size_t Num10MsFramesInNextPacket() const override;
   size_t Max10MsFramesInAPacket() const override;
@@ -44,6 +45,7 @@
                              const int16_t* audio,
                              size_t max_encoded_bytes,
                              uint8_t* encoded) override;
+  void Reset() override;
 
  private:
   // The encoder state for one channel.
@@ -66,13 +68,5 @@
   rtc::Buffer interleave_buffer_;
 };
 
-struct CodecInst;
-
-class AudioEncoderMutableG722
-    : public AudioEncoderMutableImpl<AudioEncoderG722> {
- public:
-  explicit AudioEncoderMutableG722(const CodecInst& codec_inst);
-};
-
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_G722_INCLUDE_AUDIO_ENCODER_G722_H_
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 33aba38..8f16d66 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
+++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
@@ -22,6 +22,13 @@
 
 const int kSampleRateHz = 8000;
 
+AudioEncoderIlbc::Config CreateConfig(const CodecInst& codec_inst) {
+  AudioEncoderIlbc::Config config;
+  config.frame_size_ms = codec_inst.pacsize / 8;
+  config.payload_type = codec_inst.pltype;
+  return config;
+}
+
 }  // namespace
 
 // static
@@ -35,22 +42,24 @@
 }
 
 AudioEncoderIlbc::AudioEncoderIlbc(const Config& config)
-    : payload_type_(config.payload_type),
+    : config_(config),
       num_10ms_frames_per_packet_(
           static_cast<size_t>(config.frame_size_ms / 10)),
-      num_10ms_frames_buffered_(0) {
-  CHECK(config.IsOk());
-  CHECK_EQ(0, WebRtcIlbcfix_EncoderCreate(&encoder_));
-  const int encoder_frame_size_ms = config.frame_size_ms > 30
-                                        ? config.frame_size_ms / 2
-                                        : config.frame_size_ms;
-  CHECK_EQ(0, WebRtcIlbcfix_EncoderInit(encoder_, encoder_frame_size_ms));
+      encoder_(nullptr) {
+  Reset();
 }
 
+AudioEncoderIlbc::AudioEncoderIlbc(const CodecInst& codec_inst)
+    : AudioEncoderIlbc(CreateConfig(codec_inst)) {}
+
 AudioEncoderIlbc::~AudioEncoderIlbc() {
   CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_));
 }
 
+size_t AudioEncoderIlbc::MaxEncodedBytes() const {
+  return RequiredOutputSizeBytes();
+}
+
 int AudioEncoderIlbc::SampleRateHz() const {
   return kSampleRateHz;
 }
@@ -59,10 +68,6 @@
   return 1;
 }
 
-size_t AudioEncoderIlbc::MaxEncodedBytes() const {
-  return RequiredOutputSizeBytes();
-}
-
 size_t AudioEncoderIlbc::Num10MsFramesInNextPacket() const {
   return num_10ms_frames_per_packet_;
 }
@@ -119,10 +124,22 @@
   info.encoded_bytes = static_cast<size_t>(output_len);
   DCHECK_EQ(info.encoded_bytes, RequiredOutputSizeBytes());
   info.encoded_timestamp = first_timestamp_in_buffer_;
-  info.payload_type = payload_type_;
+  info.payload_type = config_.payload_type;
   return info;
 }
 
+void AudioEncoderIlbc::Reset() {
+  if (encoder_)
+    CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_));
+  CHECK(config_.IsOk());
+  CHECK_EQ(0, WebRtcIlbcfix_EncoderCreate(&encoder_));
+  const int encoder_frame_size_ms = config_.frame_size_ms > 30
+                                        ? config_.frame_size_ms / 2
+                                        : config_.frame_size_ms;
+  CHECK_EQ(0, WebRtcIlbcfix_EncoderInit(encoder_, encoder_frame_size_ms));
+  num_10ms_frames_buffered_ = 0;
+}
+
 size_t AudioEncoderIlbc::RequiredOutputSizeBytes() const {
   switch (num_10ms_frames_per_packet_) {
     case 2:   return 38;
@@ -133,17 +150,4 @@
   }
 }
 
-namespace {
-AudioEncoderIlbc::Config CreateConfig(const CodecInst& codec_inst) {
-  AudioEncoderIlbc::Config config;
-  config.frame_size_ms = codec_inst.pacsize / 8;
-  config.payload_type = codec_inst.pltype;
-  return config;
-}
-}  // namespace
-
-AudioEncoderMutableIlbc::AudioEncoderMutableIlbc(const CodecInst& codec_inst)
-    : AudioEncoderMutableImpl<AudioEncoderIlbc>(CreateConfig(codec_inst)) {
-}
-
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h b/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h
index c3cf4d8..7e7e898 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h
+++ b/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h
@@ -13,29 +13,30 @@
 
 #include "webrtc/base/scoped_ptr.h"
 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
-#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h"
 #include "webrtc/modules/audio_coding/codecs/ilbc/interface/ilbc.h"
 
 namespace webrtc {
 
+struct CodecInst;
+
 class AudioEncoderIlbc final : public AudioEncoder {
  public:
   struct Config {
-    Config() : payload_type(102), frame_size_ms(30) {}
     bool IsOk() const;
 
-    int payload_type;
-    int frame_size_ms;  // Valid values are 20, 30, 40, and 60 ms.
+    int payload_type = 102;
+    int frame_size_ms = 30;  // Valid values are 20, 30, 40, and 60 ms.
     // Note that frame size 40 ms produces encodings with two 20 ms frames in
     // them, and frame size 60 ms consists of two 30 ms frames.
   };
 
   explicit AudioEncoderIlbc(const Config& config);
+  explicit AudioEncoderIlbc(const CodecInst& codec_inst);
   ~AudioEncoderIlbc() override;
 
+  size_t MaxEncodedBytes() const override;
   int SampleRateHz() const override;
   int NumChannels() const override;
-  size_t MaxEncodedBytes() const override;
   size_t Num10MsFramesInNextPacket() const override;
   size_t Max10MsFramesInAPacket() const override;
   int GetTargetBitrate() const override;
@@ -43,12 +44,13 @@
                              const int16_t* audio,
                              size_t max_encoded_bytes,
                              uint8_t* encoded) override;
+  void Reset() override;
 
  private:
   size_t RequiredOutputSizeBytes() const;
 
   static const size_t kMaxSamplesPerPacket = 480;
-  const int payload_type_;
+  const Config config_;
   const size_t num_10ms_frames_per_packet_;
   size_t num_10ms_frames_buffered_;
   uint32_t first_timestamp_in_buffer_;
@@ -56,13 +58,5 @@
   IlbcEncoderInstance* encoder_;
 };
 
-struct CodecInst;
-
-class AudioEncoderMutableIlbc
-    : public AudioEncoderMutableImpl<AudioEncoderIlbc> {
- public:
-  explicit AudioEncoderMutableIlbc(const CodecInst& codec_inst);
-};
-
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_INTERFACE_AUDIO_ENCODER_ILBC_H_
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 a8498fa..5484395 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
@@ -19,6 +19,8 @@
 
 namespace webrtc {
 
+struct CodecInst;
+
 template <typename T>
 class AudioEncoderIsacT final : public AudioEncoder {
  public:
@@ -28,33 +30,35 @@
   //  - 32000 Hz, 30 ms, 10000-56000 bps (if T has super-wideband support)
   //  - 48000 Hz, 30 ms, 10000-56000 bps (if T has super-wideband support)
   struct Config {
-    Config();
     bool IsOk() const;
 
-    LockedIsacBandwidthInfo* bwinfo;
+    LockedIsacBandwidthInfo* bwinfo = nullptr;
 
-    int payload_type;
-    int sample_rate_hz;
-    int frame_size_ms;
-    int bit_rate;  // Limit on the short-term average bit rate, in bits/s.
-    int max_payload_size_bytes;
-    int max_bit_rate;
+    int payload_type = 103;
+    int sample_rate_hz = 16000;
+    int frame_size_ms = 30;
+    int bit_rate = kDefaultBitRate;  // Limit on the short-term average bit
+                                     // rate, in bits/s.
+    int max_payload_size_bytes = -1;
+    int max_bit_rate = -1;
 
     // If true, the encoder will dynamically adjust frame size and bit rate;
     // the configured values are then merely the starting point.
-    bool adaptive_mode;
+    bool adaptive_mode = false;
 
     // In adaptive mode, prevent adaptive changes to the frame size. (Not used
     // in nonadaptive mode.)
-    bool enforce_frame_size;
+    bool enforce_frame_size = false;
   };
 
   explicit AudioEncoderIsacT(const Config& config);
+  explicit AudioEncoderIsacT(const CodecInst& codec_inst,
+                             LockedIsacBandwidthInfo* bwinfo);
   ~AudioEncoderIsacT() override;
 
+  size_t MaxEncodedBytes() const override;
   int SampleRateHz() const override;
   int NumChannels() const override;
-  size_t MaxEncodedBytes() const override;
   size_t Num10MsFramesInNextPacket() const override;
   size_t Max10MsFramesInAPacket() const override;
   int GetTargetBitrate() const override;
@@ -62,18 +66,26 @@
                              const int16_t* audio,
                              size_t max_encoded_bytes,
                              uint8_t* encoded) override;
+  void Reset() override;
+  void SetMaxPayloadSize(int max_payload_size_bytes) override;
+  void SetMaxBitrate(int max_rate_bps) override;
 
  private:
   // This value is taken from STREAM_SIZE_MAX_60 for iSAC float (60 ms) and
   // STREAM_MAXW16_60MS for iSAC fix (60 ms).
   static const size_t kSufficientEncodeBufferSizeBytes = 400;
 
-  const int payload_type_;
-  typename T::instance_type* isac_state_;
-  LockedIsacBandwidthInfo* bwinfo_;
+  static const int kDefaultBitRate = 32000;
+
+  // Recreate the iSAC encoder instance with the given settings, and save them.
+  void RecreateEncoderInstance(const Config& config);
+
+  Config config_;
+  typename T::instance_type* isac_state_ = nullptr;
+  LockedIsacBandwidthInfo* bwinfo_ = nullptr;
 
   // Have we accepted input but not yet emitted it in a packet?
-  bool packet_in_progress_;
+  bool packet_in_progress_ = false;
 
   // Timestamp of the first input of the currently in-progress packet.
   uint32_t packet_timestamp_;
@@ -81,8 +93,6 @@
   // Timestamp of the previously encoded packet.
   uint32_t last_encoded_timestamp_;
 
-  const int target_bitrate_bps_;
-
   DISALLOW_COPY_AND_ASSIGN(AudioEncoderIsacT);
 };
 
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 28e9b8e..ad09c3f 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
@@ -20,20 +20,20 @@
 
 namespace webrtc {
 
-const int kIsacPayloadType = 103;
-const int kDefaultBitRate = 32000;
-
 template <typename T>
-AudioEncoderIsacT<T>::Config::Config()
-    : bwinfo(nullptr),
-      payload_type(kIsacPayloadType),
-      sample_rate_hz(16000),
-      frame_size_ms(30),
-      bit_rate(kDefaultBitRate),
-      max_payload_size_bytes(-1),
-      max_bit_rate(-1),
-      adaptive_mode(false),
-      enforce_frame_size(false) {
+typename AudioEncoderIsacT<T>::Config CreateIsacConfig(
+    const CodecInst& codec_inst,
+    LockedIsacBandwidthInfo* bwinfo) {
+  typename AudioEncoderIsacT<T>::Config config;
+  config.bwinfo = bwinfo;
+  config.payload_type = codec_inst.pltype;
+  config.sample_rate_hz = codec_inst.plfreq;
+  config.frame_size_ms =
+      rtc::CheckedDivExact(1000 * codec_inst.pacsize, config.sample_rate_hz);
+  config.adaptive_mode = (codec_inst.rate == -1);
+  if (codec_inst.rate != -1)
+    config.bit_rate = codec_inst.rate;
+  return config;
 }
 
 template <typename T>
@@ -67,47 +67,26 @@
 }
 
 template <typename T>
-AudioEncoderIsacT<T>::AudioEncoderIsacT(const Config& config)
-    : payload_type_(config.payload_type),
-      bwinfo_(config.bwinfo),
-      packet_in_progress_(false),
-      target_bitrate_bps_(config.adaptive_mode ? -1 : (config.bit_rate == 0
-                                                           ? kDefaultBitRate
-                                                           : config.bit_rate)) {
-  CHECK(config.IsOk());
-  CHECK_EQ(0, T::Create(&isac_state_));
-  CHECK_EQ(0, T::EncoderInit(isac_state_, config.adaptive_mode ? 0 : 1));
-  CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz));
-  const int bit_rate = config.bit_rate == 0 ? kDefaultBitRate : config.bit_rate;
-  if (config.adaptive_mode) {
-    CHECK_EQ(0, T::ControlBwe(isac_state_, bit_rate, config.frame_size_ms,
-                              config.enforce_frame_size));
-  } else {
-    CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms));
-  }
-  if (config.max_payload_size_bytes != -1)
-    CHECK_EQ(0,
-             T::SetMaxPayloadSize(isac_state_, config.max_payload_size_bytes));
-  if (config.max_bit_rate != -1)
-    CHECK_EQ(0, T::SetMaxRate(isac_state_, config.max_bit_rate));
-
-  // When config.sample_rate_hz is set to 48000 Hz (iSAC-fb), the decoder is
-  // still set to 32000 Hz, since there is no full-band mode in the decoder.
-  const int decoder_sample_rate_hz = std::min(config.sample_rate_hz, 32000);
-
-  // Set the decoder sample rate even though we just use the encoder. This
-  // doesn't appear to be necessary to produce a valid encoding, but without it
-  // we get an encoding that isn't bit-for-bit identical with what a combined
-  // encoder+decoder object produces.
-  CHECK_EQ(0, T::SetDecSampRate(isac_state_, decoder_sample_rate_hz));
+AudioEncoderIsacT<T>::AudioEncoderIsacT(const Config& config) {
+  RecreateEncoderInstance(config);
 }
 
 template <typename T>
+AudioEncoderIsacT<T>::AudioEncoderIsacT(const CodecInst& codec_inst,
+                                        LockedIsacBandwidthInfo* bwinfo)
+    : AudioEncoderIsacT(CreateIsacConfig<T>(codec_inst, bwinfo)) {}
+
+template <typename T>
 AudioEncoderIsacT<T>::~AudioEncoderIsacT() {
   CHECK_EQ(0, T::Free(isac_state_));
 }
 
 template <typename T>
+size_t AudioEncoderIsacT<T>::MaxEncodedBytes() const {
+  return kSufficientEncodeBufferSizeBytes;
+}
+
+template <typename T>
 int AudioEncoderIsacT<T>::SampleRateHz() const {
   return T::EncSampRate(isac_state_);
 }
@@ -118,11 +97,6 @@
 }
 
 template <typename T>
-size_t AudioEncoderIsacT<T>::MaxEncodedBytes() const {
-  return kSufficientEncodeBufferSizeBytes;
-}
-
-template <typename T>
 size_t AudioEncoderIsacT<T>::Num10MsFramesInNextPacket() const {
   const int samples_in_next_packet = T::GetNewFrameLen(isac_state_);
   return static_cast<size_t>(
@@ -137,7 +111,9 @@
 
 template <typename T>
 int AudioEncoderIsacT<T>::GetTargetBitrate() const {
-  return target_bitrate_bps_;
+  if (config_.adaptive_mode)
+    return -1;
+  return config_.bit_rate == 0 ? kDefaultBitRate : config_.bit_rate;
 }
 
 template <typename T>
@@ -172,16 +148,70 @@
   EncodedInfo info;
   info.encoded_bytes = r;
   info.encoded_timestamp = packet_timestamp_;
-  info.payload_type = payload_type_;
+  info.payload_type = config_.payload_type;
   return info;
 }
 
 template <typename T>
-AudioDecoderIsacT<T>::AudioDecoderIsacT()
-    : AudioDecoderIsacT(nullptr) {
+void AudioEncoderIsacT<T>::Reset() {
+  RecreateEncoderInstance(config_);
 }
 
 template <typename T>
+void AudioEncoderIsacT<T>::SetMaxPayloadSize(int max_payload_size_bytes) {
+  auto conf = config_;
+  conf.max_payload_size_bytes = max_payload_size_bytes;
+  RecreateEncoderInstance(conf);
+}
+
+template <typename T>
+void AudioEncoderIsacT<T>::SetMaxBitrate(int max_rate_bps) {
+  auto conf = config_;
+  conf.max_bit_rate = max_rate_bps;
+  RecreateEncoderInstance(conf);
+}
+
+template <typename T>
+void AudioEncoderIsacT<T>::RecreateEncoderInstance(const Config& config) {
+  CHECK(config.IsOk());
+  packet_in_progress_ = false;
+  bwinfo_ = config.bwinfo;
+  if (isac_state_)
+    CHECK_EQ(0, T::Free(isac_state_));
+  CHECK_EQ(0, T::Create(&isac_state_));
+  CHECK_EQ(0, T::EncoderInit(isac_state_, config.adaptive_mode ? 0 : 1));
+  CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz));
+  const int bit_rate = config.bit_rate == 0 ? kDefaultBitRate : config.bit_rate;
+  if (config.adaptive_mode) {
+    CHECK_EQ(0, T::ControlBwe(isac_state_, bit_rate, config.frame_size_ms,
+                              config.enforce_frame_size));
+  } else {
+    CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms));
+  }
+  if (config.max_payload_size_bytes != -1)
+    CHECK_EQ(0,
+             T::SetMaxPayloadSize(isac_state_, config.max_payload_size_bytes));
+  if (config.max_bit_rate != -1)
+    CHECK_EQ(0, T::SetMaxRate(isac_state_, config.max_bit_rate));
+
+  // When config.sample_rate_hz is set to 48000 Hz (iSAC-fb), the decoder is
+  // still set to 32000 Hz, since there is no full-band mode in the decoder.
+  const int decoder_sample_rate_hz = std::min(config.sample_rate_hz, 32000);
+
+  // Set the decoder sample rate even though we just use the encoder. This
+  // doesn't appear to be necessary to produce a valid encoding, but without it
+  // we get an encoding that isn't bit-for-bit identical with what a combined
+  // encoder+decoder object produces.
+  CHECK_EQ(0, T::SetDecSampRate(isac_state_, decoder_sample_rate_hz));
+
+  config_ = config;
+}
+
+template <typename T>
+AudioDecoderIsacT<T>::AudioDecoderIsacT()
+    : AudioDecoderIsacT(nullptr) {}
+
+template <typename T>
 AudioDecoderIsacT<T>::AudioDecoderIsacT(LockedIsacBandwidthInfo* bwinfo)
     : bwinfo_(bwinfo), decoder_sample_rate_hz_(-1) {
   CHECK_EQ(0, T::Create(&isac_state_));
diff --git a/webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h b/webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h
index 0fd05da..e710f24 100644
--- a/webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h
+++ b/webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h
@@ -13,7 +13,6 @@
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h"
 #include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h"
 #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h"
 
@@ -123,16 +122,5 @@
 using AudioEncoderIsacFix = AudioEncoderIsacT<IsacFix>;
 using AudioDecoderIsacFix = AudioDecoderIsacT<IsacFix>;
 
-struct CodecInst;
-
-class AudioEncoderMutableIsacFix
-    : public AudioEncoderMutableImpl<AudioEncoderIsacFix> {
- public:
-  explicit AudioEncoderMutableIsacFix(const CodecInst& codec_inst,
-                                      LockedIsacBandwidthInfo* bwinfo);
-  void SetMaxPayloadSize(int max_payload_size_bytes) override;
-  void SetMaxRate(int max_rate_bps) override;
-};
-
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_INTERFACE_AUDIO_ENCODER_ISACFIX_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/fix/source/audio_encoder_isacfix.cc b/webrtc/modules/audio_coding/codecs/isac/fix/source/audio_encoder_isacfix.cc
index 2f8d4b6..9b2f317 100644
--- a/webrtc/modules/audio_coding/codecs/isac/fix/source/audio_encoder_isacfix.cc
+++ b/webrtc/modules/audio_coding/codecs/isac/fix/source/audio_encoder_isacfix.cc
@@ -10,7 +10,6 @@
 
 #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h"
 
-#include "webrtc/common_types.h"
 #include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h"
 
 namespace webrtc {
@@ -21,38 +20,4 @@
 template class AudioEncoderIsacT<IsacFix>;
 template class AudioDecoderIsacT<IsacFix>;
 
-namespace {
-AudioEncoderIsacFix::Config CreateConfig(const CodecInst& codec_inst,
-                                         LockedIsacBandwidthInfo* bwinfo) {
-  AudioEncoderIsacFix::Config config;
-  config.bwinfo = bwinfo;
-  config.payload_type = codec_inst.pltype;
-  config.sample_rate_hz = codec_inst.plfreq;
-  config.frame_size_ms =
-      rtc::CheckedDivExact(1000 * codec_inst.pacsize, config.sample_rate_hz);
-  if (codec_inst.rate != -1)
-    config.bit_rate = codec_inst.rate;
-  config.adaptive_mode = (codec_inst.rate == -1);
-  return config;
-}
-}  // namespace
-
-AudioEncoderMutableIsacFix::AudioEncoderMutableIsacFix(
-    const CodecInst& codec_inst,
-    LockedIsacBandwidthInfo* bwinfo)
-    : AudioEncoderMutableImpl<AudioEncoderIsacFix>(
-          CreateConfig(codec_inst, bwinfo)) {}
-
-void AudioEncoderMutableIsacFix::SetMaxPayloadSize(int max_payload_size_bytes) {
-  auto conf = config();
-  conf.max_payload_size_bytes = max_payload_size_bytes;
-  Reconstruct(conf);
-}
-
-void AudioEncoderMutableIsacFix::SetMaxRate(int max_rate_bps) {
-  auto conf = config();
-  conf.max_bit_rate = max_rate_bps;
-  Reconstruct(conf);
-}
-
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h b/webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h
index 58abbdf..da363d8 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h
@@ -13,7 +13,6 @@
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h"
 #include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h"
 #include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h"
 
@@ -121,16 +120,5 @@
 using AudioEncoderIsac = AudioEncoderIsacT<IsacFloat>;
 using AudioDecoderIsac = AudioDecoderIsacT<IsacFloat>;
 
-struct CodecInst;
-
-class AudioEncoderMutableIsacFloat
-    : public AudioEncoderMutableImpl<AudioEncoderIsac> {
- public:
-  AudioEncoderMutableIsacFloat(const CodecInst& codec_inst,
-                               LockedIsacBandwidthInfo* bwinfo);
-  void SetMaxPayloadSize(int max_payload_size_bytes) override;
-  void SetMaxRate(int max_rate_bps) override;
-};
-
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_AUDIO_ENCODER_ISAC_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc
index 195265d..eac7cc7 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc
@@ -10,7 +10,6 @@
 
 #include "webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h"
 
-#include "webrtc/common_types.h"
 #include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h"
 
 namespace webrtc {
@@ -19,40 +18,4 @@
 template class AudioEncoderIsacT<IsacFloat>;
 template class AudioDecoderIsacT<IsacFloat>;
 
-namespace {
-AudioEncoderIsac::Config CreateConfig(const CodecInst& codec_inst,
-                                      LockedIsacBandwidthInfo* bwinfo) {
-  AudioEncoderIsac::Config config;
-  config.bwinfo = bwinfo;
-  config.payload_type = codec_inst.pltype;
-  config.sample_rate_hz = codec_inst.plfreq;
-  config.frame_size_ms =
-      rtc::CheckedDivExact(1000 * codec_inst.pacsize, config.sample_rate_hz);
-  if (codec_inst.rate != -1)
-    config.bit_rate = codec_inst.rate;
-  config.adaptive_mode = (codec_inst.rate == -1);
-  return config;
-}
-}  // namespace
-
-AudioEncoderMutableIsacFloat::AudioEncoderMutableIsacFloat(
-    const CodecInst& codec_inst,
-    LockedIsacBandwidthInfo* bwinfo)
-    : AudioEncoderMutableImpl<AudioEncoderIsac>(
-          CreateConfig(codec_inst, bwinfo)) {
-}
-
-void AudioEncoderMutableIsacFloat::SetMaxPayloadSize(
-    int max_payload_size_bytes) {
-  auto conf = config();
-  conf.max_payload_size_bytes = max_payload_size_bytes;
-  Reconstruct(conf);
-}
-
-void AudioEncoderMutableIsacFloat::SetMaxRate(int max_rate_bps) {
-  auto conf = config();
-  conf.max_bit_rate = max_rate_bps;
-  Reconstruct(conf);
-}
-
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h b/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h
index 545fc19..41c7e58 100644
--- a/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h
+++ b/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h
@@ -17,50 +17,32 @@
 
 namespace webrtc {
 
-class MockAudioEncoder : public AudioEncoder {
+class MockAudioEncoder final : public AudioEncoder {
  public:
-  virtual ~MockAudioEncoder() { Die(); }
+  ~MockAudioEncoder() override { Die(); }
   MOCK_METHOD0(Die, void());
+  MOCK_CONST_METHOD0(MaxEncodedBytes, size_t());
   MOCK_CONST_METHOD0(SampleRateHz, int());
   MOCK_CONST_METHOD0(NumChannels, int());
-  MOCK_CONST_METHOD0(MaxEncodedBytes, size_t());
+  MOCK_CONST_METHOD0(RtpTimestampRateHz, int());
   MOCK_CONST_METHOD0(Num10MsFramesInNextPacket, size_t());
   MOCK_CONST_METHOD0(Max10MsFramesInAPacket, size_t());
   MOCK_CONST_METHOD0(GetTargetBitrate, int());
-  MOCK_METHOD1(SetTargetBitrate, void(int));
-  MOCK_METHOD1(SetProjectedPacketLossRate, void(double));
   // Note, we explicitly chose not to create a mock for the Encode method.
   MOCK_METHOD4(EncodeInternal,
                EncodedInfo(uint32_t timestamp,
                            const int16_t* audio,
                            size_t max_encoded_bytes,
                            uint8_t* encoded));
-};
-
-class MockAudioEncoderMutable : public AudioEncoderMutable {
- public:
-  MOCK_CONST_METHOD0(SampleRateHz, int());
-  MOCK_CONST_METHOD0(NumChannels, int());
-  MOCK_CONST_METHOD0(MaxEncodedBytes, size_t());
-  MOCK_CONST_METHOD0(Num10MsFramesInNextPacket, size_t());
-  MOCK_CONST_METHOD0(Max10MsFramesInAPacket, size_t());
-  MOCK_CONST_METHOD0(GetTargetBitrate, int());
-  MOCK_METHOD1(SetTargetBitrate, void(int));
-  MOCK_METHOD1(SetProjectedPacketLossRate, void(double));
-  // Note, we explicitly chose not to create a mock for the Encode method.
-  MOCK_METHOD4(EncodeInternal,
-               EncodedInfo(uint32_t timestamp,
-                           const int16_t* audio,
-                           size_t max_encoded_bytes,
-                           uint8_t* encoded));
-
   MOCK_METHOD0(Reset, void());
   MOCK_METHOD1(SetFec, bool(bool enable));
   MOCK_METHOD1(SetDtx, bool(bool enable));
   MOCK_METHOD1(SetApplication, bool(Application application));
-  MOCK_METHOD1(SetMaxPayloadSize, void(int max_payload_size_bytes));
-  MOCK_METHOD1(SetMaxRate, void(int max_rate_bps));
   MOCK_METHOD1(SetMaxPlaybackRate, bool(int frequency_hz));
+  MOCK_METHOD1(SetProjectedPacketLossRate, void(double fraction));
+  MOCK_METHOD1(SetTargetBitrate, void(int target_bps));
+  MOCK_METHOD1(SetMaxBitrate, void(int max_bps));
+  MOCK_METHOD1(SetMaxPayloadSize, void(int max_payload_size_bytes));
 };
 
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_mutable_opus_test.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_mutable_opus_test.cc
index 3a08398..29c8678 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_mutable_opus_test.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_mutable_opus_test.cc
@@ -8,6 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+// TODO(kwiberg): Merge these tests into audio_encoder_opus_unittest.cc
+
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h"
@@ -26,14 +28,14 @@
 
   void CreateCodec(int num_channels) {
     codec_inst_.channels = num_channels;
-    encoder_.reset(new AudioEncoderMutableOpus(codec_inst_));
+    encoder_.reset(new AudioEncoderOpus(codec_inst_));
     auto expected_app =
         num_channels == 1 ? AudioEncoderOpus::kVoip : AudioEncoderOpus::kAudio;
     EXPECT_EQ(expected_app, encoder_->application());
   }
 
   CodecInst codec_inst_;
-  rtc::scoped_ptr<AudioEncoderMutableOpus> encoder_;
+  rtc::scoped_ptr<AudioEncoderOpus> encoder_;
 };
 
 TEST_F(AudioEncoderMutableOpusTest, DefaultApplicationModeMono) {
@@ -46,8 +48,7 @@
 
 TEST_F(AudioEncoderMutableOpusTest, ChangeApplicationMode) {
   CreateCodec(2);
-  EXPECT_TRUE(
-      encoder_->SetApplication(AudioEncoderMutable::kApplicationSpeech));
+  EXPECT_TRUE(encoder_->SetApplication(AudioEncoder::Application::kSpeech));
   EXPECT_EQ(AudioEncoderOpus::kVoip, encoder_->application());
 }
 
@@ -60,8 +61,7 @@
   EXPECT_EQ(AudioEncoderOpus::kAudio, encoder_->application());
 
   // Now change to kVoip.
-  EXPECT_TRUE(
-      encoder_->SetApplication(AudioEncoderMutable::kApplicationSpeech));
+  EXPECT_TRUE(encoder_->SetApplication(AudioEncoder::Application::kSpeech));
   EXPECT_EQ(AudioEncoderOpus::kVoip, encoder_->application());
 
   // Trigger a reset again.
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 37ce873..e750aa1 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
@@ -11,6 +11,7 @@
 #include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h"
 
 #include "webrtc/base/checks.h"
+#include "webrtc/base/safe_conversions.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h"
 
@@ -18,36 +19,63 @@
 
 namespace {
 
+const int kSampleRateHz = 48000;
 const int kMinBitrateBps = 500;
 const int kMaxBitrateBps = 512000;
 
-// TODO(tlegrand): Remove this code when we have proper APIs to set the
-// complexity at a higher level.
-#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.
-const int kDefaultComplexity = 5;
-#else
-const int kDefaultComplexity = 9;
-#endif
+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 = codec_inst.rate;
+  config.payload_type = codec_inst.pltype;
+  config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip
+                                                : AudioEncoderOpus::kAudio;
+  return config;
+}
 
-// We always encode at 48 kHz.
-const int kSampleRateHz = 48000;
+// 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.
+// Additionally, to prevent toggling, margins are used, i.e., when jumping to
+// a loss rate from below, a higher threshold is used than jumping to the same
+// level from above.
+double OptimizePacketLossRate(double new_loss_rate, double old_loss_rate) {
+  DCHECK_GE(new_loss_rate, 0.0);
+  DCHECK_LE(new_loss_rate, 1.0);
+  DCHECK_GE(old_loss_rate, 0.0);
+  DCHECK_LE(old_loss_rate, 1.0);
+  const double kPacketLossRate20 = 0.20;
+  const double kPacketLossRate10 = 0.10;
+  const double kPacketLossRate5 = 0.05;
+  const double kPacketLossRate1 = 0.01;
+  const double kLossRate20Margin = 0.02;
+  const double kLossRate10Margin = 0.01;
+  const double kLossRate5Margin = 0.01;
+  if (new_loss_rate >=
+      kPacketLossRate20 +
+          kLossRate20Margin *
+              (kPacketLossRate20 - old_loss_rate > 0 ? 1 : -1)) {
+    return kPacketLossRate20;
+  } else if (new_loss_rate >=
+             kPacketLossRate10 +
+                 kLossRate10Margin *
+                     (kPacketLossRate10 - old_loss_rate > 0 ? 1 : -1)) {
+    return kPacketLossRate10;
+  } else if (new_loss_rate >=
+             kPacketLossRate5 +
+                 kLossRate5Margin *
+                     (kPacketLossRate5 - old_loss_rate > 0 ? 1 : -1)) {
+    return kPacketLossRate5;
+  } else if (new_loss_rate >= kPacketLossRate1) {
+    return kPacketLossRate1;
+  } else {
+    return 0.0;
+  }
+}
 
 }  // namespace
 
-AudioEncoderOpus::Config::Config()
-    : frame_size_ms(20),
-      num_channels(1),
-      payload_type(120),
-      application(kVoip),
-      bitrate_bps(64000),
-      fec_enabled(false),
-      max_playback_rate_hz(48000),
-      complexity(kDefaultComplexity),
-      dtx_enabled(false) {
-}
-
 bool AudioEncoderOpus::Config::IsOk() const {
   if (frame_size_ms <= 0 || frame_size_ms % 10 != 0)
     return false;
@@ -61,19 +89,150 @@
 }
 
 AudioEncoderOpus::AudioEncoderOpus(const Config& config)
-    : num_10ms_frames_per_packet_(
-          static_cast<size_t>(rtc::CheckedDivExact(config.frame_size_ms, 10))),
-      num_channels_(config.num_channels),
-      payload_type_(config.payload_type),
-      application_(config.application),
-      dtx_enabled_(config.dtx_enabled),
-      samples_per_10ms_frame_(static_cast<size_t>(
-          rtc::CheckedDivExact(kSampleRateHz, 100) * num_channels_)),
-      packet_loss_rate_(0.0) {
-  CHECK(config.IsOk());
-  input_buffer_.reserve(num_10ms_frames_per_packet_ * samples_per_10ms_frame_);
-  CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, num_channels_, application_));
-  SetTargetBitrate(config.bitrate_bps);
+    : packet_loss_rate_(0.0), inst_(nullptr) {
+  CHECK(RecreateEncoderInstance(config));
+}
+
+AudioEncoderOpus::AudioEncoderOpus(const CodecInst& codec_inst)
+    : AudioEncoderOpus(CreateConfig(codec_inst)) {}
+
+AudioEncoderOpus::~AudioEncoderOpus() {
+  CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
+}
+
+size_t AudioEncoderOpus::MaxEncodedBytes() const {
+  // 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_.bitrate_bps / (1000 * 8) + 1);
+  const size_t approx_encoded_bytes =
+      Num10msFramesPerPacket() * 10 * bytes_per_millisecond;
+  return 2 * approx_encoded_bytes;
+}
+
+int AudioEncoderOpus::SampleRateHz() const {
+  return kSampleRateHz;
+}
+
+int AudioEncoderOpus::NumChannels() const {
+  return config_.num_channels;
+}
+
+size_t AudioEncoderOpus::Num10MsFramesInNextPacket() const {
+  return Num10msFramesPerPacket();
+}
+
+size_t AudioEncoderOpus::Max10MsFramesInAPacket() const {
+  return Num10msFramesPerPacket();
+}
+
+int AudioEncoderOpus::GetTargetBitrate() const {
+  return config_.bitrate_bps;
+}
+
+AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeInternal(
+    uint32_t rtp_timestamp,
+    const int16_t* audio,
+    size_t max_encoded_bytes,
+    uint8_t* encoded) {
+  if (input_buffer_.empty())
+    first_timestamp_in_buffer_ = rtp_timestamp;
+  input_buffer_.insert(input_buffer_.end(), audio,
+                       audio + SamplesPer10msFrame());
+  if (input_buffer_.size() <
+      (static_cast<size_t>(Num10msFramesPerPacket()) * SamplesPer10msFrame())) {
+    return EncodedInfo();
+  }
+  CHECK_EQ(input_buffer_.size(), static_cast<size_t>(Num10msFramesPerPacket()) *
+                                     SamplesPer10msFrame());
+  int status = WebRtcOpus_Encode(
+      inst_, &input_buffer_[0],
+      rtc::CheckedDivExact(input_buffer_.size(),
+                           static_cast<size_t>(config_.num_channels)),
+      rtc::saturated_cast<int16_t>(max_encoded_bytes), encoded);
+  CHECK_GE(status, 0);  // Fails only if fed invalid data.
+  input_buffer_.clear();
+  EncodedInfo info;
+  info.encoded_bytes = static_cast<size_t>(status);
+  info.encoded_timestamp = first_timestamp_in_buffer_;
+  info.payload_type = config_.payload_type;
+  info.send_even_if_empty = true;  // Allows Opus to send empty packets.
+  info.speech = (status > 0);
+  return info;
+}
+
+void AudioEncoderOpus::Reset() {
+  CHECK(RecreateEncoderInstance(config_));
+}
+
+bool AudioEncoderOpus::SetFec(bool enable) {
+  auto conf = config_;
+  conf.fec_enabled = enable;
+  return RecreateEncoderInstance(conf);
+}
+
+bool AudioEncoderOpus::SetDtx(bool enable) {
+  auto conf = config_;
+  conf.dtx_enabled = enable;
+  return RecreateEncoderInstance(conf);
+}
+
+bool AudioEncoderOpus::SetApplication(Application application) {
+  auto conf = config_;
+  switch (application) {
+    case Application::kSpeech:
+      conf.application = AudioEncoderOpus::kVoip;
+      break;
+    case Application::kAudio:
+      conf.application = AudioEncoderOpus::kAudio;
+      break;
+  }
+  return RecreateEncoderInstance(conf);
+}
+
+bool AudioEncoderOpus::SetMaxPlaybackRate(int frequency_hz) {
+  auto conf = config_;
+  conf.max_playback_rate_hz = frequency_hz;
+  return RecreateEncoderInstance(conf);
+}
+
+void AudioEncoderOpus::SetProjectedPacketLossRate(double fraction) {
+  double opt_loss_rate = OptimizePacketLossRate(fraction, packet_loss_rate_);
+  if (packet_loss_rate_ != opt_loss_rate) {
+    packet_loss_rate_ = opt_loss_rate;
+    CHECK_EQ(0, WebRtcOpus_SetPacketLossRate(
+                    inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5)));
+  }
+}
+
+void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) {
+  config_.bitrate_bps =
+      std::max(std::min(bits_per_second, kMaxBitrateBps), kMinBitrateBps);
+  DCHECK(config_.IsOk());
+  CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.bitrate_bps));
+}
+
+int AudioEncoderOpus::Num10msFramesPerPacket() const {
+  return rtc::CheckedDivExact(config_.frame_size_ms, 10);
+}
+
+int AudioEncoderOpus::SamplesPer10msFrame() const {
+  return rtc::CheckedDivExact(kSampleRateHz, 100) * config_.num_channels;
+}
+
+// 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) {
+  if (!config.IsOk())
+    return false;
+  if (inst_)
+    CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
+  input_buffer_.clear();
+  input_buffer_.reserve(Num10msFramesPerPacket() * SamplesPer10msFrame());
+  CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, config.num_channels,
+                                       config.application));
+  CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config.bitrate_bps));
   if (config.fec_enabled) {
     CHECK_EQ(0, WebRtcOpus_EnableFec(inst_));
   } else {
@@ -87,172 +246,10 @@
   } else {
     CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_));
   }
-}
-
-AudioEncoderOpus::~AudioEncoderOpus() {
-  CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
-}
-
-int AudioEncoderOpus::SampleRateHz() const {
-  return kSampleRateHz;
-}
-
-int AudioEncoderOpus::NumChannels() const {
-  return num_channels_;
-}
-
-size_t AudioEncoderOpus::MaxEncodedBytes() const {
-  // Calculate the number of bytes we expect the encoder to produce,
-  // then multiply by two to give a wide margin for error.
-  size_t bytes_per_millisecond =
-      static_cast<size_t>(bitrate_bps_ / (1000 * 8) + 1);
-  size_t approx_encoded_bytes =
-      num_10ms_frames_per_packet_ * 10 * bytes_per_millisecond;
-  return 2 * approx_encoded_bytes;
-}
-
-size_t AudioEncoderOpus::Num10MsFramesInNextPacket() const {
-  return num_10ms_frames_per_packet_;
-}
-
-size_t AudioEncoderOpus::Max10MsFramesInAPacket() const {
-  return num_10ms_frames_per_packet_;
-}
-
-int AudioEncoderOpus::GetTargetBitrate() const {
-  return bitrate_bps_;
-}
-
-void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) {
-  bitrate_bps_ = std::max(std::min(bits_per_second, kMaxBitrateBps),
-                          kMinBitrateBps);
-  CHECK_EQ(WebRtcOpus_SetBitRate(inst_, bitrate_bps_), 0);
-}
-
-void AudioEncoderOpus::SetProjectedPacketLossRate(double fraction) {
-  DCHECK_GE(fraction, 0.0);
-  DCHECK_LE(fraction, 1.0);
-  // 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.
-  // Additionally, to prevent toggling, margins are used, i.e., when jumping to
-  // a loss rate from below, a higher threshold is used than jumping to the same
-  // level from above.
-  const double kPacketLossRate20 = 0.20;
-  const double kPacketLossRate10 = 0.10;
-  const double kPacketLossRate5 = 0.05;
-  const double kPacketLossRate1 = 0.01;
-  const double kLossRate20Margin = 0.02;
-  const double kLossRate10Margin = 0.01;
-  const double kLossRate5Margin = 0.01;
-  double opt_loss_rate;
-  if (fraction >=
-      kPacketLossRate20 +
-          kLossRate20Margin *
-              (kPacketLossRate20 - packet_loss_rate_ > 0 ? 1 : -1)) {
-    opt_loss_rate = kPacketLossRate20;
-  } else if (fraction >=
-             kPacketLossRate10 +
-                 kLossRate10Margin *
-                     (kPacketLossRate10 - packet_loss_rate_ > 0 ? 1 : -1)) {
-    opt_loss_rate = kPacketLossRate10;
-  } else if (fraction >=
-             kPacketLossRate5 +
-                 kLossRate5Margin *
-                     (kPacketLossRate5 - packet_loss_rate_ > 0 ? 1 : -1)) {
-    opt_loss_rate = kPacketLossRate5;
-  } else if (fraction >= kPacketLossRate1) {
-    opt_loss_rate = kPacketLossRate1;
-  } else {
-    opt_loss_rate = 0;
-  }
-
-  if (packet_loss_rate_ != opt_loss_rate) {
-    // Ask the encoder to change the target packet loss rate.
-    CHECK_EQ(WebRtcOpus_SetPacketLossRate(
-                 inst_, static_cast<int32_t>(opt_loss_rate * 100 + .5)),
-             0);
-    packet_loss_rate_ = opt_loss_rate;
-  }
-}
-
-AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeInternal(
-    uint32_t rtp_timestamp,
-    const int16_t* audio,
-    size_t max_encoded_bytes,
-    uint8_t* encoded) {
-  if (input_buffer_.empty())
-    first_timestamp_in_buffer_ = rtp_timestamp;
-  input_buffer_.insert(input_buffer_.end(), audio,
-                       audio + samples_per_10ms_frame_);
-  if (input_buffer_.size() <
-      (num_10ms_frames_per_packet_ * samples_per_10ms_frame_)) {
-    return EncodedInfo();
-  }
-  CHECK_EQ(input_buffer_.size(),
-           num_10ms_frames_per_packet_ * samples_per_10ms_frame_);
-  int status = WebRtcOpus_Encode(
-      inst_, &input_buffer_[0],
-      rtc::CheckedDivExact(input_buffer_.size(),
-                           static_cast<size_t>(num_channels_)),
-      max_encoded_bytes, encoded);
-  CHECK_GE(status, 0);  // Fails only if fed invalid data.
-  input_buffer_.clear();
-  EncodedInfo info;
-  info.encoded_bytes = static_cast<size_t>(status);
-  info.encoded_timestamp = first_timestamp_in_buffer_;
-  info.payload_type = payload_type_;
-  info.send_even_if_empty = true;  // Allows Opus to send empty packets.
-  info.speech = (status > 0);
-  return info;
-}
-
-namespace {
-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 = codec_inst.rate;
-  config.payload_type = codec_inst.pltype;
-  config.application = (config.num_channels == 1 ? AudioEncoderOpus::kVoip
-                                                 : AudioEncoderOpus::kAudio);
-  return config;
-}
-}  // namespace
-
-AudioEncoderMutableOpus::AudioEncoderMutableOpus(const CodecInst& codec_inst)
-    : AudioEncoderMutableImpl<AudioEncoderOpus>(CreateConfig(codec_inst)) {
-}
-
-bool AudioEncoderMutableOpus::SetFec(bool enable) {
-  auto conf = config();
-  conf.fec_enabled = enable;
-  return Reconstruct(conf);
-}
-
-bool AudioEncoderMutableOpus::SetDtx(bool enable) {
-  auto conf = config();
-  conf.dtx_enabled = enable;
-  return Reconstruct(conf);
-}
-
-bool AudioEncoderMutableOpus::SetApplication(Application application) {
-  auto conf = config();
-  switch (application) {
-    case kApplicationSpeech:
-      conf.application = AudioEncoderOpus::kVoip;
-      break;
-    case kApplicationAudio:
-      conf.application = AudioEncoderOpus::kAudio;
-      break;
-  }
-  return Reconstruct(conf);
-}
-
-bool AudioEncoderMutableOpus::SetMaxPlaybackRate(int frequency_hz) {
-  auto conf = config();
-  conf.max_playback_rate_hz = frequency_hz;
-  return Reconstruct(conf);
+  CHECK_EQ(0, WebRtcOpus_SetPacketLossRate(
+                  inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5)));
+  config_ = config;
+  return true;
 }
 
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h b/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h
index 5fab599..d95d6c6 100644
--- a/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h
+++ b/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h
@@ -13,15 +13,14 @@
 
 #include <vector>
 
+#include "webrtc/base/checks.h"
 #include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h"
 #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h"
 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
 
 namespace webrtc {
 
-// NOTE: This class has neither ThreadChecker, nor locks. The owner of an
-// AudioEncoderOpus object must ensure that it is not accessed concurrently.
+struct CodecInst;
 
 class AudioEncoderOpus final : public AudioEncoder {
  public:
@@ -31,60 +30,44 @@
   };
 
   struct Config {
-    Config();
     bool IsOk() const;
-    int frame_size_ms;
-    int num_channels;
-    int payload_type;
-    ApplicationMode application;
-    int bitrate_bps;
-    bool fec_enabled;
-    int max_playback_rate_hz;
-    int complexity;
-    bool dtx_enabled;
+    int frame_size_ms = 20;
+    int num_channels = 1;
+    int payload_type = 120;
+    ApplicationMode application = kVoip;
+    int bitrate_bps = 64000;
+    bool fec_enabled = false;
+    int max_playback_rate_hz = 48000;
+    int complexity = kDefaultComplexity;
+    bool dtx_enabled = false;
+
+   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
   };
 
   explicit AudioEncoderOpus(const Config& config);
+  explicit AudioEncoderOpus(const CodecInst& codec_inst);
   ~AudioEncoderOpus() override;
 
+  size_t MaxEncodedBytes() const override;
   int SampleRateHz() const override;
   int NumChannels() const override;
-  size_t MaxEncodedBytes() const override;
   size_t Num10MsFramesInNextPacket() const override;
   size_t Max10MsFramesInAPacket() const override;
   int GetTargetBitrate() const override;
-  void SetTargetBitrate(int bits_per_second) override;
-  void SetProjectedPacketLossRate(double fraction) override;
-
-  double packet_loss_rate() const { return packet_loss_rate_; }
-  ApplicationMode application() const { return application_; }
-  bool dtx_enabled() const { return dtx_enabled_; }
 
   EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
                              const int16_t* audio,
                              size_t max_encoded_bytes,
                              uint8_t* encoded) override;
 
- private:
-  const size_t num_10ms_frames_per_packet_;
-  const int num_channels_;
-  const int payload_type_;
-  const ApplicationMode application_;
-  int bitrate_bps_;
-  const bool dtx_enabled_;
-  const size_t samples_per_10ms_frame_;
-  std::vector<int16_t> input_buffer_;
-  OpusEncInst* inst_;
-  uint32_t first_timestamp_in_buffer_;
-  double packet_loss_rate_;
-};
-
-struct CodecInst;
-
-class AudioEncoderMutableOpus
-    : public AudioEncoderMutableImpl<AudioEncoderOpus> {
- public:
-  explicit AudioEncoderMutableOpus(const CodecInst& codec_inst);
+  void Reset() override;
   bool SetFec(bool enable) override;
 
   // Set Opus DTX. Once enabled, Opus stops transmission, when it detects voice
@@ -94,18 +77,24 @@
 
   bool SetApplication(Application application) override;
   bool SetMaxPlaybackRate(int frequency_hz) override;
-  AudioEncoderOpus::ApplicationMode application() const {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return encoder()->application();
-  }
-  double packet_loss_rate() const {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return encoder()->packet_loss_rate();
-  }
-  bool dtx_enabled() const {
-    CriticalSectionScoped cs(encoder_lock_.get());
-    return encoder()->dtx_enabled();
-  }
+  void SetProjectedPacketLossRate(double fraction) override;
+  void SetTargetBitrate(int target_bps) override;
+
+  // Getters for testing.
+  double packet_loss_rate() const { return packet_loss_rate_; }
+  ApplicationMode application() const { return config_.application; }
+  bool dtx_enabled() const { return config_.dtx_enabled; }
+
+ private:
+  int Num10msFramesPerPacket() const;
+  int SamplesPer10msFrame() const;
+  bool RecreateEncoderInstance(const Config& config);
+
+  Config config_;
+  double packet_loss_rate_;
+  std::vector<int16_t> input_buffer_;
+  OpusEncInst* inst_;
+  uint32_t first_timestamp_in_buffer_;
 };
 
 }  // 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 4ca6fe9..6c30c7f 100644
--- a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
+++ b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
@@ -16,13 +16,6 @@
 
 namespace webrtc {
 
-bool AudioEncoderPcm16B::Config::IsOk() const {
-  if ((sample_rate_hz != 8000) && (sample_rate_hz != 16000) &&
-      (sample_rate_hz != 32000) && (sample_rate_hz != 48000))
-    return false;
-  return AudioEncoderPcm::Config::IsOk();
-}
-
 size_t AudioEncoderPcm16B::EncodeCall(const int16_t* audio,
                                       size_t input_len,
                                       uint8_t* encoded) {
@@ -45,9 +38,14 @@
 }
 }  // namespace
 
-AudioEncoderMutablePcm16B::AudioEncoderMutablePcm16B(
-    const CodecInst& codec_inst)
-    : AudioEncoderMutableImpl<AudioEncoderPcm16B>(CreateConfig(codec_inst)) {
+bool AudioEncoderPcm16B::Config::IsOk() const {
+  if ((sample_rate_hz != 8000) && (sample_rate_hz != 16000) &&
+      (sample_rate_hz != 32000) && (sample_rate_hz != 48000))
+    return false;
+  return AudioEncoderPcm::Config::IsOk();
 }
 
+AudioEncoderPcm16B::AudioEncoderPcm16B(const CodecInst& codec_inst)
+    : AudioEncoderPcm16B(CreateConfig(codec_inst)) {}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h b/webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h
index 6a0fb43..5d368bc 100644
--- a/webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h
+++ b/webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h
@@ -12,11 +12,12 @@
 #define WEBRTC_MODULES_AUDIO_CODING_CODECS_PCM16B_INCLUDE_AUDIO_ENCODER_PCM16B_H_
 
 #include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_coding/codecs/audio_encoder_mutable_impl.h"
 #include "webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h"
 
 namespace webrtc {
 
+struct CodecInst;
+
 class AudioEncoderPcm16B final : public AudioEncoderPcm {
  public:
   struct Config : public AudioEncoderPcm::Config {
@@ -29,6 +30,7 @@
 
   explicit AudioEncoderPcm16B(const Config& config)
       : AudioEncoderPcm(config, config.sample_rate_hz) {}
+  explicit AudioEncoderPcm16B(const CodecInst& codec_inst);
 
  protected:
   size_t EncodeCall(const int16_t* audio,
@@ -38,13 +40,5 @@
   int BytesPerSample() const override;
 };
 
-struct CodecInst;
-
-class AudioEncoderMutablePcm16B
-    : public AudioEncoderMutableImpl<AudioEncoderPcm16B> {
- public:
-  explicit AudioEncoderMutablePcm16B(const CodecInst& codec_inst);
-};
-
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_PCM16B_INCLUDE_AUDIO_ENCODER_PCM16B_H_
diff --git a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
index 96ec3cc..a54e018 100644
--- a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
+++ b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
@@ -22,23 +22,22 @@
   CHECK(speech_encoder_) << "Speech encoder not provided.";
 }
 
-AudioEncoderCopyRed::~AudioEncoderCopyRed() {
+AudioEncoderCopyRed::~AudioEncoderCopyRed() = default;
+
+size_t AudioEncoderCopyRed::MaxEncodedBytes() const {
+  return 2 * speech_encoder_->MaxEncodedBytes();
 }
 
 int AudioEncoderCopyRed::SampleRateHz() const {
   return speech_encoder_->SampleRateHz();
 }
 
-int AudioEncoderCopyRed::RtpTimestampRateHz() const {
-  return speech_encoder_->RtpTimestampRateHz();
-}
-
 int AudioEncoderCopyRed::NumChannels() const {
   return speech_encoder_->NumChannels();
 }
 
-size_t AudioEncoderCopyRed::MaxEncodedBytes() const {
-  return 2 * speech_encoder_->MaxEncodedBytes();
+int AudioEncoderCopyRed::RtpTimestampRateHz() const {
+  return speech_encoder_->RtpTimestampRateHz();
 }
 
 size_t AudioEncoderCopyRed::Num10MsFramesInNextPacket() const {
@@ -53,16 +52,6 @@
   return speech_encoder_->GetTargetBitrate();
 }
 
-void AudioEncoderCopyRed::SetTargetBitrate(int bits_per_second) {
-  speech_encoder_->SetTargetBitrate(bits_per_second);
-}
-
-void AudioEncoderCopyRed::SetProjectedPacketLossRate(double fraction) {
-  DCHECK_GE(fraction, 0.0);
-  DCHECK_LE(fraction, 1.0);
-  speech_encoder_->SetProjectedPacketLossRate(fraction);
-}
-
 AudioEncoder::EncodedInfo AudioEncoderCopyRed::EncodeInternal(
     uint32_t rtp_timestamp,
     const int16_t* audio,
@@ -102,4 +91,42 @@
   return info;
 }
 
+void AudioEncoderCopyRed::Reset() {
+  speech_encoder_->Reset();
+  secondary_encoded_.Clear();
+  secondary_info_.encoded_bytes = 0;
+}
+
+bool AudioEncoderCopyRed::SetFec(bool enable) {
+  return speech_encoder_->SetFec(enable);
+}
+
+bool AudioEncoderCopyRed::SetDtx(bool enable) {
+  return speech_encoder_->SetDtx(enable);
+}
+
+bool AudioEncoderCopyRed::SetApplication(Application application) {
+  return speech_encoder_->SetApplication(application);
+}
+
+bool AudioEncoderCopyRed::SetMaxPlaybackRate(int frequency_hz) {
+  return speech_encoder_->SetMaxPlaybackRate(frequency_hz);
+}
+
+void AudioEncoderCopyRed::SetProjectedPacketLossRate(double fraction) {
+  speech_encoder_->SetProjectedPacketLossRate(fraction);
+}
+
+void AudioEncoderCopyRed::SetTargetBitrate(int bits_per_second) {
+  speech_encoder_->SetTargetBitrate(bits_per_second);
+}
+
+void AudioEncoderCopyRed::SetMaxBitrate(int max_bps) {
+  speech_encoder_->SetMaxBitrate(max_bps);
+}
+
+void AudioEncoderCopyRed::SetMaxPayloadSize(int max_payload_size_bytes) {
+  speech_encoder_->SetMaxPayloadSize(max_payload_size_bytes);
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
index 644255b..5e2c9b2 100644
--- a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
+++ b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
@@ -23,7 +23,7 @@
 // underlying AudioEncoder object that performs the actual encodings. The
 // current class will gather the two latest encodings from the underlying codec
 // into one packet.
-class AudioEncoderCopyRed : public AudioEncoder {
+class AudioEncoderCopyRed final : public AudioEncoder {
  public:
   struct Config {
    public:
@@ -36,19 +36,26 @@
 
   ~AudioEncoderCopyRed() override;
 
+  size_t MaxEncodedBytes() const override;
   int SampleRateHz() const override;
   int NumChannels() const override;
-  size_t MaxEncodedBytes() const override;
   int RtpTimestampRateHz() const override;
   size_t Num10MsFramesInNextPacket() const override;
   size_t Max10MsFramesInAPacket() const override;
   int GetTargetBitrate() const override;
-  void SetTargetBitrate(int bits_per_second) override;
-  void SetProjectedPacketLossRate(double fraction) override;
   EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
                              const int16_t* audio,
                              size_t max_encoded_bytes,
                              uint8_t* encoded) override;
+  void Reset() override;
+  bool SetFec(bool enable) override;
+  bool SetDtx(bool enable) override;
+  bool SetApplication(Application application) override;
+  bool SetMaxPlaybackRate(int frequency_hz) override;
+  void SetProjectedPacketLossRate(double fraction) override;
+  void SetTargetBitrate(int target_bps) override;
+  void SetMaxBitrate(int max_bps) override;
+  void SetMaxPayloadSize(int max_payload_size_bytes) override;
 
  private:
   AudioEncoder* speech_encoder_;
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.cc
index 74e98d9..b84be29 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.cc
@@ -65,7 +65,7 @@
 }
 
 bool AcmSendTestOldApi::RegisterExternalCodec(
-    AudioEncoderMutable* external_speech_encoder) {
+    AudioEncoder* external_speech_encoder) {
   acm_->RegisterExternalSendCodec(external_speech_encoder);
   input_frame_.num_channels_ = external_speech_encoder->NumChannels();
   assert(input_block_size_samples_ * input_frame_.num_channels_ <=
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.h b/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.h
index 008e264..523498b 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.h
+++ b/webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.h
@@ -20,7 +20,7 @@
 #include "webrtc/system_wrappers/interface/clock.h"
 
 namespace webrtc {
-class AudioEncoderMutable;
+class AudioEncoder;
 
 namespace test {
 class InputAudioFile;
@@ -42,7 +42,7 @@
                      int frame_size_samples);
 
   // Registers an external send codec. Returns true on success, false otherwise.
-  bool RegisterExternalCodec(AudioEncoderMutable* external_speech_encoder);
+  bool RegisterExternalCodec(AudioEncoder* external_speech_encoder);
 
   // Returns the next encoded packet. Returns NULL if the test duration was
   // exceeded. Ownership of the packet is handed over to the caller.
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
index ac0bc0b..eec00de 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
@@ -231,7 +231,7 @@
 }
 
 void AudioCodingModuleImpl::RegisterExternalSendCodec(
-    AudioEncoderMutable* external_speech_encoder) {
+    AudioEncoder* external_speech_encoder) {
   CriticalSectionScoped lock(acm_crit_sect_.get());
   codec_manager_.RegisterEncoder(external_speech_encoder);
 }
@@ -485,8 +485,8 @@
 int AudioCodingModuleImpl::SetPacketLossRate(int loss_rate) {
   CriticalSectionScoped lock(acm_crit_sect_.get());
   if (HaveValidEncoder("SetPacketLossRate")) {
-    codec_manager_.CurrentSpeechEncoder()->SetProjectedPacketLossRate(
-        loss_rate / 100.0);
+    codec_manager_.CurrentEncoder()->SetProjectedPacketLossRate(loss_rate /
+                                                                100.0);
   }
   return 0;
 }
@@ -741,7 +741,7 @@
     return -1;
   }
 
-  codec_manager_.CurrentSpeechEncoder()->SetMaxRate(max_bit_per_sec);
+  codec_manager_.CurrentEncoder()->SetMaxBitrate(max_bit_per_sec);
   return 0;
 }
 
@@ -753,7 +753,7 @@
     return -1;
   }
 
-  codec_manager_.CurrentSpeechEncoder()->SetMaxPayloadSize(max_size_bytes);
+  codec_manager_.CurrentEncoder()->SetMaxPayloadSize(max_size_bytes);
   return 0;
 }
 
@@ -762,19 +762,21 @@
   if (!HaveValidEncoder("SetOpusApplication")) {
     return -1;
   }
-  AudioEncoderMutable::Application app;
+  if (!codec_manager_.CurrentEncoderIsOpus())
+    return -1;
+  AudioEncoder::Application app;
   switch (application) {
     case kVoip:
-      app = AudioEncoderMutable::kApplicationSpeech;
+      app = AudioEncoder::Application::kSpeech;
       break;
     case kAudio:
-      app = AudioEncoderMutable::kApplicationAudio;
+      app = AudioEncoder::Application::kAudio;
       break;
     default:
       FATAL();
       return 0;
   }
-  return codec_manager_.CurrentSpeechEncoder()->SetApplication(app) ? 0 : -1;
+  return codec_manager_.CurrentEncoder()->SetApplication(app) ? 0 : -1;
 }
 
 // Informs Opus encoder of the maximum playback rate the receiver will render.
@@ -783,9 +785,10 @@
   if (!HaveValidEncoder("SetOpusMaxPlaybackRate")) {
     return -1;
   }
-  return codec_manager_.CurrentSpeechEncoder()->SetMaxPlaybackRate(frequency_hz)
-             ? 0
-             : -1;
+  if (!codec_manager_.CurrentEncoderIsOpus())
+    return -1;
+  return codec_manager_.CurrentEncoder()->SetMaxPlaybackRate(frequency_hz) ? 0
+                                                                           : -1;
 }
 
 int AudioCodingModuleImpl::EnableOpusDtx() {
@@ -793,7 +796,9 @@
   if (!HaveValidEncoder("EnableOpusDtx")) {
     return -1;
   }
-  return codec_manager_.CurrentSpeechEncoder()->SetDtx(true) ? 0 : -1;
+  if (!codec_manager_.CurrentEncoderIsOpus())
+    return -1;
+  return codec_manager_.CurrentEncoder()->SetDtx(true) ? 0 : -1;
 }
 
 int AudioCodingModuleImpl::DisableOpusDtx() {
@@ -801,7 +806,9 @@
   if (!HaveValidEncoder("DisableOpusDtx")) {
     return -1;
   }
-  return codec_manager_.CurrentSpeechEncoder()->SetDtx(false) ? 0 : -1;
+  if (!codec_manager_.CurrentEncoderIsOpus())
+    return -1;
+  return codec_manager_.CurrentEncoder()->SetDtx(false) ? 0 : -1;
 }
 
 int AudioCodingModuleImpl::PlayoutTimestamp(uint32_t* timestamp) {
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h
index fd93901..db3e927 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h
@@ -47,7 +47,7 @@
   int RegisterSendCodec(const CodecInst& send_codec) override;
 
   void RegisterExternalSendCodec(
-      AudioEncoderMutable* external_speech_encoder) override;
+      AudioEncoder* external_speech_encoder) override;
 
   // Get current send codec.
   int SendCodec(CodecInst* current_codec) const override;
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
index b7289fc..36e2734 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
@@ -1074,7 +1074,7 @@
                                      frame_size_samples);
   }
 
-  bool RegisterExternalSendCodec(AudioEncoderMutable* external_speech_encoder,
+  bool RegisterExternalSendCodec(AudioEncoder* external_speech_encoder,
                                  int payload_type) {
     payload_type_ = payload_type;
     frame_size_rtp_timestamps_ =
@@ -1176,7 +1176,7 @@
                                   codec_frame_size_rtp_timestamps));
   }
 
-  void SetUpTestExternalEncoder(AudioEncoderMutable* external_speech_encoder,
+  void SetUpTestExternalEncoder(AudioEncoder* external_speech_encoder,
                                 int payload_type) {
     ASSERT_TRUE(SetUpSender());
     ASSERT_TRUE(
@@ -1601,36 +1601,36 @@
   codec_inst.channels = 1;
   codec_inst.pacsize = 160;
   codec_inst.pltype = 0;
-  AudioEncoderMutablePcmU encoder(codec_inst);
-  MockAudioEncoderMutable mock_encoder;
+  AudioEncoderPcmU encoder(codec_inst);
+  MockAudioEncoder mock_encoder;
   // Set expectations on the mock encoder and also delegate the calls to the
   // real encoder.
+  EXPECT_CALL(mock_encoder, MaxEncodedBytes())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::MaxEncodedBytes));
+  EXPECT_CALL(mock_encoder, SampleRateHz())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::SampleRateHz));
+  EXPECT_CALL(mock_encoder, NumChannels())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::NumChannels));
+  EXPECT_CALL(mock_encoder, RtpTimestampRateHz())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::RtpTimestampRateHz));
   EXPECT_CALL(mock_encoder, Num10MsFramesInNextPacket())
       .Times(AtLeast(1))
-      .WillRepeatedly(Invoke(
-          &encoder, &AudioEncoderMutablePcmU::Num10MsFramesInNextPacket));
+      .WillRepeatedly(
+          Invoke(&encoder, &AudioEncoderPcmU::Num10MsFramesInNextPacket));
   EXPECT_CALL(mock_encoder, Max10MsFramesInAPacket())
       .Times(AtLeast(1))
       .WillRepeatedly(
-          Invoke(&encoder, &AudioEncoderMutablePcmU::Max10MsFramesInAPacket));
-  EXPECT_CALL(mock_encoder, SampleRateHz())
-      .Times(AtLeast(1))
-      .WillRepeatedly(Invoke(&encoder, &AudioEncoderMutablePcmU::SampleRateHz));
-  EXPECT_CALL(mock_encoder, NumChannels())
-      .Times(AtLeast(1))
-      .WillRepeatedly(Invoke(&encoder, &AudioEncoderMutablePcmU::NumChannels));
-  EXPECT_CALL(mock_encoder, MaxEncodedBytes())
-      .Times(AtLeast(1))
-      .WillRepeatedly(
-          Invoke(&encoder, &AudioEncoderMutablePcmU::MaxEncodedBytes));
-  EXPECT_CALL(mock_encoder, EncodeInternal(_, _, _, _))
-      .Times(AtLeast(1))
-      .WillRepeatedly(
-          Invoke(&encoder, &AudioEncoderMutablePcmU::EncodeInternal));
+          Invoke(&encoder, &AudioEncoderPcmU::Max10MsFramesInAPacket));
   EXPECT_CALL(mock_encoder, GetTargetBitrate())
       .Times(AtLeast(1))
-      .WillRepeatedly(Invoke(
-          &encoder, &AudioEncoderMutablePcmU::GetTargetBitrate));
+      .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::GetTargetBitrate));
+  EXPECT_CALL(mock_encoder, EncodeInternal(_, _, _, _))
+      .Times(AtLeast(1))
+      .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::EncodeInternal));
   ASSERT_NO_FATAL_FAILURE(
       SetUpTestExternalEncoder(&mock_encoder, codec_inst.pltype));
   Run("81a9d4c0bb72e9becc43aef124c981e9", "8f9b8750bd80fe26b6cbf6659b89f0f9",
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
index 7b9c7ed..863a86e 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
+++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
@@ -164,7 +164,8 @@
       vad_mode_(VADNormal),
       send_codec_inst_(kEmptyCodecInst),
       red_enabled_(false),
-      codec_fec_enabled_(false) {
+      codec_fec_enabled_(false),
+      encoder_is_opus_(false) {
   // Register the default payload type for RED and for CNG at sampling rates of
   // 8, 16, 32 and 48 kHz.
   for (int i = (ACMCodecDB::kNumCodecs - 1); i >= 0; i--) {
@@ -275,6 +276,8 @@
     red_enabled_ = false;
   }
 
+  encoder_is_opus_ = IsOpus(send_codec);
+
   if (new_codec) {
     // This is a new codec. Register it and return.
     DCHECK(CodecSupported(send_codec));
@@ -287,9 +290,8 @@
         vad_mode_, red_enabled_ ? RedPayloadType(send_codec.plfreq) : -1);
     DCHECK(codec_owner_.Encoder());
 
-    codec_fec_enabled_ =
-        codec_fec_enabled_ &&
-        codec_owner_.SpeechEncoder()->SetFec(codec_fec_enabled_);
+    codec_fec_enabled_ = codec_fec_enabled_ &&
+                         codec_owner_.Encoder()->SetFec(codec_fec_enabled_);
 
     send_codec_inst_ = send_codec;
     return 0;
@@ -311,18 +313,17 @@
 
   // Check if a change in Rate is required.
   if (send_codec.rate != send_codec_inst_.rate) {
-    codec_owner_.SpeechEncoder()->SetTargetBitrate(send_codec.rate);
+    codec_owner_.Encoder()->SetTargetBitrate(send_codec.rate);
     send_codec_inst_.rate = send_codec.rate;
   }
 
-  codec_fec_enabled_ = codec_fec_enabled_ &&
-                       codec_owner_.SpeechEncoder()->SetFec(codec_fec_enabled_);
+  codec_fec_enabled_ =
+      codec_fec_enabled_ && codec_owner_.Encoder()->SetFec(codec_fec_enabled_);
 
   return 0;
 }
 
-void CodecManager::RegisterEncoder(
-    AudioEncoderMutable* external_speech_encoder) {
+void CodecManager::RegisterEncoder(AudioEncoder* external_speech_encoder) {
   // Make up a CodecInst.
   send_codec_inst_.channels = external_speech_encoder->NumChannels();
   send_codec_inst_.plfreq = external_speech_encoder->SampleRateHz();
@@ -337,8 +338,8 @@
 
   if (stereo_send_)
     dtx_enabled_ = false;
-  codec_fec_enabled_ = codec_fec_enabled_ &&
-                       codec_owner_.SpeechEncoder()->SetFec(codec_fec_enabled_);
+  codec_fec_enabled_ =
+      codec_fec_enabled_ && codec_owner_.Encoder()->SetFec(codec_fec_enabled_);
   int cng_pt = dtx_enabled_
                    ? CngPayloadType(external_speech_encoder->SampleRateHz())
                    : -1;
@@ -430,9 +431,9 @@
     return -1;
   }
 
-  CHECK(codec_owner_.SpeechEncoder());
-  codec_fec_enabled_ = codec_owner_.SpeechEncoder()->SetFec(enable_codec_fec) &&
-                       enable_codec_fec;
+  CHECK(codec_owner_.Encoder());
+  codec_fec_enabled_ =
+      codec_owner_.Encoder()->SetFec(enable_codec_fec) && enable_codec_fec;
   return codec_fec_enabled_ == enable_codec_fec ? 0 : -1;
 }
 
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.h b/webrtc/modules/audio_coding/main/acm2/codec_manager.h
index bb9545d..3372b7f 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_manager.h
+++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.h
@@ -22,7 +22,6 @@
 
 class AudioDecoder;
 class AudioEncoder;
-class AudioEncoderMutable;
 
 namespace acm2 {
 
@@ -33,7 +32,7 @@
 
   int RegisterEncoder(const CodecInst& send_codec);
 
-  void RegisterEncoder(AudioEncoderMutable* external_speech_encoder);
+  void RegisterEncoder(AudioEncoder* external_speech_encoder);
 
   int GetCodecInst(CodecInst* current_codec) const;
 
@@ -58,12 +57,11 @@
 
   bool codec_fec_enabled() const { return codec_fec_enabled_; }
 
-  AudioEncoderMutable* CurrentSpeechEncoder() {
-    return codec_owner_.SpeechEncoder();
-  }
   AudioEncoder* CurrentEncoder() { return codec_owner_.Encoder(); }
   const AudioEncoder* CurrentEncoder() const { return codec_owner_.Encoder(); }
 
+  bool CurrentEncoderIsOpus() const { return encoder_is_opus_; }
+
  private:
   int CngPayloadType(int sample_rate_hz) const;
 
@@ -82,6 +80,7 @@
   bool red_enabled_;
   bool codec_fec_enabled_;
   CodecOwner codec_owner_;
+  bool encoder_is_opus_;
 
   DISALLOW_COPY_AND_ASSIGN(CodecManager);
 };
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_owner.cc b/webrtc/modules/audio_coding/main/acm2/codec_owner.cc
index 2f7228b..f0c38b8 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_owner.cc
+++ b/webrtc/modules/audio_coding/main/acm2/codec_owner.cc
@@ -94,41 +94,39 @@
 #endif
 }
 
-rtc::scoped_ptr<AudioEncoderMutable> CreateIsacEncoder(
+rtc::scoped_ptr<AudioEncoder> CreateIsacEncoder(
     const CodecInst& speech_inst,
     LockedIsacBandwidthInfo* bwinfo) {
 #if defined(WEBRTC_CODEC_ISACFX)
-  return rtc_make_scoped_ptr(
-      new AudioEncoderMutableIsacFix(speech_inst, bwinfo));
+  return rtc_make_scoped_ptr(new AudioEncoderIsacFix(speech_inst, bwinfo));
 #elif defined(WEBRTC_CODEC_ISAC)
-  return rtc_make_scoped_ptr(
-      new AudioEncoderMutableIsacFloat(speech_inst, bwinfo));
+  return rtc_make_scoped_ptr(new AudioEncoderIsac(speech_inst, bwinfo));
 #else
   FATAL() << "iSAC is not supported.";
   return rtc::scoped_ptr<AudioEncoderMutable>();
 #endif
 }
 
-rtc::scoped_ptr<AudioEncoderMutable> CreateSpeechEncoder(
+rtc::scoped_ptr<AudioEncoder> CreateSpeechEncoder(
     const CodecInst& speech_inst,
     LockedIsacBandwidthInfo* bwinfo) {
   if (IsIsac(speech_inst)) {
     return CreateIsacEncoder(speech_inst, bwinfo);
   } else if (IsOpus(speech_inst)) {
-    return rtc_make_scoped_ptr(new AudioEncoderMutableOpus(speech_inst));
+    return rtc_make_scoped_ptr(new AudioEncoderOpus(speech_inst));
   } else if (IsPcmU(speech_inst)) {
-    return rtc_make_scoped_ptr(new AudioEncoderMutablePcmU(speech_inst));
+    return rtc_make_scoped_ptr(new AudioEncoderPcmU(speech_inst));
   } else if (IsPcmA(speech_inst)) {
-    return rtc_make_scoped_ptr(new AudioEncoderMutablePcmA(speech_inst));
+    return rtc_make_scoped_ptr(new AudioEncoderPcmA(speech_inst));
   } else if (IsPcm16B(speech_inst)) {
-    return rtc_make_scoped_ptr(new AudioEncoderMutablePcm16B(speech_inst));
+    return rtc_make_scoped_ptr(new AudioEncoderPcm16B(speech_inst));
   } else if (IsIlbc(speech_inst)) {
-    return rtc_make_scoped_ptr(new AudioEncoderMutableIlbc(speech_inst));
+    return rtc_make_scoped_ptr(new AudioEncoderIlbc(speech_inst));
   } else if (IsG722(speech_inst)) {
-    return rtc_make_scoped_ptr(new AudioEncoderMutableG722(speech_inst));
+    return rtc_make_scoped_ptr(new AudioEncoderG722(speech_inst));
   } else {
     FATAL() << "Could not create encoder of type " << speech_inst.plname;
-    return rtc::scoped_ptr<AudioEncoderMutable>();
+    return rtc::scoped_ptr<AudioEncoder>();
   }
 }
 
@@ -187,7 +185,7 @@
   ChangeCngAndRed(cng_payload_type, vad_mode, red_payload_type);
 }
 
-void CodecOwner::SetEncoders(AudioEncoderMutable* external_speech_encoder,
+void CodecOwner::SetEncoders(AudioEncoder* external_speech_encoder,
                              int cng_payload_type,
                              ACMVADMode vad_mode,
                              int red_payload_type) {
@@ -199,7 +197,7 @@
 void CodecOwner::ChangeCngAndRed(int cng_payload_type,
                                  ACMVADMode vad_mode,
                                  int red_payload_type) {
-  AudioEncoderMutable* speech_encoder = SpeechEncoder();
+  AudioEncoder* speech_encoder = SpeechEncoder();
   if (cng_payload_type != -1 || red_payload_type != -1) {
     // The RED and CNG encoders need to be in sync with the speech encoder, so
     // reset the latter to ensure its buffer is empty.
@@ -230,12 +228,12 @@
   return SpeechEncoder();
 }
 
-AudioEncoderMutable* CodecOwner::SpeechEncoder() {
-  const auto& const_this = *this;
-  return const_cast<AudioEncoderMutable*>(const_this.SpeechEncoder());
+AudioEncoder* CodecOwner::SpeechEncoder() {
+  const auto* const_this = this;
+  return const_cast<AudioEncoder*>(const_this->SpeechEncoder());
 }
 
-const AudioEncoderMutable* CodecOwner::SpeechEncoder() const {
+const AudioEncoder* CodecOwner::SpeechEncoder() const {
   DCHECK(!speech_encoder_ || !external_speech_encoder_);
   return external_speech_encoder_ ? external_speech_encoder_
                                   : speech_encoder_.get();
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_owner.h b/webrtc/modules/audio_coding/main/acm2/codec_owner.h
index 2c5e942..cb533b6 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_owner.h
+++ b/webrtc/modules/audio_coding/main/acm2/codec_owner.h
@@ -34,7 +34,7 @@
                    ACMVADMode vad_mode,
                    int red_payload_type);
 
-  void SetEncoders(AudioEncoderMutable* external_speech_encoder,
+  void SetEncoders(AudioEncoder* external_speech_encoder,
                    int cng_payload_type,
                    ACMVADMode vad_mode,
                    int red_payload_type);
@@ -49,13 +49,14 @@
 
   AudioEncoder* Encoder();
   const AudioEncoder* Encoder() const;
-  AudioEncoderMutable* SpeechEncoder();
-  const AudioEncoderMutable* SpeechEncoder() const;
 
  private:
+  AudioEncoder* SpeechEncoder();
+  const AudioEncoder* SpeechEncoder() const;
+
   // At most one of these is non-null:
-  rtc::scoped_ptr<AudioEncoderMutable> speech_encoder_;
-  AudioEncoderMutable* external_speech_encoder_;
+  rtc::scoped_ptr<AudioEncoder> speech_encoder_;
+  AudioEncoder* external_speech_encoder_;
 
   // If we've created an iSAC decoder because someone called GetIsacDecoder,
   // store it here.
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_owner_unittest.cc b/webrtc/modules/audio_coding/main/acm2/codec_owner_unittest.cc
index a1366a9..0c510c0 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_owner_unittest.cc
+++ b/webrtc/modules/audio_coding/main/acm2/codec_owner_unittest.cc
@@ -99,7 +99,7 @@
 }
 
 TEST_F(CodecOwnerTest, ExternalEncoder) {
-  MockAudioEncoderMutable external_encoder;
+  MockAudioEncoder external_encoder;
   codec_owner_.SetEncoders(&external_encoder, -1, VADNormal, -1);
   const int kSampleRateHz = 8000;
   const int kPacketSizeSamples = kSampleRateHz / 100;
diff --git a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h
index 387632e..f2972e7 100644
--- a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h
+++ b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h
@@ -28,7 +28,7 @@
 struct WebRtcRTPHeader;
 class AudioFrame;
 class RTPFragmentationHeader;
-class AudioEncoderMutable;
+class AudioEncoder;
 class AudioDecoder;
 
 #define WEBRTC_10MS_PCM_AUDIO 960  // 16 bits super wideband 48 kHz
@@ -225,7 +225,7 @@
   // Registers |external_speech_encoder| as encoder. The new encoder will
   // replace any previously registered speech encoder (internal or external).
   virtual void RegisterExternalSendCodec(
-      AudioEncoderMutable* external_speech_encoder) = 0;
+      AudioEncoder* external_speech_encoder) = 0;
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t SendCodec()