Reland r8248 "Introduce ACMGenericCodecWrapper"

This effectively reverts r8249.

This new class inherits from ACMGenericCodec. The purpose is to wrap
AudioEncoder objects into an ACMGenericCodec interface. This is a
temporary construction that will be used during the ACM redesign work.

BUG=4228
COAUTHOR=kwiberg@webrtc.org
TBR=tina.legrand@webrtc.org

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

Cr-Commit-Position: refs/heads/master@{#8255}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8255 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.cc b/webrtc/modules/audio_coding/codecs/audio_encoder.cc
index 20e5953..ae1bce1 100644
--- a/webrtc/modules/audio_coding/codecs/audio_encoder.cc
+++ b/webrtc/modules/audio_coding/codecs/audio_encoder.cc
@@ -9,6 +9,7 @@
  */
 
 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
+#include "webrtc/base/checks.h"
 
 namespace webrtc {
 
@@ -18,6 +19,20 @@
 AudioEncoder::EncodedInfo::~EncodedInfo() {
 }
 
+bool AudioEncoder::Encode(uint32_t rtp_timestamp,
+                          const int16_t* audio,
+                          size_t num_samples_per_channel,
+                          size_t max_encoded_bytes,
+                          uint8_t* encoded,
+                          EncodedInfo* info) {
+  CHECK_EQ(num_samples_per_channel,
+           static_cast<size_t>(sample_rate_hz() / 100));
+  bool ret =
+      EncodeInternal(rtp_timestamp, audio, max_encoded_bytes, encoded, info);
+  CHECK_LE(info->encoded_bytes, max_encoded_bytes);
+  return ret;
+}
+
 int AudioEncoder::rtp_timestamp_rate_hz() const {
   return sample_rate_hz();
 }
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.h b/webrtc/modules/audio_coding/codecs/audio_encoder.h
index 9b0c11b..6fc5827 100644
--- a/webrtc/modules/audio_coding/codecs/audio_encoder.h
+++ b/webrtc/modules/audio_coding/codecs/audio_encoder.h
@@ -14,7 +14,6 @@
 #include <algorithm>
 #include <vector>
 
-#include "webrtc/base/checks.h"
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
@@ -63,14 +62,7 @@
               size_t num_samples_per_channel,
               size_t max_encoded_bytes,
               uint8_t* encoded,
-              EncodedInfo* info) {
-    CHECK_EQ(num_samples_per_channel,
-             static_cast<size_t>(sample_rate_hz() / 100));
-    bool ret =
-        EncodeInternal(rtp_timestamp, audio, max_encoded_bytes, encoded, info);
-    CHECK_LE(info->encoded_bytes, max_encoded_bytes);
-    return ret;
-  }
+              EncodedInfo* info);
 
   // Return the input sample rate in Hz and the number of input channels.
   // These are constants set at instantiation time.
diff --git a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
index 5b072e4..c2f6424 100644
--- a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
+++ b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
@@ -12,6 +12,7 @@
 
 #include <limits>
 
