Move some send stream configuration into webrtc::AudioSendStream.

BUG=webrtc:4690

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

Cr-Commit-Position: refs/heads/master@{#10652}
diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h
index d031d10..8ef57d3 100644
--- a/talk/media/webrtc/fakewebrtcvoiceengine.h
+++ b/talk/media/webrtc/fakewebrtcvoiceengine.h
@@ -188,9 +188,7 @@
           red_type(117),
           nack_max_packets(0),
           send_ssrc(0),
-          send_audio_level_ext_(-1),
           receive_audio_level_ext_(-1),
-          send_absolute_sender_time_ext_(-1),
           receive_absolute_sender_time_ext_(-1),
           associate_send_channel(-1),
           neteq_capacity(-1),
@@ -213,9 +211,7 @@
     int red_type;
     int nack_max_packets;
     uint32_t send_ssrc;
-    int send_audio_level_ext_;
     int receive_audio_level_ext_;
-    int send_absolute_sender_time_ext_;
     int receive_absolute_sender_time_ext_;
     int associate_send_channel;
     DtmfInfo dtmf_info;
@@ -267,14 +263,6 @@
 
   bool IsInited() const { return inited_; }
   int GetLastChannel() const { return last_channel_; }
-  int GetChannelFromLocalSsrc(uint32_t local_ssrc) const {
-    for (std::map<int, Channel*>::const_iterator iter = channels_.begin();
-         iter != channels_.end(); ++iter) {
-      if (local_ssrc == iter->second->send_ssrc)
-        return iter->first;
-    }
-    return -1;
-  }
   int GetNumChannels() const { return static_cast<int>(channels_.size()); }
   uint32_t GetLocalSSRC(int channel) {
     return channels_[channel]->send_ssrc;
@@ -364,15 +352,6 @@
     channels_[++last_channel_] = ch;
     return last_channel_;
   }
-  int GetSendRtpExtensionId(int channel, const std::string& extension) {
-    WEBRTC_ASSERT_CHANNEL(channel);
-    if (extension == kRtpAudioLevelHeaderExtension) {
-      return channels_[channel]->send_audio_level_ext_;
-    } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) {
-      return channels_[channel]->send_absolute_sender_time_ext_;
-    }
-    return -1;
-  }
   int GetReceiveRtpExtensionId(int channel, const std::string& extension) {
     WEBRTC_ASSERT_CHANNEL(channel);
     if (extension == kRtpAudioLevelHeaderExtension) {
@@ -729,13 +708,8 @@
   }
   WEBRTC_STUB(GetLocalSSRC, (int channel, unsigned int& ssrc));
   WEBRTC_STUB(GetRemoteSSRC, (int channel, unsigned int& ssrc));
-  WEBRTC_FUNC(SetSendAudioLevelIndicationStatus, (int channel, bool enable,
-      unsigned char id)) {
-    WEBRTC_CHECK_CHANNEL(channel);
-    WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id);
-    channels_[channel]->send_audio_level_ext_ = (enable) ? id : -1;
-    return 0;
-  }
+  WEBRTC_STUB(SetSendAudioLevelIndicationStatus, (int channel, bool enable,
+      unsigned char id));
   WEBRTC_FUNC(SetReceiveAudioLevelIndicationStatus, (int channel, bool enable,
       unsigned char id)) {
     WEBRTC_CHECK_CHANNEL(channel);
@@ -743,13 +717,8 @@
     channels_[channel]->receive_audio_level_ext_ = (enable) ? id : -1;
    return 0;
   }
-  WEBRTC_FUNC(SetSendAbsoluteSenderTimeStatus, (int channel, bool enable,
-      unsigned char id)) {
-    WEBRTC_CHECK_CHANNEL(channel);
-    WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id);
-    channels_[channel]->send_absolute_sender_time_ext_ = (enable) ? id : -1;
-    return 0;
-  }
+  WEBRTC_STUB(SetSendAbsoluteSenderTimeStatus, (int channel, bool enable,
+      unsigned char id));
   WEBRTC_FUNC(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable,
       unsigned char id)) {
     WEBRTC_CHECK_CHANNEL(channel);
diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc
index a7e1a43..c13b229 100644
--- a/talk/media/webrtc/webrtcvoiceengine.cc
+++ b/talk/media/webrtc/webrtcvoiceengine.cc
@@ -396,6 +396,19 @@
   return config;
 }
 
+std::vector<webrtc::RtpExtension> FindAudioRtpHeaderExtensions(
+    const std::vector<RtpHeaderExtension>& extensions) {
+  std::vector<webrtc::RtpExtension> result;
+  for (const auto& extension : extensions) {
+    if (extension.uri == kRtpAbsoluteSenderTimeHeaderExtension ||
+        extension.uri == kRtpAudioLevelHeaderExtension) {
+      result.push_back({extension.uri, extension.id});
+    } else {
+      LOG(LS_WARNING) << "Unsupported RTP extension: " << extension.ToString();
+    }
+  }
+  return result;
+}
 } // namespace {
 
 WebRtcVoiceEngine::WebRtcVoiceEngine()
