iSAC: Make separate AudioEncoder and AudioDecoder objects

The only shared state is now the bandwidth estimation info.
This reduces the amount and complexity of the locking
substantially.

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

Cr-Commit-Position: refs/heads/master@{#9762}
diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn
index 8a27900..d98d9c3 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -380,6 +380,15 @@
   ]
 }
 
+source_set("isac_common") {
+  sources = [
+    "codecs/isac/audio_encoder_isac_t.h",
+    "codecs/isac/audio_encoder_isac_t_impl.h",
+    "codecs/isac/locked_bandwidth_info.cc",
+    "codecs/isac/locked_bandwidth_info.h",
+  ]
+}
+
 config("isac_config") {
   include_dirs = [
     "../../..",
@@ -389,8 +398,6 @@
 
 source_set("isac") {
   sources = [
-    "codecs/isac/audio_encoder_isac_t.h",
-    "codecs/isac/audio_encoder_isac_t_impl.h",
     "codecs/isac/main/interface/audio_encoder_isac.h",
     "codecs/isac/main/interface/isac.h",
     "codecs/isac/main/source/arith_routines.c",
@@ -458,6 +465,7 @@
   deps = [
     ":audio_decoder_interface",
     ":audio_encoder_interface",
+    ":isac_common",
     "../../common_audio",
   ]
 }
@@ -471,8 +479,6 @@
 
 source_set("isac_fix") {
   sources = [
-    "codecs/isac/audio_encoder_isac_t.h",
-    "codecs/isac/audio_encoder_isac_t_impl.h",
     "codecs/isac/fix/interface/audio_encoder_isacfix.h",
     "codecs/isac/fix/interface/isacfix.h",
     "codecs/isac/fix/source/arith_routines.c",
@@ -533,6 +539,7 @@
 
   deps = [
     ":audio_encoder_interface",
+    ":isac_common",
     "../../common_audio",
     "../../system_wrappers",
   ]
diff --git a/webrtc/modules/audio_coding/audio_coding.gypi b/webrtc/modules/audio_coding/audio_coding.gypi
index 90a6f39..bc3c48d 100644
--- a/webrtc/modules/audio_coding/audio_coding.gypi
+++ b/webrtc/modules/audio_coding/audio_coding.gypi
@@ -15,6 +15,7 @@
     'codecs/g722/g722.gypi',
     'codecs/ilbc/ilbc.gypi',
     'codecs/isac/isac.gypi',
+    'codecs/isac/isac_common.gypi',
     'codecs/isac/isacfix.gypi',
     'codecs/pcm16b/pcm16b.gypi',
     'codecs/red/red.gypi',
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 49df3c6..7093304 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
@@ -13,17 +13,14 @@
 
 #include <vector>
 
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/base/thread_annotations.h"
 #include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
+#include "webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
 
 namespace webrtc {
 
-class CriticalSectionWrapper;
-
 template <typename T>
-class AudioEncoderDecoderIsacT : public AudioEncoder, public AudioDecoder {
+class AudioEncoderIsacT final : public AudioEncoder {
  public:
   // Allowed combinations of sample rate, frame size, and bit rate are
   //  - 16000 Hz, 30 ms, 10000-32000 bps
@@ -34,6 +31,8 @@
     Config();
     bool IsOk() const;
 
+    LockedIsacBandwidthInfo* bwinfo;
+
     int payload_type;
     int sample_rate_hz;
     int frame_size_ms;
@@ -50,18 +49,50 @@
     bool enforce_frame_size;
   };
 
-  explicit AudioEncoderDecoderIsacT(const Config& config);
-  ~AudioEncoderDecoderIsacT() override;
+  explicit AudioEncoderIsacT(const Config& config);
+  ~AudioEncoderIsacT() override;
 
-  // AudioEncoder public methods.
   int SampleRateHz() const override;
   int NumChannels() const override;
   size_t MaxEncodedBytes() const override;
   int Num10MsFramesInNextPacket() const override;
   int Max10MsFramesInAPacket() const override;
   int GetTargetBitrate() const override;
+  EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
+                             const int16_t* audio,
+                             size_t max_encoded_bytes,
+                             uint8_t* encoded) override;
 
-  // AudioDecoder methods.
+ 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_;
+
+  // Have we accepted input but not yet emitted it in a packet?
+  bool packet_in_progress_;
+
+  // Timestamp of the first input of the currently in-progress packet.
+  uint32_t packet_timestamp_;
+
+  // Timestamp of the previously encoded packet.
+  uint32_t last_encoded_timestamp_;
+
+  const int target_bitrate_bps_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioEncoderIsacT);
+};
+
+template <typename T>
+class AudioDecoderIsacT final : public AudioDecoder {
+ public:
+  AudioDecoderIsacT();
+  explicit AudioDecoderIsacT(LockedIsacBandwidthInfo* bwinfo);
+  ~AudioDecoderIsacT() override;
+
   bool HasDecodePlc() const override;
   int DecodePlc(int num_frames, int16_t* decoded) override;
   int Init() override;
@@ -71,15 +102,7 @@
                      uint32_t rtp_timestamp,
                      uint32_t arrival_timestamp) override;
   int ErrorCode() override;
-  size_t Channels() const override { return 1; }
-
-  // AudioEncoder protected method.
-  EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
-                             const int16_t* audio,
-                             size_t max_encoded_bytes,
-                             uint8_t* encoded) override;
-
-  // AudioDecoder protected method.
+  size_t Channels() const override;
   int DecodeInternal(const uint8_t* encoded,
                      size_t encoded_len,
                      int sample_rate_hz,
@@ -87,44 +110,11 @@
                      SpeechType* speech_type) 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;
+  typename T::instance_type* isac_state_;
+  LockedIsacBandwidthInfo* bwinfo_;
+  int decoder_sample_rate_hz_;
 
-  const int payload_type_;
-
-  // iSAC encoder/decoder state, guarded by a mutex to ensure that encode calls
-  // from one thread won't clash with decode calls from another thread.
-  // Note: PT_GUARDED_BY is disabled since it is not yet supported by clang.
-  const rtc::scoped_ptr<CriticalSectionWrapper> state_lock_;
-  typename T::instance_type* isac_state_
-      GUARDED_BY(state_lock_) /* PT_GUARDED_BY(lock_)*/;
-
-  int decoder_sample_rate_hz_ GUARDED_BY(state_lock_);
-
-  // Must be acquired before state_lock_.
-  const rtc::scoped_ptr<CriticalSectionWrapper> lock_;
-
-  // Have we accepted input but not yet emitted it in a packet?
-  bool packet_in_progress_ GUARDED_BY(lock_);
-
-  // Timestamp of the first input of the currently in-progress packet.
-  uint32_t packet_timestamp_ GUARDED_BY(lock_);
-
-  // Timestamp of the previously encoded packet.
-  uint32_t last_encoded_timestamp_ GUARDED_BY(lock_);
-
-  const int target_bitrate_bps_;
-
-  DISALLOW_COPY_AND_ASSIGN(AudioEncoderDecoderIsacT);
-};
-
-struct CodecInst;
-
-class AudioEncoderDecoderMutableIsac : public AudioEncoderMutable,
-                                       public AudioDecoder {
- public:
-  virtual void UpdateSettings(const CodecInst& codec_inst) = 0;
+  DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacT);
 };
 
 }  // namespace webrtc
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 d2b20e3..ce70db4 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
@@ -17,7 +17,6 @@
 
 #include "webrtc/base/checks.h"
 #include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h"
