Move some receive stream configuration into webrtc::AudioReceiveStream.

Simplify creation of VoE channels and Call streams in WVoMC.

BUG=webrtc:4690

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

Cr-Commit-Position: refs/heads/master@{#10731}
diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h
index 8ef57d3..f0bd6a6 100644
--- a/talk/media/webrtc/fakewebrtcvoiceengine.h
+++ b/talk/media/webrtc/fakewebrtcvoiceengine.h
@@ -188,8 +188,6 @@
           red_type(117),
           nack_max_packets(0),
           send_ssrc(0),
-          receive_audio_level_ext_(-1),
-          receive_absolute_sender_time_ext_(-1),
           associate_send_channel(-1),
           neteq_capacity(-1),
           neteq_fast_accelerate(false) {
@@ -211,8 +209,6 @@
     int red_type;
     int nack_max_packets;
     uint32_t send_ssrc;
-    int receive_audio_level_ext_;
-    int receive_absolute_sender_time_ext_;
     int associate_send_channel;
     DtmfInfo dtmf_info;
     std::vector<webrtc::CodecInst> recv_codecs;
@@ -352,15 +348,6 @@
     channels_[++last_channel_] = ch;
     return last_channel_;
   }
-  int GetReceiveRtpExtensionId(int channel, const std::string& extension) {
-    WEBRTC_ASSERT_CHANNEL(channel);
-    if (extension == kRtpAudioLevelHeaderExtension) {
-      return channels_[channel]->receive_audio_level_ext_;
-    } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) {
-      return channels_[channel]->receive_absolute_sender_time_ext_;
-    }
-    return -1;
-  }
 
   int GetNumSetSendCodecs() const { return num_set_send_codecs_; }
 
@@ -710,23 +697,12 @@
   WEBRTC_STUB(GetRemoteSSRC, (int channel, unsigned int& ssrc));
   WEBRTC_STUB(SetSendAudioLevelIndicationStatus, (int channel, bool enable,
       unsigned char id));
-  WEBRTC_FUNC(SetReceiveAudioLevelIndicationStatus, (int channel, bool enable,
-      unsigned char id)) {
-    WEBRTC_CHECK_CHANNEL(channel);
-    WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id);
-    channels_[channel]->receive_audio_level_ext_ = (enable) ? id : -1;
-   return 0;
-  }
+  WEBRTC_STUB(SetReceiveAudioLevelIndicationStatus, (int channel, bool enable,
+      unsigned char id));
   WEBRTC_STUB(SetSendAbsoluteSenderTimeStatus, (int channel, bool enable,
       unsigned char id));
-  WEBRTC_FUNC(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable,
-      unsigned char id)) {
-    WEBRTC_CHECK_CHANNEL(channel);
-    WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id);
-    channels_[channel]->receive_absolute_sender_time_ext_ = (enable) ? id : -1;
-    return 0;
-  }
-
+  WEBRTC_STUB(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable,
+      unsigned char id));
   WEBRTC_STUB(SetRTCPStatus, (int channel, bool enable));
   WEBRTC_STUB(GetRTCPStatus, (int channel, bool& enabled));
   WEBRTC_STUB(SetRTCP_CNAME, (int channel, const char cname[256]));
diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc
index d124305..c81ecdf 100644
--- a/talk/media/webrtc/webrtcvoiceengine.cc
+++ b/talk/media/webrtc/webrtcvoiceengine.cc
@@ -1135,6 +1135,7 @@
   }
   return false;
 }
+
 const std::vector<RtpHeaderExtension>&
 WebRtcVoiceEngine::rtp_header_extensions() const {
   RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
@@ -1353,8 +1354,7 @@
                         uint32_t ssrc, const std::string& c_name,
                         const std::vector<webrtc::RtpExtension>& extensions,
                         webrtc::Call* call)