@@ -1337,27 +1350,49 @@
     : public AudioRenderer::Sink {
  public:
   WebRtcAudioSendStream(int ch, webrtc::AudioTransport* voe_audio_transport,
-                        uint32_t ssrc, webrtc::Call* call)
+                        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),
-        call_(call) {
+        call_(call),
+        config_(nullptr) {
     RTC_DCHECK_GE(ch, 0);
     // TODO(solenberg): Once we're not using FakeWebRtcVoiceEngine anymore:
     // RTC_DCHECK(voe_audio_transport);
     RTC_DCHECK(call);
     audio_capture_thread_checker_.DetachFromThread();
-    webrtc::AudioSendStream::Config config(nullptr);
-    config.voe_channel_id = channel_;
-    config.rtp.ssrc = ssrc;
-    stream_ = call_->CreateAudioSendStream(config);
-    RTC_DCHECK(stream_);
+    config_.rtp.ssrc = ssrc;
+    config_.rtp.c_name = c_name;
+    config_.voe_channel_id = ch;
+    RecreateAudioSendStream(extensions);
   }
+
   ~WebRtcAudioSendStream() override {
     RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
     Stop();
     call_->DestroyAudioSendStream(stream_);
   }
 
+  void RecreateAudioSendStream(
+      const std::vector<webrtc::RtpExtension>& extensions) {
+    RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+    if (stream_) {
+      call_->DestroyAudioSendStream(stream_);
+      stream_ = nullptr;
+    }
+    config_.rtp.extensions = extensions;
+    RTC_DCHECK(!stream_);
+    stream_ = call_->CreateAudioSendStream(config_);
+    RTC_CHECK(stream_);
+  }
+
+  webrtc::AudioSendStream::Stats GetStats() const {
+    RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+    RTC_DCHECK(stream_);
+    return stream_->GetStats();
+  }
+
   // Starts the rendering by setting a sink to the renderer to get data
   // callback.
   // This method is called on the libjingle worker thread.
@@ -1373,11 +1408,6 @@
     renderer_ = renderer;
   }
 
-  webrtc::AudioSendStream::Stats GetStats() const {
-    RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
-    return stream_->GetStats();
-  }
-
   // Stops rendering by setting the sink of the renderer to nullptr. No data
   // callback will be received after this method.
   // This method is called on the libjingle worker thread.
@@ -1428,6 +1458,9 @@
   const int channel_ = -1;
   webrtc::AudioTransport* const voe_audio_transport_ = nullptr;
   webrtc::Call* call_ = nullptr;
+  webrtc::AudioSendStream::Config config_;
+  // The stream is owned by WebRtcAudioSendStream and may be reallocated if
+  // configuration changes.
   webrtc::AudioSendStream* stream_ = nullptr;
 
   // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler.
@@ -1486,10 +1519,24 @@
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
   // TODO(pthatcher): Refactor this to be more clean now that we have
   // all the information at once.
-  return (SetSendCodecs(params.codecs) &&
-          SetSendRtpHeaderExtensions(params.extensions) &&
-          SetMaxSendBandwidth(params.max_bandwidth_bps) &&
-          SetOptions(params.options));
+
+  if (!SetSendCodecs(params.codecs)) {
+    return false;
+  }
+
+  std::vector<webrtc::RtpExtension> send_rtp_extensions =
+      FindAudioRtpHeaderExtensions(params.extensions);
+  if (send_rtp_extensions_ != send_rtp_extensions) {
+    send_rtp_extensions_.swap(send_rtp_extensions);
+    for (auto& it : send_streams_) {
+      it.second->RecreateAudioSendStream(send_rtp_extensions_);
+    }
+  }
+
+  if (!SetMaxSendBandwidth(params.max_bandwidth_bps)) {
+    return false;
+  }
+  return SetOptions(params.options);
 }
 
 bool WebRtcVoiceMediaChannel::SetRecvParameters(
@@ -1870,26 +1917,8 @@
   receive_extensions_ = extensions;
 
   // Recreate AudioReceiveStream:s.
-  {
-    std::vector<webrtc::RtpExtension> exts;
-
-    const RtpHeaderExtension* audio_level_extension =
-        FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension);
-    if (audio_level_extension) {
-      exts.push_back({
-          kRtpAudioLevelHeaderExtension, audio_level_extension->id});
-    }
-
-    const RtpHeaderExtension* send_time_extension =
-        FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
-    if (send_time_extension) {
-      exts.push_back({
-          kRtpAbsoluteSenderTimeHeaderExtension, send_time_extension->id});
-    }
-
-    recv_rtp_extensions_.swap(exts);
-    RecreateAudioReceiveStreams();
-  }
+  recv_rtp_extensions_ = FindAudioRtpHeaderExtensions(extensions);
+  RecreateAudioReceiveStreams();
 
   return true;
 }
@@ -1915,45 +1944,6 @@
   return true;
 }
 