-#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 
 namespace webrtc {
 
@@ -25,8 +24,9 @@
 const int kDefaultBitRate = 32000;
 
 template <typename T>
-AudioEncoderDecoderIsacT<T>::Config::Config()
-    : payload_type(kIsacPayloadType),
+AudioEncoderIsacT<T>::Config::Config()
+    : bwinfo(nullptr),
+      payload_type(kIsacPayloadType),
       sample_rate_hz(16000),
       frame_size_ms(30),
       bit_rate(kDefaultBitRate),
@@ -37,11 +37,13 @@
 }
 
 template <typename T>
-bool AudioEncoderDecoderIsacT<T>::Config::IsOk() const {
+bool AudioEncoderIsacT<T>::Config::IsOk() const {
   if (max_bit_rate < 32000 && max_bit_rate != -1)
     return false;
   if (max_payload_size_bytes < 120 && max_payload_size_bytes != -1)
     return false;
+  if (adaptive_mode && !bwinfo)
+    return false;
   switch (sample_rate_hz) {
     case 16000:
       if (max_bit_rate > 53400)
@@ -65,11 +67,9 @@
 }
 
 template <typename T>
-AudioEncoderDecoderIsacT<T>::AudioEncoderDecoderIsacT(const Config& config)
+AudioEncoderIsacT<T>::AudioEncoderIsacT(const Config& config)
     : payload_type_(config.payload_type),
-      state_lock_(CriticalSectionWrapper::CreateCriticalSection()),
-      decoder_sample_rate_hz_(0),
-      lock_(CriticalSectionWrapper::CreateCriticalSection()),
+      bwinfo_(config.bwinfo),
       packet_in_progress_(false),
       target_bitrate_bps_(config.adaptive_mode ? -1 : (config.bit_rate == 0
                                                            ? kDefaultBitRate
@@ -85,80 +85,82 @@
   } else {
     CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms));
   }
-  // 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.
-  CHECK_EQ(0, T::SetDecSampRate(isac_state_,
-                                std::min(config.sample_rate_hz, 32000)));
   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));
-  CHECK_EQ(0, T::DecoderInit(isac_state_));
+
+  // 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));
 }
 
 template <typename T>
