Move DTMF sender to RtpSender (as opposed to WebRtcSession).

Previously in the spec, there was a createDtmfSender method on
PeerConnection, but that's been replaced by a "dtmf" attribute
on RtpSender, which allows getting a DTMF sender without having
an audio track.

This also simplifies the code slightly, since tracks are now not
necessary for identification.

BUG=webrtc:4180

Review-Url: https://codereview.webrtc.org/2666853002
Cr-Original-Commit-Position: refs/heads/master@{#16409}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 20cb0c1c85d4571919106019a562bbcbd35041fd
diff --git a/api/rtpsenderinterface.h b/api/rtpsenderinterface.h
index 7129376..68547b0 100644
--- a/api/rtpsenderinterface.h
+++ b/api/rtpsenderinterface.h
@@ -17,6 +17,7 @@
 #include <string>
 #include <vector>
 
+#include "webrtc/api/dtmfsenderinterface.h"
 #include "webrtc/api/mediatypes.h"
 #include "webrtc/api/mediastreaminterface.h"
 #include "webrtc/api/proxy.h"
@@ -51,6 +52,9 @@
   virtual RtpParameters GetParameters() const = 0;
   virtual bool SetParameters(const RtpParameters& parameters) = 0;
 
+  // Returns null for a video sender.
+  virtual rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const = 0;
+
  protected:
   virtual ~RtpSenderInterface() {}
 };
@@ -66,6 +70,7 @@
   PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids)
   PROXY_CONSTMETHOD0(RtpParameters, GetParameters);
   PROXY_METHOD1(bool, SetParameters, const RtpParameters&)
+  PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtmfSenderInterface>, GetDtmfSender);
 END_PROXY_MAP()
 
 }  // namespace webrtc
diff --git a/api/test/mock_rtpsender.h b/api/test/mock_rtpsender.h
index 7abc4e5..7458f45 100644
--- a/api/test/mock_rtpsender.h
+++ b/api/test/mock_rtpsender.h
@@ -29,6 +29,7 @@
   MOCK_CONST_METHOD0(stream_ids, std::vector<std::string>());
   MOCK_CONST_METHOD0(GetParameters, RtpParameters());
   MOCK_METHOD1(SetParameters, bool(const RtpParameters&));
+  MOCK_CONST_METHOD0(GetDtmfSender, rtc::scoped_refptr<DtmfSenderInterface>());
 };
 
 }  // namespace webrtc
