Introduce CodecManager and move code from AudioCodingModuleImpl

This change essentially divides AudioCodingModuleImpl into two parts:
one is the code related to managing codecs, now moved into CodecManager,
and the other is what remains in AudioCodingModuleImpl.

This change also removes AudioCodingModuleImpl::InitializeSender. The
function was essentially no-op, since it was always called immediately
after construction.

COAUTHOR=kwiberg@webrtc.org
BUG=4228
R=minyue@webrtc.org, tina.legrand@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/51469004

Cr-Commit-Position: refs/heads/master@{#8893}
diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn
index c88653e..d18ed66 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -32,6 +32,8 @@
     "main/acm2/audio_coding_module_impl.h",
     "main/acm2/call_statistics.cc",
     "main/acm2/call_statistics.h",
+    "main/acm2/codec_manager.cc",
+    "main/acm2/codec_manager.h",
     "main/acm2/initial_delay_manager.cc",
     "main/acm2/initial_delay_manager.h",
     "main/acm2/nack.cc",
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc
index c472a4a..6d7b095 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc
@@ -209,7 +209,7 @@
   return decoder_->Channels();
 }
 
-int16_t ACMGenericCodec::EncoderParams(WebRtcACMCodecParams* enc_params) {
+int16_t ACMGenericCodec::EncoderParams(WebRtcACMCodecParams* enc_params) const {
   *enc_params = acm_codec_params_;
   return 0;
 }
@@ -540,6 +540,10 @@
   return encoder_;
 }
 
+const AudioEncoder* ACMGenericCodec::GetAudioEncoder() const {
+  return encoder_;
+}
+
 }  // namespace acm2
 
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h
index 6a5a04a..d491dfd 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h
+++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h
@@ -120,7 +120,7 @@
   //   -1 if the encoder is not initialized,
   //    0 otherwise.
   //
-  int16_t EncoderParams(WebRtcACMCodecParams* enc_params);
+  int16_t EncoderParams(WebRtcACMCodecParams* enc_params) const;
 
   ///////////////////////////////////////////////////////////////////////////
   // int16_t InitEncoder(...)
@@ -410,6 +410,8 @@
 
   AudioEncoder* GetAudioEncoder();
 
+  const AudioEncoder* GetAudioEncoder() const;
+
  private:
   bool has_internal_fec_;
 
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc
index d2b7746..269d19c 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc
@@ -62,7 +62,6 @@
     }
 
     acm_->InitializeReceiver();
-    acm_->InitializeSender();
     acm_->RegisterTransportCallback(this);
 
     rtp_header_.header.sequenceNumber = 0;
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module.gypi b/webrtc/modules/audio_coding/main/acm2/audio_coding_module.gypi
index edbcaa9..6b938b6 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module.gypi
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module.gypi
@@ -70,6 +70,8 @@
         'audio_coding_module_impl.h',
         'call_statistics.cc',
         'call_statistics.h',
+        'codec_manager.cc',
+        'codec_manager.h',
         'initial_delay_manager.cc',
         'initial_delay_manager.h',
         'nack.cc',
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 c4ab6a9..d78af65 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
@@ -18,7 +18,6 @@
 #include "webrtc/base/safe_conversions.h"
 #include "webrtc/engine_configurations.h"
 #include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h"
-#include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h"
 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
 #include "webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h"
 #include "webrtc/modules/audio_coding/main/acm2/acm_resampler.h"
@@ -126,20 +125,8 @@
       id_(config.id),
       expected_codec_ts_(0xD87F3F9F),
       expected_in_ts_(0xD87F3F9F),
-      send_codec_inst_(),
-      cng_nb_pltype_(255),
-      cng_wb_pltype_(255),
-      cng_swb_pltype_(255),
-      cng_fb_pltype_(255),
-      red_nb_pltype_(255),
-      vad_enabled_(false),
-      dtx_enabled_(false),
-      vad_mode_(VADNormal),
-      current_encoder_(nullptr),
-      stereo_send_(false),
       receiver_(config),
-      red_enabled_(false),
-      codec_fec_enabled_(false),
+      codec_manager_(this),
       previous_pltype_(255),
       aux_rtp_header_(NULL),
       receiver_initialized_(false),
@@ -148,35 +135,6 @@
       callback_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
       packetization_callback_(NULL),
       vad_callback_(NULL) {
-  // Nullify send codec memory, set payload type and set codec name to
-  // invalid values.
-  const char no_name[] = "noCodecRegistered";
-  strncpy(send_codec_inst_.plname, no_name, RTP_PAYLOAD_NAME_SIZE - 1);
-  send_codec_inst_.pltype = -1;
-
-  for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) {
-    codecs_[i] = NULL;
-    mirror_codec_idx_[i] = -1;
-  }
-
-  // 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--) {
-    if (IsCodecRED(i) && ACMCodecDB::database_[i].plfreq == 8000) {
-      red_nb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
-    } else if (IsCodecCN(i)) {
-      if (ACMCodecDB::database_[i].plfreq == 8000) {
-        cng_nb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
-      } else if (ACMCodecDB::database_[i].plfreq == 16000) {
-        cng_wb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
-      } else if (ACMCodecDB::database_[i].plfreq == 32000) {
-        cng_swb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
-      } else if (ACMCodecDB::database_[i].plfreq == 48000) {
-        cng_fb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
-      }
-    }
-  }
-
   if (InitializeReceiverSafe() < 0) {
     WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
                  "Cannot initialize receiver");
@@ -185,23 +143,6 @@
 }
 
 AudioCodingModuleImpl::~AudioCodingModuleImpl() {
-  {
-    CriticalSectionScoped lock(acm_crit_sect_);
-
-    for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) {
-      if (codecs_[i] != NULL) {
-        // Mirror index holds the address of the codec memory.
-        assert(mirror_codec_idx_[i] > -1);
-        if (codecs_[mirror_codec_idx_[i]] != NULL) {
-          delete codecs_[mirror_codec_idx_[i]];
-          codecs_[mirror_codec_idx_[i]] = NULL;
-        }
-
-        codecs_[i] = NULL;
-      }
-    }
-  }
-
   if (aux_rtp_header_ != NULL) {
     delete aux_rtp_header_;
     aux_rtp_header_ = NULL;
@@ -229,7 +170,8 @@
       return -1;
     }
 
-    AudioEncoder* audio_encoder = current_encoder_->GetAudioEncoder();
+    AudioEncoder* audio_encoder =
+        codec_manager_.current_encoder()->GetAudioEncoder();
     // Scale the timestamp to the codec's RTP timestamp rate.
     uint32_t rtp_timestamp =
         first_frame_ ? input_data.input_timestamp
@@ -271,7 +213,7 @@
           frame_type, encoded_info.payload_type, encoded_info.encoded_timestamp,
           stream, encoded_info.encoded_bytes,
           my_fragmentation.fragmentationVectorSize > 0 ? &my_fragmentation