-      : channel_(ch),
-        voe_audio_transport_(voe_audio_transport),
+      : voe_audio_transport_(voe_audio_transport),
         call_(call),
         config_(nullptr) {
     RTC_DCHECK_GE(ch, 0);
@@ -1429,7 +1429,7 @@
     RTC_DCHECK(!worker_thread_checker_.CalledOnValidThread());
     RTC_DCHECK(audio_capture_thread_checker_.CalledOnValidThread());
     RTC_DCHECK(voe_audio_transport_);
-    voe_audio_transport_->OnData(channel_,
+    voe_audio_transport_->OnData(config_.voe_channel_id,
                                  audio_data,
                                  bits_per_sample,
                                  sample_rate,
@@ -1449,13 +1449,12 @@
   // Accessor to the VoE channel ID.
   int channel() const {
     RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
-    return channel_;
+    return config_.voe_channel_id;
   }
 
  private:
   rtc::ThreadChecker worker_thread_checker_;
   rtc::ThreadChecker audio_capture_thread_checker_;
-  const int channel_ = -1;
   webrtc::AudioTransport* const voe_audio_transport_ = nullptr;
   webrtc::Call* call_ = nullptr;
   webrtc::AudioSendStream::Config config_;
@@ -1473,18 +1472,72 @@
 
 class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream {
  public:
-  explicit WebRtcAudioReceiveStream(int voe_channel_id)
-      : channel_(voe_channel_id) {}
+  WebRtcAudioReceiveStream(int ch, uint32_t remote_ssrc, uint32_t local_ssrc,
+                           bool use_combined_bwe, const std::string& sync_group,
+                           const std::vector<webrtc::RtpExtension>& extensions,
+                           webrtc::Call* call)
+      : call_(call),
+        config_() {
+    RTC_DCHECK_GE(ch, 0);
+    RTC_DCHECK(call);
+    config_.rtp.remote_ssrc = remote_ssrc;
+    config_.rtp.local_ssrc = local_ssrc;
+    config_.voe_channel_id = ch;
+    config_.sync_group = sync_group;
+    RecreateAudioReceiveStream(use_combined_bwe, extensions);
+  }
 
-  int channel() { return channel_; }
+  ~WebRtcAudioReceiveStream() {
+    RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+    call_->DestroyAudioReceiveStream(stream_);
+  }
+
+  void RecreateAudioReceiveStream(
+      const std::vector<webrtc::RtpExtension>& extensions) {
+    RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+    RecreateAudioReceiveStream(config_.combined_audio_video_bwe, extensions);
+  }
+  void RecreateAudioReceiveStream(bool use_combined_bwe) {
+    RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+    RecreateAudioReceiveStream(use_combined_bwe, config_.rtp.extensions);
+  }
+
+  webrtc::AudioReceiveStream::Stats GetStats() const {
+    RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+    RTC_DCHECK(stream_);
+    return stream_->GetStats();
+  }
+
+  int channel() const {
+    RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+    return config_.voe_channel_id;
+  }
 
  private:
-  int channel_;
+  void RecreateAudioReceiveStream(bool use_combined_bwe,
+      const std::vector<webrtc::RtpExtension>& extensions) {
+    RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+    if (stream_) {
+      call_->DestroyAudioReceiveStream(stream_);
+      stream_ = nullptr;
+    }
+    config_.rtp.extensions = extensions;
+    config_.combined_audio_video_bwe = use_combined_bwe;
+    RTC_DCHECK(!stream_);
+    stream_ = call_->CreateAudioReceiveStream(config_);
+    RTC_CHECK(stream_);
+  }
+
+  rtc::ThreadChecker worker_thread_checker_;
+  webrtc::Call* call_ = nullptr;
+  webrtc::AudioReceiveStream::Config config_;
+  // The stream is owned by WebRtcAudioReceiveStream and may be reallocated if
+  // configuration changes.
+  webrtc::AudioReceiveStream* stream_ = nullptr;
 
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioReceiveStream);
 };
 
-// WebRtcVoiceMediaChannel
 WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine* engine,
                                                  const AudioOptions& options,
                                                  webrtc::Call* call)
@@ -1498,19 +1551,15 @@
 WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
   LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel";
-
-  // Remove any remaining send streams.
+  // TODO(solenberg): Should be able to delete the streams directly, without
+  //                  going through RemoveNnStream(), once stream objects handle
+  //                  all (de)configuration.
   while (!send_streams_.empty()) {
     RemoveSendStream(send_streams_.begin()->first);
   }
-
-  // Remove any remaining receive streams.
-  while (!receive_channels_.empty()) {
-    RemoveRecvStream(receive_channels_.begin()->first);
+  while (!recv_streams_.empty()) {
+    RemoveRecvStream(recv_streams_.begin()->first);
   }
-  RTC_DCHECK(receive_streams_.empty());
-
-  // Unregister ourselves from the engine.
   engine()->UnregisterChannel(this);
 }
 
@@ -1544,8 +1593,21 @@
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
   // TODO(pthatcher): Refactor this to be more clean now that we have
   // all the information at once.
-  return (SetRecvCodecs(params.codecs) &&
-          SetRecvRtpHeaderExtensions(params.extensions));
+
+  if (!SetRecvCodecs(params.codecs)) {
+    return false;
+  }
+
+  std::vector<webrtc::RtpExtension> recv_rtp_extensions =
+      FindAudioRtpHeaderExtensions(params.extensions);
+  if (recv_rtp_extensions_ != recv_rtp_extensions) {
+    recv_rtp_extensions_.swap(recv_rtp_extensions);
+    for (auto& it : recv_streams_) {
+      it.second->RecreateAudioReceiveStream(recv_rtp_extensions_);
+    }
+  }
+
+  return true;
 }
 
 bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
@@ -1579,7 +1641,10 @@
   }
 
   // TODO(solenberg): Don't recreate unless options changed.
-  RecreateAudioReceiveStreams();
+  for (auto& it : recv_streams_) {
+    it.second->RecreateAudioReceiveStream(
+        options_.combined_audio_video_bwe.value_or(false));
+  }
 
   LOG(LS_INFO) << "Set voice channel options.  Current options: "
                << options_.ToString();
@@ -1865,7 +1930,7 @@
   }
 
   // Set nack status on receive channels and update |nack_enabled_|.
-  for (const auto& ch : receive_channels_) {
+  for (const auto& ch : recv_streams_) {
     SetNack(ch.second->channel(), nack_enabled_);
   }
 
@@ -1901,49 +1966,6 @@
   return true;
 }
 