-bool WebRtcVoiceMediaChannel::SetSendRtpHeaderExtensions(
-    const std::vector<RtpHeaderExtension>& extensions) {
-  RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
-  if (send_extensions_ == extensions) {
-    return true;
-  }
-
-  for (const auto& ch : send_streams_) {
-    if (!SetChannelSendRtpHeaderExtensions(ch.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;
-}
-
 bool WebRtcVoiceMediaChannel::SetPlayout(bool playout) {
   desired_playout_ = playout;
   return ChangePlayout(desired_playout_);
@@ -2107,33 +2097,12 @@
     return false;
   }
 
-  // Enable RTCP (for quality stats and feedback messages).
-  if (engine()->voe()->rtp()->SetRTCPStatus(channel, true) == -1) {
-    LOG_RTCERR2(SetRTCPStatus, channel, 1);
-  }
-
-  SetChannelSendRtpHeaderExtensions(channel, send_extensions_);
-
-  // Set the local (send) SSRC.
-  if (engine()->voe()->rtp()->SetLocalSSRC(channel, ssrc) == -1) {
-    LOG_RTCERR2(SetLocalSSRC, channel, ssrc);
-    DeleteChannel(channel);
-    return false;
-  }
-
-  if (engine()->voe()->rtp()->SetRTCP_CNAME(channel, sp.cname.c_str()) == -1) {
-    LOG_RTCERR2(SetRTCP_CNAME, channel, sp.cname);
-    DeleteChannel(channel);
-    return false;
-  }
-
   // Save the channel to send_streams_, so that RemoveSendStream() can still
   // delete the channel in case failure happens below.
   webrtc::AudioTransport* audio_transport =
       engine()->voe()->base()->audio_transport();
-  send_streams_.insert(
-      std::make_pair(ssrc,
-          new WebRtcAudioSendStream(channel, audio_transport, ssrc, call_)));
+  send_streams_.insert(std::make_pair(ssrc, new WebRtcAudioSendStream(
+      channel, audio_transport, ssrc, sp.cname, send_rtp_extensions_, call_)));
 
   // Set the current codecs to be used for the new channel. We need to do this
   // after adding the channel to send_channels_, because of how max bitrate is
@@ -2165,6 +2134,8 @@
 
 bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32_t ssrc) {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+  LOG(LS_INFO) << "RemoveSendStream: " << ssrc;
+
   auto it = send_streams_.find(ssrc);
   if (it == send_streams_.end()) {
     LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
diff --git a/talk/media/webrtc/webrtcvoiceengine.h b/talk/media/webrtc/webrtcvoiceengine.h
index e480c13..2f74dab 100644
--- a/talk/media/webrtc/webrtcvoiceengine.h
+++ b/talk/media/webrtc/webrtcvoiceengine.h
@@ -245,8 +245,6 @@
 
  private:
   bool SetSendCodecs(const std::vector<AudioCodec>& codecs);
-  bool SetSendRtpHeaderExtensions(
-      const std::vector<RtpHeaderExtension>& extensions);
   bool SetOptions(const AudioOptions& options);
   bool SetMaxSendBandwidth(int bps);
   bool SetRecvCodecs(const std::vector<AudioCodec>& codecs);
@@ -290,9 +288,6 @@
   bool SetChannelRecvRtpHeaderExtensions(
     int channel_id,
     const std::vector<RtpHeaderExtension>& extensions);
-  bool SetChannelSendRtpHeaderExtensions(
-    int channel_id,
-    const std::vector<RtpHeaderExtension>& extensions);
 
   rtc::ThreadChecker worker_thread_checker_;
 
@@ -322,7 +317,7 @@
 
   class WebRtcAudioSendStream;
   std::map<uint32_t, WebRtcAudioSendStream*> send_streams_;
-  std::vector<RtpHeaderExtension> send_extensions_;
+  std::vector<webrtc::RtpExtension> send_rtp_extensions_;
 
   class WebRtcAudioReceiveStream;
   std::map<uint32_t, WebRtcAudioReceiveStream*> receive_channels_;
diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
index 0e2781b..b123a84 100644
--- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc
+++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
@@ -124,12 +124,10 @@
   void SetupForMultiSendStream() {
     EXPECT_TRUE(SetupEngineWithSendStream());
     // Remove stream added in Setup.
-    int default_channel_num = voe_.GetLastChannel();
-    EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(default_channel_num));
+    EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1));
     EXPECT_TRUE(channel_->RemoveSendStream(kSsrc1));
-
     // Verify the channel does not exist.
-    EXPECT_EQ(-1, voe_.GetChannelFromLocalSsrc(kSsrc1));
+    EXPECT_FALSE(call_.GetAudioSendStream(kSsrc1));
   }
   void DeliverPacket(const void* data, int len) {
     rtc::Buffer packet(reinterpret_cast<const uint8_t*>(data), len);
@@ -140,6 +138,12 @@
     engine_.Terminate();
   }
 
+  const webrtc::AudioSendStream::Config& GetSendStreamConfig(uint32_t ssrc) {
+    const auto* send_stream = call_.GetAudioSendStream(ssrc);
+    EXPECT_TRUE(send_stream);
+    return send_stream->GetConfig();
+  }
+
   void TestInsertDtmf(uint32_t ssrc, bool caller) {
     EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
     channel_ = engine_.CreateChannel(&call_, cricket::AudioOptions());
@@ -212,41 +216,44 @@
 
   void TestSetSendRtpHeaderExtensions(const std::string& ext) {
     EXPECT_TRUE(SetupEngineWithSendStream());
-    int channel_num = voe_.GetLastChannel();
 
     // Ensure extensions are off by default.
-    EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext));
+    EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size());
 
     // Ensure unknown extensions won't cause an error.
     send_parameters_.extensions.push_back(cricket::RtpHeaderExtension(
         "urn:ietf:params:unknownextention", 1));
     EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