-              : nullptr);
+                                                       : nullptr);
     }
 
     if (vad_callback_) {
@@ -290,17 +232,6 @@
 //   Sender
 //
 
-// Initialize send codec.
-int AudioCodingModuleImpl::InitializeSender() {
-  CriticalSectionScoped lock(acm_crit_sect_);
-
-  // Start with invalid values.
-  current_encoder_ = nullptr;
-  send_codec_inst_.plname[0] = '\0';
-
-  return 0;
-}
-
 // TODO(henrik.lundin): Remove this method; only used in tests.
 int AudioCodingModuleImpl::ResetEncoder() {
   CriticalSectionScoped lock(acm_crit_sect_);
@@ -310,365 +241,16 @@
   return 0;
 }
 
-ACMGenericCodec* AudioCodingModuleImpl::CreateCodec(const CodecInst& codec) {
-  ACMGenericCodec* my_codec = NULL;
-  CriticalSectionScoped lock(acm_crit_sect_);
-  my_codec = ACMCodecDB::CreateCodecInstance(
-      codec, cng_nb_pltype_, cng_wb_pltype_, cng_swb_pltype_, cng_fb_pltype_,
-      red_enabled_, red_nb_pltype_);
-  if (my_codec == NULL) {
-    // Error, could not create the codec.
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                 "ACMCodecDB::CreateCodecInstance() failed in CreateCodec()");
-    return my_codec;
-  }
-
-  return my_codec;
-}
-
-// Check if the given codec is a valid to be registered as send codec.
-static int IsValidSendCodec(const CodecInst& send_codec,
-                            bool is_primary_encoder,
-                            int acm_id,
-                            int* mirror_id) {
-  if ((send_codec.channels != 1) && (send_codec.channels != 2)) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
-                 "Wrong number of channels (%d, only mono and stereo are "
-                 "supported) for %s encoder", send_codec.channels,
-                 is_primary_encoder ? "primary" : "secondary");
-    return -1;
-  }
-
-  int codec_id = ACMCodecDB::CodecNumber(send_codec, mirror_id);
-  if (codec_id < 0) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
-                 "Invalid codec setting for the send codec.");
-    return -1;
-  }
-
-  // TODO(tlegrand): Remove this check. Already taken care of in
-  // ACMCodecDB::CodecNumber().
-  // Check if the payload-type is valid
-  if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
-                 "Invalid payload-type %d for %s.", send_codec.pltype,
-                 send_codec.plname);
-    return -1;
-  }
-
-  // Telephone-event cannot be a send codec.
-  if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
-                 "telephone-event cannot be a send codec");
-    *mirror_id = -1;
-    return -1;
-  }
-
-  if (ACMCodecDB::codec_settings_[codec_id].channel_support
-      < send_codec.channels) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
-                 "%d number of channels not supportedn for %s.",
-                 send_codec.channels, send_codec.plname);
-    *mirror_id = -1;
-    return -1;
-  }
-
-  if (!is_primary_encoder) {
-    // If registering the secondary encoder, then RED and CN are not valid
-    // choices as encoder.
-    if (IsCodecRED(&send_codec)) {
-      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
-                   "RED cannot be secondary codec");
-      *mirror_id = -1;
-      return -1;
-    }
-
-    if (IsCodecCN(&send_codec)) {
-      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
-                   "DTX cannot be secondary codec");
-      *mirror_id = -1;
-      return -1;
-    }
-  }
-  return codec_id;
-}
-
 // Can be called multiple times for Codec, CNG, RED.
 int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) {
-  int mirror_id;
-  int codec_id = IsValidSendCodec(send_codec, true, id_, &mirror_id);
-
   CriticalSectionScoped lock(acm_crit_sect_);
-
-  // Check for reported errors from function IsValidSendCodec().
-  if (codec_id < 0) {
-    return -1;
-  }
-
-  // RED can be registered with other payload type. If not registered a default
-  // payload type is used.
-  if (IsCodecRED(&send_codec)) {
-    // TODO(tlegrand): Remove this check. Already taken care of in
-    // ACMCodecDB::CodecNumber().
-    // Check if the payload-type is valid
-    if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) {
-      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                   "Invalid payload-type %d for %s.", send_codec.pltype,
-                   send_codec.plname);
-      return -1;
-    }
-    // Set RED payload type.
-    if (send_codec.plfreq == 8000) {
-      red_nb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
-    } else {
-      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                   "RegisterSendCodec() failed, invalid frequency for RED "
-                   "registration");
-      return -1;
-    }
-    SetRedPayloadType(send_codec.plfreq, send_codec.pltype);
-    return 0;
-  }
-
-  // CNG can be registered with other payload type. If not registered the
-  // default payload types from codec database will be used.
-  if (IsCodecCN(&send_codec)) {
-    // CNG is registered.
-    switch (send_codec.plfreq) {
-      case 8000: {
-        cng_nb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
-        break;
-      }
-      case 16000: {
-        cng_wb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
-        break;
-      }
-      case 32000: {
-        cng_swb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
-        break;
-      }
-      case 48000: {
-        cng_fb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
-        break;
-      }
-      default: {
-        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                     "RegisterSendCodec() failed, invalid frequency for CNG "
-                     "registration");
-        return -1;
-      }
-    }
-    SetCngPayloadType(send_codec.plfreq, send_codec.pltype);
-    return 0;
-  }
-
-  // Set Stereo, and make sure VAD and DTX is turned off.
-  if (send_codec.channels == 2) {
-    stereo_send_ = true;
-    if (vad_enabled_ || dtx_enabled_) {
-      WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
-                   "VAD/DTX is turned off, not supported when sending stereo.");
-    }
-    vad_enabled_ = false;
-    dtx_enabled_ = false;
-  } else {
-    stereo_send_ = false;
-  }
-
-  // Check if the codec is already registered as send codec.
-  bool is_send_codec;
-  if (current_encoder_) {
-    int send_codec_mirror_id;
-    int send_codec_id = ACMCodecDB::CodecNumber(send_codec_inst_,
-                                                &send_codec_mirror_id);
-    assert(send_codec_id >= 0);
-    is_send_codec = (send_codec_id == codec_id) ||
-        (mirror_id == send_codec_mirror_id);
-  } else {
-    is_send_codec = false;
-  }
-
-  // If new codec, or new settings, register.
-  if (!is_send_codec) {
-    if (codecs_[mirror_id] == NULL) {
-      codecs_[mirror_id] = CreateCodec(send_codec);
-      if (codecs_[mirror_id] == NULL) {
-        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                     "Cannot Create the codec");
-        return -1;
-      }
-      mirror_codec_idx_[mirror_id] = mirror_id;
-    }
-
-    if (mirror_id != codec_id) {
-      codecs_[codec_id] = codecs_[mirror_id];
-      mirror_codec_idx_[codec_id] = mirror_id;
-    }
-
-    ACMGenericCodec* codec_ptr = codecs_[codec_id];
-    WebRtcACMCodecParams codec_params;
-
-    memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst));
-    codec_params.enable_vad = vad_enabled_;
-    codec_params.enable_dtx = dtx_enabled_;
-    codec_params.vad_mode = vad_mode_;
-    // Force initialization.
-    if (codec_ptr->InitEncoder(&codec_params, true) < 0) {
-      // Could not initialize the encoder.
-
-      // Check if already have a registered codec.
-      // Depending on that different messages are logged.
-      if (!current_encoder_) {
-        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                     "Cannot Initialize the encoder No Encoder is registered");
-      } else {
-        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                     "Cannot Initialize the encoder, continue encoding with "
-                     "the previously registered codec");
-      }
-      return -1;
-    }
-
-    // Update states.
-    dtx_enabled_ = codec_params.enable_dtx;
-    vad_enabled_ = codec_params.enable_vad;
-    vad_mode_ = codec_params.vad_mode;
-
-    // Everything is fine so we can replace the previous codec with this one.
-    if (current_encoder_) {
-      // If we change codec we start fresh with RED.
-      // This is not strictly required by the standard.
-
-      if(codec_ptr->SetCopyRed(red_enabled_) < 0) {
-        // We tried to preserve the old red status, if failed, it means the
-        // red status has to be flipped.
-        red_enabled_ = !red_enabled_;
-      }
-
-      codec_ptr->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_);
-
-      if (!codec_ptr->HasInternalFEC()) {
-        codec_fec_enabled_ = false;
-      } else {
-        if (codec_ptr->SetFEC(codec_fec_enabled_) < 0) {
-          WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                       "Cannot set codec FEC");
-          return -1;
-        }
-      }
-    }
-
-    current_encoder_ = codecs_[codec_id];
-    DCHECK(current_encoder_);
-    memcpy(&send_codec_inst_, &send_codec, sizeof(CodecInst));
-    return 0;
-  } else {
-    // If codec is the same as already registered check if any parameters
-    // has changed compared to the current values.
-    // If any parameter is valid then apply it and record.
-    bool force_init = false;
-
-    if (mirror_id != codec_id) {
-      codecs_[codec_id] = codecs_[mirror_id];
-      mirror_codec_idx_[codec_id] = mirror_id;
-    }
-
-    // Check the payload type.
-    if (send_codec.pltype != send_codec_inst_.pltype) {
-      // At this point check if the given payload type is valid.
-      // Record it later when the sampling frequency is changed
-      // successfully.
-      if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) {
-        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                     "Out of range payload type");
-        return -1;
-      }
-    }
-
-    // If there is a codec that ONE instance of codec supports multiple
-    // sampling frequencies, then we need to take care of it here.
-    // one such a codec is iSAC. Both WB and SWB are encoded and decoded
-    // with one iSAC instance. Therefore, we need to update the encoder
-    // frequency if required.
-    if (send_codec_inst_.plfreq != send_codec.plfreq) {
-      force_init = true;
-    }
-
-    // If packet size or number of channels has changed, we need to
-    // re-initialize the encoder.
-    if (send_codec_inst_.pacsize != send_codec.pacsize) {
-      force_init = true;
-    }
-    if (send_codec_inst_.channels != send_codec.channels) {
-      force_init = true;
-    }
-
-    if (force_init) {
-      WebRtcACMCodecParams codec_params;
-
-      memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst));
-      codec_params.enable_vad = vad_enabled_;
-      codec_params.enable_dtx = dtx_enabled_;
-      codec_params.vad_mode = vad_mode_;
-
-      // Force initialization.
-      if (current_encoder_->InitEncoder(&codec_params, true) < 0) {
-        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                     "Could not change the codec packet-size.");
-        return -1;
-      }
-
-      send_codec_inst_.plfreq = send_codec.plfreq;
-      send_codec_inst_.pacsize = send_codec.pacsize;
-      send_codec_inst_.channels = send_codec.channels;
-    }
-
-    // If the change of sampling frequency has been successful then
-    // we store the payload-type.
-    send_codec_inst_.pltype = send_codec.pltype;
-
-    // Check if a change in Rate is required.
-    if (send_codec.rate != send_codec_inst_.rate) {
-      if (codecs_[codec_id]->SetBitRate(send_codec.rate) < 0) {
-        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                     "Could not change the codec rate.");
-        return -1;
-      }
-      send_codec_inst_.rate = send_codec.rate;
-    }
-
-    if (!codecs_[codec_id]->HasInternalFEC()) {
-      codec_fec_enabled_ = false;
-    } else {
-      if (codecs_[codec_id]->SetFEC(codec_fec_enabled_) < 0) {
-        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                     "Cannot set codec FEC");
-        return -1;
-      }
-    }
-
-    return 0;
-  }
+  return codec_manager_.RegisterSendCodec(send_codec);
 }
 
 // Get current send codec.