-bool WebRtcVoiceMediaChannel::SetRecvRtpHeaderExtensions(
-    const std::vector<RtpHeaderExtension>& extensions) {
-  RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
-  if (receive_extensions_ == extensions) {
-    return true;
-  }
-
-  for (const auto& ch : receive_channels_) {
-    if (!SetChannelRecvRtpHeaderExtensions(ch.second->channel(), extensions)) {
-      return false;
-    }
-  }
-
-  receive_extensions_ = extensions;
-
-  // Recreate AudioReceiveStream:s.
-  recv_rtp_extensions_ = FindAudioRtpHeaderExtensions(extensions);
-  RecreateAudioReceiveStreams();
-
-  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::SetPlayout(bool playout) {
   desired_playout_ = playout;
   return ChangePlayout(desired_playout_);
@@ -1963,7 +1985,7 @@
     return true;
   }
 
-  for (const auto& ch : receive_channels_) {
+  for (const auto& ch : recv_streams_) {
     if (!SetPlayout(ch.second->channel(), playout)) {
       LOG(LS_ERROR) << "SetPlayout " << playout << " on channel "
                     << ch.second->channel() << " failed";
@@ -2068,7 +2090,7 @@
   return id;
 }
 
-bool WebRtcVoiceMediaChannel::DeleteChannel(int channel) {
+bool WebRtcVoiceMediaChannel::DeleteVoEChannel(int channel) {
   if (engine()->voe()->network()->DeRegisterExternalTransport(channel) == -1) {
     LOG_RTCERR1(DeRegisterExternalTransport, channel);
   }
@@ -2117,10 +2139,10 @@
   // with the same SSRC in order to send receiver reports.
   if (send_streams_.size() == 1) {
     receiver_reports_ssrc_ = ssrc;
-    for (const auto& ch : receive_channels_) {
-      int recv_channel = ch.second->channel();
+    for (const auto& stream : recv_streams_) {
+      int recv_channel = stream.second->channel();
       if (engine()->voe()->rtp()->SetLocalSSRC(recv_channel, ssrc) != 0) {
-        LOG_RTCERR2(SetLocalSSRC, ch.second->channel(), ssrc);
+        LOG_RTCERR2(SetLocalSSRC, recv_channel, ssrc);
         return false;
       }
       engine()->voe()->base()->AssociateSendChannel(recv_channel, channel);
@@ -2146,15 +2168,12 @@
   int channel = it->second->channel();
   ChangeSend(channel, SEND_NOTHING);
 
-  // Delete the WebRtcVoiceChannelRenderer object connected to the channel,
-  // this will disconnect the audio renderer with the send channel.
-  delete it->second;
-  send_streams_.erase(it);
-
-  // Clean up and delete the send channel.
+  // Clean up and delete the send stream+channel.
   LOG(LS_INFO) << "Removing audio send stream " << ssrc
                << " with VoiceEngine channel #" << channel << ".";
-  if (!DeleteChannel(channel)) {
+  delete it->second;
+  send_streams_.erase(it);
+  if (!DeleteVoEChannel(channel)) {
     return false;
   }
   if (send_streams_.empty()) {
@@ -2171,7 +2190,7 @@
     return false;
   }
 
-  uint32_t ssrc = sp.first_ssrc();
+  const uint32_t ssrc = sp.first_ssrc();
   if (ssrc == 0) {
     LOG(LS_WARNING) << "AddRecvStream with ssrc==0 is not supported.";
     return false;
@@ -2183,52 +2202,19 @@
     RemoveRecvStream(ssrc);
   }
 
-  if (receive_channels_.find(ssrc) != receive_channels_.end()) {
+  if (GetReceiveChannelId(ssrc) != -1) {
     LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc;
     return false;
   }
-  RTC_DCHECK(receive_stream_params_.find(ssrc) == receive_stream_params_.end());
 
   // Create a new channel for receiving audio data.
-  int channel = CreateVoEChannel();
+  const int channel = CreateVoEChannel();
   if (channel == -1) {
     return false;
   }
-  if (!ConfigureRecvChannel(channel)) {
-    DeleteChannel(channel);
-    return false;
-  }
-
-  WebRtcAudioReceiveStream* stream = new WebRtcAudioReceiveStream(channel);
-  receive_channels_.insert(std::make_pair(ssrc, stream));
-  receive_stream_params_[ssrc] = sp;
-  AddAudioReceiveStream(ssrc);
-
-  LOG(LS_INFO) << "New audio stream " << ssrc
-               << " registered to VoiceEngine channel #"
-               << channel << ".";
-  return true;
-}
-
-bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) {
-  RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
-
-  int send_channel = GetSendChannelId(receiver_reports_ssrc_);
-  if (send_channel != -1) {
-    // Associate receive channel with first send channel (so the receive channel
-    // can obtain RTT from the send channel)
-    engine()->voe()->base()->AssociateSendChannel(channel, send_channel);
-    LOG(LS_INFO) << "VoiceEngine channel #" << channel
-                 << " is associated with channel #" << send_channel << ".";
-  }
-  if (engine()->voe()->rtp()->SetLocalSSRC(channel,
-                                           receiver_reports_ssrc_) == -1) {
-    LOG_RTCERR1(SetLocalSSRC, channel);
-    return false;
-  }
 
   // Turn off all supported codecs.
-  int ncodecs = engine()->voe()->codec()->NumOfCodecs();
+  const int ncodecs = engine()->voe()->codec()->NumOfCodecs();
   for (int i = 0; i < ncodecs; ++i) {
     webrtc::CodecInst voe_codec;
     if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) {
@@ -2236,6 +2222,7 @@
       if (engine()->voe()->codec()->SetRecPayloadType(
           channel, voe_codec) == -1) {
         LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
+        DeleteVoEChannel(channel);
         return false;
       }
     }
@@ -2249,19 +2236,29 @@
       if (engine()->voe()->codec()->SetRecPayloadType(
           channel, voe_codec) == -1) {
         LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
+        DeleteVoEChannel(channel);
         return false;
       }
     }
   }
 
-  SetNack(channel, nack_enabled_);
-
-  // Set RTP header extension for the new channel.
-  if (!SetChannelRecvRtpHeaderExtensions(channel, receive_extensions_)) {
-    return false;
+  const int send_channel = GetSendChannelId(receiver_reports_ssrc_);
+  if (send_channel != -1) {
+    // Associate receive channel with first send channel (so the receive channel
+    // can obtain RTT from the send channel)
+    engine()->voe()->base()->AssociateSendChannel(channel, send_channel);
+    LOG(LS_INFO) << "VoiceEngine channel #" << channel
+                 << " is associated with channel #" << send_channel << ".";
   }
 
+  recv_streams_.insert(std::make_pair(ssrc, new WebRtcAudioReceiveStream(
+      channel, ssrc, receiver_reports_ssrc_,
+      options_.combined_audio_video_bwe.value_or(false), sp.sync_label,
+      recv_rtp_extensions_, call_)));
+
+  SetNack(channel, nack_enabled_);
   SetPlayout(channel, playout_);
+
   return true;
 }
 
@@ -2269,28 +2266,26 @@
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
   LOG(LS_INFO) << "RemoveRecvStream: " << ssrc;
 
-  auto it = receive_channels_.find(ssrc);
-  if (it == receive_channels_.end()) {
+  const auto it = recv_streams_.find(ssrc);
+  if (it == recv_streams_.end()) {
     LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
                     << " which doesn't exist.";
     return false;
   }
 
-  RemoveAudioReceiveStream(ssrc);
-  receive_stream_params_.erase(ssrc);
-
-  const int channel = it->second->channel();
-  delete it->second;
-  receive_channels_.erase(it);
-
   // Deregister default channel, if that's the one being destroyed.
   if (IsDefaultRecvStream(ssrc)) {
     default_recv_ssrc_ = -1;
   }
 
-  LOG(LS_INFO) << "Removing audio stream " << ssrc
+  const int channel = it->second->channel();
+
+  // Clean up and delete the receive stream+channel.
+  LOG(LS_INFO) << "Removing audio receive stream " << ssrc
                << " with VoiceEngine channel #" << channel << ".";
-  return DeleteChannel(channel);
+  delete it->second;
+  recv_streams_.erase(it);
+  return DeleteVoEChannel(channel);
 }
 
 bool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32_t ssrc,
@@ -2320,7 +2315,7 @@
     AudioInfo::StreamList* actives) {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
   actives->clear();
-  for (const auto& ch : receive_channels_) {
+  for (const auto& ch : recv_streams_) {
     int level = GetOutputLevel(ch.second->channel());
     if (level > 0) {
       actives->push_back(std::make_pair(ch.first, level));
@@ -2332,7 +2327,7 @@
 int WebRtcVoiceMediaChannel::GetOutputLevel() {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
   int highest = 0;
-  for (const auto& ch : receive_channels_) {
+  for (const auto& ch : recv_streams_) {
     highest = std::max(GetOutputLevel(ch.second->channel()), highest);
   }
   return highest;
@@ -2647,7 +2642,7 @@
 
   // Get SSRC and stats for each receiver.
   RTC_DCHECK(info->receivers.size() == 0);
-  for (const auto& stream : receive_streams_) {
+  for (const auto& stream : recv_streams_) {
     webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats();
     VoiceReceiverInfo rinfo;
     rinfo.add_ssrc(stats.remote_ssrc);
@@ -2689,8 +2684,8 @@
 
 int WebRtcVoiceMediaChannel::GetReceiveChannelId(uint32_t ssrc) const {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
-  const auto it = receive_channels_.find(ssrc);
-  if (it != receive_channels_.end()) {
+  const auto it = recv_streams_.find(ssrc);
+  if (it != recv_streams_.end()) {
     return it->second->channel();
   }
   return -1;
@@ -2763,59 +2758,6 @@
   return true;
 }
 
-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;
-}
-
-void WebRtcVoiceMediaChannel::RecreateAudioReceiveStreams() {
-  RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
-  for (const auto& it : receive_channels_) {
-    RemoveAudioReceiveStream(it.first);
-  }
-  for (const auto& it : receive_channels_) {
-    AddAudioReceiveStream(it.first);
-  }
-}
-
-void WebRtcVoiceMediaChannel::AddAudioReceiveStream(uint32_t ssrc) {
-  RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
-  WebRtcAudioReceiveStream* stream = receive_channels_[ssrc];
-  RTC_DCHECK(stream != nullptr);
-  RTC_DCHECK(receive_streams_.find(ssrc) == receive_streams_.end());
-  webrtc::AudioReceiveStream::Config config;
-  config.rtp.remote_ssrc = ssrc;
-  // Only add RTP extensions if we support combined A/V BWE.
-  config.rtp.extensions = recv_rtp_extensions_;
-  config.combined_audio_video_bwe =
-      options_.combined_audio_video_bwe.value_or(false);
-  config.voe_channel_id = stream->channel();
-  config.sync_group = receive_stream_params_[ssrc].sync_label;
-  webrtc::AudioReceiveStream* s = call_->CreateAudioReceiveStream(config);
-  receive_streams_.insert(std::make_pair(ssrc, s));
-}
-
-void WebRtcVoiceMediaChannel::RemoveAudioReceiveStream(uint32_t ssrc) {
-  RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
-  auto stream_it = receive_streams_.find(ssrc);
-  if (stream_it != receive_streams_.end()) {
-    call_->DestroyAudioReceiveStream(stream_it->second);
-    receive_streams_.erase(stream_it);
-  }
-}
-
 bool WebRtcVoiceMediaChannel::SetRecvCodecsInternal(
     const std::vector<AudioCodec>& new_codecs) {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
@@ -2824,7 +2766,7 @@
     if (engine()->FindWebRtcCodec(codec, &voe_codec)) {
       LOG(LS_INFO) << ToString(codec);
       voe_codec.pltype = codec.id;
-      for (const auto& ch : receive_channels_) {
+      for (const auto& ch : recv_streams_) {
         if (engine()->voe()->codec()->SetRecPayloadType(
                 ch.second->channel(), voe_codec) == -1) {
           LOG_RTCERR2(SetRecPayloadType, ch.second->channel(),
@@ -2839,7 +2781,6 @@
   }
   return true;
 }
-
 }  // namespace cricket
 
 #endif  // HAVE_WEBRTC_VOICE
diff --git a/talk/media/webrtc/webrtcvoiceengine.h b/talk/media/webrtc/webrtcvoiceengine.h
index 2f74dab..c26aa06 100644
--- a/talk/media/webrtc/webrtcvoiceengine.h
+++ b/talk/media/webrtc/webrtcvoiceengine.h
@@ -248,8 +248,6 @@
   bool SetOptions(const AudioOptions& options);
   bool SetMaxSendBandwidth(int bps);
   bool SetRecvCodecs(const std::vector<AudioCodec>& codecs);
-  bool SetRecvRtpHeaderExtensions(
-      const std::vector<RtpHeaderExtension>& extensions);
   bool SetLocalRenderer(uint32_t ssrc, AudioRenderer* renderer);
   bool MuteStream(uint32_t ssrc, bool mute);
 
@@ -260,35 +258,20 @@
                        const std::vector<AudioCodec>& all_codecs,
                        webrtc::CodecInst* send_codec);
   bool SetPlayout(int channel, bool playout);
-
-  typedef int (webrtc::VoERTP_RTCP::* ExtensionSetterFunction)(int, bool,
-      unsigned char);
-
   void SetNack(int channel, bool nack_enabled);
   bool SetSendCodec(int channel, const webrtc::CodecInst& send_codec);
   bool ChangePlayout(bool playout);
   bool ChangeSend(SendFlags send);
   bool ChangeSend(int channel, SendFlags send);
-  bool ConfigureRecvChannel(int channel);
   int CreateVoEChannel();
-  bool DeleteChannel(int channel);
+  bool DeleteVoEChannel(int channel);
   bool IsDefaultRecvStream(uint32_t ssrc) {
     return default_recv_ssrc_ == static_cast<int64_t>(ssrc);
   }
   bool SetSendCodecs(int channel, const std::vector<AudioCodec>& codecs);
   bool SetSendBitrateInternal(int bps);
-
-  bool SetHeaderExtension(ExtensionSetterFunction setter, int channel_id,
-                          const RtpHeaderExtension* extension);
-  void RecreateAudioReceiveStreams();
-  void AddAudioReceiveStream(uint32_t ssrc);
-  void RemoveAudioReceiveStream(uint32_t ssrc);
   bool SetRecvCodecsInternal(const std::vector<AudioCodec>& new_codecs);
 
-  bool SetChannelRecvRtpHeaderExtensions(
-    int channel_id,
-    const std::vector<RtpHeaderExtension>& extensions);
-
   rtc::ThreadChecker worker_thread_checker_;
 
   WebRtcVoiceEngine* const engine_ = nullptr;
@@ -320,13 +303,7 @@
   std::vector<webrtc::RtpExtension> send_rtp_extensions_;
 
   class WebRtcAudioReceiveStream;
-  std::map<uint32_t, WebRtcAudioReceiveStream*> receive_channels_;
-  std::map<uint32_t, webrtc::AudioReceiveStream*> receive_streams_;
-  std::map<uint32_t, StreamParams> receive_stream_params_;
-  // receive_channels_ can be read from WebRtc callback thread.  Access from
-  // the WebRtc thread must be synchronized with edits on the worker thread.
-  // Reads on the worker thread are ok.
-  std::vector<RtpHeaderExtension> receive_extensions_;
+  std::map<uint32_t, WebRtcAudioReceiveStream*> recv_streams_;
   std::vector<webrtc::RtpExtension> recv_rtp_extensions_;
 
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcVoiceMediaChannel);
diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
index 2322e10..6309833 100644
--- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc
+++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
@@ -144,6 +144,12 @@
     return send_stream->GetConfig();
   }
 
+  const webrtc::AudioReceiveStream::Config& GetRecvStreamConfig(uint32_t ssrc) {
+    const auto* recv_stream = call_.GetAudioReceiveStream(ssrc);
+    EXPECT_TRUE(recv_stream);
+    return recv_stream->GetConfig();
+  }
+
   void TestInsertDtmf(uint32_t ssrc, bool caller) {
     EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
     channel_ = engine_.CreateChannel(&call_, cricket::AudioOptions());
@@ -239,7 +245,7 @@
     EXPECT_EQ(ext, GetSendStreamConfig(kSsrc1).rtp.extensions[0].name);
     EXPECT_EQ(id, GetSendStreamConfig(kSsrc1).rtp.extensions[0].id);
 
-    // Ensure extension is set properly on new channels.
+    // Ensure extension is set properly on new stream.
     EXPECT_TRUE(channel_->AddSendStream(
         cricket::StreamParams::CreateLegacy(kSsrc2)));
     EXPECT_NE(call_.GetAudioSendStream(kSsrc1),
@@ -258,42 +264,43 @@
 
   void TestSetRecvRtpHeaderExtensions(const std::string& ext) {
     EXPECT_TRUE(SetupEngineWithRecvStream());
-    int channel_num = voe_.GetLastChannel();
 
     // Ensure extensions are off by default.
-    EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
+    EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size());
 
-    cricket::AudioRecvParameters parameters;
     // Ensure unknown extensions won't cause an error.
-    parameters.extensions.push_back(cricket::RtpHeaderExtension(
+    recv_parameters_.extensions.push_back(cricket::RtpHeaderExtension(
         "urn:ietf:params:unknownextention", 1));
-    EXPECT_TRUE(channel_->SetRecvParameters(parameters));
-    EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
+    EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_));
+    EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size());
 
     // Ensure extensions stay off with an empty list of headers.
-    parameters.extensions.clear();
-    EXPECT_TRUE(channel_->SetRecvParameters(parameters));
-    EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
+    recv_parameters_.extensions.clear();
+    EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_));
+    EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size());
 
     // Ensure extension is set properly.
     const int id = 2;
-    parameters.extensions.push_back(cricket::RtpHeaderExtension(ext, id));
-    EXPECT_TRUE(channel_->SetRecvParameters(parameters));
-    EXPECT_EQ(id, voe_.GetReceiveRtpExtensionId(channel_num, ext));
+    recv_parameters_.extensions.push_back(cricket::RtpHeaderExtension(ext, id));
+    EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_));
+    EXPECT_EQ(1u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size());
+    EXPECT_EQ(ext, GetRecvStreamConfig(kSsrc1).rtp.extensions[0].name);
+    EXPECT_EQ(id, GetRecvStreamConfig(kSsrc1).rtp.extensions[0].id);
 
-    // Ensure extension is set properly on new channel.
-    // The first stream to occupy the default channel.
+    // Ensure extension is set properly on new stream.
     EXPECT_TRUE(channel_->AddRecvStream(
         cricket::StreamParams::CreateLegacy(kSsrc2)));
-    int new_channel_num = voe_.GetLastChannel();
-    EXPECT_NE(channel_num, new_channel_num);
-    EXPECT_EQ(id, voe_.GetReceiveRtpExtensionId(new_channel_num, ext));
+    EXPECT_NE(call_.GetAudioReceiveStream(kSsrc1),
+              call_.GetAudioReceiveStream(kSsrc2));
+    EXPECT_EQ(1u, GetRecvStreamConfig(kSsrc2).rtp.extensions.size());
+    EXPECT_EQ(ext, GetRecvStreamConfig(kSsrc2).rtp.extensions[0].name);
+    EXPECT_EQ(id, GetRecvStreamConfig(kSsrc2).rtp.extensions[0].id);
 
     // Ensure all extensions go back off with an empty list.
-    parameters.extensions.clear();
-    EXPECT_TRUE(channel_->SetRecvParameters(parameters));
-    EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
-    EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(new_channel_num, ext));
+    recv_parameters_.extensions.clear();
+    EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_));
+    EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size());
+    EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc2).rtp.extensions.size());
   }
 
   webrtc::AudioSendStream::Stats GetAudioSendStreamStats() const {
@@ -2402,8 +2409,9 @@
 TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrcWithMultipleStreams) {
   EXPECT_TRUE(SetupEngineWithSendStream());
   EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1));
-  EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
-  EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel()));
+  EXPECT_TRUE(channel_->AddRecvStream(
+      cricket::StreamParams::CreateLegacy(kSsrc2)));
+  EXPECT_EQ(kSsrc1, GetRecvStreamConfig(kSsrc2).rtp.local_ssrc);
 }
 
 // Test that the local SSRC is the same on sending and receiving channels if the