-AudioEncoderDecoderIsacT<T>::~AudioEncoderDecoderIsacT() {
+AudioEncoderIsacT<T>::~AudioEncoderIsacT() {
   CHECK_EQ(0, T::Free(isac_state_));
 }
 
 template <typename T>
-int AudioEncoderDecoderIsacT<T>::SampleRateHz() const {
-  CriticalSectionScoped cs(state_lock_.get());
+int AudioEncoderIsacT<T>::SampleRateHz() const {
   return T::EncSampRate(isac_state_);
 }
 
 template <typename T>
-int AudioEncoderDecoderIsacT<T>::NumChannels() const {
+int AudioEncoderIsacT<T>::NumChannels() const {
   return 1;
 }
 
 template <typename T>
-size_t AudioEncoderDecoderIsacT<T>::MaxEncodedBytes() const {
+size_t AudioEncoderIsacT<T>::MaxEncodedBytes() const {
   return kSufficientEncodeBufferSizeBytes;
 }
 
 template <typename T>
-int AudioEncoderDecoderIsacT<T>::Num10MsFramesInNextPacket() const {
-  CriticalSectionScoped cs(state_lock_.get());
+int AudioEncoderIsacT<T>::Num10MsFramesInNextPacket() const {
   const int samples_in_next_packet = T::GetNewFrameLen(isac_state_);
   return rtc::CheckedDivExact(samples_in_next_packet,
                               rtc::CheckedDivExact(SampleRateHz(), 100));
 }
 
 template <typename T>
-int AudioEncoderDecoderIsacT<T>::Max10MsFramesInAPacket() const {
+int AudioEncoderIsacT<T>::Max10MsFramesInAPacket() const {
   return 6;  // iSAC puts at most 60 ms in a packet.
 }
 
 template <typename T>
-int AudioEncoderDecoderIsacT<T>::GetTargetBitrate() const {
+int AudioEncoderIsacT<T>::GetTargetBitrate() const {
   return target_bitrate_bps_;
 }
 
 template <typename T>
-AudioEncoder::EncodedInfo AudioEncoderDecoderIsacT<T>::EncodeInternal(
+AudioEncoder::EncodedInfo AudioEncoderIsacT<T>::EncodeInternal(
     uint32_t rtp_timestamp,
     const int16_t* audio,
     size_t max_encoded_bytes,
     uint8_t* encoded) {
-  CriticalSectionScoped cs_lock(lock_.get());
   if (!packet_in_progress_) {
     // Starting a new packet; remember the timestamp for later.
     packet_in_progress_ = true;
     packet_timestamp_ = rtp_timestamp;
   }
-  int r;
-  {
-    CriticalSectionScoped cs(state_lock_.get());
-    r = T::Encode(isac_state_, audio, encoded);
-    CHECK_GE(r, 0) << "Encode failed (error code "
-                   << T::GetErrorCode(isac_state_) << ")";
+  if (bwinfo_) {
+    IsacBandwidthInfo bwinfo = bwinfo_->Get();
+    T::SetBandwidthInfo(isac_state_, &bwinfo);
   }
+  int r = T::Encode(isac_state_, audio, encoded);
+  CHECK_GE(r, 0) << "Encode failed (error code " << T::GetErrorCode(isac_state_)
+                 << ")";
 
   // T::Encode doesn't allow us to tell it the size of the output
   // buffer. All we can do is check for an overrun after the fact.
-  CHECK(static_cast<size_t>(r) <= max_encoded_bytes);
+  CHECK_LE(static_cast<size_t>(r), max_encoded_bytes);
 
   if (r == 0)
     return EncodedInfo();
@@ -174,12 +176,33 @@
 }
 
 template <typename T>
-int AudioEncoderDecoderIsacT<T>::DecodeInternal(const uint8_t* encoded,
-                                                size_t encoded_len,
-                                                int sample_rate_hz,
-                                                int16_t* decoded,
-                                                SpeechType* speech_type) {
-  CriticalSectionScoped cs(state_lock_.get());
+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_));
+  CHECK_EQ(0, T::DecoderInit(isac_state_));
+  if (bwinfo_) {
+    IsacBandwidthInfo bwinfo;
+    T::GetBandwidthInfo(isac_state_, &bwinfo);
+    bwinfo_->Set(bwinfo);
+  }
+}
+
+template <typename T>
+AudioDecoderIsacT<T>::~AudioDecoderIsacT() {
+  CHECK_EQ(0, T::Free(isac_state_));
+}
+
+template <typename T>
+int AudioDecoderIsacT<T>::DecodeInternal(const uint8_t* encoded,
+                                         size_t encoded_len,
+                                         int sample_rate_hz,
+                                         int16_t* decoded,
+                                         SpeechType* speech_type) {
   // We want to crate the illusion that iSAC supports 48000 Hz decoding, while
   // in fact it outputs 32000 Hz. This is the iSAC fullband mode.
   if (sample_rate_hz == 48000)
@@ -199,40 +222,47 @@
 }
 
 template <typename T>
-bool AudioEncoderDecoderIsacT<T>::HasDecodePlc() const {
+bool AudioDecoderIsacT<T>::HasDecodePlc() const {
   return false;
 }
 
 template <typename T>
-int AudioEncoderDecoderIsacT<T>::DecodePlc(int num_frames, int16_t* decoded) {
-  CriticalSectionScoped cs(state_lock_.get());
+int AudioDecoderIsacT<T>::DecodePlc(int num_frames, int16_t* decoded) {
   return T::DecodePlc(isac_state_, decoded, num_frames);
 }
 
 template <typename T>
-int AudioEncoderDecoderIsacT<T>::Init() {
-  CriticalSectionScoped cs(state_lock_.get());
+int AudioDecoderIsacT<T>::Init() {
   return T::DecoderInit(isac_state_);
 }
 
 template <typename T>
-int AudioEncoderDecoderIsacT<T>::IncomingPacket(const uint8_t* payload,
-                                                size_t payload_len,
-                                                uint16_t rtp_sequence_number,
-                                                uint32_t rtp_timestamp,
-                                                uint32_t arrival_timestamp) {
-  CriticalSectionScoped cs(state_lock_.get());
-  return T::UpdateBwEstimate(
+int AudioDecoderIsacT<T>::IncomingPacket(const uint8_t* payload,
+                                         size_t payload_len,
+                                         uint16_t rtp_sequence_number,
+                                         uint32_t rtp_timestamp,
+                                         uint32_t arrival_timestamp) {
+  int ret = T::UpdateBwEstimate(
       isac_state_, payload, static_cast<int32_t>(payload_len),
       rtp_sequence_number, rtp_timestamp, arrival_timestamp);
+  if (bwinfo_) {
+    IsacBandwidthInfo bwinfo;
+    T::GetBandwidthInfo(isac_state_, &bwinfo);
+    bwinfo_->Set(bwinfo);
+  }
+  return ret;
 }
 
 template <typename T>
-int AudioEncoderDecoderIsacT<T>::ErrorCode() {
-  CriticalSectionScoped cs(state_lock_.get());
+int AudioDecoderIsacT<T>::ErrorCode() {
   return T::GetErrorCode(isac_state_);
 }
 
+template <typename T>
+size_t AudioDecoderIsacT<T>::Channels() const {
+  return 1;
+}
+
 }  // namespace webrtc
 
 #endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
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 02b5d3c..9d51161 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
@@ -120,46 +120,18 @@
   }
 };
 
-typedef AudioEncoderDecoderIsacT<IsacFix> AudioEncoderDecoderIsacFix;
+using AudioEncoderIsacFix = AudioEncoderIsacT<IsacFix>;
+using AudioDecoderIsacFix = AudioDecoderIsacT<IsacFix>;
 
 struct CodecInst;
 
-class AudioEncoderDecoderMutableIsacFix
-    : public AudioEncoderMutableImpl<AudioEncoderDecoderIsacFix,
-                                     AudioEncoderDecoderMutableIsac> {
+class AudioEncoderMutableIsacFix
+    : public AudioEncoderMutableImpl<AudioEncoderIsacFix> {
  public:
-  explicit AudioEncoderDecoderMutableIsacFix(const CodecInst& codec_inst);
-  void UpdateSettings(const CodecInst& codec_inst) override;
+  explicit AudioEncoderMutableIsacFix(const CodecInst& codec_inst,
+                                      LockedIsacBandwidthInfo* bwinfo);
   void SetMaxPayloadSize(int max_payload_size_bytes) override;
   void SetMaxRate(int max_rate_bps) override;
-
-  // From AudioDecoder.
-  int Decode(const uint8_t* encoded,
-             size_t encoded_len,
-             int sample_rate_hz,
-             size_t max_decoded_bytes,
-             int16_t* decoded,
-             SpeechType* speech_type) override;
-  int DecodeRedundant(const uint8_t* encoded,
-                      size_t encoded_len,
-                      int sample_rate_hz,
-                      size_t max_decoded_bytes,
-                      int16_t* decoded,
-                      SpeechType* speech_type) override;
-  bool HasDecodePlc() const override;
-  int DecodePlc(int num_frames, int16_t* decoded) override;
-  int Init() override;
-  int IncomingPacket(const uint8_t* payload,
-                     size_t payload_len,
-                     uint16_t rtp_sequence_number,
-                     uint32_t rtp_timestamp,
-                     uint32_t arrival_timestamp) override;
-  int ErrorCode() override;
-  int PacketDuration(const uint8_t* encoded, size_t encoded_len) const override;
-  int PacketDurationRedundant(const uint8_t* encoded,
-                              size_t encoded_len) const override;
-  bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const override;
-  size_t Channels() const override;
 };
 
 }  // namespace webrtc
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 c7999b5..2f8d4b6 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
@@ -17,13 +17,15 @@
 
 const uint16_t IsacFix::kFixSampleRate;
 
-// Explicit instantiation of AudioEncoderDecoderIsacT<IsacFix>, a.k.a.
-// AudioEncoderDecoderIsacFix.
-template class AudioEncoderDecoderIsacT<IsacFix>;
+// Explicit instantiation:
+template class AudioEncoderIsacT<IsacFix>;
+template class AudioDecoderIsacT<IsacFix>;
 
 namespace {
-AudioEncoderDecoderIsacFix::Config CreateConfig(const CodecInst& codec_inst) {
-  AudioEncoderDecoderIsacFix::Config config;
+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 =
@@ -35,110 +37,22 @@
 }
 }  // namespace
 
-AudioEncoderDecoderMutableIsacFix::AudioEncoderDecoderMutableIsacFix(
-    const CodecInst& codec_inst)
-    : AudioEncoderMutableImpl<AudioEncoderDecoderIsacFix,
-                              AudioEncoderDecoderMutableIsac>(
-          CreateConfig(codec_inst)) {
-}
+AudioEncoderMutableIsacFix::AudioEncoderMutableIsacFix(
+    const CodecInst& codec_inst,
+    LockedIsacBandwidthInfo* bwinfo)
+    : AudioEncoderMutableImpl<AudioEncoderIsacFix>(
+          CreateConfig(codec_inst, bwinfo)) {}
 
-void AudioEncoderDecoderMutableIsacFix::UpdateSettings(
-    const CodecInst& codec_inst) {
-  bool success = Reconstruct(CreateConfig(codec_inst));
-  DCHECK(success);
-}
-
-void AudioEncoderDecoderMutableIsacFix::SetMaxPayloadSize(
-    int max_payload_size_bytes) {
+void AudioEncoderMutableIsacFix::SetMaxPayloadSize(int max_payload_size_bytes) {
   auto conf = config();
   conf.max_payload_size_bytes = max_payload_size_bytes;
   Reconstruct(conf);
 }
 
-void AudioEncoderDecoderMutableIsacFix::SetMaxRate(int max_rate_bps) {
+void AudioEncoderMutableIsacFix::SetMaxRate(int max_rate_bps) {
   auto conf = config();
   conf.max_bit_rate = max_rate_bps;
   Reconstruct(conf);
 }
 
-int AudioEncoderDecoderMutableIsacFix::Decode(const uint8_t* encoded,
-                                              size_t encoded_len,
-                                              int sample_rate_hz,
-                                              size_t max_decoded_bytes,
-                                              int16_t* decoded,
-                                              SpeechType* speech_type) {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->Decode(encoded, encoded_len, sample_rate_hz,
-                           max_decoded_bytes, decoded, speech_type);
-}
-
-int AudioEncoderDecoderMutableIsacFix::DecodeRedundant(
-    const uint8_t* encoded,
-    size_t encoded_len,
-    int sample_rate_hz,
-    size_t max_decoded_bytes,
-    int16_t* decoded,
-    SpeechType* speech_type) {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->DecodeRedundant(encoded, encoded_len, sample_rate_hz,
-                                    max_decoded_bytes, decoded, speech_type);
-}
-
-bool AudioEncoderDecoderMutableIsacFix::HasDecodePlc() const {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->HasDecodePlc();
-}
-
-int AudioEncoderDecoderMutableIsacFix::DecodePlc(int num_frames,
-                                                 int16_t* decoded) {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->DecodePlc(num_frames, decoded);
-}
-
-int AudioEncoderDecoderMutableIsacFix::Init() {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->Init();
-}
-
-int AudioEncoderDecoderMutableIsacFix::IncomingPacket(
-    const uint8_t* payload,
-    size_t payload_len,
-    uint16_t rtp_sequence_number,
-    uint32_t rtp_timestamp,
-    uint32_t arrival_timestamp) {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->IncomingPacket(payload, payload_len, rtp_sequence_number,
-                                   rtp_timestamp, arrival_timestamp);
-}
-
-int AudioEncoderDecoderMutableIsacFix::ErrorCode() {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->ErrorCode();
-}
-
-int AudioEncoderDecoderMutableIsacFix::PacketDuration(
-    const uint8_t* encoded,
-    size_t encoded_len) const {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->PacketDuration(encoded, encoded_len);
-}
-
-int AudioEncoderDecoderMutableIsacFix::PacketDurationRedundant(
-    const uint8_t* encoded,
-    size_t encoded_len) const {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->PacketDurationRedundant(encoded, encoded_len);
-}
-
-bool AudioEncoderDecoderMutableIsacFix::PacketHasFec(const uint8_t* encoded,
-                                                     size_t encoded_len) const {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->PacketHasFec(encoded, encoded_len);
-}
-
-size_t AudioEncoderDecoderMutableIsacFix::Channels() const {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->Channels();
-}
-
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/isac/fix/source/isacfix.c b/webrtc/modules/audio_coding/codecs/isac/fix/source/isacfix.c
index ba055eb..9b61d60 100644
--- a/webrtc/modules/audio_coding/codecs/isac/fix/source/isacfix.c
+++ b/webrtc/modules/audio_coding/codecs/isac/fix/source/isacfix.c
@@ -241,6 +241,31 @@
 }
 #endif
 
+static void InitFunctionPointers(void) {
+  WebRtcIsacfix_AutocorrFix = WebRtcIsacfix_AutocorrC;
+  WebRtcIsacfix_FilterMaLoopFix = WebRtcIsacfix_FilterMaLoopC;
+  WebRtcIsacfix_CalculateResidualEnergy =
+      WebRtcIsacfix_CalculateResidualEnergyC;
+  WebRtcIsacfix_AllpassFilter2FixDec16 = WebRtcIsacfix_AllpassFilter2FixDec16C;
+  WebRtcIsacfix_HighpassFilterFixDec32 = WebRtcIsacfix_HighpassFilterFixDec32C;
+  WebRtcIsacfix_Time2Spec = WebRtcIsacfix_Time2SpecC;
+  WebRtcIsacfix_Spec2Time = WebRtcIsacfix_Spec2TimeC;
+  WebRtcIsacfix_MatrixProduct1 = WebRtcIsacfix_MatrixProduct1C;
+  WebRtcIsacfix_MatrixProduct2 = WebRtcIsacfix_MatrixProduct2C;
+
+#ifdef WEBRTC_DETECT_NEON
+  if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
+    WebRtcIsacfix_InitNeon();
+  }
+#elif defined(WEBRTC_HAS_NEON)
+  WebRtcIsacfix_InitNeon();
+#endif
+
+#if defined(MIPS32_LE)
+  WebRtcIsacfix_InitMIPS();
+#endif
+}
+
 /****************************************************************************
  * WebRtcIsacfix_EncoderInit(...)
  *
@@ -317,29 +342,7 @@
   WebRtcIsacfix_InitPostFilterbank(&ISAC_inst->ISACenc_obj.interpolatorstr_obj);
 #endif
 
-  // Initiaze function pointers.
-  WebRtcIsacfix_AutocorrFix = WebRtcIsacfix_AutocorrC;
-  WebRtcIsacfix_FilterMaLoopFix = WebRtcIsacfix_FilterMaLoopC;
-  WebRtcIsacfix_CalculateResidualEnergy =
-      WebRtcIsacfix_CalculateResidualEnergyC;
-  WebRtcIsacfix_AllpassFilter2FixDec16 = WebRtcIsacfix_AllpassFilter2FixDec16C;
-  WebRtcIsacfix_HighpassFilterFixDec32 = WebRtcIsacfix_HighpassFilterFixDec32C;
-  WebRtcIsacfix_Time2Spec = WebRtcIsacfix_Time2SpecC;
-  WebRtcIsacfix_Spec2Time = WebRtcIsacfix_Spec2TimeC;
-  WebRtcIsacfix_MatrixProduct1 = WebRtcIsacfix_MatrixProduct1C;
-  WebRtcIsacfix_MatrixProduct2 = WebRtcIsacfix_MatrixProduct2C;
-
-#ifdef WEBRTC_DETECT_NEON
-  if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
-    WebRtcIsacfix_InitNeon();
-  }
-#elif defined(WEBRTC_HAS_NEON)
-  WebRtcIsacfix_InitNeon();
-#endif
-
-#if defined(MIPS32_LE)
-  WebRtcIsacfix_InitMIPS();
-#endif
+  InitFunctionPointers();
 
   return statusInit;
 }
@@ -575,6 +578,8 @@
 {
   ISACFIX_SubStruct *ISAC_inst;
 
+  InitFunctionPointers();
+
   /* typecast pointer to real structure */
   ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst;
 
diff --git a/webrtc/modules/audio_coding/codecs/isac/isac.gypi b/webrtc/modules/audio_coding/codecs/isac/isac.gypi
index 50cc867..8ecc2dc 100644
--- a/webrtc/modules/audio_coding/codecs/isac/isac.gypi
+++ b/webrtc/modules/audio_coding/codecs/isac/isac.gypi
@@ -15,6 +15,7 @@
         '<(webrtc_root)/common_audio/common_audio.gyp:common_audio',
         'audio_decoder_interface',
         'audio_encoder_interface',
+        'isac_common',
       ],
       'include_dirs': [
         'main/interface',
@@ -27,8 +28,6 @@
         ],
       },
       'sources': [
-        'audio_encoder_isac_t.h',
-        'audio_encoder_isac_t_impl.h',
         'main/interface/audio_encoder_isac.h',
         'main/interface/isac.h',
         'main/source/arith_routines.c',
diff --git a/webrtc/modules/audio_coding/codecs/isac/isac_common.gypi b/webrtc/modules/audio_coding/codecs/isac/isac_common.gypi
new file mode 100644
index 0000000..135ecd2
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/isac_common.gypi
@@ -0,0 +1,22 @@
+# 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.
+
+{
+  'targets': [
+    {
+      'target_name': 'isac_common',
+      'type': 'static_library',
+      'sources': [
+        'audio_encoder_isac_t.h',
+        'audio_encoder_isac_t_impl.h',
+        'locked_bandwidth_info.cc',
+        'locked_bandwidth_info.h',
+      ],
+    },
+  ],
+}
diff --git a/webrtc/modules/audio_coding/codecs/isac/isacfix.gypi b/webrtc/modules/audio_coding/codecs/isac/isacfix.gypi
index e20177c..81b4375 100644
--- a/webrtc/modules/audio_coding/codecs/isac/isacfix.gypi
+++ b/webrtc/modules/audio_coding/codecs/isac/isacfix.gypi
@@ -14,6 +14,7 @@
       'dependencies': [
         '<(webrtc_root)/common_audio/common_audio.gyp:common_audio',
         '<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
+        'isac_common',
       ],
       'include_dirs': [
         'fix/interface',
@@ -26,8 +27,6 @@
         ],
       },
       'sources': [
-        'audio_encoder_isac_t.h',
-        'audio_encoder_isac_t_impl.h',
         'fix/interface/audio_encoder_isacfix.h',
         'fix/interface/isacfix.h',
         'fix/source/arith_routines.c',
diff --git a/webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.cc b/webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.cc
new file mode 100644
index 0000000..78b415c
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.cc
@@ -0,0 +1,22 @@
+/*
+ *  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.
+ */
+
+#include "webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
+
+namespace webrtc {
+
+LockedIsacBandwidthInfo::LockedIsacBandwidthInfo()
+      : lock_(CriticalSectionWrapper::CreateCriticalSection()) {
+  bwinfo_.in_use = 0;
+}
+
+LockedIsacBandwidthInfo::~LockedIsacBandwidthInfo() = default;
+
+}  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h b/webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h
new file mode 100644
index 0000000..bf39003
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h
@@ -0,0 +1,45 @@
+/*
+ *  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_ISAC_LOCKED_BANDWIDTH_INFO_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_LOCKED_BANDWIDTH_INFO_H_
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/thread_annotations.h"
+#include "webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h"
+#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
+
+namespace webrtc {
+
+// An IsacBandwidthInfo that's safe to access from multiple threads because
+// it's protected by a mutex.
+class LockedIsacBandwidthInfo final {
+ public:
+  LockedIsacBandwidthInfo();
+  ~LockedIsacBandwidthInfo();
+
+  IsacBandwidthInfo Get() const {
+    CriticalSectionScoped cs(lock_.get());
+    return bwinfo_;
+  }
+
+  void Set(const IsacBandwidthInfo& bwinfo) {
+    CriticalSectionScoped cs(lock_.get());
+    bwinfo_ = bwinfo;
+  }
+
+ private:
+  const rtc::scoped_ptr<CriticalSectionWrapper> lock_;
+  IsacBandwidthInfo bwinfo_ GUARDED_BY(lock_);
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_LOCKED_BANDWIDTH_INFO_H_
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 2799892..c0f3b11 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
@@ -118,46 +118,18 @@
   }
 };
 
-typedef AudioEncoderDecoderIsacT<IsacFloat> AudioEncoderDecoderIsac;
+using AudioEncoderIsac = AudioEncoderIsacT<IsacFloat>;
+using AudioDecoderIsac = AudioDecoderIsacT<IsacFloat>;
 
 struct CodecInst;
 
-class AudioEncoderDecoderMutableIsacFloat
-    : public AudioEncoderMutableImpl<AudioEncoderDecoderIsac,
-                                     AudioEncoderDecoderMutableIsac> {
+class AudioEncoderMutableIsacFloat
+    : public AudioEncoderMutableImpl<AudioEncoderIsac> {
  public:
-  explicit AudioEncoderDecoderMutableIsacFloat(const CodecInst& codec_inst);
-  void UpdateSettings(const CodecInst& codec_inst) override;
+  AudioEncoderMutableIsacFloat(const CodecInst& codec_inst,
+                               LockedIsacBandwidthInfo* bwinfo);
   void SetMaxPayloadSize(int max_payload_size_bytes) override;
   void SetMaxRate(int max_rate_bps) override;
-
-  // From AudioDecoder.
-  int Decode(const uint8_t* encoded,
-             size_t encoded_len,
-             int sample_rate_hz,
-             size_t max_decoded_bytes,
-             int16_t* decoded,
-             SpeechType* speech_type) override;
-  int DecodeRedundant(const uint8_t* encoded,
-                      size_t encoded_len,
-                      int sample_rate_hz,
-                      size_t max_decoded_bytes,
-                      int16_t* decoded,
-                      SpeechType* speech_type) override;
-  bool HasDecodePlc() const override;
-  int DecodePlc(int num_frames, int16_t* decoded) override;
-  int Init() override;
-  int IncomingPacket(const uint8_t* payload,
-                     size_t payload_len,
-                     uint16_t rtp_sequence_number,
-                     uint32_t rtp_timestamp,
-                     uint32_t arrival_timestamp) override;
-  int ErrorCode() override;
-  int PacketDuration(const uint8_t* encoded, size_t encoded_len) const override;
-  int PacketDurationRedundant(const uint8_t* encoded,
-                              size_t encoded_len) const override;
-  bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const override;
-  size_t Channels() const override;
 };
 
 }  // namespace webrtc
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 201a2d4..195265d 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
@@ -15,13 +15,15 @@
 
 namespace webrtc {
 
-// Explicit instantiation of AudioEncoderDecoderIsacT<IsacFloat>, a.k.a.
-// AudioEncoderDecoderIsac.
-template class AudioEncoderDecoderIsacT<IsacFloat>;
+// Explicit instantiation:
+template class AudioEncoderIsacT<IsacFloat>;
+template class AudioDecoderIsacT<IsacFloat>;
 
 namespace {
-AudioEncoderDecoderIsac::Config CreateConfig(const CodecInst& codec_inst) {
-  AudioEncoderDecoderIsac::Config config;
+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 =
@@ -33,111 +35,24 @@
 }
 }  // namespace
 
-AudioEncoderDecoderMutableIsacFloat::AudioEncoderDecoderMutableIsacFloat(
-    const CodecInst& codec_inst)
-    : AudioEncoderMutableImpl<AudioEncoderDecoderIsac,
-                              AudioEncoderDecoderMutableIsac>(
-          CreateConfig(codec_inst)) {
+AudioEncoderMutableIsacFloat::AudioEncoderMutableIsacFloat(
+    const CodecInst& codec_inst,
+    LockedIsacBandwidthInfo* bwinfo)
+    : AudioEncoderMutableImpl<AudioEncoderIsac>(
+          CreateConfig(codec_inst, bwinfo)) {
 }
 
-void AudioEncoderDecoderMutableIsacFloat::UpdateSettings(
-    const CodecInst& codec_inst) {
-  bool success = Reconstruct(CreateConfig(codec_inst));
-  DCHECK(success);
-}
-
-void AudioEncoderDecoderMutableIsacFloat::SetMaxPayloadSize(
+void AudioEncoderMutableIsacFloat::SetMaxPayloadSize(
     int max_payload_size_bytes) {
   auto conf = config();
   conf.max_payload_size_bytes = max_payload_size_bytes;
   Reconstruct(conf);
 }
 
-void AudioEncoderDecoderMutableIsacFloat::SetMaxRate(int max_rate_bps) {
+void AudioEncoderMutableIsacFloat::SetMaxRate(int max_rate_bps) {
   auto conf = config();
   conf.max_bit_rate = max_rate_bps;
   Reconstruct(conf);
 }
 
-int AudioEncoderDecoderMutableIsacFloat::Decode(const uint8_t* encoded,
-                                                size_t encoded_len,
-                                                int sample_rate_hz,
-                                                size_t max_decoded_bytes,
-                                                int16_t* decoded,
-                                                SpeechType* speech_type) {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->Decode(encoded, encoded_len, sample_rate_hz,
-                           max_decoded_bytes, decoded, speech_type);
-}
-
-int AudioEncoderDecoderMutableIsacFloat::DecodeRedundant(
-    const uint8_t* encoded,
-    size_t encoded_len,
-    int sample_rate_hz,
-    size_t max_decoded_bytes,
-    int16_t* decoded,
-    SpeechType* speech_type) {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->DecodeRedundant(encoded, encoded_len, sample_rate_hz,
-                                    max_decoded_bytes, decoded, speech_type);
-}
-
-bool AudioEncoderDecoderMutableIsacFloat::HasDecodePlc() const {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->HasDecodePlc();
-}
-
-int AudioEncoderDecoderMutableIsacFloat::DecodePlc(int num_frames,
-                                                   int16_t* decoded) {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->DecodePlc(num_frames, decoded);
-}
-
-int AudioEncoderDecoderMutableIsacFloat::Init() {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->Init();
-}
-
-int AudioEncoderDecoderMutableIsacFloat::IncomingPacket(
-    const uint8_t* payload,
-    size_t payload_len,
-    uint16_t rtp_sequence_number,
-    uint32_t rtp_timestamp,
-    uint32_t arrival_timestamp) {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->IncomingPacket(payload, payload_len, rtp_sequence_number,
-                                   rtp_timestamp, arrival_timestamp);
-}
-
-int AudioEncoderDecoderMutableIsacFloat::ErrorCode() {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->ErrorCode();
-}
-
-int AudioEncoderDecoderMutableIsacFloat::PacketDuration(
-    const uint8_t* encoded,
-    size_t encoded_len) const {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->PacketDuration(encoded, encoded_len);
-}
-
-int AudioEncoderDecoderMutableIsacFloat::PacketDurationRedundant(
-    const uint8_t* encoded,
-    size_t encoded_len) const {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->PacketDurationRedundant(encoded, encoded_len);
-}
-
-bool AudioEncoderDecoderMutableIsacFloat::PacketHasFec(
-    const uint8_t* encoded,
-    size_t encoded_len) const {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->PacketHasFec(encoded, encoded_len);
-}
-
-size_t AudioEncoderDecoderMutableIsacFloat::Channels() const {
-  CriticalSectionScoped cs(encoder_lock_.get());
-  return encoder()->Channels();
-}
-
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc
index ee5c031..ff941ea 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc
@@ -17,13 +17,13 @@
 
 namespace {
 
-void TestBadConfig(const AudioEncoderDecoderIsac::Config& config) {
+void TestBadConfig(const AudioEncoderIsac::Config& config) {
   EXPECT_FALSE(config.IsOk());
 }
 
-void TestGoodConfig(const AudioEncoderDecoderIsac::Config& config) {
+void TestGoodConfig(const AudioEncoderIsac::Config& config) {
   EXPECT_TRUE(config.IsOk());
-  AudioEncoderDecoderIsac ed(config);
+  AudioEncoderIsac aei(config);
 }
 
 // Wrap subroutine calls that test things in this, so that the error messages
@@ -34,7 +34,7 @@
 }  // namespace
 
 TEST(AudioEncoderIsacTest, TestConfigBitrate) {
-  AudioEncoderDecoderIsac::Config config;
+  AudioEncoderIsac::Config config;
 
   // The default value is some real, positive value.
   EXPECT_GT(config.bit_rate, 1);
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 568ae1e..71c436b 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
@@ -721,9 +721,9 @@
         receive_packet_count_(0),
         next_insert_packet_time_ms_(0),
         fake_clock_(new SimulatedClock(0)) {
-    AudioEncoderDecoderIsac::Config config;
+    AudioEncoderIsac::Config config;
     config.payload_type = kPayloadType;
-    isac_encoder_.reset(new AudioEncoderDecoderIsac(config));
+    isac_encoder_.reset(new AudioEncoderIsac(config));
     clock_ = fake_clock_.get();
   }
 
@@ -845,7 +845,7 @@
   bool codec_registered_ GUARDED_BY(crit_sect_);
   int receive_packet_count_ GUARDED_BY(crit_sect_);
   int64_t next_insert_packet_time_ms_ GUARDED_BY(crit_sect_);
-  rtc::scoped_ptr<AudioEncoderDecoderIsac> isac_encoder_;
+  rtc::scoped_ptr<AudioEncoderIsac> isac_encoder_;
   rtc::scoped_ptr<SimulatedClock> fake_clock_;
   test::AudioLoop audio_loop_;
 };
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_owner.cc b/webrtc/modules/audio_coding/main/acm2/codec_owner.cc
index 4d214be..ed23e10 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_owner.cc
+++ b/webrtc/modules/audio_coding/main/acm2/codec_owner.cc
@@ -75,55 +75,61 @@
 }
 }  // namespace
 
-CodecOwner::CodecOwner()
-    : isac_is_encoder_(false), external_speech_encoder_(nullptr) {
+CodecOwner::CodecOwner() : external_speech_encoder_(nullptr) {
 }
 
 CodecOwner::~CodecOwner() = default;
 
 namespace {
-AudioEncoderDecoderMutableIsac* CreateIsacCodec(const CodecInst& speech_inst) {
+
+rtc::scoped_ptr<AudioDecoder> CreateIsacDecoder(
+    LockedIsacBandwidthInfo* bwinfo) {
 #if defined(WEBRTC_CODEC_ISACFX)
-  return new AudioEncoderDecoderMutableIsacFix(speech_inst);
+  return rtc_make_scoped_ptr(new AudioDecoderIsacFix(bwinfo));
 #elif defined(WEBRTC_CODEC_ISAC)
-  return new AudioEncoderDecoderMutableIsacFloat(speech_inst);
+  return rtc_make_scoped_ptr(new AudioDecoderIsac(bwinfo));
 #else
   FATAL() << "iSAC is not supported.";
-  return nullptr;
+  return rtc::scoped_ptr<AudioDecoder>();
 #endif
 }
 
-void CreateSpeechEncoder(
+rtc::scoped_ptr<AudioEncoderMutable> CreateIsacEncoder(
     const CodecInst& speech_inst,
-    rtc::scoped_ptr<AudioEncoderMutable>* speech_encoder,
-    rtc::scoped_ptr<AudioEncoderDecoderMutableIsac>* isac_codec,
-    bool* isac_is_encoder) {
+    LockedIsacBandwidthInfo* bwinfo) {
+#if defined(WEBRTC_CODEC_ISACFX)
+  return rtc_make_scoped_ptr(
+      new AudioEncoderMutableIsacFix(speech_inst, bwinfo));
+#elif defined(WEBRTC_CODEC_ISAC)
+  return rtc_make_scoped_ptr(
+      new AudioEncoderMutableIsacFloat(speech_inst, bwinfo));
+#else
+  FATAL() << "iSAC is not supported.";
+  return rtc::scoped_ptr<AudioEncoderMutable>();
+#endif
+}
+
+rtc::scoped_ptr<AudioEncoderMutable> CreateSpeechEncoder(
+    const CodecInst& speech_inst,
+    LockedIsacBandwidthInfo* bwinfo) {
   if (IsIsac(speech_inst)) {
-    if (*isac_codec) {
-      (*isac_codec)->UpdateSettings(speech_inst);
-    } else {
-      isac_codec->reset(CreateIsacCodec(speech_inst));
-    }
-    *isac_is_encoder = true;
-    speech_encoder->reset();
-    return;
-  }
-  if (IsOpus(speech_inst)) {
-    speech_encoder->reset(new AudioEncoderMutableOpus(speech_inst));
+    return CreateIsacEncoder(speech_inst, bwinfo);
+  } else if (IsOpus(speech_inst)) {
+    return rtc_make_scoped_ptr(new AudioEncoderMutableOpus(speech_inst));
   } else if (IsPcmU(speech_inst)) {
-    speech_encoder->reset(new AudioEncoderMutablePcmU(speech_inst));
+    return rtc_make_scoped_ptr(new AudioEncoderMutablePcmU(speech_inst));
   } else if (IsPcmA(speech_inst)) {
-    speech_encoder->reset(new AudioEncoderMutablePcmA(speech_inst));
+    return rtc_make_scoped_ptr(new AudioEncoderMutablePcmA(speech_inst));
   } else if (IsPcm16B(speech_inst)) {
-    speech_encoder->reset(new AudioEncoderMutablePcm16B(speech_inst));
+    return rtc_make_scoped_ptr(new AudioEncoderMutablePcm16B(speech_inst));
   } else if (IsIlbc(speech_inst)) {
-    speech_encoder->reset(new AudioEncoderMutableIlbc(speech_inst));
+    return rtc_make_scoped_ptr(new AudioEncoderMutableIlbc(speech_inst));
   } else if (IsG722(speech_inst)) {
-    speech_encoder->reset(new AudioEncoderMutableG722(speech_inst));
+    return rtc_make_scoped_ptr(new AudioEncoderMutableG722(speech_inst));
   } else {
     FATAL();
+    return rtc::scoped_ptr<AudioEncoderMutable>();
   }
-  *isac_is_encoder = false;
 }
 
 AudioEncoder* CreateRedEncoder(int red_payload_type,
@@ -176,8 +182,7 @@
                              int cng_payload_type,
                              ACMVADMode vad_mode,
                              int red_payload_type) {
-  CreateSpeechEncoder(speech_inst, &speech_encoder_, &isac_codec_,
-                      &isac_is_encoder_);
+  speech_encoder_ = CreateSpeechEncoder(speech_inst, &isac_bandwidth_info_);
   external_speech_encoder_ = nullptr;
   ChangeCngAndRed(cng_payload_type, vad_mode, red_payload_type);
 }
@@ -188,7 +193,6 @@
                              int red_payload_type) {
   external_speech_encoder_ = external_speech_encoder;
   speech_encoder_.reset();
-  isac_is_encoder_ = false;
   ChangeCngAndRed(cng_payload_type, vad_mode, red_payload_type);
 }
 
@@ -204,24 +208,13 @@
   AudioEncoder* encoder =
       CreateRedEncoder(red_payload_type, speech_encoder, &red_encoder_);
   CreateCngEncoder(cng_payload_type, vad_mode, encoder, &cng_encoder_);
-  int num_true =
-      !!speech_encoder_ + !!external_speech_encoder_ + isac_is_encoder_;
-  DCHECK_EQ(num_true, 1);
-  DCHECK(!isac_is_encoder_ || isac_codec_);
+  DCHECK_EQ(!!speech_encoder_ + !!external_speech_encoder_, 1);
 }
 
 AudioDecoder* CodecOwner::GetIsacDecoder() {
-  if (!isac_codec_) {
-    DCHECK(!isac_is_encoder_);
-    // None of the parameter values in |speech_inst| matter when the codec is
-    // used only as a decoder.
-    CodecInst speech_inst;
-    speech_inst.plfreq = 16000;
-    speech_inst.rate = -1;
-    speech_inst.pacsize = 480;
-    isac_codec_.reset(CreateIsacCodec(speech_inst));
-  }
-  return isac_codec_.get();
+  if (!isac_decoder_)
+    isac_decoder_ = CreateIsacDecoder(&isac_bandwidth_info_);
+  return isac_decoder_.get();
 }
 
 AudioEncoder* CodecOwner::Encoder() {
@@ -243,15 +236,9 @@
 }
 
 const AudioEncoderMutable* CodecOwner::SpeechEncoder() const {
-  int num_true =
-      !!speech_encoder_ + !!external_speech_encoder_ + isac_is_encoder_;
-  DCHECK_GE(num_true, 0);
-  DCHECK_LE(num_true, 1);
-  if (external_speech_encoder_)
-    return external_speech_encoder_;
-  if (speech_encoder_)
-    return speech_encoder_.get();
-  return isac_is_encoder_ ? isac_codec_.get() : nullptr;
+  DCHECK(!speech_encoder_ || !external_speech_encoder_);
+  return external_speech_encoder_ ? external_speech_encoder_
+                                  : speech_encoder_.get();
 }
 
 }  // namespace acm2
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_owner.h b/webrtc/modules/audio_coding/main/acm2/codec_owner.h
index 2468c3c..2c5e942 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_owner.h
+++ b/webrtc/modules/audio_coding/main/acm2/codec_owner.h
@@ -53,21 +53,17 @@
   const AudioEncoderMutable* SpeechEncoder() const;
 
  private:
-  // There are three main cases for the state of the encoder members below:
-  // 1. An external encoder is used. |external_speech_encoder_| points to it.
-  //    |speech_encoder_| is null, and |isac_is_encoder_| is false.
-  // 2. The internal iSAC codec is used as encoder. |isac_codec_| points to it
-  //    and |isac_is_encoder_| is true. |external_speech_encoder_| and
-  //    |speech_encoder_| are null.
-  // 3. Another internal encoder is used. |speech_encoder_| points to it.
-  //    |external_speech_encoder_| is null, and |isac_is_encoder_| is false.
-  // In addition to case 2, |isac_codec_| is valid when GetIsacDecoder has been
-  // called.
+  // At most one of these is non-null:
   rtc::scoped_ptr<AudioEncoderMutable> speech_encoder_;
-  rtc::scoped_ptr<AudioEncoderDecoderMutableIsac> isac_codec_;
-  bool isac_is_encoder_;
   AudioEncoderMutable* external_speech_encoder_;
 
+  // If we've created an iSAC decoder because someone called GetIsacDecoder,
+  // store it here.
+  rtc::scoped_ptr<AudioDecoder> isac_decoder_;
+
+  // iSAC bandwidth estimation info, for use with iSAC encoders and decoders.
+  LockedIsacBandwidthInfo isac_bandwidth_info_;
+
   // |cng_encoder_| and |red_encoder_| are valid iff CNG or RED, respectively,
   // are active.
   rtc::scoped_ptr<AudioEncoder> cng_encoder_;
diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc
index 6a9b953..53dc033 100644
--- a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc
+++ b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc
@@ -559,22 +559,13 @@
       return new AudioDecoderIlbc;
 #endif
 #if defined(WEBRTC_CODEC_ISACFX)
-    case kDecoderISAC: {
-      AudioEncoderDecoderIsacFix::Config config;
-      return new AudioEncoderDecoderIsacFix(config);
-    }
+    case kDecoderISAC:
+      return new AudioDecoderIsacFix();
 #elif defined(WEBRTC_CODEC_ISAC)
-    case kDecoderISAC: {
-      AudioEncoderDecoderIsac::Config config;
-      config.sample_rate_hz = 16000;
-      return new AudioEncoderDecoderIsac(config);
-    }
+    case kDecoderISAC:
     case kDecoderISACswb:
-    case kDecoderISACfb: {
-      AudioEncoderDecoderIsac::Config config;
-      config.sample_rate_hz = 32000;
-      return new AudioEncoderDecoderIsac(config);
-    }
+    case kDecoderISACfb:
+      return new AudioDecoderIsac();
 #endif
 #ifdef WEBRTC_CODEC_PCM16
     case kDecoderPCM16B:
diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
index d54fbe9..3983c07 100644
--- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
@@ -358,17 +358,14 @@
     codec_input_rate_hz_ = 16000;
     frame_size_ = 480;
     data_length_ = 10 * frame_size_;
-    AudioEncoderDecoderIsac::Config config;
+    AudioEncoderIsac::Config config;
     config.payload_type = payload_type_;
     config.sample_rate_hz = codec_input_rate_hz_;
     config.adaptive_mode = false;
     config.frame_size_ms =
         1000 * static_cast<int>(frame_size_) / codec_input_rate_hz_;
-
-    // We need to create separate AudioEncoderDecoderIsac objects for encoding
-    // and decoding, because the test class destructor destroys them both.
-    audio_encoder_.reset(new AudioEncoderDecoderIsac(config));
-    decoder_ = new AudioEncoderDecoderIsac(config);
+    audio_encoder_.reset(new AudioEncoderIsac(config));
+    decoder_ = new AudioDecoderIsac();
   }
 };
 
@@ -378,17 +375,14 @@
     codec_input_rate_hz_ = 32000;
     frame_size_ = 960;
     data_length_ = 10 * frame_size_;
-    AudioEncoderDecoderIsac::Config config;
+    AudioEncoderIsac::Config config;
     config.payload_type = payload_type_;
     config.sample_rate_hz = codec_input_rate_hz_;
     config.adaptive_mode = false;
     config.frame_size_ms =
         1000 * static_cast<int>(frame_size_) / codec_input_rate_hz_;
-
-    // We need to create separate AudioEncoderDecoderIsac objects for encoding
-    // and decoding, because the test class destructor destroys them both.
-    audio_encoder_.reset(new AudioEncoderDecoderIsac(config));
-    decoder_ = new AudioEncoderDecoderIsac(config);
+    audio_encoder_.reset(new AudioEncoderIsac(config));
+    decoder_ = new AudioDecoderIsac();
   }
 };
 
@@ -398,18 +392,14 @@
     codec_input_rate_hz_ = 16000;
     frame_size_ = 480;
     data_length_ = 10 * frame_size_;
-    AudioEncoderDecoderIsacFix::Config config;
+    AudioEncoderIsacFix::Config config;
     config.payload_type = payload_type_;
     config.sample_rate_hz = codec_input_rate_hz_;
     config.adaptive_mode = false;
     config.frame_size_ms =
         1000 * static_cast<int>(frame_size_) / codec_input_rate_hz_;
-
-    // We need to create separate AudioEncoderDecoderIsacFix objects for
-    // encoding and decoding, because the test class destructor destroys them
-    // both.
-    audio_encoder_.reset(new AudioEncoderDecoderIsacFix(config));
-    decoder_ = new AudioEncoderDecoderIsacFix(config);
+    audio_encoder_.reset(new AudioEncoderIsacFix(config));
+    decoder_ = new AudioDecoderIsacFix();
   }
 };