-int AudioCodingModuleImpl::SendCodec(
-    CodecInst* current_codec) const {
-  WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
-               "SendCodec()");
+int AudioCodingModuleImpl::SendCodec(CodecInst* current_codec) const {
   CriticalSectionScoped lock(acm_crit_sect_);
-
-  if (!current_encoder_) {
-    WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
-                 "SendCodec Failed, no codec is registered");
-    return -1;
-  }
-  WebRtcACMCodecParams encoder_param;
-  current_encoder_->EncoderParams(&encoder_param);
-  encoder_param.codec_inst.pltype = send_codec_inst_.pltype;
-  memcpy(current_codec, &(encoder_param.codec_inst), sizeof(CodecInst));
-
-  return 0;
+  return codec_manager_.SendCodec(current_codec);
 }
 
 // Get current send frequency.
@@ -677,13 +259,13 @@
                "SendFrequency()");
   CriticalSectionScoped lock(acm_crit_sect_);
 
-  if (!current_encoder_) {
+  if (!codec_manager_.current_encoder()) {
     WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
                  "SendFrequency Failed, no codec is registered");
     return -1;
   }
 
-  return send_codec_inst_.plfreq;
+  return codec_manager_.current_encoder()->GetAudioEncoder()->SampleRateHz();
 }
 
 // Get encode bitrate.
@@ -693,14 +275,14 @@
 int AudioCodingModuleImpl::SendBitrate() const {
   CriticalSectionScoped lock(acm_crit_sect_);
 
-  if (!current_encoder_) {
+  if (!codec_manager_.current_encoder()) {
     WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
                  "SendBitrate Failed, no codec is registered");
     return -1;
   }
 
   WebRtcACMCodecParams encoder_param;
-  current_encoder_->EncoderParams(&encoder_param);
+  codec_manager_.current_encoder()->EncoderParams(&encoder_param);
 
   return encoder_param.codec_inst.rate;
 }
@@ -779,7 +361,9 @@
   }
 
   // Check whether we need an up-mix or down-mix?
-  bool remix = ptr_frame->num_channels_ != send_codec_inst_.channels;
+  bool remix =
+      ptr_frame->num_channels_ !=
+      codec_manager_.current_encoder()->GetAudioEncoder()->NumChannels();
 
   if (remix) {
     if (ptr_frame->num_channels_ == 1) {
@@ -796,13 +380,15 @@
   const int16_t* ptr_audio = ptr_frame->data_;
 
   // For pushing data to primary, point the |ptr_audio| to correct buffer.
-  if (send_codec_inst_.channels != ptr_frame->num_channels_)
+  if (codec_manager_.current_encoder()->GetAudioEncoder()->NumChannels() !=
+      ptr_frame->num_channels_)
     ptr_audio = input_data->buffer;
 
   input_data->input_timestamp = ptr_frame->timestamp_;
   input_data->audio = ptr_audio;
   input_data->length_per_channel = ptr_frame->samples_per_channel_;
-  input_data->audio_channel = send_codec_inst_.channels;
+  input_data->audio_channel =
+      codec_manager_.current_encoder()->GetAudioEncoder()->NumChannels();
 
   return 0;
 }
@@ -814,12 +400,15 @@
 // is required, |*ptr_out| points to |in_frame|.
 int AudioCodingModuleImpl::PreprocessToAddData(const AudioFrame& in_frame,
                                                const AudioFrame** ptr_out) {
-  bool resample = (in_frame.sample_rate_hz_ != send_codec_inst_.plfreq);
+  bool resample =
+      (in_frame.sample_rate_hz_ !=
+       codec_manager_.current_encoder()->GetAudioEncoder()->SampleRateHz());
 
   // This variable is true if primary codec and secondary codec (if exists)
   // are both mono and input is stereo.
   bool down_mix =
-      (in_frame.num_channels_ == 2) && (send_codec_inst_.channels == 1);
+      (in_frame.num_channels_ == 2) &&
+      (codec_manager_.current_encoder()->GetAudioEncoder()->NumChannels() == 1);
 
   if (!first_10ms_data_) {
     expected_in_ts_ = in_frame.timestamp_;
@@ -827,9 +416,13 @@
     first_10ms_data_ = true;
   } else if (in_frame.timestamp_ != expected_in_ts_) {
     // TODO(turajs): Do we need a warning here.
-    expected_codec_ts_ += (in_frame.timestamp_ - expected_in_ts_) *
-        static_cast<uint32_t>((static_cast<double>(send_codec_inst_.plfreq) /
-                    static_cast<double>(in_frame.sample_rate_hz_)));
+    expected_codec_ts_ +=
+        (in_frame.timestamp_ - expected_in_ts_) *
+        static_cast<uint32_t>(
+            (static_cast<double>(codec_manager_.current_encoder()
+                                     ->GetAudioEncoder()
+                                     ->SampleRateHz()) /
+             static_cast<double>(in_frame.sample_rate_hz_)));
     expected_in_ts_ = in_frame.timestamp_;
   }
 
@@ -867,20 +460,19 @@
     // The result of the resampler is written to output frame.
     dest_ptr_audio = preprocess_frame_.data_;
 
-    preprocess_frame_.samples_per_channel_ =
-        resampler_.Resample10Msec(src_ptr_audio,
-                                  in_frame.sample_rate_hz_,
-                                  send_codec_inst_.plfreq,
-                                  preprocess_frame_.num_channels_,
-                                  AudioFrame::kMaxDataSizeSamples,
-                                  dest_ptr_audio);
+    preprocess_frame_.samples_per_channel_ = resampler_.Resample10Msec(
+        src_ptr_audio, in_frame.sample_rate_hz_,
+        codec_manager_.current_encoder()->GetAudioEncoder()->SampleRateHz(),
+        preprocess_frame_.num_channels_, AudioFrame::kMaxDataSizeSamples,
+        dest_ptr_audio);
 
     if (preprocess_frame_.samples_per_channel_ < 0) {
       WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
                    "Cannot add 10 ms audio, resampling failed");
       return -1;
     }
-    preprocess_frame_.sample_rate_hz_ = send_codec_inst_.plfreq;
+    preprocess_frame_.sample_rate_hz_ =
+        codec_manager_.current_encoder()->GetAudioEncoder()->SampleRateHz();
   }
 
   expected_codec_ts_ += preprocess_frame_.samples_per_channel_;
@@ -895,8 +487,7 @@
 
 bool AudioCodingModuleImpl::REDStatus() const {
   CriticalSectionScoped lock(acm_crit_sect_);
-
-  return red_enabled_;
+  return codec_manager_.red_enabled();
 }
 
 // Configure RED status i.e on/off.