diff --git a/webrtc/audio/audio_receive_stream.cc b/webrtc/audio/audio_receive_stream.cc
index bdccea2..82e8ddf 100644
--- a/webrtc/audio/audio_receive_stream.cc
+++ b/webrtc/audio/audio_receive_stream.cc
@@ -73,19 +73,35 @@
   RTC_DCHECK(remote_bitrate_estimator_);
   RTC_DCHECK(audio_state_.get());
   RTC_DCHECK(rtp_header_parser_);
-  for (const auto& ext : config.rtp.extensions) {
+
+  const int channel_id = config.voe_channel_id;
+  ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine());
+  int error = rtp->SetLocalSSRC(channel_id, config.rtp.local_ssrc);
+  RTC_DCHECK_EQ(0, error);
+  for (const auto& extension : config.rtp.extensions) {
     // One-byte-extension local identifiers are in the range 1-14 inclusive.
-    RTC_DCHECK_GE(ext.id, 1);
-    RTC_DCHECK_LE(ext.id, 14);
-    if (ext.name == RtpExtension::kAudioLevel) {
-      RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension(
-          kRtpExtensionAudioLevel, ext.id));
-    } else if (ext.name == RtpExtension::kAbsSendTime) {
-      RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension(
-          kRtpExtensionAbsoluteSendTime, ext.id));
-    } else if (ext.name == RtpExtension::kTransportSequenceNumber) {
-      RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension(
-          kRtpExtensionTransportSequenceNumber, ext.id));
+    RTC_DCHECK_GE(extension.id, 1);
+    RTC_DCHECK_LE(extension.id, 14);
+    if (extension.name == RtpExtension::kAudioLevel) {
+      error = rtp->SetReceiveAudioLevelIndicationStatus(channel_id, true,
+                                                        extension.id);
+      RTC_DCHECK_EQ(0, error);
+      bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
+          kRtpExtensionAudioLevel, extension.id);
+      RTC_DCHECK(registered);
+    } else if (extension.name == RtpExtension::kAbsSendTime) {
+      error = rtp->SetReceiveAbsoluteSenderTimeStatus(channel_id, true,
+                                                      extension.id);
+      RTC_DCHECK_EQ(0, error);
+      bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
+          kRtpExtensionAbsoluteSendTime, extension.id);
+      RTC_DCHECK(registered);
+    } else if (extension.name == RtpExtension::kTransportSequenceNumber) {
+      // TODO(holmer): Need to do something here or in  DeliverRtp() to actually
+      //               handle audio packets with this header extension.
+      bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
+          kRtpExtensionTransportSequenceNumber, extension.id);
+      RTC_DCHECK(registered);
     } else {
       RTC_NOTREACHED() << "Unsupported RTP extension.";
     }
