Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / media / webrtc / webrtcvoiceengine.cc
index b4b96d1..81a6cdc 100644 (file)
 #include <string>
 #include <vector>
 
-#include "talk/base/base64.h"
-#include "talk/base/byteorder.h"
-#include "talk/base/common.h"
-#include "talk/base/helpers.h"
-#include "talk/base/logging.h"
-#include "talk/base/stringencode.h"
-#include "talk/base/stringutils.h"
 #include "talk/media/base/audiorenderer.h"
 #include "talk/media/base/constants.h"
 #include "talk/media/base/streamparams.h"
 #include "talk/media/base/voiceprocessor.h"
 #include "talk/media/webrtc/webrtcvoe.h"
+#include "webrtc/base/base64.h"
+#include "webrtc/base/byteorder.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/stringencode.h"
+#include "webrtc/base/stringutils.h"
 #include "webrtc/common.h"
 #include "webrtc/modules/audio_processing/include/audio_processing.h"
 
@@ -107,12 +107,6 @@ static const int kDefaultSoundclipDeviceId = -2;
 static const int kDefaultAudioDeviceId = 0;
 #endif
 
-// extension header for audio levels, as defined in
-// http://tools.ietf.org/html/draft-ietf-avtext-client-to-mixer-audio-level-03
-static const char kRtpAudioLevelHeaderExtension[] =
-    "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
-static const int kRtpAudioLevelHeaderExtensionId = 1;
-
 static const char kIsacCodecName[] = "ISAC";
 static const char kL16CodecName[] = "L16";
 // Codec parameters for Opus.
@@ -128,7 +122,7 @@ static const int kOpusMaxBitrate = 510000;
 // Default audio dscp value.
 // See http://tools.ietf.org/html/rfc2474 for details.
 // See also http://tools.ietf.org/html/draft-jennings-rtcweb-qos-00
-static const talk_base::DiffServCodePoint kAudioDscpValue = talk_base::DSCP_EF;
+static const rtc::DiffServCodePoint kAudioDscpValue = rtc::DSCP_EF;
 
 // Ensure we open the file in a writeable path on ChromeOS and Android. This
 // workaround can be removed when it's possible to specify a filename for audio
@@ -161,7 +155,7 @@ static std::string ToString(const webrtc::CodecInst& codec) {
   return ss.str();
 }
 