@@ -904,23 +495,7 @@
 #ifdef WEBRTC_CODEC_RED
     bool enable_red) {
   CriticalSectionScoped lock(acm_crit_sect_);
-
-  if (enable_red == true && codec_fec_enabled_ == true) {
-    WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
-                 "Codec internal FEC and RED cannot be co-enabled.");
-    return -1;
-  }
-
-  // If a send codec is registered, set RED for the codec. We now only support
-  // copy red.
-  if (HaveValidEncoder("SetCopyRed") &&
-      current_encoder_->SetCopyRed(enable_red) < 0) {
-      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                   "SetREDStatus failed");
-      return -1;
-  }
-  red_enabled_ = enable_red;
-  return 0;
+  return codec_manager_.SetCopyRed(enable_red) ? 0 : -1;
 #else
     bool /* enable_red */) {
   WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
@@ -935,33 +510,18 @@
 
 bool AudioCodingModuleImpl::CodecFEC() const {
   CriticalSectionScoped lock(acm_crit_sect_);
-  return codec_fec_enabled_;
+  return codec_manager_.codec_fec_enabled();
 }
 
 int AudioCodingModuleImpl::SetCodecFEC(bool enable_codec_fec) {
   CriticalSectionScoped lock(acm_crit_sect_);
-
-  if (enable_codec_fec == true && red_enabled_ == true) {
-    WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
-                 "Codec internal FEC and RED cannot be co-enabled.");
-    return -1;
-  }
-
-  // Set codec FEC.
-  if (HaveValidEncoder("SetCodecFEC") &&
-      current_encoder_->SetFEC(enable_codec_fec) < 0) {
-      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                   "Set codec internal FEC failed.");
-    return -1;
-  }
-  codec_fec_enabled_ = enable_codec_fec;
-  return 0;
+  return codec_manager_.SetCodecFEC(enable_codec_fec);
 }
 
 int AudioCodingModuleImpl::SetPacketLossRate(int loss_rate) {
   CriticalSectionScoped lock(acm_crit_sect_);
   if (HaveValidEncoder("SetPacketLossRate") &&
-      current_encoder_->SetPacketLossRate(loss_rate) < 0) {
+      codec_manager_.current_encoder()->SetPacketLossRate(loss_rate) < 0) {
       WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
                    "Set packet loss rate failed.");
     return -1;
@@ -976,60 +536,14 @@
                                   bool enable_vad,
                                   ACMVADMode mode) {
   CriticalSectionScoped lock(acm_crit_sect_);
-  return SetVADSafe(enable_dtx, enable_vad, mode);
-}
-
-int AudioCodingModuleImpl::SetVADSafe(bool enable_dtx,
-                                      bool enable_vad,
-                                      ACMVADMode mode) {
-  // Sanity check of the mode.
-  if ((mode != VADNormal) && (mode != VADLowBitrate)
-      && (mode != VADAggr) && (mode != VADVeryAggr)) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                 "Invalid VAD Mode %d, no change is made to VAD/DTX status",
-                 mode);
-    return -1;
-  }
-
-  // Check that the send codec is mono. We don't support VAD/DTX for stereo
-  // sending.
-  if ((enable_dtx || enable_vad) && stereo_send_) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                 "VAD/DTX not supported for stereo sending");
-    dtx_enabled_ = false;
-    vad_enabled_ = false;
-    vad_mode_ = mode;
-    return -1;
-  }
-
-  // Store VAD/DTX settings. Values can be changed in the call to "SetVAD"
-  // below.
-  dtx_enabled_ = enable_dtx;
-  vad_enabled_ = enable_vad;
-  vad_mode_ = mode;
-
-  // If a send codec is registered, set VAD/DTX for the codec.
-  if (HaveValidEncoder("SetVAD") &&
-      current_encoder_->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_) < 0) {
-      // SetVAD failed.
-      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                   "SetVAD failed");
-      vad_enabled_ = false;
-      dtx_enabled_ = false;
-      return -1;
-  }
-  return 0;
+  return codec_manager_.SetVAD(enable_dtx, enable_vad, mode);
 }
 
 // Get VAD/DTX settings.
 int AudioCodingModuleImpl::VAD(bool* dtx_enabled, bool* vad_enabled,
                                ACMVADMode* mode) const {
   CriticalSectionScoped lock(acm_crit_sect_);
-
-  *dtx_enabled = dtx_enabled_;
-  *vad_enabled = vad_enabled_;
-  *mode = vad_mode_;
-
+  codec_manager_.VAD(dtx_enabled, vad_enabled, mode);
   return 0;
 }
 
@@ -1108,56 +622,24 @@
 // for codecs, CNG (NB, WB and SWB), DTMF, RED.
 int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) {
   CriticalSectionScoped lock(acm_crit_sect_);
-
-  if (codec.channels > 2 || codec.channels < 0) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                 "Unsupported number of channels, %d.", codec.channels);
-    return -1;
-  }
-
-  // TODO(turajs) do we need this for NetEq 4?
-  if (!receiver_initialized_) {
-    if (InitializeReceiverSafe() < 0) {
-      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                   "Cannot initialize receiver, failed registering codec.");
-      return -1;
-    }
-  }
-
-  int mirror_id;
-  int codec_id = ACMCodecDB::ReceiverCodecNumber(codec, &mirror_id);
-
-  if (codec_id < 0 || codec_id >= ACMCodecDB::kNumCodecs) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                 "Wrong codec params to be registered as receive codec");
-    return -1;
-  }
-
-  // Check if the payload-type is valid.
-  if (!ACMCodecDB::ValidPayloadType(codec.pltype)) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                 "Invalid payload-type %d for %s.", codec.pltype,
-                 codec.plname);
-    return -1;
-  }
-
-  AudioDecoder* decoder = NULL;
-  // Get |decoder| associated with |codec|. |decoder| can be NULL if |codec|
-  // does not own its decoder.
-  if (GetAudioDecoder(codec, codec_id, mirror_id, &decoder) < 0) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                 "Wrong codec params to be registered as receive codec");
-    return -1;
-  }
-  uint8_t payload_type = static_cast<uint8_t>(codec.pltype);
-  return receiver_.AddCodec(codec_id, payload_type, codec.channels, decoder);
+  DCHECK(receiver_initialized_);
+  return codec_manager_.RegisterReceiveCodec(codec);
 }
 
 // Get current received codec.
 int AudioCodingModuleImpl::ReceiveCodec(CodecInst* current_codec) const {
+  CriticalSectionScoped lock(acm_crit_sect_);
   return receiver_.LastAudioCodec(current_codec);
 }
 
+int AudioCodingModuleImpl::RegisterDecoder(int acm_codec_id,
+                                           uint8_t payload_type,
+                                           int channels,
+                                           AudioDecoder* audio_decoder) {
+  return receiver_.AddCodec(acm_codec_id, payload_type, channels,
+                            audio_decoder);
+}
+
 // Incoming packet from network parsed and ready for decode.
 int AudioCodingModuleImpl::IncomingPacket(const uint8_t* incoming_payload,
                                           const size_t payload_length,
@@ -1312,7 +794,7 @@
     return -1;
   }
 
-  return current_encoder_->SetISACMaxRate(max_bit_per_sec);
+  return codec_manager_.current_encoder()->SetISACMaxRate(max_bit_per_sec);
 }
 
 // TODO(henrik.lundin): Remove? Only used in tests. Deprecated in VoiceEngine.
@@ -1323,7 +805,8 @@
     return -1;
   }
 
-  return current_encoder_->SetISACMaxPayloadSize(max_size_bytes);
+  return codec_manager_.current_encoder()->SetISACMaxPayloadSize(
+      max_size_bytes);
 }
 
 // TODO(henrik.lundin): Remove? Only used in tests.
@@ -1349,8 +832,8 @@
   if (!HaveValidEncoder("SetOpusApplication")) {
     return -1;
   }
-  return current_encoder_->SetOpusApplication(application,
-                                              disable_dtx_if_needed);
+  return codec_manager_.current_encoder()->SetOpusApplication(
+      application, disable_dtx_if_needed);
 }
 
 // Informs Opus encoder of the maximum playback rate the receiver will render.
@@ -1359,7 +842,7 @@
   if (!HaveValidEncoder("SetOpusMaxPlaybackRate")) {
     return -1;
   }