@@ -97,18 +113,61 @@
   LOG(LS_INFO) << "~AudioReceiveStream: " << config_.ToString();
 }
 
+void AudioReceiveStream::Start() {
+  RTC_DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void AudioReceiveStream::Stop() {
+  RTC_DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void AudioReceiveStream::SignalNetworkState(NetworkState state) {
+  RTC_DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+bool AudioReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
+  // TODO(solenberg): Tests call this function on a network thread, libjingle
+  // calls on the worker thread. We should move towards always using a network
+  // thread. Then this check can be enabled.
+  // RTC_DCHECK(!thread_checker_.CalledOnValidThread());
+  return false;
+}
+
+bool AudioReceiveStream::DeliverRtp(const uint8_t* packet,
+                                    size_t length,
+                                    const PacketTime& packet_time) {
+  // TODO(solenberg): Tests call this function on a network thread, libjingle
+  // calls on the worker thread. We should move towards always using a network
+  // thread. Then this check can be enabled.
+  // RTC_DCHECK(!thread_checker_.CalledOnValidThread());
+  RTPHeader header;
+  if (!rtp_header_parser_->Parse(packet, length, &header)) {
+    return false;
+  }
+
+  // Only forward if the parsed header has absolute sender time. RTP timestamps
+  // may have different rates for audio and video and shouldn't be mixed.
+  if (config_.combined_audio_video_bwe &&
+      header.extension.hasAbsoluteSendTime) {
+    int64_t arrival_time_ms = TickTime::MillisecondTimestamp();
+    if (packet_time.timestamp >= 0)
+      arrival_time_ms = (packet_time.timestamp + 500) / 1000;
+    size_t payload_size = length - header.headerLength;
+    remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_size,
+                                              header, false);
+  }
+  return true;
+}
+
 webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const {
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
   webrtc::AudioReceiveStream::Stats stats;
   stats.remote_ssrc = config_.rtp.remote_ssrc;
-  internal::AudioState* audio_state =
-      static_cast<internal::AudioState*>(audio_state_.get());
-  VoiceEngine* voice_engine = audio_state->voice_engine();
-  ScopedVoEInterface<VoECodec> codec(voice_engine);
-  ScopedVoEInterface<VoENetEqStats> neteq(voice_engine);
-  ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine);
-  ScopedVoEInterface<VoEVideoSync> sync(voice_engine);
-  ScopedVoEInterface<VoEVolumeControl> volume(voice_engine);
+  ScopedVoEInterface<VoECodec> codec(voice_engine());
+  ScopedVoEInterface<VoENetEqStats> neteq(voice_engine());
+  ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine());
+  ScopedVoEInterface<VoEVideoSync> sync(voice_engine());
+  ScopedVoEInterface<VoEVolumeControl> volume(voice_engine());
 
   webrtc::CallStatistics call_stats = {0};
   int error = rtp->GetRTCPStatistics(config_.voe_channel_id, call_stats);