-    EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext));
+    EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size());
 
     // Ensure extensions stay off with an empty list of headers.
     send_parameters_.extensions.clear();
     EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
-    EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext));
+    EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size());
 
     // Ensure extension is set properly.
     const int id = 1;
     send_parameters_.extensions.push_back(cricket::RtpHeaderExtension(ext, id));
     EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
-    EXPECT_EQ(id, voe_.GetSendRtpExtensionId(channel_num, ext));
+    EXPECT_EQ(1u, GetSendStreamConfig(kSsrc1).rtp.extensions.size());
+    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.
     EXPECT_TRUE(channel_->AddSendStream(
         cricket::StreamParams::CreateLegacy(kSsrc2)));
-    int new_channel_num = voe_.GetLastChannel();
-    EXPECT_NE(channel_num, new_channel_num);
-    EXPECT_EQ(id, voe_.GetSendRtpExtensionId(new_channel_num, ext));
+    EXPECT_NE(call_.GetAudioSendStream(kSsrc1),
+              call_.GetAudioSendStream(kSsrc2));
+    EXPECT_EQ(1u, GetSendStreamConfig(kSsrc2).rtp.extensions.size());
+    EXPECT_EQ(ext, GetSendStreamConfig(kSsrc2).rtp.extensions[0].name);
+    EXPECT_EQ(id, GetSendStreamConfig(kSsrc2).rtp.extensions[0].id);
 
     // Ensure all extensions go back off with an empty list.
     send_parameters_.codecs.push_back(kPcmuCodec);
     send_parameters_.extensions.clear();
     EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
-    EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext));
-    EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(new_channel_num, ext));
+    EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size());
+    EXPECT_EQ(0u, GetSendStreamConfig(kSsrc2).rtp.extensions.size());
   }
 
   void TestSetRecvRtpHeaderExtensions(const std::string& ext) {
@@ -1976,21 +1983,16 @@
   for (uint32_t ssrc : kSsrcs4) {
     EXPECT_TRUE(channel_->AddSendStream(
         cricket::StreamParams::CreateLegacy(ssrc)));
-    EXPECT_NE(nullptr, call_.GetAudioSendStream(ssrc));
-
     // Verify that we are in a sending state for all the created streams.
-    int channel_num = voe_.GetChannelFromLocalSsrc(ssrc);
-    EXPECT_TRUE(voe_.GetSend(channel_num));
+    EXPECT_TRUE(voe_.GetSend(GetSendStreamConfig(ssrc).voe_channel_id));
   }
   EXPECT_EQ(arraysize(kSsrcs4), call_.GetAudioSendStreams().size());
 
   // Delete the send streams.
   for (uint32_t ssrc : kSsrcs4) {
     EXPECT_TRUE(channel_->RemoveSendStream(ssrc));
-    EXPECT_EQ(nullptr, call_.GetAudioSendStream(ssrc));
-    // Stream should already be deleted.
+    EXPECT_FALSE(call_.GetAudioSendStream(ssrc));
     EXPECT_FALSE(channel_->RemoveSendStream(ssrc));
-    EXPECT_EQ(-1, voe_.GetChannelFromLocalSsrc(ssrc));
   }
   EXPECT_EQ(0u, call_.GetAudioSendStreams().size());
 }