-  return current_encoder_->SetOpusMaxPlaybackRate(frequency_hz);
+  return codec_manager_.current_encoder()->SetOpusMaxPlaybackRate(frequency_hz);
 }
 
 int AudioCodingModuleImpl::EnableOpusDtx(bool force_voip) {
@@ -1367,7 +850,7 @@
   if (!HaveValidEncoder("EnableOpusDtx")) {
     return -1;
   }
-  return current_encoder_->EnableOpusDtx(force_voip);
+  return codec_manager_.current_encoder()->EnableOpusDtx(force_voip);
 }
 
 int AudioCodingModuleImpl::DisableOpusDtx() {
@@ -1375,7 +858,7 @@
   if (!HaveValidEncoder("DisableOpusDtx")) {
     return -1;
   }
-  return current_encoder_->DisableOpusDtx();
+  return codec_manager_.current_encoder()->DisableOpusDtx();
 }
 
 int AudioCodingModuleImpl::PlayoutTimestamp(uint32_t* timestamp) {
@@ -1383,7 +866,7 @@
 }
 
 bool AudioCodingModuleImpl::HaveValidEncoder(const char* caller_name) const {
-  if (!current_encoder_) {
+  if (!codec_manager_.current_encoder()) {
     WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
                  "%s failed: No send codec is registered.", caller_name);
     return false;
@@ -1415,60 +898,6 @@
 //  return status;
 }
 
-int AudioCodingModuleImpl::GetAudioDecoder(const CodecInst& codec, int codec_id,
-                                           int mirror_id,
-                                           AudioDecoder** decoder) {
-  if (ACMCodecDB::OwnsDecoder(codec_id)) {
-    // This codec has to own its own decoder. Therefore, it should create the
-    // corresponding AudioDecoder class and insert it into NetEq. If the codec
-    // does not exist create it.
-    //
-    // TODO(turajs): this part of the code is common with RegisterSendCodec(),
-    //               make a method for it.
-    if (codecs_[mirror_id] == NULL) {
-      codecs_[mirror_id] = CreateCodec(codec);
-      if (codecs_[mirror_id] == NULL) {
-        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                     "Cannot Create the codec");
-        return -1;
-      }
-      mirror_codec_idx_[mirror_id] = mirror_id;
-    }
-
-    if (mirror_id != codec_id) {
-      codecs_[codec_id] = codecs_[mirror_id];
-      mirror_codec_idx_[codec_id] = mirror_id;
-    }
-    *decoder = codecs_[codec_id]->Decoder();
-    if (!*decoder) {
-      assert(false);
-      return -1;
-    }
-  } else {
-    *decoder = NULL;
-  }
-
-  return 0;
-}
-
-void AudioCodingModuleImpl::SetCngPayloadType(int sample_rate_hz,
-                                              int payload_type) {
-  for (auto* codec : codecs_) {
-    if (codec) {
-      codec->SetCngPt(sample_rate_hz, payload_type);
-    }
-  }
-}
-
-void AudioCodingModuleImpl::SetRedPayloadType(int sample_rate_hz,
-                                              int payload_type) {
-  for (auto* codec : codecs_) {
-    if (codec) {
-      codec->SetRedPt(sample_rate_hz, payload_type);
-    }
-  }
-}
-
 int AudioCodingModuleImpl::SetInitialPlayoutDelay(int delay_ms) {
   {
     CriticalSectionScoped lock(acm_crit_sect_);
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 04a2059..1e9cbb9 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
@@ -20,6 +20,7 @@
 #include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h"
 #include "webrtc/modules/audio_coding/main/acm2/acm_receiver.h"
 #include "webrtc/modules/audio_coding/main/acm2/acm_resampler.h"
+#include "webrtc/modules/audio_coding/main/acm2/codec_manager.h"
 
 namespace webrtc {
 
@@ -42,9 +43,6 @@
   //   Sender
   //
 
-  // Initialize send codec.
-  int InitializeSender() override;
-
   // Reset send codec.
   int ResetEncoder() override;
 
@@ -135,6 +133,11 @@
   // Get current received codec.
   int ReceiveCodec(CodecInst* current_codec) const override;
 
+  int RegisterDecoder(int acm_codec_id,
+                      uint8_t payload_type,
+                      int channels,
+                      AudioDecoder* audio_decoder);
+
   // Incoming packet from network parsed and ready for decode.
   int IncomingPacket(const uint8_t* incoming_payload,
                      const size_t payload_length,
@@ -249,18 +252,11 @@
   int Add10MsDataInternal(const AudioFrame& audio_frame, InputData* input_data);
   int Encode(const InputData& input_data);
 
-  ACMGenericCodec* CreateCodec(const CodecInst& codec);
-
   int InitializeReceiverSafe() EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
 
   bool HaveValidEncoder(const char* caller_name) const
       EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
 
-  // Set VAD/DTX status. This function does not acquire a lock, and it is
-  // created to be called only from inside a critical section.
-  int SetVADSafe(bool enable_dtx, bool enable_vad, ACMVADMode mode)
-      EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
-
   // Preprocessing of input audio, including resampling and down-mixing if
   // required, before pushing audio into encoder's buffer.
   //
@@ -280,54 +276,13 @@
   // to |index|.
   int UpdateUponReceivingCodec(int index);
 
-  // Get a pointer to AudioDecoder of the given codec. For some codecs, e.g.
-  // iSAC, encoding and decoding have to be performed on a shared
-  // codec-instance. By calling this method, we get the codec-instance that ACM
-  // owns, then pass that to NetEq. This way, we perform both encoding and
-  // decoding on the same codec-instance. Furthermore, ACM would have control
-  // over decoder functionality if required. If |codec| does not share an
-  // instance between encoder and decoder, the |*decoder| is set NULL.
-  // The field ACMCodecDB::CodecSettings.owns_decoder indicates that if a
-  // codec owns the decoder-instance. For such codecs |*decoder| should be a
-  // valid pointer, otherwise it will be NULL.
-  int GetAudioDecoder(const CodecInst& codec, int codec_id,
-                      int mirror_id, AudioDecoder** decoder)
-      EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
-
-  void SetCngPayloadType(int sample_rate_hz, int payload_type)
-      EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
-
-  void SetRedPayloadType(int sample_rate_hz, int payload_type)
-      EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
-
   CriticalSectionWrapper* acm_crit_sect_;
   int id_;  // TODO(henrik.lundin) Make const.
   uint32_t expected_codec_ts_ GUARDED_BY(acm_crit_sect_);
   uint32_t expected_in_ts_ GUARDED_BY(acm_crit_sect_);
-  CodecInst send_codec_inst_ GUARDED_BY(acm_crit_sect_);
-
-  uint8_t cng_nb_pltype_ GUARDED_BY(acm_crit_sect_);
-  uint8_t cng_wb_pltype_ GUARDED_BY(acm_crit_sect_);
-  uint8_t cng_swb_pltype_ GUARDED_BY(acm_crit_sect_);
-  uint8_t cng_fb_pltype_ GUARDED_BY(acm_crit_sect_);
-
-  uint8_t red_nb_pltype_ GUARDED_BY(acm_crit_sect_);
-  bool vad_enabled_ GUARDED_BY(acm_crit_sect_);
-  bool dtx_enabled_ GUARDED_BY(acm_crit_sect_);
-  ACMVADMode vad_mode_ GUARDED_BY(acm_crit_sect_);
-  ACMGenericCodec* codecs_[ACMCodecDB::kMaxNumCodecs]
-      GUARDED_BY(acm_crit_sect_);
-  ACMGenericCodec* current_encoder_ GUARDED_BY(acm_crit_sect_);
-  int mirror_codec_idx_[ACMCodecDB::kMaxNumCodecs] GUARDED_BY(acm_crit_sect_);
-  bool stereo_send_ GUARDED_BY(acm_crit_sect_);
   ACMResampler resampler_ GUARDED_BY(acm_crit_sect_);
   AcmReceiver receiver_;  // AcmReceiver has it's own internal lock.
-
-  // RED.
-  bool red_enabled_ GUARDED_BY(acm_crit_sect_);
-
-  // Codec internal FEC
-  bool codec_fec_enabled_ GUARDED_BY(acm_crit_sect_);
+  CodecManager codec_manager_ GUARDED_BY(acm_crit_sect_);
 
   // This is to keep track of CN instances where we can send DTMFs.
   uint8_t previous_pltype_ GUARDED_BY(acm_crit_sect_);
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
new file mode 100644
index 0000000..c3e340e
--- /dev/null
+++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
@@ -0,0 +1,612 @@
+/*
+ *  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/main/acm2/codec_manager.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h"
+
+namespace webrtc {
+namespace acm2 {
+
+namespace {
+bool IsCodecRED(const CodecInst* codec) {
+  return (STR_CASE_CMP(codec->plname, "RED") == 0);
+}
+
+bool IsCodecRED(int index) {
+  return (IsCodecRED(&ACMCodecDB::database_[index]));
+}
+
+bool IsCodecCN(const CodecInst* codec) {
+  return (STR_CASE_CMP(codec->plname, "CN") == 0);
+}
+
+bool IsCodecCN(int index) {
+  return (IsCodecCN(&ACMCodecDB::database_[index]));
+}
+
+// Check if the given codec is a valid to be registered as send codec.
+int IsValidSendCodec(const CodecInst& send_codec,
+                     bool is_primary_encoder,
+                     int* mirror_id) {
+  int dummy_id = 0;
+  if ((send_codec.channels != 1) && (send_codec.channels != 2)) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                 "Wrong number of channels (%d, only mono and stereo are "
+                 "supported) for %s encoder",
+                 send_codec.channels,
+                 is_primary_encoder ? "primary" : "secondary");
+    return -1;
+  }
+
+  int codec_id = ACMCodecDB::CodecNumber(send_codec, mirror_id);
+  if (codec_id < 0) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                 "Invalid codec setting for the send codec.");
+    return -1;
+  }
+
+  // TODO(tlegrand): Remove this check. Already taken care of in
+  // ACMCodecDB::CodecNumber().
+  // Check if the payload-type is valid
+  if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                 "Invalid payload-type %d for %s.", send_codec.pltype,
+                 send_codec.plname);
+    return -1;
+  }
+
+  // Telephone-event cannot be a send codec.
+  if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                 "telephone-event cannot be a send codec");
+    *mirror_id = -1;
+    return -1;
+  }
+
+  if (ACMCodecDB::codec_settings_[codec_id].channel_support <
+      send_codec.channels) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                 "%d number of channels not supportedn for %s.",
+                 send_codec.channels, send_codec.plname);
+    *mirror_id = -1;
+    return -1;
+  }
+
+  if (!is_primary_encoder) {
+    // If registering the secondary encoder, then RED and CN are not valid
+    // choices as encoder.
+    if (IsCodecRED(&send_codec)) {
+      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                   "RED cannot be secondary codec");
+      *mirror_id = -1;
+      return -1;
+    }
+
+    if (IsCodecCN(&send_codec)) {
+      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                   "DTX cannot be secondary codec");
+      *mirror_id = -1;
+      return -1;
+    }
+  }
+  return codec_id;
+}
+
+const CodecInst kEmptyCodecInst = {-1, "noCodecRegistered", 0, 0, 0, 0};
+}  // namespace
+
+CodecManager::CodecManager(AudioCodingModuleImpl* acm)
+    : acm_(acm),
+      cng_nb_pltype_(255),
+      cng_wb_pltype_(255),
+      cng_swb_pltype_(255),
+      cng_fb_pltype_(255),
+      red_nb_pltype_(255),
+      stereo_send_(false),
+      vad_enabled_(false),
+      dtx_enabled_(false),
+      vad_mode_(VADNormal),
+      current_encoder_(nullptr),
+      send_codec_inst_(kEmptyCodecInst),
+      red_enabled_(false),
+      codec_fec_enabled_(false) {
+  for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) {
+    codecs_[i] = nullptr;
+    mirror_codec_idx_[i] = -1;
+  }
+
+  // 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--) {
+    if (IsCodecRED(i) && ACMCodecDB::database_[i].plfreq == 8000) {
+      red_nb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
+    } else if (IsCodecCN(i)) {
+      if (ACMCodecDB::database_[i].plfreq == 8000) {
+        cng_nb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
+      } else if (ACMCodecDB::database_[i].plfreq == 16000) {
+        cng_wb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
+      } else if (ACMCodecDB::database_[i].plfreq == 32000) {
+        cng_swb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
+      } else if (ACMCodecDB::database_[i].plfreq == 48000) {
+        cng_fb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
+      }
+    }
+  }
+  thread_checker_.DetachFromThread();
+}
+
+CodecManager::~CodecManager() {
+  for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) {
+    if (codecs_[i] != NULL) {
+      // Mirror index holds the address of the codec memory.
+      assert(mirror_codec_idx_[i] > -1);
+      if (codecs_[mirror_codec_idx_[i]] != NULL) {
+        delete codecs_[mirror_codec_idx_[i]];
+        codecs_[mirror_codec_idx_[i]] = NULL;
+      }
+
+      codecs_[i] = NULL;
+    }
+  }
+}
+
+int CodecManager::RegisterSendCodec(const CodecInst& send_codec) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  int mirror_id;
+  int codec_id = IsValidSendCodec(send_codec, true, &mirror_id);
+
+  // Check for reported errors from function IsValidSendCodec().
+  if (codec_id < 0) {
+    return -1;
+  }
+
+  int dummy_id = 0;
+  // RED can be registered with other payload type. If not registered a default
+  // payload type is used.
+  if (IsCodecRED(&send_codec)) {
+    // TODO(tlegrand): Remove this check. Already taken care of in
+    // ACMCodecDB::CodecNumber().
+    // Check if the payload-type is valid
+    if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) {
+      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                   "Invalid payload-type %d for %s.", send_codec.pltype,
+                   send_codec.plname);
+      return -1;
+    }
+    // Set RED payload type.
+    if (send_codec.plfreq == 8000) {
+      red_nb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
+    } else {
+      WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                   "RegisterSendCodec() failed, invalid frequency for RED "
+                   "registration");
+      return -1;
+    }
+    SetRedPayloadType(send_codec.plfreq, send_codec.pltype);
+    return 0;
+  }
+
+  // CNG can be registered with other payload type. If not registered the
+  // default payload types from codec database will be used.
+  if (IsCodecCN(&send_codec)) {
+    // CNG is registered.
+    switch (send_codec.plfreq) {
+      case 8000: {
+        cng_nb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
+        break;
+      }
+      case 16000: {
+        cng_wb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
+        break;
+      }
+      case 32000: {
+        cng_swb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
+        break;
+      }
+      case 48000: {
+        cng_fb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
+        break;
+      }
+      default: {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                     "RegisterSendCodec() failed, invalid frequency for CNG "
+                     "registration");
+        return -1;
+      }
+    }
+    SetCngPayloadType(send_codec.plfreq, send_codec.pltype);
+    return 0;
+  }
+
+  // Set Stereo, and make sure VAD and DTX is turned off.
+  if (send_codec.channels == 2) {
+    stereo_send_ = true;
+    if (vad_enabled_ || dtx_enabled_) {
+      WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, dummy_id,
+                   "VAD/DTX is turned off, not supported when sending stereo.");
+    }
+    vad_enabled_ = false;
+    dtx_enabled_ = false;
+  } else {
+    stereo_send_ = false;
+  }
+
+  // Check if the codec is already registered as send codec.
+  bool is_send_codec;
+  if (current_encoder_) {
+    int send_codec_mirror_id;
+    int send_codec_id =
+        ACMCodecDB::CodecNumber(send_codec_inst_, &send_codec_mirror_id);
+    assert(send_codec_id >= 0);
+    is_send_codec =
+        (send_codec_id == codec_id) || (mirror_id == send_codec_mirror_id);
+  } else {
+    is_send_codec = false;
+  }
+
+  // If new codec, or new settings, register.
+  if (!is_send_codec) {
+    if (!codecs_[mirror_id]) {
+      codecs_[mirror_id] = ACMCodecDB::CreateCodecInstance(
+          send_codec, cng_nb_pltype_, cng_wb_pltype_, cng_swb_pltype_,
+          cng_fb_pltype_, red_enabled_, red_nb_pltype_);
+      if (!codecs_[mirror_id]) {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                     "Cannot Create the codec");
+        return -1;
+      }
+      mirror_codec_idx_[mirror_id] = mirror_id;
+    }
+
+    if (mirror_id != codec_id) {
+      codecs_[codec_id] = codecs_[mirror_id];
+      mirror_codec_idx_[codec_id] = mirror_id;
+    }
+
+    ACMGenericCodec* codec_ptr = codecs_[codec_id];
+    WebRtcACMCodecParams codec_params;
+
+    memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst));
+    codec_params.enable_vad = vad_enabled_;
+    codec_params.enable_dtx = dtx_enabled_;
+    codec_params.vad_mode = vad_mode_;
+    // Force initialization.
+    if (codec_ptr->InitEncoder(&codec_params, true) < 0) {
+      // Could not initialize the encoder.
+
+      // Check if already have a registered codec.
+      // Depending on that different messages are logged.
+      if (!current_encoder_) {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                     "Cannot Initialize the encoder No Encoder is registered");
+      } else {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                     "Cannot Initialize the encoder, continue encoding with "
+                     "the previously registered codec");
+      }
+      return -1;
+    }
+
+    // Update states.
+    dtx_enabled_ = codec_params.enable_dtx;
+    vad_enabled_ = codec_params.enable_vad;
+    vad_mode_ = codec_params.vad_mode;
+
+    // Everything is fine so we can replace the previous codec with this one.
+    if (current_encoder_) {
+      // If we change codec we start fresh with RED.
+      // This is not strictly required by the standard.
+
+      if (codec_ptr->SetCopyRed(red_enabled_) < 0) {
+        // We tried to preserve the old red status, if failed, it means the
+        // red status has to be flipped.
+        red_enabled_ = !red_enabled_;
+      }
+
+      codec_ptr->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_);
+
+      if (!codec_ptr->HasInternalFEC()) {
+        codec_fec_enabled_ = false;
+      } else {
+        if (codec_ptr->SetFEC(codec_fec_enabled_) < 0) {
+          WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                       "Cannot set codec FEC");
+          return -1;
+        }
+      }
+    }
+
+    current_encoder_ = codecs_[codec_id];
+    DCHECK(current_encoder_);
+    memcpy(&send_codec_inst_, &send_codec, sizeof(CodecInst));
+    return 0;
+  } else {
+    // If codec is the same as already registered check if any parameters
+    // has changed compared to the current values.
+    // If any parameter is valid then apply it and record.
+    bool force_init = false;
+
+    if (mirror_id != codec_id) {
+      codecs_[codec_id] = codecs_[mirror_id];
+      mirror_codec_idx_[codec_id] = mirror_id;
+    }
+
+    // Check the payload type.
+    if (send_codec.pltype != send_codec_inst_.pltype) {
+      // At this point check if the given payload type is valid.
+      // Record it later when the sampling frequency is changed
+      // successfully.
+      if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                     "Out of range payload type");
+        return -1;
+      }
+    }
+
+    // If there is a codec that ONE instance of codec supports multiple
+    // sampling frequencies, then we need to take care of it here.
+    // one such a codec is iSAC. Both WB and SWB are encoded and decoded
+    // with one iSAC instance. Therefore, we need to update the encoder
+    // frequency if required.
+    if (send_codec_inst_.plfreq != send_codec.plfreq) {
+      force_init = true;
+    }
+
+    // If packet size or number of channels has changed, we need to
+    // re-initialize the encoder.
+    if (send_codec_inst_.pacsize != send_codec.pacsize) {
+      force_init = true;
+    }
+    if (send_codec_inst_.channels != send_codec.channels) {
+      force_init = true;
+    }
+
+    if (force_init) {
+      WebRtcACMCodecParams codec_params;
+
+      memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst));
+      codec_params.enable_vad = vad_enabled_;
+      codec_params.enable_dtx = dtx_enabled_;
+      codec_params.vad_mode = vad_mode_;
+
+      // Force initialization.
+      if (current_encoder_->InitEncoder(&codec_params, true) < 0) {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                     "Could not change the codec packet-size.");
+        return -1;
+      }
+
+      send_codec_inst_.plfreq = send_codec.plfreq;
+      send_codec_inst_.pacsize = send_codec.pacsize;
+      send_codec_inst_.channels = send_codec.channels;
+    }
+
+    // If the change of sampling frequency has been successful then
+    // we store the payload-type.
+    send_codec_inst_.pltype = send_codec.pltype;
+
+    // Check if a change in Rate is required.
+    if (send_codec.rate != send_codec_inst_.rate) {
+      if (codecs_[codec_id]->SetBitRate(send_codec.rate) < 0) {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                     "Could not change the codec rate.");
+        return -1;
+      }
+      send_codec_inst_.rate = send_codec.rate;
+    }
+
+    if (!codecs_[codec_id]->HasInternalFEC()) {
+      codec_fec_enabled_ = false;
+    } else {
+      if (codecs_[codec_id]->SetFEC(codec_fec_enabled_) < 0) {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
+                     "Cannot set codec FEC");
+        return -1;
+      }
+    }
+
+    return 0;
+  }
+}
+
+int CodecManager::SendCodec(CodecInst* current_codec) const {
+  int dummy_id = 0;
+  WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id,
+               "SendCodec()");
+
+  if (!current_encoder_) {
+    WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id,
+                 "SendCodec Failed, no codec is registered");
+    return -1;
+  }
+  WebRtcACMCodecParams encoder_param;
+  current_encoder_->EncoderParams(&encoder_param);
+  encoder_param.codec_inst.pltype = send_codec_inst_.pltype;
+  memcpy(current_codec, &(encoder_param.codec_inst), sizeof(CodecInst));
+
+  return 0;
+}
+
+// Register possible receive codecs, can be called multiple times,
+// for codecs, CNG (NB, WB and SWB), DTMF, RED.
+int CodecManager::RegisterReceiveCodec(const CodecInst& codec) {
+  if (codec.channels > 2 || codec.channels < 0) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
+                 "Unsupported number of channels, %d.", codec.channels);
+    return -1;
+  }
+
+  int mirror_id;
+  int codec_id = ACMCodecDB::ReceiverCodecNumber(codec, &mirror_id);
+
+  if (codec_id < 0 || codec_id >= ACMCodecDB::kNumCodecs) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
+                 "Wrong codec params to be registered as receive codec");
+    return -1;
+  }
+
+  // Check if the payload-type is valid.
+  if (!ACMCodecDB::ValidPayloadType(codec.pltype)) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
+                 "Invalid payload-type %d for %s.", codec.pltype, codec.plname);
+    return -1;
+  }
+
+  AudioDecoder* decoder = NULL;
+  // Get |decoder| associated with |codec|. |decoder| can be NULL if |codec|
+  // does not own its decoder.
+  if (GetAudioDecoder(codec, codec_id, mirror_id, &decoder) < 0) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
+                 "Wrong codec params to be registered as receive codec");
+    return -1;
+  }
+  uint8_t payload_type = static_cast<uint8_t>(codec.pltype);
+  return acm_->RegisterDecoder(codec_id, payload_type, codec.channels, decoder);
+}
+
+bool CodecManager::SetCopyRed(bool enable) {
+  if (enable && codec_fec_enabled_) {
+    WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
+                 "Codec internal FEC and RED cannot be co-enabled.");
+    return false;
+  }
+  if (current_encoder_ && current_encoder_->SetCopyRed(enable) < 0) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
+                 "SetCopyRed failed");
+    return false;
+  }
+  red_enabled_ = enable;
+  return true;
+}
+
+int CodecManager::SetVAD(bool enable_dtx, bool enable_vad, ACMVADMode mode) {
+  // Sanity check of the mode.
+  if ((mode != VADNormal) && (mode != VADLowBitrate) && (mode != VADAggr) &&
+      (mode != VADVeryAggr)) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
+                 "Invalid VAD Mode %d, no change is made to VAD/DTX status",
+                 mode);
+    return -1;
+  }
+
+  // Check that the send codec is mono. We don't support VAD/DTX for stereo
+  // sending.
+  if ((enable_dtx || enable_vad) && stereo_send_) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
+                 "VAD/DTX not supported for stereo sending");
+    dtx_enabled_ = false;
+    vad_enabled_ = false;
+    vad_mode_ = mode;
+    return -1;
+  }
+
+  // Store VAD/DTX settings. Values can be changed in the call to "SetVAD"
+  // below.
+  dtx_enabled_ = enable_dtx;
+  vad_enabled_ = enable_vad;
+  vad_mode_ = mode;
+
+  // If a send codec is registered, set VAD/DTX for the codec.
+  if (current_encoder_ &&
+      current_encoder_->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_) < 0) {
+    // SetVAD failed.
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
+                 "SetVAD failed");
+    vad_enabled_ = false;
+    dtx_enabled_ = false;
+    return -1;
+  }
+  return 0;
+}
+
+void CodecManager::VAD(bool* dtx_enabled,
+                       bool* vad_enabled,
+                       ACMVADMode* mode) const {
+  *dtx_enabled = dtx_enabled_;
+  *vad_enabled = vad_enabled_;
+  *mode = vad_mode_;
+}
+
+int CodecManager::SetCodecFEC(bool enable_codec_fec) {
+  if (enable_codec_fec == true && red_enabled_ == true) {
+    WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
+                 "Codec internal FEC and RED cannot be co-enabled.");
+    return -1;
+  }
+
+  // Set codec FEC.
+  if (current_encoder_ && current_encoder_->SetFEC(enable_codec_fec) < 0) {
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
+                 "Set codec internal FEC failed.");
+    return -1;
+  }
+  codec_fec_enabled_ = enable_codec_fec;
+  return 0;
+}
+
+void CodecManager::SetCngPayloadType(int sample_rate_hz, int payload_type) {
+  for (auto* codec : codecs_) {
+    if (codec) {
+      codec->SetCngPt(sample_rate_hz, payload_type);
+    }
+  }
+}
+
+void CodecManager::SetRedPayloadType(int sample_rate_hz, int payload_type) {
+  for (auto* codec : codecs_) {
+    if (codec) {
+      codec->SetRedPt(sample_rate_hz, payload_type);
+    }
+  }
+}
+
+int CodecManager::GetAudioDecoder(const CodecInst& codec,
+                                  int codec_id,
+                                  int mirror_id,
+                                  AudioDecoder** decoder) {
+  if (ACMCodecDB::OwnsDecoder(codec_id)) {
+    // This codec has to own its own decoder. Therefore, it should create the
+    // corresponding AudioDecoder class and insert it into NetEq. If the codec
+    // does not exist create it.
+    //
+    // TODO(turajs): this part of the code is common with RegisterSendCodec(),
+    //               make a method for it.
+    if (codecs_[mirror_id] == NULL) {
+      codecs_[mirror_id] = ACMCodecDB::CreateCodecInstance(
+          codec, cng_nb_pltype_, cng_wb_pltype_, cng_swb_pltype_,
+          cng_fb_pltype_, red_enabled_, red_nb_pltype_);
+      if (codecs_[mirror_id] == NULL) {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
+                     "Cannot Create the codec");
+        return -1;
+      }
+      mirror_codec_idx_[mirror_id] = mirror_id;
+    }
+
+    if (mirror_id != codec_id) {
+      codecs_[codec_id] = codecs_[mirror_id];
+      mirror_codec_idx_[codec_id] = mirror_id;
+    }
+    *decoder = codecs_[codec_id]->Decoder();
+    if (!*decoder) {
+      assert(false);
+      return -1;
+    }
+  } else {
+    *decoder = NULL;
+  }
+
+  return 0;
+}
+
+}  // namespace acm2
+}  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.h b/webrtc/modules/audio_coding/main/acm2/codec_manager.h
new file mode 100644
index 0000000..8d5350d
--- /dev/null
+++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.h
@@ -0,0 +1,101 @@
+/*
+ *  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_MAIN_ACM2_CODEC_MANAGER_H_
+#define WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_CODEC_MANAGER_H_
+
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/base/thread_checker.h"
+#include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h"
+#include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h"
+#include "webrtc/common_types.h"
+
+namespace webrtc {
+
+class AudioDecoder;
+
+namespace acm2 {
+
+class ACMGenericCodec;
+class AudioCodingModuleImpl;
+
+class CodecManager final {
+ public:
+  explicit CodecManager(AudioCodingModuleImpl* acm);
+  ~CodecManager();
+
+  int RegisterSendCodec(const CodecInst& send_codec);
+
+  int SendCodec(CodecInst* current_codec) const;
+
+  int RegisterReceiveCodec(const CodecInst& receive_codec);
+
+  bool SetCopyRed(bool enable);
+
+  int SetVAD(bool enable_dtx, bool enable_vad, ACMVADMode mode);
+
+  void VAD(bool* dtx_enabled, bool* vad_enabled, ACMVADMode* mode) const;
+
+  int SetCodecFEC(bool enable_codec_fec);
+
+  bool stereo_send() const { return stereo_send_; }
+
+  bool red_enabled() const { return red_enabled_; }
+
+  bool codec_fec_enabled() const { return codec_fec_enabled_; }
+
+  ACMGenericCodec* current_encoder() { return current_encoder_; }
+
+  const ACMGenericCodec* current_encoder() const { return current_encoder_; }
+
+ private:
+  void SetCngPayloadType(int sample_rate_hz, int payload_type);
+
+  void SetRedPayloadType(int sample_rate_hz, int payload_type);
+
+  // Get a pointer to AudioDecoder of the given codec. For some codecs, e.g.
+  // iSAC, encoding and decoding have to be performed on a shared
+  // codec-instance. By calling this method, we get the codec-instance that ACM
+  // owns, then pass that to NetEq. This way, we perform both encoding and
+  // decoding on the same codec-instance. Furthermore, ACM would have control
+  // over decoder functionality if required. If |codec| does not share an
+  // instance between encoder and decoder, the |*decoder| is set NULL.
+  // The field ACMCodecDB::CodecSettings.owns_decoder indicates that if a
+  // codec owns the decoder-instance. For such codecs |*decoder| should be a
+  // valid pointer, otherwise it will be NULL.
+  int GetAudioDecoder(const CodecInst& codec,
+                      int codec_id,
+                      int mirror_id,
+                      AudioDecoder** decoder);
+
+  AudioCodingModuleImpl* acm_;
+  rtc::ThreadChecker thread_checker_;
+  uint8_t cng_nb_pltype_;
+  uint8_t cng_wb_pltype_;
+  uint8_t cng_swb_pltype_;
+  uint8_t cng_fb_pltype_;
+  uint8_t red_nb_pltype_;
+  bool stereo_send_;
+  bool vad_enabled_;
+  bool dtx_enabled_;
+  ACMVADMode vad_mode_;
+  ACMGenericCodec* current_encoder_;
+  CodecInst send_codec_inst_;
+  bool red_enabled_;
+  bool codec_fec_enabled_;
+  ACMGenericCodec* codecs_[ACMCodecDB::kMaxNumCodecs];
+  int mirror_codec_idx_[ACMCodecDB::kMaxNumCodecs];
+
+  DISALLOW_COPY_AND_ASSIGN(CodecManager);
+};
+
+}  // namespace acm2
+}  // namespace webrtc
+#endif  // WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_CODEC_MANAGER_H_
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 014b9f3..796444e 100644
--- a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h
+++ b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h
@@ -191,20 +191,6 @@
   //
 
   ///////////////////////////////////////////////////////////////////////////
-  // int32_t InitializeSender()
-  // Any encoder-related state of ACM will be initialized to the
-  // same state when ACM is created. This will not interrupt or
-  // effect decoding functionality of ACM. ACM will lose all the
-  // encoding-related settings by calling this function.
-  // For instance, a send codec has to be registered again.
-  //
-  // Return value:
-  //   -1 if failed to initialize,
-  //    0 if succeeded.
-  //
-  virtual int32_t InitializeSender() = 0;
-
-  ///////////////////////////////////////////////////////////////////////////
   // int32_t ResetEncoder()
   // This API resets the states of encoder. All the encoder settings, such as
   // send-codec or VAD/DTX, will be preserved.
diff --git a/webrtc/modules/audio_coding/main/test/APITest.cc b/webrtc/modules/audio_coding/main/test/APITest.cc
index ccb5c59..1cdf6c7 100644
--- a/webrtc/modules/audio_coding/main/test/APITest.cc
+++ b/webrtc/modules/audio_coding/main/test/APITest.cc
@@ -1144,9 +1144,6 @@
         WriteLockScoped wl(_apiTestRWLock);
         *thereIsEncoder = false;
       }
-      CHECK_ERROR_MT(myACM->InitializeSender());
-      Wait(1000);
-
       // After Initialization CN is lost, re-register them
       if (AudioCodingModule::Codec("CN", &myCodec, 8000, 1) >= 0) {
         CHECK_ERROR_MT(myACM->RegisterSendCodec(myCodec));
diff --git a/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc b/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc
index b785cc3..8394bc0 100644
--- a/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc
+++ b/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc
@@ -53,7 +53,6 @@
 
 void Sender::Setup(AudioCodingModule *acm, RTPStream *rtpStream,
                    std::string in_file_name, int sample_rate, int channels) {
-  acm->InitializeSender();
   struct CodecInst sendCodec;
   int noOfCodecs = acm->NumberOfCodecs();
   int codecNo;
diff --git a/webrtc/modules/audio_coding/main/test/TwoWayCommunication.cc b/webrtc/modules/audio_coding/main/test/TwoWayCommunication.cc
index f4db1db..1014fc9 100644
--- a/webrtc/modules/audio_coding/main/test/TwoWayCommunication.cc
+++ b/webrtc/modules/audio_coding/main/test/TwoWayCommunication.cc
@@ -281,7 +281,6 @@
   // In the middle of a session with data flowing between two sides, called A
   // and B, APIs will be called, like ResetEncoder(), and the code should
   // continue to run, and be able to recover.
-  bool expect_error_add = false;
   while (!_inFileA.EndOfFile() && !_inFileB.EndOfFile()) {
     msecPassed += 10;
     EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
@@ -290,12 +289,7 @@
 
     EXPECT_GT(_inFileB.Read10MsData(audioFrame), 0);
 
-    // Expect call to pass except for the time when no send codec is registered.
-    if (!expect_error_add) {
-      EXPECT_GE(_acmB->Add10MsData(audioFrame), 0);
-    } else {
-      EXPECT_EQ(-1, _acmB->Add10MsData(audioFrame));
-    }
+    EXPECT_GE(_acmB->Add10MsData(audioFrame), 0);
     EXPECT_GE(_acmRefB->Add10MsData(audioFrame), 0);
     EXPECT_EQ(0, _acmA->PlayoutData10Ms(outFreqHzA, &audioFrame));
     _outFileA.Write10MsData(audioFrame);
@@ -315,14 +309,11 @@
     // side B.
     if (((secPassed % 5) == 4) && (msecPassed == 0)) {
       EXPECT_EQ(0, _acmA->ResetEncoder());
-      EXPECT_EQ(0, _acmB->InitializeSender());
-      expect_error_add = true;
     }
     // Re-register send codec on side B.
     if (((secPassed % 5) == 4) && (msecPassed >= 990)) {
       EXPECT_EQ(0, _acmB->RegisterSendCodec(codecInst_B));
       EXPECT_EQ(0, _acmB->SendCodec(&dummy));
-      expect_error_add = false;
     }
     // Reset decoder on side B, and initialize receiver on side A.
     if (((secPassed % 7) == 6) && (msecPassed == 0)) {
diff --git a/webrtc/modules/utility/source/coder.cc b/webrtc/modules/utility/source/coder.cc
index b106c75..dc0799a 100644
--- a/webrtc/modules/utility/source/coder.cc
+++ b/webrtc/modules/utility/source/coder.cc
@@ -21,7 +21,6 @@
       _encodedLengthInBytes(0),
       _decodeTimestamp(0)
 {
-    _acm->InitializeSender();
     _acm->InitializeReceiver();
     _acm->RegisterTransportCallback(this);
 }
diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc
index 719cc35..472ed8b 100644
--- a/webrtc/voice_engine/channel.cc
+++ b/webrtc/voice_engine/channel.cc
@@ -953,12 +953,12 @@
 
     // --- ACM initialization
 
-    if ((audio_coding_->InitializeReceiver() == -1) ||
+    if ((audio_coding_->InitializeReceiver() == -1)
 #ifdef WEBRTC_CODEC_AVT
         // out-of-band Dtmf tones are played out by default
-        (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
+        || (audio_coding_->SetDtmfPlayoutStatus(true) == -1)
 #endif
-        (audio_coding_->InitializeSender() == -1))
+       )
     {
         _engineStatisticsPtr->SetLastError(
             VE_AUDIO_CODING_MODULE_ERROR, kTraceError,