@@ -175,50 +234,12 @@
   return config_;
 }
 
-void AudioReceiveStream::Start() {
-  RTC_DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-void AudioReceiveStream::Stop() {
-  RTC_DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-void AudioReceiveStream::SignalNetworkState(NetworkState state) {
-  RTC_DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-bool AudioReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
-  // TODO(solenberg): Tests call this function on a network thread, libjingle
-  // calls on the worker thread. We should move towards always using a network
-  // thread. Then this check can be enabled.
-  // RTC_DCHECK(!thread_checker_.CalledOnValidThread());
-  return false;
-}
-
-bool AudioReceiveStream::DeliverRtp(const uint8_t* packet,
-                                    size_t length,
-                                    const PacketTime& packet_time) {
-  // TODO(solenberg): Tests call this function on a network thread, libjingle
-  // calls on the worker thread. We should move towards always using a network
-  // thread. Then this check can be enabled.
-  // RTC_DCHECK(!thread_checker_.CalledOnValidThread());
-  RTPHeader header;
-  if (!rtp_header_parser_->Parse(packet, length, &header)) {
-    return false;
-  }
-
-  // Only forward if the parsed header has absolute sender time. RTP timestamps
-  // may have different rates for audio and video and shouldn't be mixed.
-  if (config_.combined_audio_video_bwe &&
-      header.extension.hasAbsoluteSendTime) {
-    int64_t arrival_time_ms = TickTime::MillisecondTimestamp();
-    if (packet_time.timestamp >= 0)
-      arrival_time_ms = (packet_time.timestamp + 500) / 1000;
-    size_t payload_size = length - header.headerLength;
-    remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_size,
-                                              header, false);
-  }
-  return true;
+VoiceEngine* AudioReceiveStream::voice_engine() const {
+  internal::AudioState* audio_state =
+      static_cast<internal::AudioState*>(audio_state_.get());
+  VoiceEngine* voice_engine = audio_state->voice_engine();
+  RTC_DCHECK(voice_engine);
+  return voice_engine;
 }
 }  // namespace internal
 }  // namespace webrtc