-static void LogMultiline(talk_base::LoggingSeverity sev, char* text) {
+static void LogMultiline(rtc::LoggingSeverity sev, char* text) {
   const char* delim = "\r\n";
   for (char* tok = strtok(text, delim); tok; tok = strtok(NULL, delim)) {
     LOG_V(sev) << tok;
@@ -172,13 +166,13 @@ static void LogMultiline(talk_base::LoggingSeverity sev, char* text) {
 static int SeverityToFilter(int severity) {
   int filter = webrtc::kTraceNone;
   switch (severity) {
-    case talk_base::LS_VERBOSE:
+    case rtc::LS_VERBOSE:
       filter |= webrtc::kTraceAll;
-    case talk_base::LS_INFO:
+    case rtc::LS_INFO:
       filter |= (webrtc::kTraceStateInfo | webrtc::kTraceInfo);
-    case talk_base::LS_WARNING:
+    case rtc::LS_WARNING:
       filter |= (webrtc::kTraceTerseInfo | webrtc::kTraceWarning);
-    case talk_base::LS_ERROR:
+    case rtc::LS_ERROR:
       filter |= (webrtc::kTraceError | webrtc::kTraceCritical);
   }
   return filter;
@@ -194,6 +188,18 @@ static bool IsCodecMultiRate(const webrtc::CodecInst& codec) {
   return false;
 }
 
+static bool IsTelephoneEventCodec(const std::string& name) {
+  return _stricmp(name.c_str(), "telephone-event") == 0;
+}
+
+static bool IsCNCodec(const std::string& name) {
+  return _stricmp(name.c_str(), "CN") == 0;
+}
+
+static bool IsRedCodec(const std::string& name) {
+  return _stricmp(name.c_str(), "red") == 0;
+}
+
 static bool FindCodec(const std::vector<AudioCodec>& codecs,
                       const AudioCodec& codec,
                       AudioCodec* found_codec) {
@@ -229,8 +235,9 @@ static AudioOptions GetDefaultEngineOptions() {
   options.adjust_agc_delta.Set(0);
   options.experimental_agc.Set(false);
   options.experimental_aec.Set(false);
+  options.experimental_ns.Set(false);
   options.aec_dump.Set(false);
-  options.experimental_acm.Set(false);
+  options.opus_fec.Set(false);
   return options;
 }
 
@@ -321,7 +328,7 @@ class WebRtcSoundclipMedia : public SoundclipMedia {
  private:
   WebRtcVoiceEngine *engine_;
   int webrtc_channel_;
-  talk_base::scoped_ptr<WebRtcSoundclipStream> stream_;
+  rtc::scoped_ptr<WebRtcSoundclipStream> stream_;
 };
 
 WebRtcVoiceEngine::WebRtcVoiceEngine()
@@ -334,7 +341,6 @@ WebRtcVoiceEngine::WebRtcVoiceEngine()
       log_filter_(SeverityToFilter(kDefaultLogSeverity)),
       is_dumping_aec_(false),
       desired_local_monitor_enable_(false),
-      use_experimental_acm_(false),
       tx_processor_ssrc_(0),
       rx_processor_ssrc_(0) {
   Construct();
@@ -352,7 +358,6 @@ WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper,
       log_filter_(SeverityToFilter(kDefaultLogSeverity)),
       is_dumping_aec_(false),
       desired_local_monitor_enable_(false),
-      use_experimental_acm_(false),
       tx_processor_ssrc_(0),
       rx_processor_ssrc_(0) {
   Construct();
@@ -378,12 +383,11 @@ void WebRtcVoiceEngine::Construct() {
   // Load our RTP Header extensions.
   rtp_header_extensions_.push_back(
       RtpHeaderExtension(kRtpAudioLevelHeaderExtension,
-                         kRtpAudioLevelHeaderExtensionId));
+                         kRtpAudioLevelHeaderExtensionDefaultId));
+  rtp_header_extensions_.push_back(
+      RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension,
+                         kRtpAbsoluteSenderTimeHeaderExtensionDefaultId));
   options_ = GetDefaultEngineOptions();
-
-  // Initialize the VoE Configuration to the default ACM.
-  voe_config_.Set<webrtc::AudioCodingModuleFactory>(
-      new webrtc::AudioCodingModuleFactory);
 }
 
 static bool IsOpus(const AudioCodec& codec) {
@@ -396,12 +400,8 @@ static bool IsIsac(const AudioCodec& codec) {
 
 // True if params["stereo"] == "1"
 static bool IsOpusStereoEnabled(const AudioCodec& codec) {
-  CodecParameterMap::const_iterator param =
-      codec.params.find(kCodecParamStereo);
-  if (param == codec.params.end()) {
-    return false;
-  }
-  return param->second == kParamValueTrue;
+  int value;
+  return codec.GetParam(kCodecParamStereo, &value) && value == 1;
 }
 
 static bool IsValidOpusBitrate(int bitrate) {
@@ -423,6 +423,22 @@ static int GetOpusBitrateFromParams(const AudioCodec& codec) {
   return bitrate;
 }
 
+// Return true if params[kCodecParamUseInbandFec] == "1", false
+// otherwise.
+static bool IsOpusFecEnabled(const AudioCodec& codec) {
+  int value;
+  return codec.GetParam(kCodecParamUseInbandFec, &value) && value == 1;
+}
+
+// Set params[kCodecParamUseInbandFec]. Caller should make sure codec is Opus.
+static void SetOpusFec(AudioCodec* codec, bool opus_fec) {
+  if (opus_fec) {
+    codec->SetParam(kCodecParamUseInbandFec, 1);
+  } else {
+    codec->RemoveParam(kCodecParamUseInbandFec);
+  }
+}
+
 void WebRtcVoiceEngine::ConstructCodecs() {
   LOG(LS_INFO) << "WebRtc VoiceEngine codecs:";
   int ncodecs = voe_wrapper_->codec()->NumOfCodecs();
@@ -459,14 +475,15 @@ void WebRtcVoiceEngine::ConstructCodecs() {
           // Only add fmtp parameters that differ from the spec.
           if (kPreferredMinPTime != kOpusDefaultMinPTime) {
             codec.params[kCodecParamMinPTime] =
-                talk_base::ToString(kPreferredMinPTime);
+                rtc::ToString(kPreferredMinPTime);
           }
           if (kPreferredMaxPTime != kOpusDefaultMaxPTime) {
             codec.params[kCodecParamMaxPTime] =
-                talk_base::ToString(kPreferredMaxPTime);
+                rtc::ToString(kPreferredMaxPTime);
           }
           // TODO(hellner): Add ptime, sprop-stereo, stereo and useinbandfec
           // when they can be set to values other than the default.
+          SetOpusFec(&codec, false);
         }
         codecs_.push_back(codec);
       } else {
@@ -501,7 +518,7 @@ WebRtcVoiceEngine::~WebRtcVoiceEngine() {
   tracing_->SetTraceCallback(NULL);
 }
 
-bool WebRtcVoiceEngine::Init(talk_base::Thread* worker_thread) {
+bool WebRtcVoiceEngine::Init(rtc::Thread* worker_thread) {
   LOG(LS_INFO) << "WebRtcVoiceEngine::Init";
   bool res = InitInternal();
   if (res) {
@@ -516,7 +533,7 @@ bool WebRtcVoiceEngine::Init(talk_base::Thread* worker_thread) {
 bool WebRtcVoiceEngine::InitInternal() {
   // Temporarily turn logging level up for the Init call
   int old_filter = log_filter_;
-  int extended_filter = log_filter_ | SeverityToFilter(talk_base::LS_INFO);
+  int extended_filter = log_filter_ | SeverityToFilter(rtc::LS_INFO);
   SetTraceFilter(extended_filter);
   SetTraceOptions("");
 
@@ -534,7 +551,7 @@ bool WebRtcVoiceEngine::InitInternal() {
   char buffer[1024] = "";
   voe_wrapper_->base()->GetVersion(buffer);
   LOG(LS_INFO) << "WebRtc VoiceEngine Version:";
-  LogMultiline(talk_base::LS_INFO, buffer);
+  LogMultiline(rtc::LS_INFO, buffer);
 
   // Save the default AGC configuration settings. This must happen before
   // calling SetOptions or the default will be overwritten.
@@ -717,16 +734,11 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
   options.typing_detection.Set(false);
   options.experimental_agc.Set(false);
   options.experimental_aec.Set(false);
+  options.experimental_ns.Set(false);
 #endif
 
   LOG(LS_INFO) << "Applying audio options: " << options.ToString();
 
-  // Configure whether ACM1 or ACM2 is used.
-  bool enable_acm2 = false;
-  if (options.experimental_acm.Get(&enable_acm2)) {
-    EnableExperimentalAcm(enable_acm2);
-  }
-
   webrtc::VoEAudioProcessing* voep = voe_wrapper_->processing();
 
   bool echo_cancellation;
@@ -804,8 +816,33 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
     }
   }
 
+  bool experimental_ns;
+  if (options.experimental_ns.Get(&experimental_ns)) {
+    webrtc::AudioProcessing* audioproc =
+        voe_wrapper_->base()->audio_processing();
+#ifdef USE_WEBRTC_DEV_BRANCH
+    webrtc::Config config;
+    config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(
+        experimental_ns));
+    audioproc->SetExtraOptions(config);
+#else
+    // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine
+    // returns NULL on audio_processing().
+    if (audioproc) {
+      if (audioproc->EnableExperimentalNs(experimental_ns) == -1) {
+        LOG_RTCERR1(EnableExperimentalNs, experimental_ns);
+        return false;
+      }
+    } else {
+      LOG(LS_VERBOSE) << "Experimental noise suppression set to "
+                      << experimental_ns;
+    }
+#endif
+  }
+
   bool highpass_filter;
   if (options.highpass_filter.Get(&highpass_filter)) {
+    LOG(LS_INFO) << "High pass filter enabled? " << highpass_filter;
     if (voep->EnableHighPassFilter(highpass_filter) == -1) {
       LOG_RTCERR1(SetHighpassFilterStatus, highpass_filter);
       return false;
@@ -814,6 +851,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
 
   bool stereo_swapping;
   if (options.stereo_swapping.Get(&stereo_swapping)) {
+    LOG(LS_INFO) << "Stereo swapping enabled? " << stereo_swapping;
     voep->EnableStereoChannelSwapping(stereo_swapping);
     if (voep->IsStereoChannelSwappingEnabled() != stereo_swapping) {
       LOG_RTCERR1(EnableStereoChannelSwapping, stereo_swapping);
@@ -823,6 +861,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
 
   bool typing_detection;
   if (options.typing_detection.Get(&typing_detection)) {
+    LOG(LS_INFO) << "Typing detection is enabled? " << typing_detection;
     if (voep->SetTypingDetectionStatus(typing_detection) == -1) {
       // In case of error, log the info and continue
       LOG_RTCERR1(SetTypingDetectionStatus, typing_detection);
@@ -831,6 +870,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
 
   int adjust_agc_delta;
   if (options.adjust_agc_delta.Get(&adjust_agc_delta)) {
+    LOG(LS_INFO) << "Adjust agc delta is " << adjust_agc_delta;
     if (!AdjustAgcLevel(adjust_agc_delta)) {
       return false;
     }
@@ -838,6 +878,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
 
   bool aec_dump;
   if (options.aec_dump.Get(&aec_dump)) {
+    LOG(LS_INFO) << "Aec dump is enabled? " << aec_dump;
     if (aec_dump)
       StartAecDump(kAecDumpByAudioOptionFilename);
     else
@@ -846,6 +887,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
 
   bool experimental_aec;
   if (options.experimental_aec.Get(&experimental_aec)) {
+    LOG(LS_INFO) << "Experimental aec is " << experimental_aec;
     webrtc::AudioProcessing* audioproc =
         voe_wrapper_->base()->audio_processing();
     // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine
@@ -860,6 +902,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
 
   uint32 recording_sample_rate;
   if (options.recording_sample_rate.Get(&recording_sample_rate)) {
+    LOG(LS_INFO) << "Recording sample rate is " << recording_sample_rate;
     if (voe_wrapper_->hw()->SetRecordingSampleRate(recording_sample_rate)) {
       LOG_RTCERR1(SetRecordingSampleRate, recording_sample_rate);
     }
@@ -867,11 +910,21 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
 
   uint32 playout_sample_rate;
   if (options.playout_sample_rate.Get(&playout_sample_rate)) {
+    LOG(LS_INFO) << "Playout sample rate is " << playout_sample_rate;
     if (voe_wrapper_->hw()->SetPlayoutSampleRate(playout_sample_rate)) {
       LOG_RTCERR1(SetPlayoutSampleRate, playout_sample_rate);
     }
   }
 
+  bool opus_fec;
+  if (options.opus_fec.Get(&opus_fec)) {
+    LOG(LS_INFO) << "Opus FEC is enabled? " << opus_fec;
+    for (std::vector<AudioCodec>::iterator it = codecs_.begin();
+        it != codecs_.end(); ++it) {
+      if (IsOpus(*it))
+        SetOpusFec(&(*it), opus_fec);
+    }
+  }
 
   return true;
 }
@@ -903,9 +956,9 @@ struct ResumeEntry {
 bool WebRtcVoiceEngine::SetDevices(const Device* in_device,
                                    const Device* out_device) {
 #if !defined(IOS)
-  int in_id = in_device ? talk_base::FromString<int>(in_device->id) :
+  int in_id = in_device ? rtc::FromString<int>(in_device->id) :
       kDefaultAudioDeviceId;
-  int out_id = out_device ? talk_base::FromString<int>(out_device->id) :
+  int out_id = out_device ? rtc::FromString<int>(out_device->id) :
       kDefaultAudioDeviceId;
   // The device manager uses -1 as the default device, which was the case for
   // VoE 3.5. VoE 4.0, however, uses 0 as the default in Linux and Mac.
@@ -956,6 +1009,9 @@ bool WebRtcVoiceEngine::SetDevices(const Device* in_device,
       LOG_RTCERR2(SetRecordingDevice, in_name, in_id);
       ret = false;
     }
+    webrtc::AudioProcessing* ap = voe()->base()->audio_processing();
+    if (ap)
+      ap->Initialize();
   }
 
   // Find the playout device id in VoiceEngine and set playout device.
@@ -1198,7 +1254,7 @@ void WebRtcVoiceEngine::SetTraceFilter(int filter) {
 void WebRtcVoiceEngine::SetTraceOptions(const std::string& options) {
   // Set encrypted trace file.
   std::vector<std::string> opts;
-  talk_base::tokenize(options, ' ', '"', '"', &opts);
+  rtc::tokenize(options, ' ', '"', '"', &opts);
   std::vector<std::string>::iterator tracefile =
       std::find(opts.begin(), opts.end(), "tracefile");
   if (tracefile != opts.end() && ++tracefile != opts.end()) {
@@ -1216,7 +1272,7 @@ void WebRtcVoiceEngine::SetTraceOptions(const std::string& options) {
   std::vector<std::string>::iterator tracefilter =
       std::find(opts.begin(), opts.end(), "tracefilter");
   if (tracefilter != opts.end() && ++tracefilter != opts.end()) {
-    if (!tracing_->SetTraceFilter(talk_base::FromString<int>(*tracefilter))) {
+    if (!tracing_->SetTraceFilter(rtc::FromString<int>(*tracefilter))) {
       LOG_RTCERR1(SetTraceFilter, *tracefilter);
     }
   }
@@ -1261,32 +1317,17 @@ bool WebRtcVoiceEngine::ShouldIgnoreTrace(const std::string& trace) {
   return false;
 }
 
-void WebRtcVoiceEngine::EnableExperimentalAcm(bool enable) {
-  if (enable == use_experimental_acm_)
-    return;
-  if (enable) {
-    LOG(LS_INFO) << "VoiceEngine is set to use new ACM (ACM2 + NetEq4).";
-    voe_config_.Set<webrtc::AudioCodingModuleFactory>(
-        new webrtc::NewAudioCodingModuleFactory());
-  } else {
-    LOG(LS_INFO) << "VoiceEngine is set to use legacy ACM (ACM1 + Neteq3).";
-    voe_config_.Set<webrtc::AudioCodingModuleFactory>(
-        new webrtc::AudioCodingModuleFactory());
-  }
-  use_experimental_acm_ = enable;
-}
-
 void WebRtcVoiceEngine::Print(webrtc::TraceLevel level, const char* trace,
                               int length) {
-  talk_base::LoggingSeverity sev = talk_base::LS_VERBOSE;
+  rtc::LoggingSeverity sev = rtc::LS_VERBOSE;
   if (level == webrtc::kTraceError || level == webrtc::kTraceCritical)
-    sev = talk_base::LS_ERROR;
+    sev = rtc::LS_ERROR;
   else if (level == webrtc::kTraceWarning)
-    sev = talk_base::LS_WARNING;
+    sev = rtc::LS_WARNING;
   else if (level == webrtc::kTraceStateInfo || level == webrtc::kTraceInfo)
-    sev = talk_base::LS_INFO;
+    sev = rtc::LS_INFO;
   else if (level == webrtc::kTraceTerseInfo)
-    sev = talk_base::LS_INFO;
+    sev = rtc::LS_INFO;
 
   // Skip past boilerplate prefix text
   if (length < 72) {
@@ -1302,7 +1343,7 @@ void WebRtcVoiceEngine::Print(webrtc::TraceLevel level, const char* trace,
 }
 
 void WebRtcVoiceEngine::CallbackOnError(int channel_num, int err_code) {
-  talk_base::CritScope lock(&channels_cs_);
+  rtc::CritScope lock(&channels_cs_);
   WebRtcVoiceMediaChannel* channel = NULL;
   uint32 ssrc = 0;
   LOG(LS_WARNING) << "VoiceEngine error " << err_code << " reported on channel "
@@ -1362,12 +1403,12 @@ bool WebRtcVoiceEngine::FindChannelNumFromSsrc(
 }
 
 void WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel *channel) {
-  talk_base::CritScope lock(&channels_cs_);
+  rtc::CritScope lock(&channels_cs_);
   channels_.push_back(channel);
 }
 
 void WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel *channel) {
-  talk_base::CritScope lock(&channels_cs_);
+  rtc::CritScope lock(&channels_cs_);
   ChannelList::iterator i = std::find(channels_.begin(),
                                       channels_.end(),
                                       channel);
@@ -1433,11 +1474,11 @@ bool WebRtcVoiceEngine::SetAudioDeviceModule(webrtc::AudioDeviceModule* adm,
   return true;
 }
 
-bool WebRtcVoiceEngine::StartAecDump(talk_base::PlatformFile file) {
-  FILE* aec_dump_file_stream = talk_base::FdopenPlatformFileForWriting(file);
+bool WebRtcVoiceEngine::StartAecDump(rtc::PlatformFile file) {
+  FILE* aec_dump_file_stream = rtc::FdopenPlatformFileForWriting(file);
   if (!aec_dump_file_stream) {
     LOG(LS_ERROR) << "Could not open AEC dump file stream.";
-    if (!talk_base::ClosePlatformFile(file))
+    if (!rtc::ClosePlatformFile(file))
       LOG(LS_WARNING) << "Could not close file.";
     return false;
   }
@@ -1469,7 +1510,7 @@ bool WebRtcVoiceEngine::RegisterProcessor(
 
   webrtc::ProcessingTypes processing_type;
   {
-    talk_base::CritScope cs(&signal_media_critical_);
+    rtc::CritScope cs(&signal_media_critical_);
     if (direction == MPD_RX) {
       processing_type = webrtc::kPlaybackAllChannelsMixed;
       if (SignalRxMediaFrame.is_empty()) {
@@ -1534,7 +1575,7 @@ bool WebRtcVoiceEngine::UnregisterProcessorChannel(
 
   int deregister_id = -1;
   {
-    talk_base::CritScope cs(&signal_media_critical_);
+    rtc::CritScope cs(&signal_media_critical_);
     if ((processor_direction & channel_direction) != 0 && !signal->is_empty()) {
       signal->disconnect(voice_processor);
       int channel_id = -1;
@@ -1590,7 +1631,7 @@ void WebRtcVoiceEngine::Process(int channel,
                                 int length,
                                 int sampling_freq,
                                 bool is_stereo) {
-    talk_base::CritScope cs(&signal_media_critical_);
+    rtc::CritScope cs(&signal_media_critical_);
     AudioFrame frame(audio10ms, length, sampling_freq, is_stereo);
     if (type == webrtc::kPlaybackAllChannelsMixed) {
       SignalRxMediaFrame(rx_processor_ssrc_, MPD_RX, &frame);
@@ -1639,17 +1680,89 @@ int WebRtcVoiceEngine::CreateSoundclipVoiceChannel() {
   return CreateVoiceChannel(voe_wrapper_sc_.get());
 }
 
-// This struct relies on the generated copy constructor and assignment operator
-// since it is used in an stl::map.
-struct WebRtcVoiceMediaChannel::WebRtcVoiceChannelInfo {
-  WebRtcVoiceChannelInfo() : channel(-1), renderer(NULL) {}
-  WebRtcVoiceChannelInfo(int ch, AudioRenderer* r)
-      : channel(ch),
-        renderer(r) {}
-  ~WebRtcVoiceChannelInfo() {}
+class WebRtcVoiceMediaChannel::WebRtcVoiceChannelRenderer
+    : public AudioRenderer::Sink {
+ public:
+  WebRtcVoiceChannelRenderer(int ch,
+                             webrtc::AudioTransport* voe_audio_transport)
+      : channel_(ch),
+        voe_audio_transport_(voe_audio_transport),
+        renderer_(NULL) {
+  }
+  virtual ~WebRtcVoiceChannelRenderer() {
+    Stop();
+  }
+
+  // Starts the rendering by setting a sink to the renderer to get data
+  // callback.
+  // This method is called on the libjingle worker thread.
+  // TODO(xians): Make sure Start() is called only once.
+  void Start(AudioRenderer* renderer) {
+    rtc::CritScope lock(&lock_);
+    ASSERT(renderer != NULL);
+    if (renderer_ != NULL) {
+      ASSERT(renderer_ == renderer);
+      return;
+    }
+
+    // TODO(xians): Remove AddChannel() call after Chrome turns on APM
+    // in getUserMedia by default.
+    renderer->AddChannel(channel_);
+    renderer->SetSink(this);
+    renderer_ = renderer;
+  }
+
+  // Stops rendering by setting the sink of the renderer to NULL. No data
+  // callback will be received after this method.
+  // This method is called on the libjingle worker thread.
+  void Stop() {
+    rtc::CritScope lock(&lock_);
+    if (renderer_ == NULL)
+      return;
+
+    renderer_->RemoveChannel(channel_);
+    renderer_->SetSink(NULL);
+    renderer_ = NULL;
+  }
+
+  // AudioRenderer::Sink implementation.
+  // This method is called on the audio thread.
+  virtual void OnData(const void* audio_data,
+                      int bits_per_sample,
+                      int sample_rate,
+                      int number_of_channels,
+                      int number_of_frames) OVERRIDE {
+    voe_audio_transport_->OnData(channel_,
+                                 audio_data,
+                                 bits_per_sample,
+                                 sample_rate,
+                                 number_of_channels,
+                                 number_of_frames);
+  }
+
+  // Callback from the |renderer_| when it is going away. In case Start() has
+  // never been called, this callback won't be triggered.
+  virtual void OnClose() OVERRIDE {
+    rtc::CritScope lock(&lock_);
+    // Set |renderer_| to NULL to make sure no more callback will get into
+    // the renderer.
+    renderer_ = NULL;
+  }
+
+  // Accessor to the VoE channel ID.
+  int channel() const { return channel_; }
+
+ private:
+  const int channel_;
+  webrtc::AudioTransport* const voe_audio_transport_;
+
+  // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler.
+  // PeerConnection will make sure invalidating the pointer before the object
+  // goes away.
+  AudioRenderer* renderer_;
 
-  int channel;
-  AudioRenderer* renderer;
+  // Protects |renderer_| in Start(), Stop() and OnClose().
+  rtc::CriticalSection lock_;
 };
 
 // WebRtcVoiceMediaChannel
@@ -1770,7 +1883,7 @@ bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
     }
   }
   if (dscp_option_changed) {
-    talk_base::DiffServCodePoint dscp = talk_base::DSCP_DEFAULT;
+    rtc::DiffServCodePoint dscp = rtc::DSCP_DEFAULT;
     if (options_.dscp.GetWithDefaultIfUnset(false))
       dscp = kAudioDscpValue;
     if (MediaChannel::SetDscp(dscp) != 0) {
@@ -1841,8 +1954,8 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecs(
       for (ChannelMap::iterator it = receive_channels_.begin();
            it != receive_channels_.end() && ret; ++it) {
         if (engine()->voe()->codec()->SetRecPayloadType(
-                it->second.channel, voe_codec) == -1) {
-          LOG_RTCERR2(SetRecPayloadType, it->second.channel,
+                it->second->channel(), voe_codec) == -1) {
+          LOG_RTCERR2(SetRecPayloadType, it->second->channel(),
                       ToString(voe_codec));
           ret = false;
         }
@@ -1864,17 +1977,27 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecs(
 
 bool WebRtcVoiceMediaChannel::SetSendCodecs(
     int channel, const std::vector<AudioCodec>& codecs) {
-  // Disable VAD, and FEC unless we know the other side wants them.
+  // Disable VAD, FEC, and RED unless we know the other side wants them.
   engine()->voe()->codec()->SetVADStatus(channel, false);
   engine()->voe()->rtp()->SetNACKStatus(channel, false, 0);
+#ifdef USE_WEBRTC_DEV_BRANCH
+  engine()->voe()->rtp()->SetREDStatus(channel, false);
+  engine()->voe()->codec()->SetFECStatus(channel, false);
+#else
+  // TODO(minyue): Remove code under #else case after new WebRTC roll.
   engine()->voe()->rtp()->SetFECStatus(channel, false);
+#endif  // USE_WEBRTC_DEV_BRANCH
 
   // Scan through the list to figure out the codec to use for sending, along
   // with the proper configuration for VAD and DTMF.
-  bool first = true;
+  bool found_send_codec = false;
   webrtc::CodecInst send_codec;
   memset(&send_codec, 0, sizeof(send_codec));
 
+  bool nack_enabled = nack_enabled_;
+  bool enable_codec_fec = false;
+
+  // Set send codec (the first non-telephone-event/CN codec)
   for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
        it != codecs.end(); ++it) {
     // Ignore codecs we don't know about. The negotiation step should prevent
@@ -1885,6 +2008,11 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
       continue;
     }
 
+    if (IsTelephoneEventCodec(it->name) || IsCNCodec(it->name)) {
+      // Skip telephone-event/CN codec, which will be handled later.
+      continue;
+    }
+
     // If OPUS, change what we send according to the "stereo" codec
     // parameter, and not the "channels" parameter.  We set
     // voe_codec.channels to 2 if "stereo=1" and 1 otherwise.  If
@@ -1920,21 +2048,99 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
       }
     }
 
+    // We'll use the first codec in the list to actually send audio data.
+    // Be sure to use the payload type requested by the remote side.
+    // "red", for RED audio, is a special case where the actual codec to be
+    // used is specified in params.
+    if (IsRedCodec(it->name)) {
+      // Parse out the RED parameters. If we fail, just ignore RED;
+      // we don't support all possible params/usage scenarios.
+      if (!GetRedSendCodec(*it, codecs, &send_codec)) {
+        continue;
+      }
+
+      // Enable redundant encoding of the specified codec. Treat any
+      // failure as a fatal internal error.
+#ifdef USE_WEBRTC_DEV_BRANCH
+      LOG(LS_INFO) << "Enabling RED on channel " << channel;
+      if (engine()->voe()->rtp()->SetREDStatus(channel, true, it->id) == -1) {
+        LOG_RTCERR3(SetREDStatus, channel, true, it->id);
+#else
+      // TODO(minyue): Remove code under #else case after new WebRTC roll.
+      LOG(LS_INFO) << "Enabling FEC";
+      if (engine()->voe()->rtp()->SetFECStatus(channel, true, it->id) == -1) {
+        LOG_RTCERR3(SetFECStatus, channel, true, it->id);
+#endif  // USE_WEBRTC_DEV_BRANCH
+        return false;
+      }
+    } else {
+      send_codec = voe_codec;
+      nack_enabled = IsNackEnabled(*it);
+      // For Opus as the send codec, we enable inband FEC if requested.
+      enable_codec_fec = IsOpus(*it) && IsOpusFecEnabled(*it);
+    }
+    found_send_codec = true;
+    break;
+  }
+
+  if (nack_enabled_ != nack_enabled) {
+    SetNack(channel, nack_enabled);
+    nack_enabled_ = nack_enabled;
+  }
+
+  if (!found_send_codec) {
+    LOG(LS_WARNING) << "Received empty list of codecs.";
+    return false;
+  }
+
+  // Set the codec immediately, since SetVADStatus() depends on whether
+  // the current codec is mono or stereo.
+  if (!SetSendCodec(channel, send_codec))
+    return false;
+
+  // FEC should be enabled after SetSendCodec.
+  if (enable_codec_fec) {
+    LOG(LS_INFO) << "Attempt to enable codec internal FEC on channel "
+                 << channel;
+#ifdef USE_WEBRTC_DEV_BRANCH
+    if (engine()->voe()->codec()->SetFECStatus(channel, true) == -1) {
+      // Enable codec internal FEC. Treat any failure as fatal internal error.
+      LOG_RTCERR2(SetFECStatus, channel, true);
+      return false;
+    }
+#endif  // USE_WEBRTC_DEV_BRANCH
+  }
+
+  // Always update the |send_codec_| to the currently set send codec.
+  send_codec_.reset(new webrtc::CodecInst(send_codec));
+
+  if (send_bw_setting_) {
+    SetSendBandwidthInternal(send_bw_bps_);
+  }
+
+  // Loop through the codecs list again to config the telephone-event/CN codec.
+  for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
+       it != codecs.end(); ++it) {
+    // Ignore codecs we don't know about. The negotiation step should prevent
+    // this, but double-check to be sure.
+    webrtc::CodecInst voe_codec;
+    if (!engine()->FindWebRtcCodec(*it, &voe_codec)) {
+      LOG(LS_WARNING) << "Unknown codec " << ToString(*it);
+      continue;
+    }
+
     // Find the DTMF telephone event "codec" and tell VoiceEngine channels
     // about it.
-    if (_stricmp(it->name.c_str(), "telephone-event") == 0 ||
-        _stricmp(it->name.c_str(), "audio/telephone-event") == 0) {
+    if (IsTelephoneEventCodec(it->name)) {
       if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType(
               channel, it->id) == -1) {
         LOG_RTCERR2(SetSendTelephoneEventPayloadType, channel, it->id);
         return false;
       }
-    }
-
-    // Turn voice activity detection/comfort noise on if supported.
-    // Set the wideband CN payload type appropriately.
-    // (narrowband always uses the static payload type 13).
-    if (_stricmp(it->name.c_str(), "CN") == 0) {
+    } else if (IsCNCodec(it->name)) {
+      // Turn voice activity detection/comfort noise on if supported.
+      // Set the wideband CN payload type appropriately.
+      // (narrowband always uses the static payload type 13).
       webrtc::PayloadFrequencies cn_freq;
       switch (it->clockrate) {
         case 8000:
@@ -1967,7 +2173,6 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
           // send the offer.
         }
       }
-
       // Only turn on VAD if we have a CN payload type that matches the
       // clockrate for the codec we are going to use.
       if (it->clockrate == send_codec.plfreq) {
@@ -1978,56 +2183,7 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
         }
       }
     }
-
-    // We'll use the first codec in the list to actually send audio data.
-    // Be sure to use the payload type requested by the remote side.
-    // "red", for FEC audio, is a special case where the actual codec to be
-    // used is specified in params.
-    if (first) {
-      if (_stricmp(it->name.c_str(), "red") == 0) {
-        // Parse out the RED parameters. If we fail, just ignore RED;
-        // we don't support all possible params/usage scenarios.
-        if (!GetRedSendCodec(*it, codecs, &send_codec)) {
-          continue;
-        }
-
-        // Enable redundant encoding of the specified codec. Treat any
-        // failure as a fatal internal error.
-        LOG(LS_INFO) << "Enabling FEC";
-        if (engine()->voe()->rtp()->SetFECStatus(channel, true, it->id) == -1) {
-          LOG_RTCERR3(SetFECStatus, channel, true, it->id);
-          return false;
-        }
-      } else {
-        send_codec = voe_codec;
-        nack_enabled_ = IsNackEnabled(*it);
-        SetNack(channel, nack_enabled_);
-      }
-      first = false;
-      // Set the codec immediately, since SetVADStatus() depends on whether
-      // the current codec is mono or stereo.
-      if (!SetSendCodec(channel, send_codec))
-        return false;
-    }
-  }
-
-  // If we're being asked to set an empty list of codecs, due to a buggy client,
-  // choose the most common format: PCMU
-  if (first) {
-    LOG(LS_WARNING) << "Received empty list of codecs; using PCMU/8000";
-    AudioCodec codec(0, "PCMU", 8000, 0, 1, 0);
-    engine()->FindWebRtcCodec(codec, &send_codec);
-    if (!SetSendCodec(channel, send_codec))
-      return false;
-  }
-
-  // Always update the |send_codec_| to the currently set send codec.
-  send_codec_.reset(new webrtc::CodecInst(send_codec));
-
-  if (send_bw_setting_) {
-    SetSendBandwidthInternal(send_bw_bps_);
   }
-
   return true;
 }
 
@@ -2047,13 +2203,13 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
   send_codecs_ = codecs;
   for (ChannelMap::iterator iter = send_channels_.begin();
        iter != send_channels_.end(); ++iter) {
-    if (!SetSendCodecs(iter->second.channel, codecs)) {
+    if (!SetSendCodecs(iter->second->channel(), codecs)) {
       return false;
     }
   }
 
+  // Set nack status on receive channels and update |nack_enabled_|.
   SetNack(receive_channels_, nack_enabled_);
-
   return true;
 }
 
@@ -2061,7 +2217,7 @@ void WebRtcVoiceMediaChannel::SetNack(const ChannelMap& channels,
                                       bool nack_enabled) {
   for (ChannelMap::const_iterator it = channels.begin();
        it != channels.end(); ++it) {
-    SetNack(it->second.channel, nack_enabled);
+    SetNack(it->second->channel(), nack_enabled);
   }
 }
 
@@ -2081,7 +2237,7 @@ bool WebRtcVoiceMediaChannel::SetSendCodec(
                << ", bitrate=" << send_codec.rate;
   for (ChannelMap::iterator iter = send_channels_.begin();
        iter != send_channels_.end(); ++iter) {
-    if (!SetSendCodec(iter->second.channel, send_codec))
+    if (!SetSendCodec(iter->second->channel(), send_codec))
       return false;
   }
 
@@ -2093,6 +2249,13 @@ bool WebRtcVoiceMediaChannel::SetSendCodec(
   LOG(LS_INFO) << "Send channel " << channel <<  " selected voice codec "
                << ToString(send_codec) << ", bitrate=" << send_codec.rate;
 
+  webrtc::CodecInst current_codec;
+  if (engine()->voe()->codec()->GetSendCodec(channel, current_codec) == 0 &&
+      (send_codec == current_codec)) {
+    // Codec is already configured, we can return without setting it again.
+    return true;
+  }
+
   if (engine()->voe()->codec()->SetSendCodec(channel, send_codec) == -1) {
     LOG_RTCERR2(SetSendCodec, channel, ToString(send_codec));
     return false;
@@ -2102,43 +2265,94 @@ bool WebRtcVoiceMediaChannel::SetSendCodec(
 
 bool WebRtcVoiceMediaChannel::SetRecvRtpHeaderExtensions(
     const std::vector<RtpHeaderExtension>& extensions) {
-  // We don't support any incoming extensions headers right now.
+  if (receive_extensions_ == extensions) {
+    return true;
+  }
+
+  // The default channel may or may not be in |receive_channels_|. Set the rtp
+  // header extensions for default channel regardless.
+  if (!SetChannelRecvRtpHeaderExtensions(voe_channel(), extensions)) {
+    return false;
+  }
+
+  // Loop through all receive channels and enable/disable the extensions.
+  for (ChannelMap::const_iterator channel_it = receive_channels_.begin();
+       channel_it != receive_channels_.end(); ++channel_it) {
+    if (!SetChannelRecvRtpHeaderExtensions(channel_it->second->channel(),
+                                           extensions)) {
+      return false;
+    }
+  }
+
+  receive_extensions_ = extensions;
+  return true;
+}
+
+bool WebRtcVoiceMediaChannel::SetChannelRecvRtpHeaderExtensions(
+    int channel_id, const std::vector<RtpHeaderExtension>& extensions) {
+  const RtpHeaderExtension* audio_level_extension =
+      FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension);
+  if (!SetHeaderExtension(
+      &webrtc::VoERTP_RTCP::SetReceiveAudioLevelIndicationStatus, channel_id,
+      audio_level_extension)) {
+    return false;
+  }
+
+  const RtpHeaderExtension* send_time_extension =
+      FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
+  if (!SetHeaderExtension(
+      &webrtc::VoERTP_RTCP::SetReceiveAbsoluteSenderTimeStatus, channel_id,
+      send_time_extension)) {
+    return false;
+  }
   return true;
 }
 
 bool WebRtcVoiceMediaChannel::SetSendRtpHeaderExtensions(
     const std::vector<RtpHeaderExtension>& extensions) {
-  // Enable the audio level extension header if requested.
-  std::vector<RtpHeaderExtension>::const_iterator it;
-  for (it = extensions.begin(); it != extensions.end(); ++it) {
-    if (it->uri == kRtpAudioLevelHeaderExtension) {
-      break;
-    }
+  if (send_extensions_ == extensions) {
+    return true;
   }
 
-  bool enable = (it != extensions.end());
-  int id = 0;
+  // The default channel may or may not be in |send_channels_|. Set the rtp
+  // header extensions for default channel regardless.
 
-  if (enable) {
-    id = it->id;
-    if (id < kMinRtpHeaderExtensionId ||
-        id > kMaxRtpHeaderExtensionId) {
-      LOG(LS_WARNING) << "Invalid RTP header extension id " << id;
-      return false;
-    }
+  if (!SetChannelSendRtpHeaderExtensions(voe_channel(), extensions)) {
+    return false;
   }
 
-  LOG(LS_INFO) << "Enabling audio level header extension with ID " << id;
-  for (ChannelMap::const_iterator iter = send_channels_.begin();
-       iter != send_channels_.end(); ++iter) {
-    if (engine()->voe()->rtp()->SetRTPAudioLevelIndicationStatus(
-            iter->second.channel, enable, id) == -1) {
-      LOG_RTCERR3(SetRTPAudioLevelIndicationStatus,
-                  iter->second.channel, enable, id);
+  // Loop through all send channels and enable/disable the extensions.
+  for (ChannelMap::const_iterator channel_it = send_channels_.begin();
+       channel_it != send_channels_.end(); ++channel_it) {
+    if (!SetChannelSendRtpHeaderExtensions(channel_it->second->channel(),
+                                           extensions)) {
       return false;
     }
   }
 
+  send_extensions_ = extensions;
+  return true;
+}
+
+bool WebRtcVoiceMediaChannel::SetChannelSendRtpHeaderExtensions(
+    int channel_id, const std::vector<RtpHeaderExtension>& extensions) {
+  const RtpHeaderExtension* audio_level_extension =
+      FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension);
+
+  if (!SetHeaderExtension(
+      &webrtc::VoERTP_RTCP::SetSendAudioLevelIndicationStatus, channel_id,
+      audio_level_extension)) {
+    return false;
+  }
+
+  const RtpHeaderExtension* send_time_extension =
+      FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
+  if (!SetHeaderExtension(
+      &webrtc::VoERTP_RTCP::SetSendAbsoluteSenderTimeStatus, channel_id,
+      send_time_extension)) {
+    return false;
+  }
+
   return true;
 }
 
@@ -2168,9 +2382,9 @@ bool WebRtcVoiceMediaChannel::ChangePlayout(bool playout) {
   }
   for (ChannelMap::iterator it = receive_channels_.begin();
        it != receive_channels_.end() && result; ++it) {
-    if (!SetPlayout(it->second.channel, playout)) {
+    if (!SetPlayout(it->second->channel(), playout)) {
       LOG(LS_ERROR) << "SetPlayout " << playout << " on channel "
-                    << it->second.channel << " failed";
+                    << it->second->channel() << " failed";
       result = false;
     }
   }
@@ -2208,7 +2422,7 @@ bool WebRtcVoiceMediaChannel::ChangeSend(SendFlags send) {
   // Change the settings on each send channel.
   for (ChannelMap::iterator iter = send_channels_.begin();
        iter != send_channels_.end(); ++iter) {
-    if (!ChangeSend(iter->second.channel, send))
+    if (!ChangeSend(iter->second->channel(), send))
       return false;
   }
 
@@ -2242,6 +2456,7 @@ bool WebRtcVoiceMediaChannel::ChangeSend(int channel, SendFlags send) {
   return true;
 }
 
+// TODO(ronghuawu): Change this method to return bool.
 void WebRtcVoiceMediaChannel::ConfigureSendChannel(int channel) {
   if (engine()->voe()->network()->RegisterExternalTransport(
           channel, *this) == -1) {
@@ -2253,6 +2468,9 @@ void WebRtcVoiceMediaChannel::ConfigureSendChannel(int channel) {
 
   // Reset all recv codecs; they will be enabled via SetRecvCodecs.
   ResetRecvCodecs(channel);
+
+  // Set RTP header extension for the new channel.
+  SetChannelSendRtpHeaderExtensions(channel, send_extensions_);
 }
 
 bool WebRtcVoiceMediaChannel::DeleteChannel(int channel) {
@@ -2280,7 +2498,7 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
   bool default_channel_is_available = true;
   for (ChannelMap::const_iterator iter = send_channels_.begin();
        iter != send_channels_.end(); ++iter) {
-    if (IsDefaultChannel(iter->second.channel)) {
+    if (IsDefaultChannel(iter->second->channel())) {
       default_channel_is_available = false;
       break;
     }
@@ -2300,7 +2518,11 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
 
   // Save the channel to send_channels_, so that RemoveSendStream() can still
   // delete the channel in case failure happens below.
-  send_channels_[sp.first_ssrc()] = WebRtcVoiceChannelInfo(channel, NULL);
+  webrtc::AudioTransport* audio_transport =
+      engine()->voe()->base()->audio_transport();
+  send_channels_.insert(std::make_pair(
+      sp.first_ssrc(),
+      new WebRtcVoiceChannelRenderer(channel, audio_transport)));
 
   // Set the send (local) SSRC.
   // If there are multiple send SSRCs, we can only set the first one here, and
@@ -2319,10 +2541,10 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
     for (ChannelMap::const_iterator it = receive_channels_.begin();
          it != receive_channels_.end(); ++it) {
       // Only update the SSRC for non-default channels.
-      if (!IsDefaultChannel(it->second.channel)) {
-        if (engine()->voe()->rtp()->SetLocalSSRC(it->second.channel,
+      if (!IsDefaultChannel(it->second->channel())) {
+        if (engine()->voe()->rtp()->SetLocalSSRC(it->second->channel(),
                                                  sp.first_ssrc()) != 0) {
-          LOG_RTCERR2(SetLocalSSRC, it->second.channel, sp.first_ssrc());
+          LOG_RTCERR2(SetLocalSSRC, it->second->channel(), sp.first_ssrc());
           return false;
         }
       }
@@ -2349,12 +2571,13 @@ bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32 ssrc) {
     return false;
   }
 
-  int channel = it->second.channel;
+  int channel = it->second->channel();
   ChangeSend(channel, SEND_NOTHING);
 
-  // Notify the audio renderer that the send channel is going away.
-  if (it->second.renderer)
-    it->second.renderer->RemoveChannel(channel);
+  // Delete the WebRtcVoiceChannelRenderer object connected to the channel,
+  // this will disconnect the audio renderer with the send channel.
+  delete it->second;
+  send_channels_.erase(it);
 
   if (IsDefaultChannel(channel)) {
     // Do not delete the default channel since the receive channels depend on
@@ -2368,7 +2591,6 @@ bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32 ssrc) {
       return false;
   }
 
-  send_channels_.erase(it);
   if (send_channels_.empty())
     ChangeSend(SEND_NOTHING);
 
@@ -2376,7 +2598,7 @@ bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32 ssrc) {
 }
 
 bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
-  talk_base::CritScope lock(&receive_channels_cs_);
+  rtc::CritScope lock(&receive_channels_cs_);
 
   if (!VERIFY(sp.ssrcs.size() == 1))
     return false;
@@ -2394,12 +2616,15 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
 
   // Reuse default channel for recv stream in non-conference mode call
   // when the default channel is not being used.
+  webrtc::AudioTransport* audio_transport =
+      engine()->voe()->base()->audio_transport();
   if (!InConferenceMode() && default_receive_ssrc_ == 0) {
     LOG(LS_INFO) << "Recv stream " << sp.first_ssrc()
                  << " reuse default channel";
     default_receive_ssrc_ = sp.first_ssrc();
     receive_channels_.insert(std::make_pair(
-        default_receive_ssrc_, WebRtcVoiceChannelInfo(voe_channel(), NULL)));
+        default_receive_ssrc_,
+        new WebRtcVoiceChannelRenderer(voe_channel(), audio_transport)));
     return SetPlayout(voe_channel(), playout_);
   }
 
@@ -2416,7 +2641,8 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
   }
 
   receive_channels_.insert(
-      std::make_pair(ssrc, WebRtcVoiceChannelInfo(channel, NULL)));
+      std::make_pair(
+          ssrc, new WebRtcVoiceChannelRenderer(channel, audio_transport)));
 
   LOG(LS_INFO) << "New audio stream " << ssrc
                << " registered to VoiceEngine channel #"
@@ -2481,11 +2707,16 @@ bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) {
   }
   SetNack(channel, nack_enabled_);
 
+  // Set RTP header extension for the new channel.
+  if (!SetChannelRecvRtpHeaderExtensions(channel, receive_extensions_)) {
+    return false;
+  }
+
   return SetPlayout(channel, playout_);
 }
 
 bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32 ssrc) {
-  talk_base::CritScope lock(&receive_channels_cs_);
+  rtc::CritScope lock(&receive_channels_cs_);
   ChannelMap::iterator it = receive_channels_.find(ssrc);
   if (it == receive_channels_.end()) {
     LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
@@ -2493,34 +2724,28 @@ bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32 ssrc) {
     return false;
   }
 
+  // Delete the WebRtcVoiceChannelRenderer object connected to the channel, this
+  // will disconnect the audio renderer with the receive channel.
+  // Cache the channel before the deletion.
+  const int channel = it->second->channel();
+  delete it->second;
+  receive_channels_.erase(it);
+
   if (ssrc == default_receive_ssrc_) {
-    ASSERT(IsDefaultChannel(it->second.channel));
+    ASSERT(IsDefaultChannel(channel));
     // Recycle the default channel is for recv stream.
     if (playout_)
       SetPlayout(voe_channel(), false);
 
-    if (it->second.renderer)
-      it->second.renderer->RemoveChannel(voe_channel());
-
     default_receive_ssrc_ = 0;
-    receive_channels_.erase(it);
     return true;
   }
 
-  // Non default channel.
-  // Notify the renderer that channel is going away.
-  if (it->second.renderer)
-    it->second.renderer->RemoveChannel(it->second.channel);
-
   LOG(LS_INFO) << "Removing audio stream " << ssrc
-               << " with VoiceEngine channel #" << it->second.channel << ".";
-  if (!DeleteChannel(it->second.channel)) {
-    // Erase the entry anyhow.
-    receive_channels_.erase(it);
+               << " with VoiceEngine channel #" << channel << ".";
+  if (!DeleteChannel(channel))
     return false;
-  }
 
-  receive_channels_.erase(it);
   bool enable_default_channel_playout = false;
   if (receive_channels_.empty()) {
     // The last stream was removed. We can now enable the default
@@ -2558,19 +2783,11 @@ bool WebRtcVoiceMediaChannel::SetRemoteRenderer(uint32 ssrc,
     return true;
   }
 
-  AudioRenderer* remote_renderer = it->second.renderer;
-  if (renderer) {
-    ASSERT(remote_renderer == NULL || remote_renderer == renderer);
-    if (!remote_renderer) {
-      renderer->AddChannel(it->second.channel);
-    }
-  } else if (remote_renderer) {
-    // |renderer| == NULL, remove the channel from the renderer.
-    remote_renderer->RemoveChannel(it->second.channel);
-  }
+  if (renderer)
+    it->second->Start(renderer);
+  else
+    it->second->Stop();
 
-  // Assign the new value to the struct.
-  it->second.renderer = renderer;
   return true;
 }
 
@@ -2588,17 +2805,11 @@ bool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32 ssrc,
     return true;
   }
 
-  AudioRenderer* local_renderer = it->second.renderer;
-  if (renderer) {
-    ASSERT(local_renderer == NULL || local_renderer == renderer);
-    if (!local_renderer)
-      renderer->AddChannel(it->second.channel);
-  } else if (local_renderer) {
-    local_renderer->RemoveChannel(it->second.channel);
-  }
+  if (renderer)
+    it->second->Start(renderer);
+  else
+    it->second->Stop();
 
-  // Assign the new value to the struct.
-  it->second.renderer = renderer;
   return true;
 }
 
@@ -2609,7 +2820,7 @@ bool WebRtcVoiceMediaChannel::GetActiveStreams(
   actives->clear();
   for (ChannelMap::iterator it = receive_channels_.begin();
        it != receive_channels_.end(); ++it) {
-    int level = GetOutputLevel(it->second.channel);
+    int level = GetOutputLevel(it->second->channel());
     if (level > 0) {
       actives->push_back(std::make_pair(it->first, level));
     }
@@ -2622,8 +2833,8 @@ int WebRtcVoiceMediaChannel::GetOutputLevel() {
   int highest = GetOutputLevel(voe_channel());
   for (ChannelMap::iterator it = receive_channels_.begin();
        it != receive_channels_.end(); ++it) {
-    int level = GetOutputLevel(it->second.channel);
-    highest = talk_base::_max(level, highest);
+    int level = GetOutputLevel(it->second->channel());
+    highest = rtc::_max(level, highest);
   }
   return highest;
 }
@@ -2655,7 +2866,7 @@ void WebRtcVoiceMediaChannel::SetTypingDetectionParameters(int time_window,
 
 bool WebRtcVoiceMediaChannel::SetOutputScaling(
     uint32 ssrc, double left, double right) {
-  talk_base::CritScope lock(&receive_channels_cs_);
+  rtc::CritScope lock(&receive_channels_cs_);
   // Collect the channels to scale the output volume.
   std::vector<int> channels;
   if (0 == ssrc) {  // Collect all channels, including the default one.
@@ -2665,7 +2876,7 @@ bool WebRtcVoiceMediaChannel::SetOutputScaling(
       channels.push_back(voe_channel());
     for (ChannelMap::const_iterator it = receive_channels_.begin();
          it != receive_channels_.end(); ++it) {
-      channels.push_back(it->second.channel);
+      channels.push_back(it->second->channel());
     }
   } else {  // Collect only the channel of the specified ssrc.
     int channel = GetReceiveChannelNum(ssrc);
@@ -2678,7 +2889,7 @@ bool WebRtcVoiceMediaChannel::SetOutputScaling(
 
   // Scale the output volume for the collected channels. We first normalize to
   // scale the volume and then set the left and right pan.
-  float scale = static_cast<float>(talk_base::_max(left, right));
+  float scale = static_cast<float>(rtc::_max(left, right));
   if (scale > 0.0001f) {
     left /= scale;
     right /= scale;
@@ -2707,7 +2918,7 @@ bool WebRtcVoiceMediaChannel::GetOutputScaling(
     uint32 ssrc, double* left, double* right) {
   if (!left || !right) return false;
 
-  talk_base::CritScope lock(&receive_channels_cs_);
+  rtc::CritScope lock(&receive_channels_cs_);
   // Determine which channel based on ssrc.
   int channel = (0 == ssrc) ? voe_channel() : GetReceiveChannelNum(ssrc);
   if (channel == -1) {
@@ -2801,7 +3012,7 @@ bool WebRtcVoiceMediaChannel::InsertDtmf(uint32 ssrc, int event,
       bool default_channel_is_inuse = false;
       for (ChannelMap::const_iterator iter = send_channels_.begin();
            iter != send_channels_.end(); ++iter) {
-        if (IsDefaultChannel(iter->second.channel)) {
+        if (IsDefaultChannel(iter->second->channel())) {
           default_channel_is_inuse = true;
           break;
         }
@@ -2809,7 +3020,7 @@ bool WebRtcVoiceMediaChannel::InsertDtmf(uint32 ssrc, int event,
       if (default_channel_is_inuse) {
         channel = voe_channel();
       } else if (!send_channels_.empty()) {
-        channel = send_channels_.begin()->second.channel;
+        channel = send_channels_.begin()->second->channel();
       }
     } else {
       channel = GetSendChannelNum(ssrc);
@@ -2840,7 +3051,7 @@ bool WebRtcVoiceMediaChannel::InsertDtmf(uint32 ssrc, int event,
 }
 
 void WebRtcVoiceMediaChannel::OnPacketReceived(
-    talk_base::Buffer* packet, const talk_base::PacketTime& packet_time) {
+    rtc::Buffer* packet, const rtc::PacketTime& packet_time) {
   // Pick which channel to send this packet to. If this packet doesn't match
   // any multiplexed streams, just send it to the default channel. Otherwise,
   // send it to the specific decoder instance for that stream.
@@ -2874,7 +3085,7 @@ void WebRtcVoiceMediaChannel::OnPacketReceived(
 }
 
 void WebRtcVoiceMediaChannel::OnRtcpReceived(
-    talk_base::Buffer* packet, const talk_base::PacketTime& packet_time) {
+    rtc::Buffer* packet, const rtc::PacketTime& packet_time) {
   // Sending channels need all RTCP packets with feedback information.
   // Even sender reports can contain attached report blocks.
   // Receiving channels need sender reports in order to create
@@ -2907,11 +3118,12 @@ void WebRtcVoiceMediaChannel::OnRtcpReceived(
   for (ChannelMap::iterator iter = send_channels_.begin();
        iter != send_channels_.end(); ++iter) {
     // Make sure not sending the same packet to default channel more than once.
-    if (IsDefaultChannel(iter->second.channel) && has_sent_to_default_channel)
+    if (IsDefaultChannel(iter->second->channel()) &&
+        has_sent_to_default_channel)
       continue;
 
     engine()->voe()->network()->ReceivedRTCPPacket(
-        iter->second.channel,
+        iter->second->channel(),
         packet->data(),
         static_cast<unsigned int>(packet->length()));
   }
@@ -2927,6 +3139,23 @@ bool WebRtcVoiceMediaChannel::MuteStream(uint32 ssrc, bool muted) {
     LOG_RTCERR2(SetInputMute, channel, muted);
     return false;
   }
+  // We set the AGC to mute state only when all the channels are muted.
+  // This implementation is not ideal, instead we should signal the AGC when
+  // the mic channel is muted/unmuted. We can't do it today because there
+  // is no good way to know which stream is mapping to the mic channel.
+  bool all_muted = muted;
+  for (ChannelMap::const_iterator iter = send_channels_.begin();
+       iter != send_channels_.end() && all_muted; ++iter) {
+    if (engine()->voe()->volume()->GetInputMute(iter->second->channel(),
+                                                all_muted)) {
+      LOG_RTCERR1(GetInputMute, iter->second->channel());
+      return false;
+    }
+  }
+
+  webrtc::AudioProcessing* ap = engine()->voe()->base()->audio_processing();
+  if (ap)
+    ap->set_output_will_be_muted(all_muted);
   return true;
 }
 
@@ -3022,7 +3251,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
 
   for (ChannelMap::const_iterator channel_iter = send_channels_.begin();
        channel_iter != send_channels_.end(); ++channel_iter) {
-    const int channel = channel_iter->second.channel;
+    const int channel = channel_iter->second->channel();
 
     // Fill in the sender info, based on what we know, and what the
     // remote side told us it got from its RTCP report.
@@ -3094,7 +3323,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
   std::vector<int> channels;
   for (ChannelMap::const_iterator it = receive_channels_.begin();
        it != receive_channels_.end(); ++it) {
-    channels.push_back(it->second.channel);
+    channels.push_back(it->second->channel());
   }
   if (channels.empty()) {
     channels.push_back(voe_channel());
@@ -3116,6 +3345,12 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
       rinfo.fraction_lost = static_cast<float>(cs.fractionLost) / (1 << 8);
       rinfo.packets_lost = cs.cumulativeLost;
       rinfo.ext_seqnum = cs.extendedMax;
+#ifdef USE_WEBRTC_DEV_BRANCH
+      rinfo.capture_start_ntp_time_ms = cs.capture_start_ntp_time_ms_;
+#endif
+      if (codec.pltype != -1) {
+        rinfo.codec_name = codec.plname;
+      }
       // Convert samples to milliseconds.
       if (codec.plfreq / 1000 > 0) {
         rinfo.jitter_ms = cs.jitterSamples / (codec.plfreq / 1000);
@@ -3131,6 +3366,20 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
         rinfo.expand_rate =
             static_cast<float>(ns.currentExpandRate) / (1 << 14);
       }
+
+      webrtc::AudioDecodingCallStats ds;
+      if (engine()->voe()->neteq() &&
+          engine()->voe()->neteq()->GetDecodingCallStatistics(
+              *it, &ds) != -1) {
+        rinfo.decoding_calls_to_silence_generator =
+            ds.calls_to_silence_generator;
+        rinfo.decoding_calls_to_neteq = ds.calls_to_neteq;
+        rinfo.decoding_normal = ds.decoded_normal;
+        rinfo.decoding_plc = ds.decoded_plc;
+        rinfo.decoding_cng = ds.decoded_cng;
+        rinfo.decoding_plc_cng = ds.decoded_plc_cng;
+      }
+
       if (engine()->voe()->sync()) {
         int jitter_buffer_delay_ms = 0;
         int playout_buffer_delay_ms = 0;
@@ -3159,7 +3408,7 @@ void WebRtcVoiceMediaChannel::GetLastMediaError(
 }
 
 bool WebRtcVoiceMediaChannel::FindSsrc(int channel_num, uint32* ssrc) {
-  talk_base::CritScope lock(&receive_channels_cs_);
+  rtc::CritScope lock(&receive_channels_cs_);
   ASSERT(ssrc != NULL);
   if (channel_num == -1 && send_ != SEND_NOTHING) {
     // Sometimes the VoiceEngine core will throw error with channel_num = -1.
@@ -3172,7 +3421,7 @@ bool WebRtcVoiceMediaChannel::FindSsrc(int channel_num, uint32* ssrc) {
     // Check whether this is a sending channel.
     for (ChannelMap::const_iterator it = send_channels_.begin();
          it != send_channels_.end(); ++it) {
-      if (it->second.channel == channel_num) {
+      if (it->second->channel() == channel_num) {
         // This is a sending channel.
         uint32 local_ssrc = 0;
         if (engine()->voe()->rtp()->GetLocalSSRC(
@@ -3186,7 +3435,7 @@ bool WebRtcVoiceMediaChannel::FindSsrc(int channel_num, uint32* ssrc) {
     // Check whether this is a receiving channel.
     for (ChannelMap::const_iterator it = receive_channels_.begin();
         it != receive_channels_.end(); ++it) {
-      if (it->second.channel == channel_num) {
+      if (it->second->channel() == channel_num) {
         *ssrc = it->first;
         return true;
       }
@@ -3214,14 +3463,14 @@ int WebRtcVoiceMediaChannel::GetOutputLevel(int channel) {
 int WebRtcVoiceMediaChannel::GetReceiveChannelNum(uint32 ssrc) {
   ChannelMap::iterator it = receive_channels_.find(ssrc);
   if (it != receive_channels_.end())
-    return it->second.channel;
+    return it->second->channel();
   return (ssrc == default_receive_ssrc_) ?  voe_channel() : -1;
 }
 
 int WebRtcVoiceMediaChannel::GetSendChannelNum(uint32 ssrc) {
   ChannelMap::iterator it = send_channels_.find(ssrc);
   if (it != send_channels_.end())
-    return it->second.channel;
+    return it->second->channel();
 
   return -1;
 }
@@ -3241,9 +3490,9 @@ bool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec,
   if (it != red_codec.params.end()) {
     red_params = it->second;
     std::vector<std::string> red_pts;
-    if (talk_base::split(red_params, '/', &red_pts) != 2 ||
+    if (rtc::split(red_params, '/', &red_pts) != 2 ||
         red_pts[0] != red_pts[1] ||
-        !talk_base::FromString(red_pts[0], &red_pt)) {
+        !rtc::FromString(red_pts[0], &red_pt)) {
       LOG(LS_WARNING) << "RED params " << red_params << " not supported.";
       return false;
     }
@@ -3320,7 +3569,7 @@ uint32 WebRtcVoiceMediaChannel::ParseSsrc(const void* data, size_t len,
   size_t ssrc_pos = (!rtcp) ? 8 : 4;
   uint32 ssrc = 0;
   if (len >= (ssrc_pos + sizeof(ssrc))) {
-    ssrc = talk_base::GetBE32(static_cast<const char*>(data) + ssrc_pos);
+    ssrc = rtc::GetBE32(static_cast<const char*>(data) + ssrc_pos);
   }
   return ssrc;
 }
@@ -3358,6 +3607,23 @@ VoiceMediaChannel::Error
   }
 }
 
+bool WebRtcVoiceMediaChannel::SetHeaderExtension(ExtensionSetterFunction setter,
+    int channel_id, const RtpHeaderExtension* extension) {
+  bool enable = false;
+  int id = 0;
+  std::string uri;
+  if (extension) {
+    enable = true;
+    id = extension->id;
+    uri = extension->uri;
+  }
+  if ((engine()->voe()->rtp()->*setter)(channel_id, enable, id) != 0) {
+    LOG_RTCERR4(*setter, uri, channel_id, enable, id);
+    return false;
+  }
+  return true;
+}
+
 int WebRtcSoundclipStream::Read(void *buf, int len) {
   size_t res = 0;
   mem_.Read(buf, len, &res, NULL);