+#include "webrtc/base/checks.h"
 #include "webrtc/modules/audio_coding/codecs/g711/include/g711_interface.h"
 
 namespace webrtc {
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 4982e5a..2727611 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
@@ -11,6 +11,7 @@
 #ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_INTERFACE_AUDIO_ENCODER_ISACFIX_H_
 #define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_INTERFACE_AUDIO_ENCODER_ISACFIX_H_
 
+#include "webrtc/base/checks.h"
 #include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h"
 #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.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 41ed490..4ab88b6 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
@@ -11,6 +11,7 @@
 #ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_AUDIO_ENCODER_ISAC_H_
 #define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_AUDIO_ENCODER_ISAC_H_
 
+#include "webrtc/base/checks.h"
 #include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h"
 #include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h"
 
diff --git a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
index c3d5601..2b0fb91 100644
--- a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
+++ b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
@@ -12,6 +12,8 @@
 
 #include <string.h>
 
+#include "webrtc/base/checks.h"
+
 namespace webrtc {
 
 AudioEncoderCopyRed::AudioEncoderCopyRed(const Config& config)
diff --git a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc
index 35a8b2f..de1339d 100644
--- a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc
@@ -9,6 +9,7 @@
  */
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/checks.h"
 #include "webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h"
 #include "webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h"
 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
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 209d589..c65e053 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc
@@ -12,15 +12,59 @@
 
 #include <assert.h>
 #include <string.h>
+#include <algorithm>
+#include <utility>
 
+#include "webrtc/base/checks.h"
 #include "webrtc/common_audio/vad/include/webrtc_vad.h"
+#include "webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h"
 #include "webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h"
+#include "webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h"
+#include "webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h"
+#include "webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h"
+#include "webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h"
+#include "webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h"
+#include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h"
+#include "webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h"
+#include "webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.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/system_wrappers/interface/trace.h"
 
 namespace webrtc {
 
+namespace {
+static const int kInvalidPayloadType = 255;
+
+void SetCngPtInMap(
+    std::map<int, std::pair<int, WebRtcACMEncodingType>>* cng_pt_map,
+    int sample_rate_hz,
+    int payload_type) {
+  if (payload_type == kInvalidPayloadType)
+    return;
+  CHECK_GE(payload_type, 0);
+  CHECK_LT(payload_type, 128);
+  WebRtcACMEncodingType encoding_type;
+  switch (sample_rate_hz) {
+    case 8000:
+      encoding_type = kPassiveDTXNB;
+      break;
+    case 16000:
+      encoding_type = kPassiveDTXWB;
+      break;
+    case 32000:
+      encoding_type = kPassiveDTXSWB;
+      break;
+    case 48000:
+      encoding_type = kPassiveDTXFB;
+      break;
+    default:
+      FATAL() << "Unsupported frequency.";
+  }
+  (*cng_pt_map)[payload_type] = std::make_pair(sample_rate_hz, encoding_type);
+}
+}  // namespace
+
 namespace acm2 {
 
 // Enum for CNG
@@ -216,7 +260,8 @@
 int16_t ACMGenericCodec::Encode(uint8_t* bitstream,
                                 int16_t* bitstream_len_byte,
                                 uint32_t* timestamp,
-                                WebRtcACMEncodingType* encoding_type) {
+                                WebRtcACMEncodingType* encoding_type,
+                                AudioEncoder::EncodedInfo* /*encoded_info*/) {
   if (!HasFrameToEncode()) {
     // There is not enough audio
     *timestamp = 0;
@@ -651,6 +696,9 @@
   return SetVADSafe(enable_dtx, enable_vad, mode);
 }
 
+void ACMGenericCodec::SetCngPt(int sample_rate_hz, int payload_type) {
+}
+
 int16_t ACMGenericCodec::SetVADSafe(bool* enable_dtx,
                                     bool* enable_vad,
                                     ACMVADMode* mode) {
@@ -1022,6 +1070,663 @@
   return -1;
 }
 
+AudioDecoderProxy::AudioDecoderProxy()
+    : decoder_lock_(CriticalSectionWrapper::CreateCriticalSection()),
+      decoder_(nullptr) {
+}
+
+void AudioDecoderProxy::SetDecoder(AudioDecoder* decoder) {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  decoder_ = decoder;
+  channels_ = decoder->channels();
+  CHECK_EQ(decoder_->Init(), 0);
+}
+
+bool AudioDecoderProxy::IsSet() const {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return (decoder_ != nullptr);
+}
+
+int AudioDecoderProxy::Decode(const uint8_t* encoded,
+                              size_t encoded_len,
+                              int16_t* decoded,
+                              SpeechType* speech_type) {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->Decode(encoded, encoded_len, decoded, speech_type);
+}
+
+int AudioDecoderProxy::DecodeRedundant(const uint8_t* encoded,
+                                       size_t encoded_len,
+                                       int16_t* decoded,
+                                       SpeechType* speech_type) {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->DecodeRedundant(encoded, encoded_len, decoded, speech_type);
+}
+
+bool AudioDecoderProxy::HasDecodePlc() const {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->HasDecodePlc();
+}
+
+int AudioDecoderProxy::DecodePlc(int num_frames, int16_t* decoded) {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->DecodePlc(num_frames, decoded);
+}
+
+int AudioDecoderProxy::Init() {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->Init();
+}
+
+int AudioDecoderProxy::IncomingPacket(const uint8_t* payload,
+                                      size_t payload_len,
+                                      uint16_t rtp_sequence_number,
+                                      uint32_t rtp_timestamp,
+                                      uint32_t arrival_timestamp) {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->IncomingPacket(payload, payload_len, rtp_sequence_number,
+                                  rtp_timestamp, arrival_timestamp);
+}
+
+int AudioDecoderProxy::ErrorCode() {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->ErrorCode();
+}
+
+int AudioDecoderProxy::PacketDuration(const uint8_t* encoded,
+                                      size_t encoded_len) {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->PacketDuration(encoded, encoded_len);
+}
+
+int AudioDecoderProxy::PacketDurationRedundant(const uint8_t* encoded,
+                                               size_t encoded_len) const {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->PacketDurationRedundant(encoded, encoded_len);
+}
+
+bool AudioDecoderProxy::PacketHasFec(const uint8_t* encoded,
+                                     size_t encoded_len) const {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->PacketHasFec(encoded, encoded_len);
+}
+
+CNG_dec_inst* AudioDecoderProxy::CngDecoderInstance() {
+  CriticalSectionScoped decoder_lock(decoder_lock_.get());
+  return decoder_->CngDecoderInstance();
+}
+
+////////////////////////////////////////
+// ACMGenericCodecWrapper implementation
+
+ACMGenericCodecWrapper::ACMGenericCodecWrapper(const CodecInst& codec_inst,
+                                               int cng_pt_nb,
+                                               int cng_pt_wb,
+                                               int cng_pt_swb,
+                                               int cng_pt_fb,
+                                               bool enable_red,
+                                               int red_payload_type)
+    : ACMGenericCodec(enable_red),
+      encoder_(NULL),
+      bitrate_bps_(0),
+      fec_enabled_(false),
+      loss_rate_(0),
+      max_playback_rate_hz_(48000),
+      max_payload_size_bytes_(-1),
+      max_rate_bps_(-1),
+      is_opus_(false),
+      is_isac_(false),
+      first_frame_(true),
+      red_payload_type_(red_payload_type),
+      opus_application_set_(false) {
+  acm_codec_params_.codec_inst = codec_inst;
+  acm_codec_params_.enable_dtx = false;
+  acm_codec_params_.enable_vad = false;
+  acm_codec_params_.vad_mode = VADNormal;
+  SetCngPtInMap(&cng_pt_, 8000, cng_pt_nb);
+  SetCngPtInMap(&cng_pt_, 16000, cng_pt_wb);
+  SetCngPtInMap(&cng_pt_, 32000, cng_pt_swb);
+  SetCngPtInMap(&cng_pt_, 48000, cng_pt_fb);
+  ResetAudioEncoder();
+  CHECK(encoder_);
+}
+
+ACMGenericCodec* ACMGenericCodecWrapper::CreateInstance() {
+  FATAL();
+  return 0;
+}
+
+int16_t ACMGenericCodecWrapper::Encode(
+    uint8_t* bitstream,
+    int16_t* bitstream_len_byte,
+    uint32_t* timestamp,
+    WebRtcACMEncodingType* encoding_type,
+    AudioEncoder::EncodedInfo* encoded_info) {
+  WriteLockScoped wl(codec_wrapper_lock_);
+  CHECK(!input_.empty());
+  CHECK(encoder_->Encode(rtp_timestamp_, &input_[0],
+                         input_.size() / encoder_->num_channels(),
+                         2 * MAX_PAYLOAD_SIZE_BYTE, bitstream, encoded_info));
+  input_.clear();
+  *bitstream_len_byte = static_cast<int16_t>(encoded_info->encoded_bytes);
+  if (encoded_info->encoded_bytes == 0) {
+    *encoding_type = kNoEncoding;
+    return 0;
+  }
+  *timestamp = encoded_info->encoded_timestamp;
+
+  int payload_type = encoded_info->payload_type;
+  if (!encoded_info->redundant.empty())
+    payload_type = encoded_info->redundant[0].payload_type;
+
+  auto cng_iter = cng_pt_.find(payload_type);
+  if (cng_iter == cng_pt_.end()) {
+    *encoding_type = kActiveNormalEncoded;
+  } else {
+    *encoding_type = cng_iter->second.second;
+  }
+  return *bitstream_len_byte;
+}
+
+bool ACMGenericCodecWrapper::EncoderInitialized() {
+  FATAL();
+  return 0;
+}
+
+int16_t ACMGenericCodecWrapper::EncoderParams(
+    WebRtcACMCodecParams* enc_params) {
+  ReadLockScoped rl(codec_wrapper_lock_);
+  *enc_params = acm_codec_params_;
+  return 0;
+}
+
+int16_t ACMGenericCodecWrapper::InitEncoder(WebRtcACMCodecParams* codec_params,
+                                            bool force_initialization) {
+  WriteLockScoped wl(codec_wrapper_lock_);
+  bitrate_bps_ = 0;
+  loss_rate_ = 0;
+  acm_codec_params_ = *codec_params;
+  if (force_initialization)
+    opus_application_set_ = false;
+  opus_application_ = GetOpusApplication(codec_params->codec_inst.channels);
+  opus_application_set_ = true;
+  ResetAudioEncoder();
+  return 0;
+}
+
+void ACMGenericCodecWrapper::ResetAudioEncoder() {
+  const CodecInst& codec_inst = acm_codec_params_.codec_inst;
+  bool using_codec_internal_red = false;
+  if (!STR_CASE_CMP(codec_inst.plname, "PCMU")) {
+    AudioEncoderPcmU::Config config;
+    config.num_channels = codec_inst.channels;
+    config.frame_size_ms = codec_inst.pacsize / 8;
+    config.payload_type = codec_inst.pltype;
+    audio_encoder_.reset(new AudioEncoderPcmU(config));
+  } else if (!STR_CASE_CMP(codec_inst.plname, "PCMA")) {
+    AudioEncoderPcmA::Config config;
+    config.num_channels = codec_inst.channels;
+    config.frame_size_ms = codec_inst.pacsize / 8;
+    config.payload_type = codec_inst.pltype;
+    audio_encoder_.reset(new AudioEncoderPcmA(config));
+#ifdef WEBRTC_CODEC_PCM16
+  } else if (!STR_CASE_CMP(codec_inst.plname, "L16")) {
+    AudioEncoderPcm16B::Config config;
+    config.num_channels = codec_inst.channels;
+    config.sample_rate_hz = codec_inst.plfreq;
+    config.frame_size_ms = codec_inst.pacsize / (config.sample_rate_hz / 1000);
+    config.payload_type = codec_inst.pltype;
+    audio_encoder_.reset(new AudioEncoderPcm16B(config));
+#endif
+#ifdef WEBRTC_CODEC_ILBC
+  } else if (!STR_CASE_CMP(codec_inst.plname, "ILBC")) {
+    AudioEncoderIlbc::Config config;
+    config.frame_size_ms = codec_inst.pacsize / 8;
+    config.payload_type = codec_inst.pltype;
+    audio_encoder_.reset(new AudioEncoderIlbc(config));
+#endif
+#ifdef WEBRTC_CODEC_OPUS
+  } else if (!STR_CASE_CMP(codec_inst.plname, "opus")) {
+    is_opus_ = true;
+    has_internal_fec_ = true;
+    AudioEncoderOpus::Config config;
+    config.frame_size_ms = codec_inst.pacsize / 48;
+    config.num_channels = codec_inst.channels;
+    config.fec_enabled = fec_enabled_;
+    config.bitrate_bps = codec_inst.rate;
+    config.max_playback_rate_hz = max_playback_rate_hz_;
+    config.payload_type = codec_inst.pltype;
+    switch (GetOpusApplication(config.num_channels)) {
+      case kVoip:
+        config.application = AudioEncoderOpus::ApplicationMode::kVoip;
+        break;
+      case kAudio:
+        config.application = AudioEncoderOpus::ApplicationMode::kAudio;
+        break;
+    }
+    audio_encoder_.reset(new AudioEncoderOpus(config));
+#endif
+#ifdef WEBRTC_CODEC_G722
+  } else if (!STR_CASE_CMP(codec_inst.plname, "G722")) {
+    AudioEncoderG722::Config config;
+    config.num_channels = codec_inst.channels;
+    config.frame_size_ms = codec_inst.pacsize / 16;
+    config.payload_type = codec_inst.pltype;
+    audio_encoder_.reset(new AudioEncoderG722(config));
+#endif
+#ifdef WEBRTC_CODEC_ISACFX
+  } else if (!STR_CASE_CMP(codec_inst.plname, "ISAC")) {
+    DCHECK_EQ(codec_inst.plfreq, 16000);
+    is_isac_ = true;
+    AudioEncoderDecoderIsacFix* enc_dec;
+    if (codec_inst.rate == -1) {
+      // Adaptive mode.
+      AudioEncoderDecoderIsacFix::ConfigAdaptive config;
+      config.payload_type = codec_inst.pltype;
+      enc_dec = new AudioEncoderDecoderIsacFix(config);
+    } else {
+      // Channel independent mode.
+      AudioEncoderDecoderIsacFix::Config config;
+      config.bit_rate = codec_inst.rate;
+      config.frame_size_ms = codec_inst.pacsize / 16;
+      config.payload_type = codec_inst.pltype;
+      enc_dec = new AudioEncoderDecoderIsacFix(config);
+    }
+    audio_encoder_.reset(enc_dec);
+    decoder_proxy_.SetDecoder(enc_dec);
+#endif
+#ifdef WEBRTC_CODEC_ISAC
+  } else if (!STR_CASE_CMP(codec_inst.plname, "ISAC")) {
+    is_isac_ = true;
+    if (copy_red_enabled_) {
+      using_codec_internal_red = true;
+      AudioEncoderDecoderIsacRed* enc_dec;
+      if (codec_inst.rate == -1) {
+        // Adaptive mode.
+        AudioEncoderDecoderIsacRed::ConfigAdaptive config;
+        config.sample_rate_hz = codec_inst.plfreq;
+        config.initial_frame_size_ms = rtc::CheckedDivExact(
+            1000 * codec_inst.pacsize, config.sample_rate_hz);
+        config.max_payload_size_bytes = max_payload_size_bytes_;
+        config.max_bit_rate = max_rate_bps_;
+        config.payload_type = codec_inst.pltype;
+        config.red_payload_type = red_payload_type_;
+        enc_dec = new AudioEncoderDecoderIsacRed(config);
+      } else {
+        // Channel independent mode.
+        AudioEncoderDecoderIsacRed::Config config;
+        config.sample_rate_hz = codec_inst.plfreq;
+        config.bit_rate = codec_inst.rate;
+        config.frame_size_ms = rtc::CheckedDivExact(1000 * codec_inst.pacsize,
+                                                    config.sample_rate_hz);
+        config.max_payload_size_bytes = max_payload_size_bytes_;
+        config.max_bit_rate = max_rate_bps_;
+        config.payload_type = codec_inst.pltype;
+        config.red_payload_type = red_payload_type_;
+        enc_dec = new AudioEncoderDecoderIsacRed(config);
+      }
+      audio_encoder_.reset(enc_dec);
+      decoder_proxy_.SetDecoder(enc_dec);
+    } else {
+      AudioEncoderDecoderIsac* enc_dec;
+      if (codec_inst.rate == -1) {
+        // Adaptive mode.
+        AudioEncoderDecoderIsac::ConfigAdaptive config;
+        config.sample_rate_hz = codec_inst.plfreq;
+        config.initial_frame_size_ms = rtc::CheckedDivExact(
+            1000 * codec_inst.pacsize, config.sample_rate_hz);
+        config.max_payload_size_bytes = max_payload_size_bytes_;
+        config.max_bit_rate = max_rate_bps_;
+        config.payload_type = codec_inst.pltype;
+        enc_dec = new AudioEncoderDecoderIsac(config);
+      } else {
+        // Channel independent mode.
+        AudioEncoderDecoderIsac::Config config;
+        config.sample_rate_hz = codec_inst.plfreq;
+        config.bit_rate = codec_inst.rate;
+        config.frame_size_ms = rtc::CheckedDivExact(1000 * codec_inst.pacsize,
+                                                    config.sample_rate_hz);
+        config.max_payload_size_bytes = max_payload_size_bytes_;
+        config.max_bit_rate = max_rate_bps_;
+        config.payload_type = codec_inst.pltype;
+        enc_dec = new AudioEncoderDecoderIsac(config);
+      }
+      audio_encoder_.reset(enc_dec);
+      decoder_proxy_.SetDecoder(enc_dec);
+    }
+#endif
+  } else {
+    FATAL();
+  }
+  if (bitrate_bps_ != 0)
+    audio_encoder_->SetTargetBitrate(bitrate_bps_);
+  audio_encoder_->SetProjectedPacketLossRate(loss_rate_ / 100.0);
+  encoder_ = audio_encoder_.get();
+
+  // Attach RED if needed.
+  if (copy_red_enabled_ && !using_codec_internal_red) {
+    CHECK_NE(red_payload_type_, kInvalidPayloadType);
+    AudioEncoderCopyRed::Config config;
+    config.payload_type = red_payload_type_;
+    config.speech_encoder = encoder_;
+    red_encoder_.reset(new AudioEncoderCopyRed(config));
+    encoder_ = red_encoder_.get();
+  } else {
+    red_encoder_.reset();
+  }
+
+  // Attach CNG if needed.
+  // Reverse-lookup from sample rate to complete key-value pair.
+  const int sample_rate_hz = audio_encoder_->sample_rate_hz();
+  // Create a local const reference to cng_pt_. The reason is that GCC doesn't
+  // accept using "const decltype(...)" for the argument in the lambda below.
+  const auto& cng_pt = cng_pt_;
+  auto pt_iter = find_if(cng_pt.begin(), cng_pt.end(),
+                         [sample_rate_hz](decltype(*cng_pt.begin()) p) {
+    return p.second.first == sample_rate_hz;
+  });
+  if (acm_codec_params_.enable_dtx && pt_iter != cng_pt_.end()) {
+    AudioEncoderCng::Config config;
+    config.num_channels = acm_codec_params_.codec_inst.channels;
+    config.payload_type = pt_iter->first;
+    config.speech_encoder = encoder_;
+    switch (acm_codec_params_.vad_mode) {
+      case VADNormal:
+        config.vad_mode = Vad::kVadNormal;
+        break;
+      case VADLowBitrate:
+        config.vad_mode = Vad::kVadLowBitrate;
+        break;
+      case VADAggr:
+        config.vad_mode = Vad::kVadAggressive;
+        break;
+      case VADVeryAggr:
+        config.vad_mode = Vad::kVadVeryAggressive;
+        break;
+      default:
+        FATAL();
+    }
+    cng_encoder_.reset(new AudioEncoderCng(config));
+    encoder_ = cng_encoder_.get();
+  } else {
+    cng_encoder_.reset();
+  }
+}
+
+OpusApplicationMode ACMGenericCodecWrapper::GetOpusApplication(
+    int num_channels) const {
+  if (opus_application_set_)
+    return opus_application_;
+  return num_channels == 1 ? kVoip : kAudio;
+}
+
+int32_t ACMGenericCodecWrapper::Add10MsData(const uint32_t timestamp,
+                                            const int16_t* data,
+                                            const uint16_t length_per_channel,
+                                            const uint8_t audio_channel) {
+  WriteLockScoped wl(codec_wrapper_lock_);
+  CHECK(input_.empty());
+  CHECK_EQ(length_per_channel, encoder_->sample_rate_hz() / 100);
+  for (int i = 0; i < length_per_channel * encoder_->num_channels(); ++i) {
+    input_.push_back(data[i]);
+  }
+  rtp_timestamp_ = first_frame_
+                       ? timestamp
+                       : last_rtp_timestamp_ +
+                             rtc::CheckedDivExact(
+                                 timestamp - last_timestamp_,
+                                 static_cast<uint32_t>(rtc::CheckedDivExact(
+                                     audio_encoder_->sample_rate_hz(),
+                                     audio_encoder_->rtp_timestamp_rate_hz())));
+  last_timestamp_ = timestamp;
+  last_rtp_timestamp_ = rtp_timestamp_;
+  first_frame_ = false;
+
+  CHECK_EQ(audio_channel, encoder_->num_channels());
+  return 0;
+}
+
+uint32_t ACMGenericCodecWrapper::NoMissedSamples() const {
+  FATAL();
+  return 0;
+}
+
+void ACMGenericCodecWrapper::ResetNoMissedSamples() {
+  FATAL();
+}
+
+int16_t ACMGenericCodecWrapper::SetBitRate(const int32_t bitrate_bps) {
+  WriteLockScoped wl(codec_wrapper_lock_);
+  encoder_->SetTargetBitrate(bitrate_bps);
+  bitrate_bps_ = bitrate_bps;
+  return 0;
+}
+
+uint32_t ACMGenericCodecWrapper::EarliestTimestamp() const {
+  FATAL();
+  return 0;
+}
+
+int16_t ACMGenericCodecWrapper::SetVAD(bool* enable_dtx,
+                                       bool* enable_vad,
+                                       ACMVADMode* mode) {
+  WriteLockScoped wl(codec_wrapper_lock_);
+  if (is_opus_) {
+    *enable_dtx = false;
+    *enable_vad = false;
+    return 0;
+  }
+  // Note: |enable_vad| is not used; VAD is enabled based on the DTX setting and
+  // the |enable_vad| is set equal to |enable_dtx|.
+  // The case when VAD is enabled but DTX is disabled may result in a
+  // kPassiveNormalEncoded frame type, but this is not a case that VoE
+  // distinguishes from the cases where DTX is in fact used. In the case where
+  // DTX is enabled but VAD is disabled, the comment in the ACM interface states
+  // that VAD will be enabled anyway.
+  DCHECK_EQ(*enable_dtx, *enable_vad);
+  *enable_vad = *enable_dtx;
+  acm_codec_params_.enable_dtx = *enable_dtx;
+  acm_codec_params_.enable_vad = *enable_vad;
+  acm_codec_params_.vad_mode = *mode;
+  if (acm_codec_params_.enable_dtx && !cng_encoder_) {
+    ResetAudioEncoder();
+  } else if (!acm_codec_params_.enable_dtx && cng_encoder_) {
+    cng_encoder_.reset();
+    encoder_ = audio_encoder_.get();
+  }
+  return 0;
+}
+
+void ACMGenericCodecWrapper::SetCngPt(int sample_rate_hz, int payload_type) {
+  WriteLockScoped wl(codec_wrapper_lock_);
+  SetCngPtInMap(&cng_pt_, sample_rate_hz, payload_type);
+  ResetAudioEncoder();
+}
+
+int32_t ACMGenericCodecWrapper::ReplaceInternalDTX(
+    const bool replace_internal_dtx) {
+  FATAL();
+  return 0;
+}
+
+int32_t ACMGenericCodecWrapper::GetEstimatedBandwidth() {
+  FATAL();
+  return 0;
+}
+
+int32_t ACMGenericCodecWrapper::SetEstimatedBandwidth(
+    int32_t estimated_bandwidth) {
+  FATAL();
+  return 0;
+}
+
+int32_t ACMGenericCodecWrapper::GetRedPayload(uint8_t* red_payload,
+                                              int16_t* payload_bytes) {
+  FATAL();
+  return 0;
+}
+
+int16_t ACMGenericCodecWrapper::ResetEncoder() {
+  return 0;
+}
+
+void ACMGenericCodecWrapper::DestructEncoder() {
+}
+
+int16_t ACMGenericCodecWrapper::SamplesLeftToEncode() {
+  FATAL();
+  return 0;
+}
+
+void ACMGenericCodecWrapper::SetUniqueID(const uint32_t id) {
+  // Do nothing.
+}
+
+int16_t ACMGenericCodecWrapper::UpdateDecoderSampFreq(int16_t codec_id) {
+#ifdef WEBRTC_CODEC_ISAC
+  WriteLockScoped wl(codec_wrapper_lock_);
+  if (is_isac_) {
+    switch (codec_id) {
+      case ACMCodecDB::kISAC:
+        static_cast<AudioEncoderDecoderIsac*>(audio_encoder_.get())
+            ->UpdateDecoderSampleRate(16000);
+        return 0;
+      case ACMCodecDB::kISACSWB:
+      case ACMCodecDB::kISACFB:
+        static_cast<AudioEncoderDecoderIsac*>(audio_encoder_.get())
+            ->UpdateDecoderSampleRate(32000);
+        return 0;
+      default:
+        FATAL() << "Unexpected codec id.";
+    }
+  }
+#endif
+  return 0;
+}
+
+int16_t ACMGenericCodecWrapper::UpdateEncoderSampFreq(uint16_t samp_freq_hz) {
+  FATAL();
+  return 0;
+}
+
+int16_t ACMGenericCodecWrapper::EncoderSampFreq(uint16_t* samp_freq_hz) {
+  FATAL();
+  return 0;
+}
+
+int32_t ACMGenericCodecWrapper::ConfigISACBandwidthEstimator(
+    const uint8_t init_frame_size_msec,
+    const uint16_t init_rate_bps,
+    const bool enforce_frame_size) {
+  FATAL();
+  return 0;
+}
+
+int32_t ACMGenericCodecWrapper::SetISACMaxPayloadSize(
+    const uint16_t max_payload_len_bytes) {
+  WriteLockScoped wl(codec_wrapper_lock_);
+  if (!is_isac_)
+    return -1;  // Needed for tests to pass.
+  max_payload_size_bytes_ = max_payload_len_bytes;
+  ResetAudioEncoder();
+  return 0;
+}
+
+int32_t ACMGenericCodecWrapper::SetISACMaxRate(const uint32_t max_rate_bps) {
+  WriteLockScoped wl(codec_wrapper_lock_);
+  if (!is_isac_)
+    return -1;  // Needed for tests to pass.
+  max_rate_bps_ = max_rate_bps;
+  ResetAudioEncoder();
+  return 0;
+}
+
+int16_t ACMGenericCodecWrapper::REDPayloadISAC(const int32_t isac_rate,
+                                               const int16_t isac_bw_estimate,
+                                               uint8_t* payload,
+                                               int16_t* payload_len_bytes) {
+  FATAL();
+  return 0;
+}
+
+int ACMGenericCodecWrapper::SetOpusMaxPlaybackRate(int frequency_hz) {
+  WriteLockScoped wl(codec_wrapper_lock_);
+  if (!is_opus_)
+    return -1;  // Needed for tests to pass.
+  max_playback_rate_hz_ = frequency_hz;
+  ResetAudioEncoder();
+  return 0;
+}
+
+bool ACMGenericCodecWrapper::HasFrameToEncode() const {
+  FATAL();
+  return 0;
+}
+
+AudioDecoder* ACMGenericCodecWrapper::Decoder(int /* codec_id */) {
+  ReadLockScoped rl(codec_wrapper_lock_);
+  return decoder_proxy_.IsSet() ? &decoder_proxy_ : nullptr;
+}
+
+int ACMGenericCodecWrapper::SetFEC(bool enable_fec) {
+  if (!HasInternalFEC())
+    return enable_fec ? -1 : 0;
+  WriteLockScoped wl(codec_wrapper_lock_);
+  if (fec_enabled_ != enable_fec) {
+    fec_enabled_ = enable_fec;
+    ResetAudioEncoder();
+  }
+  return 0;
+}
+
+int ACMGenericCodecWrapper::SetOpusApplication(
+    OpusApplicationMode application) {
+  WriteLockScoped wl(codec_wrapper_lock_);
+  opus_application_ = application;
+  opus_application_set_ = true;
+  ResetAudioEncoder();
+  return 0;
+}
+
+int ACMGenericCodecWrapper::SetPacketLossRate(int loss_rate) {
+  WriteLockScoped wl(codec_wrapper_lock_);
+  encoder_->SetProjectedPacketLossRate(loss_rate / 100.0);
+  loss_rate_ = loss_rate;
+  return 0;
+}
+
+void ACMGenericCodecWrapper::EnableCopyRed(bool enable, int red_payload_type) {
+  ACMGenericCodec::EnableCopyRed(enable, red_payload_type);
+  WriteLockScoped wl(codec_wrapper_lock_);
+  red_payload_type_ = red_payload_type;
+  ResetAudioEncoder();
+}
+
+bool ACMGenericCodecWrapper::ExternalRedNeeded() {
+  return false;
+}
+
+void ACMGenericCodecWrapper::DestructEncoderSafe() {
+  FATAL();
+}
+
+int16_t ACMGenericCodecWrapper::InternalEncode(uint8_t* bitstream,
+                                               int16_t* bitstream_len_byte) {
+  FATAL();
+  return 0;
+}
+
+int16_t ACMGenericCodecWrapper::InternalInitEncoder(
+    WebRtcACMCodecParams* codec_params) {
+  FATAL();
+  return 0;
+}
+
+int16_t ACMGenericCodecWrapper::InternalCreateEncoder() {
+  FATAL();
+  return 0;
+}
+
 }  // 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 9d04510..d2caea7 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h
+++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h
@@ -11,12 +11,17 @@
 #ifndef WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_ACM_GENERIC_CODEC_H_
 #define WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_ACM_GENERIC_CODEC_H_
 
+#include <map>
+
 #include "webrtc/base/thread_annotations.h"
 #include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h"
 #include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
+#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
 #include "webrtc/modules/audio_coding/neteq/interface/neteq.h"
+#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
 #include "webrtc/system_wrappers/interface/trace.h"
 
 #define MAX_FRAME_SIZE_10MSEC 6
@@ -106,10 +111,11 @@
   //   -1 if error is occurred, otherwise the length of the bit-stream in
   //      bytes.
   //
-  int16_t Encode(uint8_t* bitstream,
-                 int16_t* bitstream_len_byte,
-                 uint32_t* timestamp,
-                 WebRtcACMEncodingType* encoding_type);
+  virtual int16_t Encode(uint8_t* bitstream,
+                         int16_t* bitstream_len_byte,
+                         uint32_t* timestamp,
+                         WebRtcACMEncodingType* encoding_type,
+                         AudioEncoder::EncodedInfo* encoded_info);
 
   ///////////////////////////////////////////////////////////////////////////
   // bool EncoderInitialized();
@@ -118,7 +124,7 @@
   //   True if the encoder is successfully initialized,
   //   false otherwise.
   //
-  bool EncoderInitialized();
+  virtual bool EncoderInitialized();
 
   ///////////////////////////////////////////////////////////////////////////
   // int16_t EncoderParams()
@@ -134,7 +140,7 @@
   //   -1 if the encoder is not initialized,
   //    0 otherwise.
   //
-  int16_t EncoderParams(WebRtcACMCodecParams* enc_params);
+  virtual int16_t EncoderParams(WebRtcACMCodecParams* enc_params);
 
   ///////////////////////////////////////////////////////////////////////////
   // int16_t InitEncoder(...)
@@ -152,8 +158,8 @@
   //  -1 if failed to initialize.
   //
   //
-  int16_t InitEncoder(WebRtcACMCodecParams* codec_params,
-                      bool force_initialization);
+  virtual int16_t InitEncoder(WebRtcACMCodecParams* codec_params,
+                              bool force_initialization);
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t Add10MsData(...)
@@ -174,10 +180,10 @@
   //   -1 if failed
   //    0 otherwise.
   //
-  int32_t Add10MsData(const uint32_t timestamp,
-                      const int16_t* data,
-                      const uint16_t length,
-                      const uint8_t audio_channel);
+  virtual int32_t Add10MsData(const uint32_t timestamp,
+                              const int16_t* data,
+                              const uint16_t length,
+                              const uint8_t audio_channel);
 
   ///////////////////////////////////////////////////////////////////////////
   // uint32_t NoMissedSamples()
@@ -189,14 +195,14 @@
   // Return Value:
   //   Number of samples which are overwritten.
   //
-  uint32_t NoMissedSamples() const;
+  virtual uint32_t NoMissedSamples() const;
 
   ///////////////////////////////////////////////////////////////////////////
   // void ResetNoMissedSamples()
   // This function resets the number of overwritten samples to zero.
   // (We might remove this function if we remove NoMissedSamples())
   //
-  void ResetNoMissedSamples();
+  virtual void ResetNoMissedSamples();
 
   ///////////////////////////////////////////////////////////////////////////
   // int16_t SetBitRate()
@@ -210,7 +216,7 @@
   //      codec is not rate-adjustable.
   //    0 if the rate is adjusted successfully
   //
-  int16_t SetBitRate(const int32_t bitrate_bps);
+  virtual int16_t SetBitRate(const int32_t bitrate_bps);
 
   ///////////////////////////////////////////////////////////////////////////
   // uint32_t EarliestTimestamp()
@@ -220,7 +226,7 @@
   // Return value:
   //   timestamp of the first 10 ms audio in the audio buffer.
   //
-  uint32_t EarliestTimestamp() const;
+  virtual uint32_t EarliestTimestamp() const;
 
   ///////////////////////////////////////////////////////////////////////////
   // int16_t SetVAD()
@@ -249,7 +255,10 @@
   //   -1 if failed to set DTX & VAD as specified,
   //    0 if succeeded.
   //
-  int16_t SetVAD(bool* enable_dtx, bool* enable_vad, ACMVADMode* mode);
+  virtual int16_t SetVAD(bool* enable_dtx, bool* enable_vad, ACMVADMode* mode);
+
+  // Registers comfort noise at |sample_rate_hz| to use |payload_type|.
+  virtual void SetCngPt(int sample_rate_hz, int payload_type);
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t ReplaceInternalDTX()
@@ -264,7 +273,7 @@
   //   -1 if failed to replace internal DTX,
   //    0 if succeeded.
   //
-  int32_t ReplaceInternalDTX(const bool replace_internal_dtx);
+  virtual int32_t ReplaceInternalDTX(const bool replace_internal_dtx);
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t IsInternalDTXReplaced()
@@ -303,7 +312,7 @@
   //   -1 if fails to get decoder estimated bandwidth,
   //    >0 estimated bandwidth in bits/sec.
   //
-  int32_t GetEstimatedBandwidth();
+  virtual int32_t GetEstimatedBandwidth();
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t SetEstimatedBandwidth()
@@ -317,7 +326,7 @@
   //   -1 if fails to set estimated bandwidth,
   //    0 on success.
   //
-  int32_t SetEstimatedBandwidth(int32_t estimated_bandwidth);
+  virtual int32_t SetEstimatedBandwidth(int32_t estimated_bandwidth);
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t GetRedPayload()
@@ -332,7 +341,7 @@
   //   -1 if fails to get codec specific RED,
   //    0 if succeeded.
   //
-  int32_t GetRedPayload(uint8_t* red_payload, int16_t* payload_bytes);
+  virtual int32_t GetRedPayload(uint8_t* red_payload, int16_t* payload_bytes);
 
   ///////////////////////////////////////////////////////////////////////////
   // int16_t ResetEncoder()
@@ -344,7 +353,7 @@
   //   -1 if failed,
   //    0 if succeeded.
   //
-  int16_t ResetEncoder();
+  virtual int16_t ResetEncoder();
 
   ///////////////////////////////////////////////////////////////////////////
   // void DestructEncoder()
@@ -353,7 +362,7 @@
   // instance we cannot delete the encoder and instead we will initialize the
   // encoder. We also delete VAD and DTX if they have been created.
   //
-  void DestructEncoder();
+  virtual void DestructEncoder();
 
   ///////////////////////////////////////////////////////////////////////////
   // int16_t SamplesLeftToEncode()
@@ -362,7 +371,7 @@
   // Return value:
   //   Number of samples.
   //
-  int16_t SamplesLeftToEncode();
+  virtual int16_t SamplesLeftToEncode();
 
   ///////////////////////////////////////////////////////////////////////////
   // SetUniqueID()
@@ -371,7 +380,7 @@
   // Input
   //   -id                 : A number to identify the codec.
   //
-  void SetUniqueID(const uint32_t id);
+  virtual void SetUniqueID(const uint32_t id);
 
   ///////////////////////////////////////////////////////////////////////////
   // UpdateDecoderSampFreq()
@@ -560,7 +569,7 @@
   // Returns true if there is enough audio buffered for encoding, such that
   // calling Encode() will return a payload.
   //
-  bool HasFrameToEncode() const;
+  virtual bool HasFrameToEncode() const;
 
   //
   // Returns pointer to the AudioDecoder class of this codec. A codec which
@@ -972,6 +981,181 @@
   uint32_t unique_id_;
 };
 
+// Proxy for AudioDecoder
+class AudioDecoderProxy final : public AudioDecoder {
+ public:
+  AudioDecoderProxy();
+  void SetDecoder(AudioDecoder* decoder);
+  bool IsSet() const;
+  int Decode(const uint8_t* encoded,
+             size_t encoded_len,
+             int16_t* decoded,
+             SpeechType* speech_type) override;
+  int DecodeRedundant(const uint8_t* encoded,
+                      size_t encoded_len,
+                      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) 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;
+  CNG_dec_inst* CngDecoderInstance() override;
+
+ private:
+  scoped_ptr<CriticalSectionWrapper> decoder_lock_;
+  AudioDecoder* decoder_ GUARDED_BY(decoder_lock_);
+};
+
+class ACMGenericCodecWrapper : public ACMGenericCodec {
+ public:
+  ACMGenericCodecWrapper(const CodecInst& codec_inst,
+                         int cng_pt_nb,
+                         int cng_pt_wb,
+                         int cng_pt_swb,
+                         int cng_pt_fb,
+                         bool enable_red,
+                         int red_payload_type);
+  virtual ~ACMGenericCodecWrapper() = default;
+
+  ACMGenericCodec* CreateInstance() override;
+
+  int16_t Encode(uint8_t* bitstream,
+                 int16_t* bitstream_len_byte,
+                 uint32_t* timestamp,
+                 WebRtcACMEncodingType* encoding_type,
+                 AudioEncoder::EncodedInfo* encoded_info) override;
+
+  bool EncoderInitialized() override;
+
+  int16_t EncoderParams(WebRtcACMCodecParams* enc_params) override;
+
+  int16_t InitEncoder(WebRtcACMCodecParams* codec_params,
+                      bool force_initialization) override;
+
+  int32_t Add10MsData(const uint32_t timestamp,
+                      const int16_t* data,
+                      const uint16_t length,
+                      const uint8_t audio_channel) override;
+
+  uint32_t NoMissedSamples() const override;
+
+  void ResetNoMissedSamples() override;
+
+  int16_t SetBitRate(const int32_t bitrate_bps) override;
+
+  uint32_t EarliestTimestamp() const override;
+
+  int16_t SetVAD(bool* enable_dtx, bool* enable_vad, ACMVADMode* mode) override;
+
+  void SetCngPt(int sample_rate_hz, int payload_type) override;
+
+  int32_t ReplaceInternalDTX(const bool replace_internal_dtx) override;
+
+  int32_t GetEstimatedBandwidth() override;
+
+  int32_t SetEstimatedBandwidth(int32_t estimated_bandwidth) override;
+
+  int32_t GetRedPayload(uint8_t* red_payload, int16_t* payload_bytes) override;
+
+  int16_t ResetEncoder() override;
+
+  void DestructEncoder() override;
+
+  int16_t SamplesLeftToEncode() override;
+
+  void SetUniqueID(const uint32_t id) override;
+
+  int16_t UpdateDecoderSampFreq(int16_t codec_id) override;
+
+  int16_t UpdateEncoderSampFreq(uint16_t samp_freq_hz) override
+      EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
+
+  int16_t EncoderSampFreq(uint16_t* samp_freq_hz) override
+      SHARED_LOCKS_REQUIRED(codec_wrapper_lock_);
+
+  int32_t ConfigISACBandwidthEstimator(const uint8_t init_frame_size_msec,
+                                       const uint16_t init_rate_bps,
+                                       const bool enforce_frame_size) override;
+
+  int32_t SetISACMaxPayloadSize(const uint16_t max_payload_len_bytes) override;
+
+  int32_t SetISACMaxRate(const uint32_t max_rate_bps) override;
+
+  int16_t REDPayloadISAC(const int32_t isac_rate,
+                         const int16_t isac_bw_estimate,
+                         uint8_t* payload,
+                         int16_t* payload_len_bytes) override;
+
+  int SetOpusMaxPlaybackRate(int /* frequency_hz */) override;
+
+  bool HasFrameToEncode() const override;
+
+  AudioDecoder* Decoder(int /* codec_id */) override;
+
+  int SetFEC(bool enable_fec) override;
+
+  int SetOpusApplication(OpusApplicationMode mode) override;
+
+  int SetPacketLossRate(int /* loss_rate */) override;
+
+  void EnableCopyRed(bool enable, int red_payload_type) override;
+
+  bool ExternalRedNeeded() override;
+
+ protected:
+  void DestructEncoderSafe() override
+      EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
+
+  int16_t InternalEncode(uint8_t* bitstream,
+                         int16_t* bitstream_len_byte) override
+      EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
+
+  int16_t InternalInitEncoder(WebRtcACMCodecParams* codec_params) override
+      EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
+
+  int16_t InternalCreateEncoder() override;
+
+ private:
+  void ResetAudioEncoder() EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
+
+  OpusApplicationMode GetOpusApplication(int num_channels) const
+      EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
+
+  scoped_ptr<AudioEncoder> audio_encoder_ GUARDED_BY(codec_wrapper_lock_);
+  scoped_ptr<AudioEncoder> cng_encoder_ GUARDED_BY(codec_wrapper_lock_);
+  scoped_ptr<AudioEncoder> red_encoder_ GUARDED_BY(codec_wrapper_lock_);
+  AudioEncoder* encoder_ GUARDED_BY(codec_wrapper_lock_);
+  AudioDecoderProxy decoder_proxy_ GUARDED_BY(codec_wrapper_lock_);
+  std::vector<int16_t> input_ GUARDED_BY(codec_wrapper_lock_);
+  WebRtcACMCodecParams acm_codec_params_ GUARDED_BY(codec_wrapper_lock_);
+  int bitrate_bps_ GUARDED_BY(codec_wrapper_lock_);
+  bool fec_enabled_ GUARDED_BY(codec_wrapper_lock_);
+  int loss_rate_ GUARDED_BY(codec_wrapper_lock_);
+  int max_playback_rate_hz_ GUARDED_BY(codec_wrapper_lock_);
+  int max_payload_size_bytes_ GUARDED_BY(codec_wrapper_lock_);
+  int max_rate_bps_ GUARDED_BY(codec_wrapper_lock_);
+  bool is_opus_ GUARDED_BY(codec_wrapper_lock_);
+  bool is_isac_ GUARDED_BY(codec_wrapper_lock_);
+  bool first_frame_ GUARDED_BY(codec_wrapper_lock_);
+  uint32_t rtp_timestamp_ GUARDED_BY(codec_wrapper_lock_);
+  uint32_t last_rtp_timestamp_ GUARDED_BY(codec_wrapper_lock_);
+  // Map from payload type to sample rate (Hz) and encoding type.
+  std::map<int, std::pair<int, WebRtcACMEncodingType>> cng_pt_
+      GUARDED_BY(codec_wrapper_lock_);
+  int red_payload_type_ GUARDED_BY(codec_wrapper_lock_);
+  OpusApplicationMode opus_application_ GUARDED_BY(codec_wrapper_lock_);
+  bool opus_application_set_ GUARDED_BY(codec_wrapper_lock_);
+};
+
 }  // namespace acm2
 
 }  // namespace webrtc
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 b59d301..4098889 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
@@ -258,9 +258,9 @@
     if (!HaveValidEncoder("Process")) {
       return -1;
     }
-    status = codecs_[current_send_codec_idx_]->Encode(stream, &length_bytes,
-                                                      &rtp_timestamp,
-                                                      &encoding_type);
+    AudioEncoder::EncodedInfo encoded_info;
+    status = codecs_[current_send_codec_idx_]->Encode(
+        stream, &length_bytes, &rtp_timestamp, &encoding_type, &encoded_info);
     if (status < 0) {
       // Encode failed.
       WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,