diff --git a/webrtc/audio/audio_receive_stream.h b/webrtc/audio/audio_receive_stream.h
index a461aad..e7a2952 100644
--- a/webrtc/audio/audio_receive_stream.h
+++ b/webrtc/audio/audio_receive_stream.h
@@ -44,6 +44,8 @@
   const webrtc::AudioReceiveStream::Config& config() const;
 
  private:
+  VoiceEngine* voice_engine() const;
+
   rtc::ThreadChecker thread_checker_;
   RemoteBitrateEstimator* const remote_bitrate_estimator_;
   const webrtc::AudioReceiveStream::Config config_;
diff --git a/webrtc/audio/audio_receive_stream_unittest.cc b/webrtc/audio/audio_receive_stream_unittest.cc
index 715b52a..5efd5b0 100644
--- a/webrtc/audio/audio_receive_stream_unittest.cc
+++ b/webrtc/audio/audio_receive_stream_unittest.cc
@@ -38,7 +38,8 @@
 const uint32_t kRemoteSsrc = 1234;
 const uint32_t kLocalSsrc = 5678;
 const size_t kAbsoluteSendTimeLength = 4;
-const int kAbsSendTimeId = 3;
+const int kAbsSendTimeId = 2;
+const int kAudioLevelId = 3;
 const int kJitterBufferDelay = -7;
 const int kPlayoutBufferDelay = 302;
 const unsigned int kSpeechOutputLevel = 99;