@@ -2015,7 +2017,7 @@
   // Verify ISAC and VAD are corrected configured on all send channels.
   webrtc::CodecInst gcodec;
   for (uint32_t ssrc : kSsrcs4) {
-    int channel_num = voe_.GetChannelFromLocalSsrc(ssrc);
+    int channel_num = GetSendStreamConfig(ssrc).voe_channel_id;
     EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
     EXPECT_STREQ("ISAC", gcodec.plname);
     EXPECT_TRUE(voe_.GetVAD(channel_num));
@@ -2026,7 +2028,7 @@
   parameters.codecs[0] = kPcmuCodec;
   EXPECT_TRUE(channel_->SetSendParameters(parameters));
   for (uint32_t ssrc : kSsrcs4) {
-    int channel_num = voe_.GetChannelFromLocalSsrc(ssrc);
+    int channel_num = GetSendStreamConfig(ssrc).voe_channel_id;
     EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
     EXPECT_STREQ("PCMU", gcodec.plname);
     EXPECT_FALSE(voe_.GetVAD(channel_num));
@@ -2049,7 +2051,7 @@
   EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
   for (uint32_t ssrc : kSsrcs4) {
     // Verify that we are in a sending state for all the send streams.
-    int channel_num = voe_.GetChannelFromLocalSsrc(ssrc);
+    int channel_num = GetSendStreamConfig(ssrc).voe_channel_id;
     EXPECT_TRUE(voe_.GetSend(channel_num));
   }
 
@@ -2057,7 +2059,7 @@
   EXPECT_TRUE(channel_->SetSend(cricket::SEND_NOTHING));
   for (uint32_t ssrc : kSsrcs4) {
     // Verify that we are in a stop state for all the send streams.
-    int channel_num = voe_.GetChannelFromLocalSsrc(ssrc);
+    int channel_num = GetSendStreamConfig(ssrc).voe_channel_id;
     EXPECT_FALSE(voe_.GetSend(channel_num));
   }
 }
@@ -2338,7 +2340,7 @@
 // SSRC is set in SetupEngine by calling AddSendStream.
 TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrc) {
   EXPECT_TRUE(SetupEngineWithSendStream());
-  EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel()));
+  EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1));
 }
 
 TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
@@ -2399,7 +2401,7 @@
 // SSRC is set in SetupEngine by calling AddSendStream.
 TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrcWithMultipleStreams) {
   EXPECT_TRUE(SetupEngineWithSendStream());
-  EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel()));
+  EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1));
   EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
   EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel()));
 }
@@ -2414,9 +2416,8 @@
   int receive_channel_num = voe_.GetLastChannel();
   EXPECT_TRUE(channel_->AddSendStream(
       cricket::StreamParams::CreateLegacy(1234)));
-  int send_channel_num = voe_.GetLastChannel();
 
-  EXPECT_EQ(1234U, voe_.GetLocalSSRC(send_channel_num));
+  EXPECT_TRUE(call_.GetAudioSendStream(1234));
   EXPECT_EQ(1234U, voe_.GetLocalSSRC(receive_channel_num));
 }
 
@@ -3053,6 +3054,8 @@
   EXPECT_EQ(arraysize(kSsrcs), call_.GetAudioReceiveStreams().size());
 }
 
+// TODO(solenberg): Remove, once recv streams are configured through Call.
+//                  (This is then covered by TestSetRecvRtpHeaderExtensions.)
 TEST_F(WebRtcVoiceEngineTestFake, ConfiguresAudioReceiveStreamRtpExtensions) {
   // Test that setting the header extensions results in the expected state
   // changes on an associated Call.
diff --git a/webrtc/audio/audio_receive_stream_unittest.cc b/webrtc/audio/audio_receive_stream_unittest.cc
index 755d634..edd804f 100644
--- a/webrtc/audio/audio_receive_stream_unittest.cc
+++ b/webrtc/audio/audio_receive_stream_unittest.cc
@@ -20,6 +20,9 @@
 namespace test {
 namespace {
 
+using testing::_;
+using testing::Return;
+
 AudioDecodingCallStats MakeAudioDecodeStatsForTest() {
   AudioDecodingCallStats audio_decode_stats;
   audio_decode_stats.calls_to_silence_generator = 234;
@@ -50,9 +53,9 @@
 struct ConfigHelper {
   ConfigHelper() {
     EXPECT_CALL(voice_engine_,
-        RegisterVoiceEngineObserver(testing::_)).WillOnce(testing::Return(0));
+        RegisterVoiceEngineObserver(_)).WillOnce(Return(0));
     EXPECT_CALL(voice_engine_,
-        DeRegisterVoiceEngineObserver()).WillOnce(testing::Return(0));
+        DeRegisterVoiceEngineObserver()).WillOnce(Return(0));
     AudioState::Config config;
     config.voice_engine = &voice_engine_;
     audio_state_ = AudioState::Create(config);
@@ -69,9 +72,7 @@
   MockVoiceEngine& voice_engine() { return voice_engine_; }
 
   void SetupMockForGetStats() {
-    using testing::_;
     using testing::DoAll;
-    using testing::Return;
     using testing::SetArgPointee;
     using testing::SetArgReferee;
     EXPECT_CALL(voice_engine_, GetRemoteSSRC(kChannelId, _))
@@ -94,7 +95,7 @@
 
  private:
   MockRemoteBitrateEstimator remote_bitrate_estimator_;
-  MockVoiceEngine voice_engine_;
+  testing::StrictMock<MockVoiceEngine> voice_engine_;
   rtc::scoped_refptr<AudioState> audio_state_;
   AudioReceiveStream::Config stream_config_;
 };
diff --git a/webrtc/audio/audio_send_stream.cc b/webrtc/audio/audio_send_stream.cc
index da24249..14112de 100644
--- a/webrtc/audio/audio_send_stream.cc
+++ b/webrtc/audio/audio_send_stream.cc
@@ -34,6 +34,7 @@
     }
   }
   ss << ']';
+  ss << ", c_name: " << c_name;
   ss << '}';
   return ss.str();
 }
@@ -58,6 +59,31 @@
   LOG(LS_INFO) << "AudioSendStream: " << config_.ToString();
   RTC_DCHECK_NE(config_.voe_channel_id, -1);
   RTC_DCHECK(audio_state_.get());
+
+  const int channel_id = config.voe_channel_id;
+  ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine());
+  int error = rtp->SetRTCPStatus(channel_id, true);
+  RTC_DCHECK_EQ(0, error);
+  error = rtp->SetLocalSSRC(channel_id, config.rtp.ssrc);
+  RTC_DCHECK_EQ(0, error);
+  error = rtp->SetRTCP_CNAME(channel_id, config.rtp.c_name.c_str());
+  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(extension.id, 1);
+    RTC_DCHECK_LE(extension.id, 14);
+    if (extension.name == RtpExtension::kAbsSendTime) {
+      error = rtp->SetSendAbsoluteSenderTimeStatus(channel_id, true,
+                                                   extension.id);
+      RTC_DCHECK_EQ(0, error);
+    } else if (extension.name == RtpExtension::kAudioLevel) {
+      error = rtp->SetSendAudioLevelIndicationStatus(channel_id, true,
+                                                     extension.id);
+      RTC_DCHECK_EQ(0, error);
+    } else {
+      RTC_NOTREACHED() << "Registering unsupported RTP extension.";
+    }
+  }
 }
 
 AudioSendStream::~AudioSendStream() {
@@ -65,19 +91,38 @@
   LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString();
 }
 