diff --git a/pc/dtmfsender.cc b/pc/dtmfsender.cc
index 2ef921b..bbb100e 100644
--- a/pc/dtmfsender.cc
+++ b/pc/dtmfsender.cc
@@ -63,8 +63,8 @@
     AudioTrackInterface* track,
     rtc::Thread* signaling_thread,
     DtmfProviderInterface* provider) {
-  if (!track || !signaling_thread) {
-    return NULL;
+  if (!signaling_thread) {
+    return nullptr;
   }
   rtc::scoped_refptr<DtmfSender> dtmf_sender(
       new rtc::RefCountedObject<DtmfSender>(track, signaling_thread,
@@ -81,7 +81,6 @@
       provider_(provider),
       duration_(kDtmfDefaultDurationMs),
       inter_tone_gap_(kDtmfDefaultGapMs) {
-  RTC_DCHECK(track_ != NULL);
   RTC_DCHECK(signaling_thread_ != NULL);
   // TODO(deadbeef): Once we can use shared_ptr and weak_ptr,
   // do that instead of relying on a "destroyed" signal.
@@ -109,7 +108,7 @@
   if (!provider_) {
     return false;
   }
-  return provider_->CanInsertDtmf(track_->id());
+  return provider_->CanInsertDtmf();
 }
 
 bool DtmfSender::InsertDtmf(const std::string& tones, int duration,
@@ -206,7 +205,7 @@
     }
     // The provider starts playout of the given tone on the
     // associated RTP media stream, using the appropriate codec.
-    if (!provider_->InsertDtmf(track_->id(), code, duration_)) {
+    if (!provider_->InsertDtmf(code, duration_)) {
       LOG(LS_ERROR) << "The DtmfProvider can no longer send DTMF.";
       return;
     }
diff --git a/pc/dtmfsender.h b/pc/dtmfsender.h
index a019e78..5eab055 100644
--- a/pc/dtmfsender.h
+++ b/pc/dtmfsender.h
@@ -34,14 +34,13 @@
 // to send DTMF.
 class DtmfProviderInterface {
  public:
-  // Returns true if the audio track with given id (|track_id|) is capable
-  // of sending DTMF. Otherwise returns false.
-  virtual bool CanInsertDtmf(const std::string& track_id) = 0;
-  // Sends DTMF |code| via the audio track with given id (|track_id|).
+  // Returns true if the audio sender is capable of sending DTMF. Otherwise
+  // returns false.
+  virtual bool CanInsertDtmf() = 0;
+  // Sends DTMF |code|.
   // The |duration| indicates the length of the DTMF tone in ms.
   // Returns true on success and false on failure.
-  virtual bool InsertDtmf(const std::string& track_id,
-                          int code, int duration) = 0;
+  virtual bool InsertDtmf(int code, int duration) = 0;
   // Returns a |sigslot::signal0<>| signal. The signal should fire before
   // the provider is destroyed.
   virtual sigslot::signal0<>* GetOnDestroyedSignal() = 0;
@@ -55,6 +54,8 @@
       public sigslot::has_slots<>,
       public rtc::MessageHandler {
  public:
+  // |track| is only there for backwards compatibility, since there's a track
+  // accessor method.
   static rtc::scoped_refptr<DtmfSender> Create(
       AudioTrackInterface* track,
       rtc::Thread* signaling_thread,
diff --git a/pc/dtmfsender_unittest.cc b/pc/dtmfsender_unittest.cc
index a58c1ec..109760c 100644
--- a/pc/dtmfsender_unittest.cc
+++ b/pc/dtmfsender_unittest.cc
@@ -78,13 +78,9 @@
   }
 
   // Implements DtmfProviderInterface.
-  bool CanInsertDtmf(const std::string& track_label) override {
-    return (can_insert_dtmf_tracks_.count(track_label) != 0);
-  }
+  bool CanInsertDtmf() override { return can_insert_; }
 
-  bool InsertDtmf(const std::string& track_label,
-                  int code,
-                  int duration) override {
+  bool InsertDtmf(int code, int duration) override {
     int gap = 0;
     // TODO(ronghuawu): Make the timer (basically the rtc::TimeNanos)
     // mockable and use a fake timer in the unit tests.
@@ -110,15 +106,10 @@
   }
 
   // helper functions
-  void AddCanInsertDtmfTrack(const std::string& label) {
-    can_insert_dtmf_tracks_.insert(label);
-  }
-  void RemoveCanInsertDtmfTrack(const std::string& label) {
-    can_insert_dtmf_tracks_.erase(label);
-  }
+  void SetCanInsertDtmf(bool can_insert) { can_insert_ = can_insert; }
 
  private:
-  std::set<std::string> can_insert_dtmf_tracks_;
+  bool can_insert_ = false;
   std::vector<DtmfInfo> dtmf_info_queue_;
   int64_t last_insert_dtmf_call_;
   sigslot::signal0<> SignalDestroyed;
@@ -130,7 +121,7 @@
       : track_(AudioTrack::Create(kTestAudioLabel, NULL)),
         observer_(new rtc::RefCountedObject<FakeDtmfObserver>()),
         provider_(new FakeDtmfProvider()) {
-    provider_->AddCanInsertDtmfTrack(kTestAudioLabel);
+    provider_->SetCanInsertDtmf(true);
     dtmf_ = DtmfSender::Create(track_, rtc::Thread::Current(),
                                provider_.get());
     dtmf_->RegisterObserver(observer_.get());
@@ -227,7 +218,7 @@
 
 TEST_F(DtmfSenderTest, CanInsertDtmf) {
   EXPECT_TRUE(dtmf_->CanInsertDtmf());
-  provider_->RemoveCanInsertDtmfTrack(kTestAudioLabel);
+  provider_->SetCanInsertDtmf(false);
   EXPECT_FALSE(dtmf_->CanInsertDtmf());
 }
 
@@ -333,7 +324,7 @@
   std::string tones = "3,4";
   int duration = 100;
   int inter_tone_gap = 50;
-  provider_->RemoveCanInsertDtmfTrack(kTestAudioLabel);
+  provider_->SetCanInsertDtmf(false);
   EXPECT_FALSE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
 }
 
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 14e1809..a38c986 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -949,20 +949,15 @@
   }
   if (!track) {
     LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
-    return NULL;
+    return nullptr;
   }
-  if (!local_streams_->FindAudioTrack(track->id())) {
-    LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
-    return NULL;
+  auto it = FindSenderForTrack(track);
+  if (it == senders_.end()) {
+    LOG(LS_ERROR) << "CreateDtmfSender called with a non-added track.";
+    return nullptr;
   }
 
-  rtc::scoped_refptr<DtmfSenderInterface> sender(
-      DtmfSender::Create(track, signaling_thread(), session_.get()));
-  if (!sender.get()) {
-    LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
-    return NULL;
-  }
-  return DtmfSenderProxy::Create(signaling_thread(), sender.get());
+  return (*it)->GetDtmfSender();
 }
 
 rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
diff --git a/pc/rtpsender.cc b/pc/rtpsender.cc
index 3e8c7e1..c8ac830 100644
--- a/pc/rtpsender.cc
+++ b/pc/rtpsender.cc
@@ -57,6 +57,7 @@
       sink_adapter_(new LocalAudioSinkAdapter()) {
   track_->RegisterObserver(this);
   track_->AddSink(sink_adapter_.get());
+  CreateDtmfSender();
 }
 
 AudioRtpSender::AudioRtpSender(AudioTrackInterface* track,
@@ -71,6 +72,7 @@
       sink_adapter_(new LocalAudioSinkAdapter()) {
   track_->RegisterObserver(this);
   track_->AddSink(sink_adapter_.get());
+  CreateDtmfSender();
 }
 
 AudioRtpSender::AudioRtpSender(cricket::VoiceChannel* channel,
@@ -79,12 +81,50 @@
       stream_id_(rtc::CreateRandomUuid()),
       channel_(channel),
       stats_(stats),
-      sink_adapter_(new LocalAudioSinkAdapter()) {}
+      sink_adapter_(new LocalAudioSinkAdapter()) {
+  CreateDtmfSender();
+}
 
 AudioRtpSender::~AudioRtpSender() {
+  // For DtmfSender.
+  SignalDestroyed();
   Stop();
 }
 
+bool AudioRtpSender::CanInsertDtmf() {
+  if (!channel_) {
+    LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
+    return false;
+  }
+  // Check that this RTP sender is active (description has been applied that
+  // matches an SSRC to its ID).
+  if (!ssrc_) {
+    LOG(LS_ERROR) << "CanInsertDtmf: Sender does not have SSRC.";
+    return false;
+  }
+  return channel_->CanInsertDtmf();
+}
+
+bool AudioRtpSender::InsertDtmf(int code, int duration) {
+  if (!channel_) {
+    LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
+    return false;
+  }
+  if (!ssrc_) {
+    LOG(LS_ERROR) << "CanInsertDtmf: Sender does not have SSRC.";
+    return false;
+  }
+  if (!channel_->InsertDtmf(ssrc_, code, duration)) {
+    LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
+    return false;
+  }
+  return true;
+}
+
+sigslot::signal0<>* AudioRtpSender::GetOnDestroyedSignal() {
+  return &SignalDestroyed;
+}
+
 void AudioRtpSender::OnChanged() {
   TRACE_EVENT0("webrtc", "AudioRtpSender::OnChanged");
   RTC_DCHECK(!stopped_);
@@ -158,6 +198,10 @@
   return channel_->SetRtpSendParameters(ssrc_, parameters);
 }
 
+rtc::scoped_refptr<DtmfSenderInterface> AudioRtpSender::GetDtmfSender() const {
+  return dtmf_sender_proxy_;
+}
+
 void AudioRtpSender::SetSsrc(uint32_t ssrc) {
   TRACE_EVENT0("webrtc", "AudioRtpSender::SetSsrc");
   if (stopped_ || ssrc == ssrc_) {
@@ -237,6 +281,20 @@
   }
 }
 
+void AudioRtpSender::CreateDtmfSender() {
+  // Should be on signaling thread.
+  // TODO(deadbeef): Add thread checking to RtpSender/RtpReceiver
+  // implementations.
+  rtc::scoped_refptr<DtmfSenderInterface> sender(
+      DtmfSender::Create(track_, rtc::Thread::Current(), this));
+  if (!sender.get()) {
+    LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
+    RTC_NOTREACHED();
+  }
+  dtmf_sender_proxy_ =
+      DtmfSenderProxy::Create(rtc::Thread::Current(), sender.get());
+}
+
 VideoRtpSender::VideoRtpSender(VideoTrackInterface* track,
                                const std::string& stream_id,
                                cricket::VideoChannel* channel)
@@ -336,6 +394,11 @@
   return channel_->SetRtpSendParameters(ssrc_, parameters);
 }
 
+rtc::scoped_refptr<DtmfSenderInterface> VideoRtpSender::GetDtmfSender() const {
+  LOG(LS_ERROR) << "Tried to get DTMF sender from video sender.";
+  return nullptr;
+}
+
 void VideoRtpSender::SetSsrc(uint32_t ssrc) {
   TRACE_EVENT0("webrtc", "VideoRtpSender::SetSsrc");
   if (stopped_ || ssrc == ssrc_) {
diff --git a/pc/rtpsender.h b/pc/rtpsender.h
index ed244b4..0322399 100644
--- a/pc/rtpsender.h
+++ b/pc/rtpsender.h
@@ -24,6 +24,7 @@
 #include "webrtc/base/criticalsection.h"
 #include "webrtc/media/base/audiosource.h"
 #include "webrtc/pc/channel.h"
+#include "webrtc/pc/dtmfsender.h"
 #include "webrtc/pc/statscollector.h"
 
 namespace webrtc {
@@ -68,7 +69,8 @@
   rtc::CriticalSection lock_;
 };
 
-class AudioRtpSender : public ObserverInterface,
+class AudioRtpSender : public DtmfProviderInterface,
+                       public ObserverInterface,
                        public rtc::RefCountedObject<RtpSenderInternal> {
  public:
   // StatsCollector provided so that Add/RemoveLocalAudioTrack can be called
@@ -91,10 +93,15 @@
 
   virtual ~AudioRtpSender();
 
-  // ObserverInterface implementation
+  // DtmfSenderProvider implementation.
+  bool CanInsertDtmf() override;
+  bool InsertDtmf(int code, int duration) override;
+  sigslot::signal0<>* GetOnDestroyedSignal() override;
+
+  // ObserverInterface implementation.
   void OnChanged() override;
 
-  // RtpSenderInterface implementation
+  // RtpSenderInterface implementation.
   bool SetTrack(MediaStreamTrackInterface* track) override;
   rtc::scoped_refptr<MediaStreamTrackInterface> track() const override {
     return track_;
@@ -116,6 +123,8 @@
   RtpParameters GetParameters() const override;
   bool SetParameters(const RtpParameters& parameters) override;
 
+  rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override;
+
   // RtpSenderInternal implementation.
   void SetSsrc(uint32_t ssrc) override;
 
@@ -140,11 +149,16 @@
   // Helper function to call SetAudioSend with "stop sending" parameters.
   void ClearAudioSend();
 
+  void CreateDtmfSender();
+
+  sigslot::signal0<> SignalDestroyed;
+
   std::string id_;
   std::string stream_id_;
   cricket::VoiceChannel* channel_ = nullptr;
   StatsCollector* stats_;
   rtc::scoped_refptr<AudioTrackInterface> track_;
+  rtc::scoped_refptr<DtmfSenderInterface> dtmf_sender_proxy_;
   uint32_t ssrc_ = 0;
   bool cached_track_enabled_ = false;
   bool stopped_ = false;
@@ -197,6 +211,8 @@
   RtpParameters GetParameters() const override;
   bool SetParameters(const RtpParameters& parameters) override;
 
+  rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override;
+
   // RtpSenderInternal implementation.
   void SetSsrc(uint32_t ssrc) override;
 
diff --git a/pc/rtpsenderreceiver_unittest.cc b/pc/rtpsenderreceiver_unittest.cc
index 86c0612..508a417 100644
--- a/pc/rtpsenderreceiver_unittest.cc
+++ b/pc/rtpsenderreceiver_unittest.cc
@@ -13,6 +13,7 @@
 #include <utility>
 
 #include "webrtc/base/gunit.h"
+#include "webrtc/base/sigslot.h"
 #include "webrtc/logging/rtc_event_log/rtc_event_log.h"
 #include "webrtc/media/base/fakemediaengine.h"
 #include "webrtc/media/base/mediachannel.h"
@@ -38,6 +39,8 @@
 using ::testing::InvokeWithoutArgs;
 using ::testing::Return;
 
+namespace {
+
 static const char kStreamLabel1[] = "local_stream_1";
 static const char kVideoTrackId[] = "video_1";
 static const char kAudioTrackId[] = "audio_1";
@@ -45,10 +48,14 @@
 static const uint32_t kVideoSsrc2 = 100;
 static const uint32_t kAudioSsrc = 99;
 static const uint32_t kAudioSsrc2 = 101;
+static const int kDefaultTimeout = 10000;  // 10 seconds.
+
+}  // namespace
 
 namespace webrtc {
 
-class RtpSenderReceiverTest : public testing::Test {
+class RtpSenderReceiverTest : public testing::Test,
+                              public sigslot::has_slots<> {
  public:
   RtpSenderReceiverTest()
       :  // Create fake media engine/etc. so we can create channels to use to
@@ -75,6 +82,8 @@
         &fake_media_controller_, rtp_transport, nullptr, rtc::Thread::Current(),
         cricket::CN_VIDEO, nullptr, rtcp_mux_required, srtp_required,
         cricket::VideoOptions());
+    voice_channel_->Enable(true);
+    video_channel_->Enable(true);
     voice_media_channel_ = media_engine_->GetVoiceChannel(0);
     video_media_channel_ = media_engine_->GetVideoChannel(0);
     RTC_CHECK(voice_channel_);
@@ -104,7 +113,14 @@
         cricket::StreamParams::CreateLegacy(kVideoSsrc2));
   }
 
-  void TearDown() override { channel_manager_.Terminate(); }
+  // Needed to use DTMF sender.
+  void AddDtmfCodec() {
+    cricket::AudioSendParameters params;
+    const cricket::AudioCodec kTelephoneEventCodec(106, "telephone-event", 8000,
+                                                   0, 1);
+    params.codecs.push_back(kTelephoneEventCodec);
+    voice_media_channel_->SetSendParameters(params);
+  }
 
   void AddVideoTrack() { AddVideoTrack(false); }
 
@@ -124,9 +140,13 @@
         new AudioRtpSender(stream_->GetAudioTracks()[0], stream_->label(),
                            voice_channel_, nullptr);
     audio_rtp_sender_->SetSsrc(kAudioSsrc);
+    audio_rtp_sender_->GetOnDestroyedSignal()->connect(
+        this, &RtpSenderReceiverTest::OnAudioSenderDestroyed);
     VerifyVoiceChannelInput();
   }
 
+  void OnAudioSenderDestroyed() { audio_sender_destroyed_signal_fired_ = true; }
+
   void CreateVideoRtpSender() { CreateVideoRtpSender(false); }
 
   void CreateVideoRtpSender(bool is_screencast) {
@@ -247,6 +267,7 @@
   rtc::scoped_refptr<MediaStreamInterface> stream_;
   rtc::scoped_refptr<VideoTrackInterface> video_track_;
   rtc::scoped_refptr<AudioTrackInterface> audio_track_;
+  bool audio_sender_destroyed_signal_fired_ = false;
 };
 
 // Test that |voice_channel_| is updated when an audio track is associated
@@ -721,4 +742,66 @@
   DestroyVideoRtpSender();
 }
 
+TEST_F(RtpSenderReceiverTest, AudioSenderHasDtmfSender) {
+  CreateAudioRtpSender();
+  EXPECT_NE(nullptr, audio_rtp_sender_->GetDtmfSender());
+}
+
+TEST_F(RtpSenderReceiverTest, VideoSenderDoesNotHaveDtmfSender) {
+  CreateVideoRtpSender();
+  EXPECT_EQ(nullptr, video_rtp_sender_->GetDtmfSender());
+}
+
+// Test that the DTMF sender is really using |voice_channel_|, and thus returns
+// true/false from CanSendDtmf based on what |voice_channel_| returns.
+TEST_F(RtpSenderReceiverTest, CanInsertDtmf) {
+  AddDtmfCodec();
+  CreateAudioRtpSender();
+  auto dtmf_sender = audio_rtp_sender_->GetDtmfSender();
+  ASSERT_NE(nullptr, dtmf_sender);
+  EXPECT_TRUE(dtmf_sender->CanInsertDtmf());
+}
+
+TEST_F(RtpSenderReceiverTest, CanNotInsertDtmf) {
+  CreateAudioRtpSender();
+  auto dtmf_sender = audio_rtp_sender_->GetDtmfSender();
+  ASSERT_NE(nullptr, dtmf_sender);
+  // DTMF codec has not been added, as it was in the above test.
+  EXPECT_FALSE(dtmf_sender->CanInsertDtmf());
+}
+
+TEST_F(RtpSenderReceiverTest, InsertDtmf) {
+  AddDtmfCodec();
+  CreateAudioRtpSender();
+  auto dtmf_sender = audio_rtp_sender_->GetDtmfSender();
+  ASSERT_NE(nullptr, dtmf_sender);
+
+  EXPECT_EQ(0U, voice_media_channel_->dtmf_info_queue().size());
+
+  // Insert DTMF
+  const int expected_duration = 90;
+  dtmf_sender->InsertDtmf("012", expected_duration, 100);
+
+  // Verify
+  ASSERT_EQ_WAIT(3U, voice_media_channel_->dtmf_info_queue().size(),
+                 kDefaultTimeout);
+  const uint32_t send_ssrc =
+      voice_media_channel_->send_streams()[0].first_ssrc();
+  EXPECT_TRUE(CompareDtmfInfo(voice_media_channel_->dtmf_info_queue()[0],
+                              send_ssrc, 0, expected_duration));
+  EXPECT_TRUE(CompareDtmfInfo(voice_media_channel_->dtmf_info_queue()[1],
+                              send_ssrc, 1, expected_duration));
+  EXPECT_TRUE(CompareDtmfInfo(voice_media_channel_->dtmf_info_queue()[2],
+                              send_ssrc, 2, expected_duration));
+}
+
+// Make sure the signal from "GetOnDestroyedSignal()" fires when the sender is
+// destroyed, which is needed for the DTMF sender.
+TEST_F(RtpSenderReceiverTest, TestOnDestroyedSignal) {
+  CreateAudioRtpSender();
+  EXPECT_FALSE(audio_sender_destroyed_signal_fired_);
+  audio_rtp_sender_ = nullptr;
+  EXPECT_TRUE(audio_sender_destroyed_signal_fired_);
+}
+
 }  // namespace webrtc
diff --git a/pc/webrtcsession.cc b/pc/webrtcsession.cc
index cfcc487..a02aa57 100644
--- a/pc/webrtcsession.cc
+++ b/pc/webrtcsession.cc
@@ -231,29 +231,6 @@
   return true;
 }
 
-static bool GetAudioSsrcByTrackId(const SessionDescription* session_description,
-                                  const std::string& track_id,
-                                  uint32_t* ssrc) {
-  const cricket::ContentInfo* audio_info =
-      cricket::GetFirstAudioContent(session_description);
-  if (!audio_info) {
-    LOG(LS_ERROR) << "Audio not used in this call";
-    return false;
-  }
-
-  const cricket::MediaContentDescription* audio_content =
-      static_cast<const cricket::MediaContentDescription*>(
-          audio_info->description);
-  const cricket::StreamParams* stream =
-      cricket::GetStreamByIds(audio_content->streams(), "", track_id);
-  if (!stream) {
-    return false;
-  }
-
-  *ssrc = stream->first_ssrc();
-  return true;
-}
-
 static bool GetTrackIdBySsrc(const SessionDescription* session_description,
                              uint32_t ssrc,
                              std::string* track_id) {
@@ -523,7 +500,6 @@
     quic_data_transport_.reset();
   }
 #endif
-  SignalDestroyed();
 
   LOG(LS_INFO) << "Session: " << id() << " is destroyed.";
 }
@@ -1248,49 +1224,6 @@
   return desc.str();
 }
 
-bool WebRtcSession::CanInsertDtmf(const std::string& track_id) {
-  RTC_DCHECK(signaling_thread()->IsCurrent());
-  if (!voice_channel_) {
-    LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
-    return false;
-  }
-  uint32_t send_ssrc = 0;
-  // The Dtmf is negotiated per channel not ssrc, so we only check if the ssrc
-  // exists.
-  if (!local_description() ||
-      !GetAudioSsrcByTrackId(local_description()->description(), track_id,
-                             &send_ssrc)) {
-    LOG(LS_ERROR) << "CanInsertDtmf: Track does not exist: " << track_id;
-    return false;
-  }
-  return voice_channel_->CanInsertDtmf();
-}
-
-bool WebRtcSession::InsertDtmf(const std::string& track_id,
-                               int code, int duration) {
-  RTC_DCHECK(signaling_thread()->IsCurrent());
-  if (!voice_channel_) {
-    LOG(LS_ERROR) << "InsertDtmf: No audio channel exists.";
-    return false;
-  }
-  uint32_t send_ssrc = 0;
-  if (!(local_description() &&
-        GetAudioSsrcByTrackId(local_description()->description(),
-                              track_id, &send_ssrc))) {
-    LOG(LS_ERROR) << "InsertDtmf: Track does not exist: " << track_id;
-    return false;
-  }
-  if (!voice_channel_->InsertDtmf(send_ssrc, code, duration)) {
-    LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
-    return false;
-  }
-  return true;
-}
-
-sigslot::signal0<>* WebRtcSession::GetOnDestroyedSignal() {
-  return &SignalDestroyed;
-}
-
 bool WebRtcSession::SendData(const cricket::SendDataParams& params,
                              const rtc::CopyOnWriteBuffer& payload,
                              cricket::SendDataResult* result) {
diff --git a/pc/webrtcsession.h b/pc/webrtcsession.h
index c250833..f8e0830 100644
--- a/pc/webrtcsession.h
+++ b/pc/webrtcsession.h
@@ -27,7 +27,6 @@
 #include "webrtc/p2p/base/candidate.h"
 #include "webrtc/p2p/base/transportcontroller.h"
 #include "webrtc/pc/datachannel.h"
-#include "webrtc/pc/dtmfsender.h"
 #include "webrtc/pc/mediacontroller.h"
 #include "webrtc/pc/mediasession.h"
 
@@ -140,8 +139,6 @@
 // packets are represented by TransportChannels.  The application-level protocol
 // is represented by SessionDecription objects.
 class WebRtcSession :
-
-    public DtmfProviderInterface,
     public DataChannelProviderInterface,
     public sigslot::has_slots<> {
  public:
@@ -285,12 +282,6 @@
   virtual bool GetLocalTrackIdBySsrc(uint32_t ssrc, std::string* track_id);
   virtual bool GetRemoteTrackIdBySsrc(uint32_t ssrc, std::string* track_id);
 
-  // Implements DtmfProviderInterface.
-  bool CanInsertDtmf(const std::string& track_id) override;
-  bool InsertDtmf(const std::string& track_id,
-                  int code, int duration) override;
-  sigslot::signal0<>* GetOnDestroyedSignal() override;
-
   // Implements DataChannelProviderInterface.
   bool SendData(const cricket::SendDataParams& params,
                 const rtc::CopyOnWriteBuffer& payload,
@@ -361,8 +352,6 @@
   sigslot::signal0<> SignalVideoChannelDestroyed;
   sigslot::signal0<> SignalDataChannelCreated;
   sigslot::signal0<> SignalDataChannelDestroyed;
-  // Called when the whole session is destroyed.
-  sigslot::signal0<> SignalDestroyed;
 
   // Called when a valid data channel OPEN message is received.
   // std::string represents the data channel label.
diff --git a/pc/webrtcsession_unittest.cc b/pc/webrtcsession_unittest.cc
index efd5d0c..716ba25 100644
--- a/pc/webrtcsession_unittest.cc
+++ b/pc/webrtcsession_unittest.cc
@@ -434,8 +434,6 @@
             fake_sctp_transport_factory_)));
     session_->SignalDataChannelOpenMessage.connect(
         this, &WebRtcSessionTest::OnDataChannelOpenMessage);
-    session_->GetOnDestroyedSignal()->connect(
-        this, &WebRtcSessionTest::OnSessionDestroyed);
 
     configuration_.rtcp_mux_policy = rtcp_mux_policy;
     EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
@@ -454,8 +452,6 @@
     last_data_channel_config_ = config;
   }
 
-  void OnSessionDestroyed() { session_destroyed_ = true; }
-
   void Init() {
     Init(nullptr, PeerConnectionInterface::kRtcpMuxPolicyNegotiate);
   }
@@ -502,17 +498,6 @@
          PeerConnectionInterface::kRtcpMuxPolicyNegotiate);
   }
 
-  void InitWithDtmfCodec() {
-    // Add kTelephoneEventCodec for dtmf test.
-    const cricket::AudioCodec kTelephoneEventCodec(106, "telephone-event", 8000,
-                                                   0, 1);
-    std::vector<cricket::AudioCodec> codecs;
-    codecs.push_back(kTelephoneEventCodec);
-    media_engine_->SetAudioCodecs(codecs);
-    desc_factory_->set_audio_codecs(codecs, codecs);
-    Init();
-  }
-
   void InitWithGcm() {
     rtc::CryptoOptions crypto_options;
     crypto_options.enable_gcm_crypto_suites = true;
@@ -1197,18 +1182,6 @@
       EXPECT_EQ(expected_candidate_num, observer_.mline_1_candidates_.size());
     }
   }
-  // Tests that we can only send DTMF when the dtmf codec is supported.
-  void TestCanInsertDtmf(bool can) {
-    if (can) {
-      InitWithDtmfCodec();
-    } else {
-      Init();
-    }
-    SendAudioVideoStream1();
-    CreateAndSetRemoteOfferAndLocalAnswer();
-    EXPECT_FALSE(session_->CanInsertDtmf(""));
-    EXPECT_EQ(can, session_->CanInsertDtmf(kAudioTrack1));
-  }
 
   bool ContainsVideoCodecWithName(const SessionDescriptionInterface* desc,
                                   const std::string& codec_name) {
@@ -1567,7 +1540,6 @@
   // Last values received from data channel creation signal.
   std::string last_data_channel_label_;
   InternalDataChannelInit last_data_channel_config_;
-  bool session_destroyed_ = false;
   bool with_gcm_ = false;
 };
 
@@ -3507,39 +3479,6 @@
   CreateAndSetRemoteOfferAndLocalAnswer();
 }
 
-TEST_F(WebRtcSessionTest, CanNotInsertDtmf) {
-  TestCanInsertDtmf(false);
-}
-
-TEST_F(WebRtcSessionTest, CanInsertDtmf) {
-  TestCanInsertDtmf(true);
-}
-
-TEST_F(WebRtcSessionTest, InsertDtmf) {
-  // Setup
-  Init();
-  SendAudioVideoStream1();
-  CreateAndSetRemoteOfferAndLocalAnswer();
-  FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0);
-  EXPECT_EQ(0U, channel->dtmf_info_queue().size());
-
-  // Insert DTMF
-  const int expected_duration = 90;
-  session_->InsertDtmf(kAudioTrack1, 0, expected_duration);
-  session_->InsertDtmf(kAudioTrack1, 1, expected_duration);
-  session_->InsertDtmf(kAudioTrack1, 2, expected_duration);
-
-  // Verify
-  ASSERT_EQ(3U, channel->dtmf_info_queue().size());
-  const uint32_t send_ssrc = channel->send_streams()[0].first_ssrc();
-  EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[0], send_ssrc, 0,
-                              expected_duration));
-  EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[1], send_ssrc, 1,
-                              expected_duration));
-  EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[2], send_ssrc, 2,
-                              expected_duration));
-}
-
 // This test verifies the |initial_offerer| flag when session initiates the
 // call.
 TEST_F(WebRtcSessionTest, TestInitiatorFlagAsOriginator) {
@@ -4400,14 +4339,6 @@
   TestPacketOptions();
 }
 
-// Make sure the signal from "GetOnDestroyedSignal()" fires when the session
-// is destroyed.
-TEST_F(WebRtcSessionTest, TestOnDestroyedSignal) {
-  Init();
-  session_.reset();
-  EXPECT_TRUE(session_destroyed_);
-}
-
 // TODO(bemasc): Add a TestIceStatesBundle with BUNDLE enabled.  That test
 // currently fails because upon disconnection and reconnection OnIceComplete is
 // called more than once without returning to IceGatheringGathering.