@@ -59,10 +60,23 @@
     AudioState::Config config;
     config.voice_engine = &voice_engine_;
     audio_state_ = AudioState::Create(config);
+
+    EXPECT_CALL(voice_engine_, SetLocalSSRC(kChannelId, kLocalSsrc))
+        .WillOnce(Return(0));
+    EXPECT_CALL(voice_engine_,
+        SetReceiveAbsoluteSenderTimeStatus(kChannelId, true, kAbsSendTimeId))
+            .WillOnce(Return(0));
+    EXPECT_CALL(voice_engine_,
+        SetReceiveAudioLevelIndicationStatus(kChannelId, true, kAudioLevelId))
+            .WillOnce(Return(0));
     stream_config_.voe_channel_id = kChannelId;
     stream_config_.rtp.local_ssrc = kLocalSsrc;
     stream_config_.rtp.remote_ssrc = kRemoteSsrc;
-  }
+    stream_config_.rtp.extensions.push_back(
+        RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
+    stream_config_.rtp.extensions.push_back(
+        RtpExtension(RtpExtension::kAudioLevel, kAudioLevelId));
+}
 
   MockRemoteBitrateEstimator* remote_bitrate_estimator() {
     return &remote_bitrate_estimator_;
@@ -144,7 +158,7 @@
   config.combined_audio_video_bwe = true;
   EXPECT_EQ(
       "{rtp: {remote_ssrc: 1234, local_ssrc: 5678, extensions: [{name: "
-      "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 3}]}, "
+      "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 2}]}, "
       "receive_transport: nullptr, rtcp_send_transport: nullptr, "
       "voe_channel_id: 2, combined_audio_video_bwe: true}",
       config.ToString());
@@ -159,8 +173,6 @@
 TEST(AudioReceiveStreamTest, AudioPacketUpdatesBweWithTimestamp) {
   ConfigHelper helper;
   helper.config().combined_audio_video_bwe = true;
-  helper.config().rtp.extensions.push_back(
-      RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
   internal::AudioReceiveStream recv_stream(
       helper.remote_bitrate_estimator(), helper.config(), helper.audio_state());
   uint8_t rtp_packet[30];