+void AudioSendStream::Start() {
+  RTC_DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void AudioSendStream::Stop() {
+  RTC_DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void AudioSendStream::SignalNetworkState(NetworkState state) {
+  RTC_DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+bool AudioSendStream::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;
+}
+
 webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const {
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
   webrtc::AudioSendStream::Stats stats;
   stats.local_ssrc = config_.rtp.ssrc;
-  internal::AudioState* audio_state =
-      static_cast<internal::AudioState*>(audio_state_.get());
-  VoiceEngine* voice_engine = audio_state->voice_engine();
-  ScopedVoEInterface<VoEAudioProcessing> processing(voice_engine);
-  ScopedVoEInterface<VoECodec> codec(voice_engine);
-  ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine);
-  ScopedVoEInterface<VoEVolumeControl> volume(voice_engine);
+  ScopedVoEInterface<VoEAudioProcessing> processing(voice_engine());
+  ScopedVoEInterface<VoECodec> codec(voice_engine());
+  ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine());
+  ScopedVoEInterface<VoEVolumeControl> volume(voice_engine());
   unsigned int ssrc = 0;
   webrtc::CallStatistics call_stats = {0};
+  // TODO(solenberg): Change error code checking to RTC_CHECK_EQ(..., -1), if
+  //                  possible...
   if (rtp->GetLocalSSRC(config_.voe_channel_id, ssrc) == -1 ||
       rtp->GetRTCPStatistics(config_.voe_channel_id, call_stats) == -1) {
     return stats;
@@ -153,6 +198,8 @@
     }
   }
 
+  internal::AudioState* audio_state =
+      static_cast<internal::AudioState*>(audio_state_.get());
   stats.typing_noise_detected = audio_state->typing_noise_detected();
 
   return stats;
@@ -163,24 +210,12 @@
   return config_;
 }
 
-void AudioSendStream::Start() {
-  RTC_DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-void AudioSendStream::Stop() {
-  RTC_DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-void AudioSendStream::SignalNetworkState(NetworkState state) {
-  RTC_DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-bool AudioSendStream::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;
+VoiceEngine* AudioSendStream::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_send_stream.h b/webrtc/audio/audio_send_stream.h
index 3d911c1..a4eb89d 100644
--- a/webrtc/audio/audio_send_stream.h
+++ b/webrtc/audio/audio_send_stream.h
@@ -16,6 +16,9 @@
 #include "webrtc/base/thread_checker.h"
 
 namespace webrtc {
+
+class VoiceEngine;
+
 namespace internal {
 
 class AudioSendStream final : public webrtc::AudioSendStream {
@@ -36,6 +39,8 @@
   const webrtc::AudioSendStream::Config& config() const;
 
  private:
+  VoiceEngine* voice_engine() const;
+
   rtc::ThreadChecker thread_checker_;
   const webrtc::AudioSendStream::Config config_;
   rtc::scoped_refptr<webrtc::AudioState> audio_state_;
diff --git a/webrtc/audio/audio_send_stream_unittest.cc b/webrtc/audio/audio_send_stream_unittest.cc
index ada15ac..1801e9d 100644
--- a/webrtc/audio/audio_send_stream_unittest.cc
+++ b/webrtc/audio/audio_send_stream_unittest.cc
@@ -19,8 +19,14 @@
 namespace test {
 namespace {
 
+using testing::_;
+using testing::Return;
+
 const int kChannelId = 1;
 const uint32_t kSsrc = 1234;
+const char* kCName = "foo_name";
+const int kAudioLevelId = 2;
+const int kAbsSendTimeId = 3;
 const int kEchoDelayMedian = 254;
 const int kEchoDelayStdDev = -3;
 const int kEchoReturnLoss = -65;
@@ -33,21 +39,45 @@
 
 struct ConfigHelper {
   ConfigHelper() : stream_config_(nullptr) {
+    using testing::StrEq;
+
     EXPECT_CALL(voice_engine_,
-        RegisterVoiceEngineObserver(testing::_)).WillOnce(testing::Return(0));
+        RegisterVoiceEngineObserver(_)).WillOnce(Return(0));
     EXPECT_CALL(voice_engine_,
-        DeRegisterVoiceEngineObserver()).WillOnce(testing::Return(0));
+        DeRegisterVoiceEngineObserver()).WillOnce(Return(0));
     AudioState::Config config;
     config.voice_engine = &voice_engine_;
     audio_state_ = AudioState::Create(config);
+
+    EXPECT_CALL(voice_engine_, SetRTCPStatus(kChannelId, true))
+        .WillOnce(Return(0));
+    EXPECT_CALL(voice_engine_, SetLocalSSRC(kChannelId, kSsrc))
+        .WillOnce(Return(0));
+    EXPECT_CALL(voice_engine_, SetRTCP_CNAME(kChannelId, StrEq(kCName)))
+        .WillOnce(Return(0));
+    EXPECT_CALL(voice_engine_,
+        SetSendAbsoluteSenderTimeStatus(kChannelId, true, kAbsSendTimeId))
+            .WillOnce(Return(0));
+    EXPECT_CALL(voice_engine_,
+        SetSendAudioLevelIndicationStatus(kChannelId, true, kAudioLevelId))
+            .WillOnce(Return(0));
     stream_config_.voe_channel_id = kChannelId;
     stream_config_.rtp.ssrc = kSsrc;
+    stream_config_.rtp.c_name = kCName;
+    stream_config_.rtp.extensions.push_back(
+        RtpExtension(RtpExtension::kAudioLevel, kAudioLevelId));
+    stream_config_.rtp.extensions.push_back(
+        RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
   }
 
   AudioSendStream::Config& config() { return stream_config_; }
   rtc::scoped_refptr<AudioState> audio_state() { return audio_state_; }
 
   void SetupMockForGetStats() {
+    using testing::DoAll;
+    using testing::SetArgPointee;
+    using testing::SetArgReferee;
+
     std::vector<ReportBlock> report_blocks;
     webrtc::ReportBlock block = kReportBlock;
     report_blocks.push_back(block);  // Has wrong SSRC.
@@ -56,11 +86,6 @@
     block.fraction_lost = 0;
     report_blocks.push_back(block);  // Duplicate SSRC, bad fraction_lost.
 
-    using testing::_;
-    using testing::DoAll;
-    using testing::Return;
-    using testing::SetArgPointee;
-    using testing::SetArgReferee;
     EXPECT_CALL(voice_engine_, GetLocalSSRC(kChannelId, _))
         .WillRepeatedly(DoAll(SetArgReferee<1>(0), Return(0)));
     EXPECT_CALL(voice_engine_, GetRTCPStatistics(kChannelId, _))
@@ -83,25 +108,26 @@
   }
 
  private:
-  MockVoiceEngine voice_engine_;
+  testing::StrictMock<MockVoiceEngine> voice_engine_;
   rtc::scoped_refptr<AudioState> audio_state_;
   AudioSendStream::Config stream_config_;
 };
 }  // namespace
 
 TEST(AudioSendStreamTest, ConfigToString) {
-  const int kAbsSendTimeId = 3;
   AudioSendStream::Config config(nullptr);
   config.rtp.ssrc = kSsrc;
   config.rtp.extensions.push_back(
       RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
+  config.rtp.c_name = kCName;
   config.voe_channel_id = kChannelId;
   config.cng_payload_type = 42;
   config.red_payload_type = 17;
   EXPECT_EQ(
       "{rtp: {ssrc: 1234, extensions: [{name: "
-      "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 3}]}, "
-      "voe_channel_id: 1, cng_payload_type: 42, red_payload_type: 17}",
+      "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 3}], "
+      "c_name: foo_name}, voe_channel_id: 1, cng_payload_type: 42, "
+      "red_payload_type: 17}",
       config.ToString());
 }
 
diff --git a/webrtc/audio/audio_state_unittest.cc b/webrtc/audio/audio_state_unittest.cc
index 170eff5..11fbdb4 100644
--- a/webrtc/audio/audio_state_unittest.cc
+++ b/webrtc/audio/audio_state_unittest.cc
@@ -30,7 +30,7 @@
   MockVoiceEngine& voice_engine() { return voice_engine_; }
 
  private:
-  MockVoiceEngine voice_engine_;
+  testing::StrictMock<MockVoiceEngine> voice_engine_;
   AudioState::Config config_;
 };
 }  // namespace
diff --git a/webrtc/audio_send_stream.h b/webrtc/audio_send_stream.h
index 89b73e6..c5db82b 100644
--- a/webrtc/audio_send_stream.h
+++ b/webrtc/audio_send_stream.h
@@ -61,6 +61,9 @@
 
       // RTP header extensions used for the received stream.
       std::vector<RtpExtension> extensions;
+
+      // RTCP CNAME, see RFC 3550.
+      std::string c_name;
     } rtp;
 
     // Transport for outgoing packets. The transport is expected to exist for
diff --git a/webrtc/call/bitrate_estimator_tests.cc b/webrtc/call/bitrate_estimator_tests.cc
index 6bccb43..54a78ea 100644
--- a/webrtc/call/bitrate_estimator_tests.cc
+++ b/webrtc/call/bitrate_estimator_tests.cc
@@ -118,13 +118,6 @@
   virtual ~BitrateEstimatorTest() { EXPECT_TRUE(streams_.empty()); }
 
   virtual void SetUp() {
-    EXPECT_CALL(mock_voice_engine_,
-        RegisterVoiceEngineObserver(testing::_)).WillOnce(testing::Return(0));
-    EXPECT_CALL(mock_voice_engine_,
-        DeRegisterVoiceEngineObserver()).WillOnce(testing::Return(0));
-    EXPECT_CALL(mock_voice_engine_, GetEventLog())
-        .WillRepeatedly(testing::Return(nullptr));
-
     AudioState::Config audio_state_config;
     audio_state_config.voice_engine = &mock_voice_engine_;
     Call::Config config;
@@ -265,7 +258,7 @@
     test::FakeDecoder fake_decoder_;
   };
 
-  test::MockVoiceEngine mock_voice_engine_;
+  testing::NiceMock<test::MockVoiceEngine> mock_voice_engine_;
   TraceObserver receiver_trace_;
   rtc::scoped_ptr<test::DirectTransport> send_transport_;
   rtc::scoped_ptr<test::DirectTransport> receive_transport_;
diff --git a/webrtc/call/call_unittest.cc b/webrtc/call/call_unittest.cc
index b26024d..75c8238 100644
--- a/webrtc/call/call_unittest.cc
+++ b/webrtc/call/call_unittest.cc
@@ -20,12 +20,6 @@
 
 struct CallHelper {
   CallHelper() {
-    EXPECT_CALL(voice_engine_,
-        RegisterVoiceEngineObserver(testing::_)).WillOnce(testing::Return(0));
-    EXPECT_CALL(voice_engine_,
-        DeRegisterVoiceEngineObserver()).WillOnce(testing::Return(0));
-    EXPECT_CALL(voice_engine_,
-        GetEventLog()).WillOnce(testing::Return(nullptr));
     webrtc::AudioState::Config audio_state_config;
     audio_state_config.voice_engine = &voice_engine_;
     webrtc::Call::Config config;
@@ -36,7 +30,7 @@
   webrtc::Call* operator->() { return call_.get(); }
 
  private:
-  webrtc::test::MockVoiceEngine voice_engine_;
+  testing::NiceMock<webrtc::test::MockVoiceEngine> voice_engine_;
   rtc::scoped_ptr<webrtc::Call> call_;
 };
 }  // namespace
diff --git a/webrtc/config.h b/webrtc/config.h
index 4b863c8..114303e 100644
--- a/webrtc/config.h
+++ b/webrtc/config.h
@@ -49,10 +49,13 @@
   int red_rtx_payload_type;
 };
 
-// RTP header extension to use for the video stream, see RFC 5285.
+// RTP header extension, see RFC 5285.
 struct RtpExtension {
   RtpExtension(const std::string& name, int id) : name(name), id(id) {}
   std::string ToString() const;
+  bool operator==(const RtpExtension& rhs) const {
+    return name == rhs.name && id == rhs.id;
+  }
   static bool IsSupportedForAudio(const std::string& name);
   static bool IsSupportedForVideo(const std::string& name);
 
diff --git a/webrtc/test/mock_voice_engine.h b/webrtc/test/mock_voice_engine.h
index 77b4ec8..dead226 100644
--- a/webrtc/test/mock_voice_engine.h
+++ b/webrtc/test/mock_voice_engine.h
@@ -19,7 +19,7 @@
 
 // NOTE: This class inherits from VoiceEngineImpl so that its clients will be
 // able to get the various interfaces as usual, via T::GetInterface().
-class MockVoiceEngine final : public VoiceEngineImpl {
+class MockVoiceEngine : public VoiceEngineImpl {
  public:
   MockVoiceEngine() : VoiceEngineImpl(new Config(), true) {
     // Increase ref count so this object isn't automatically deleted whenever