Refactoring DataChannelController from PeerConnection part 4

This CL:
- Moved HasDataChannel and data_channel_type_
- Moved rtp_data_channels_
- Moved sctp_data_channels_
- Moved data_channel_controller to its own .h file
- Various changes to reduce the coupling between the classes
- Removed friendship between DataChannelController and PeerConnection

Bug: webrtc:11146
Change-Id: Ib8c395e4c90ce34baf40812d1dade0ffa79f2438
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/161094
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29987}
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 70beceb..aaf6c4e 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -167,6 +167,7 @@
     "data_channel.cc",
     "data_channel.h",
     "data_channel_controller.cc",
+    "data_channel_controller.h",
     "dtmf_sender.cc",
     "dtmf_sender.h",
     "ice_server_parsing.cc",
diff --git a/pc/data_channel_controller.cc b/pc/data_channel_controller.cc
index 484886b..cc9f1493 100644
--- a/pc/data_channel_controller.cc
+++ b/pc/data_channel_controller.cc
@@ -8,22 +8,23 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-// This file contains the implementation of the class
-// webrtc::PeerConnection::DataChannelController.
-//
-// The intent is that this should be webrtc::DataChannelController, but
-// as a migration stage, it is simpler to have it as an inner class,
-// declared in the header file pc/peer_connection.h
+#include "pc/data_channel_controller.h"
+
+#include <utility>
 
 #include "pc/peer_connection.h"
 #include "pc/sctp_utils.h"
 
 namespace webrtc {
 
-bool PeerConnection::DataChannelController::SendData(
-    const cricket::SendDataParams& params,
-    const rtc::CopyOnWriteBuffer& payload,
-    cricket::SendDataResult* result) {
+bool DataChannelController::HasDataChannels() const {
+  RTC_DCHECK_RUN_ON(signaling_thread());
+  return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
+}
+
+bool DataChannelController::SendData(const cricket::SendDataParams& params,
+                                     const rtc::CopyOnWriteBuffer& payload,
+                                     cricket::SendDataResult* result) {
   // RTC_DCHECK_RUN_ON(signaling_thread());
   if (data_channel_transport()) {
     SendDataParams send_params;
@@ -59,7 +60,7 @@
   return false;
 }
 
-bool PeerConnection::DataChannelController::ConnectDataChannel(
+bool DataChannelController::ConnectDataChannel(
     DataChannel* webrtc_data_channel) {
   RTC_DCHECK_RUN_ON(signaling_thread());
   if (!rtp_data_channel() && !data_channel_transport()) {
@@ -87,7 +88,7 @@
   return true;
 }
 
-void PeerConnection::DataChannelController::DisconnectDataChannel(
+void DataChannelController::DisconnectDataChannel(
     DataChannel* webrtc_data_channel) {
   RTC_DCHECK_RUN_ON(signaling_thread());
   if (!rtp_data_channel() && !data_channel_transport()) {
@@ -108,7 +109,7 @@
   }
 }
 
-void PeerConnection::DataChannelController::AddSctpDataStream(int sid) {
+void DataChannelController::AddSctpDataStream(int sid) {
   if (data_channel_transport()) {
     network_thread()->Invoke<void>(RTC_FROM_HERE, [this, sid] {
       if (data_channel_transport()) {
@@ -118,7 +119,7 @@
   }
 }
 
-void PeerConnection::DataChannelController::RemoveSctpDataStream(int sid) {
+void DataChannelController::RemoveSctpDataStream(int sid) {
   if (data_channel_transport()) {
     network_thread()->Invoke<void>(RTC_FROM_HERE, [this, sid] {
       if (data_channel_transport()) {
@@ -128,13 +129,13 @@
   }
 }
 
-bool PeerConnection::DataChannelController::ReadyToSendData() const {
+bool DataChannelController::ReadyToSendData() const {
   RTC_DCHECK_RUN_ON(signaling_thread());
   return (rtp_data_channel() && rtp_data_channel()->ready_to_send_data()) ||
          (data_channel_transport() && data_channel_transport_ready_to_send_);
 }
 
-void PeerConnection::DataChannelController::OnDataReceived(
+void DataChannelController::OnDataReceived(
     int channel_id,
     DataMessageType type,
     const rtc::CopyOnWriteBuffer& buffer) {
@@ -151,7 +152,7 @@
       });
 }
 
-void PeerConnection::DataChannelController::OnChannelClosing(int channel_id) {
+void DataChannelController::OnChannelClosing(int channel_id) {
   RTC_DCHECK_RUN_ON(network_thread());
   data_channel_transport_invoker_->AsyncInvoke<void>(
       RTC_FROM_HERE, signaling_thread(), [this, channel_id] {
@@ -160,7 +161,7 @@
       });
 }
 
-void PeerConnection::DataChannelController::OnChannelClosed(int channel_id) {
+void DataChannelController::OnChannelClosed(int channel_id) {
   RTC_DCHECK_RUN_ON(network_thread());
   data_channel_transport_invoker_->AsyncInvoke<void>(
       RTC_FROM_HERE, signaling_thread(), [this, channel_id] {
@@ -169,7 +170,7 @@
       });
 }
 
-void PeerConnection::DataChannelController::OnReadyToSend() {
+void DataChannelController::OnReadyToSend() {
   RTC_DCHECK_RUN_ON(network_thread());
   data_channel_transport_invoker_->AsyncInvoke<void>(
       RTC_FROM_HERE, signaling_thread(), [this] {
@@ -180,12 +181,12 @@
       });
 }
 
-void PeerConnection::DataChannelController::SetupDataChannelTransport_n() {
+void DataChannelController::SetupDataChannelTransport_n() {
   RTC_DCHECK_RUN_ON(network_thread());
   data_channel_transport_invoker_ = std::make_unique<rtc::AsyncInvoker>();
 }
 
-void PeerConnection::DataChannelController::TeardownDataChannelTransport_n() {
+void DataChannelController::TeardownDataChannelTransport_n() {
   RTC_DCHECK_RUN_ON(network_thread());
   data_channel_transport_invoker_ = nullptr;
   if (data_channel_transport()) {
@@ -194,7 +195,7 @@
   set_data_channel_transport(nullptr);
 }
 
-void PeerConnection::DataChannelController::OnTransportChanged(
+void DataChannelController::OnTransportChanged(
     DataChannelTransportInterface* new_data_channel_transport) {
   RTC_DCHECK_RUN_ON(network_thread());
   if (data_channel_transport() &&
@@ -211,8 +212,8 @@
       // necessary when bundling is applied.
       data_channel_transport_invoker_->AsyncInvoke<void>(
           RTC_FROM_HERE, signaling_thread(), [this] {
-            RTC_DCHECK_RUN_ON(pc_->signaling_thread());
-            for (auto channel : pc_->sctp_data_channels_) {
+            RTC_DCHECK_RUN_ON(signaling_thread());
+            for (auto channel : sctp_data_channels_) {
               channel->OnTransportChannelCreated();
             }
           });
@@ -220,7 +221,7 @@
   }
 }
 
-bool PeerConnection::DataChannelController::HandleOpenMessage_s(
+bool DataChannelController::HandleOpenMessage_s(
     const cricket::ReceiveDataParams& params,
     const rtc::CopyOnWriteBuffer& buffer) {
   if (params.type == cricket::DMT_CONTROL && IsOpenMessage(buffer)) {
@@ -241,7 +242,7 @@
   return false;
 }
 
-void PeerConnection::DataChannelController::OnDataChannelOpenMessage(
+void DataChannelController::OnDataChannelOpenMessage(
     const std::string& label,
     const InternalDataChannelInit& config) {
   rtc::scoped_refptr<DataChannel> channel(
@@ -253,29 +254,26 @@
 
   rtc::scoped_refptr<DataChannelInterface> proxy_channel =
       DataChannelProxy::Create(signaling_thread(), channel);
-  {
-    RTC_DCHECK_RUN_ON(pc_->signaling_thread());
-    pc_->Observer()->OnDataChannel(std::move(proxy_channel));
-    pc_->NoteUsageEvent(UsageEvent::DATA_ADDED);
-  }
+  pc_->Observer()->OnDataChannel(std::move(proxy_channel));
+  pc_->NoteDataAddedEvent();
 }
 
 rtc::scoped_refptr<DataChannel>
-PeerConnection::DataChannelController::InternalCreateDataChannel(
+DataChannelController::InternalCreateDataChannel(
     const std::string& label,
     const InternalDataChannelInit* config) {
-  RTC_DCHECK_RUN_ON(pc_->signaling_thread());
+  RTC_DCHECK_RUN_ON(signaling_thread());
   if (pc_->IsClosed()) {
     return nullptr;
   }
-  if (pc_->data_channel_type() == cricket::DCT_NONE) {
+  if (data_channel_type_ == cricket::DCT_NONE) {
     RTC_LOG(LS_ERROR)
         << "InternalCreateDataChannel: Data is not supported in this call.";
     return nullptr;
   }
   InternalDataChannelInit new_config =
       config ? (*config) : InternalDataChannelInit();
-  if (DataChannel::IsSctpLike(pc_->data_channel_type_)) {
+  if (DataChannel::IsSctpLike(data_channel_type_)) {
     if (new_config.id < 0) {
       rtc::SSLRole role;
       if ((pc_->GetSctpSslRole(&role)) &&
@@ -292,36 +290,33 @@
   }
 
   rtc::scoped_refptr<DataChannel> channel(
-      DataChannel::Create(this, pc_->data_channel_type(), label, new_config));
+      DataChannel::Create(this, data_channel_type(), label, new_config));
   if (!channel) {
     sid_allocator_.ReleaseSid(new_config.id);
     return nullptr;
   }
 
   if (channel->data_channel_type() == cricket::DCT_RTP) {
-    if (pc_->rtp_data_channels_.find(channel->label()) !=
-        pc_->rtp_data_channels_.end()) {
+    if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
       RTC_LOG(LS_ERROR) << "DataChannel with label " << channel->label()
                         << " already exists.";
       return nullptr;
     }
-    pc_->rtp_data_channels_[channel->label()] = channel;
+    rtp_data_channels_[channel->label()] = channel;
   } else {
-    RTC_DCHECK(DataChannel::IsSctpLike(pc_->data_channel_type_));
-    pc_->sctp_data_channels_.push_back(channel);
+    RTC_DCHECK(DataChannel::IsSctpLike(data_channel_type_));
+    sctp_data_channels_.push_back(channel);
     channel->SignalClosed.connect(pc_,
                                   &PeerConnection::OnSctpDataChannelClosed);
   }
-
-  pc_->SignalDataChannelCreated_(channel.get());
+  SignalDataChannelCreated_(channel.get());
   return channel;
 }
 
-void PeerConnection::DataChannelController::AllocateSctpSids(
-    rtc::SSLRole role) {
-  RTC_DCHECK_RUN_ON(pc_->signaling_thread());
+void DataChannelController::AllocateSctpSids(rtc::SSLRole role) {
+  RTC_DCHECK_RUN_ON(signaling_thread());
   std::vector<rtc::scoped_refptr<DataChannel>> channels_to_close;
-  for (const auto& channel : pc_->sctp_data_channels_) {
+  for (const auto& channel : sctp_data_channels_) {
     if (channel->id() < 0) {
       int sid;
       if (!sid_allocator_.AllocateSid(role, &sid)) {
@@ -339,11 +334,10 @@
   }
 }
 
-void PeerConnection::DataChannelController::OnSctpDataChannelClosed(
-    DataChannel* channel) {
-  RTC_DCHECK_RUN_ON(pc_->signaling_thread());
-  for (auto it = pc_->sctp_data_channels_.begin();
-       it != pc_->sctp_data_channels_.end(); ++it) {
+void DataChannelController::OnSctpDataChannelClosed(DataChannel* channel) {
+  RTC_DCHECK_RUN_ON(signaling_thread());
+  for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
+       ++it) {
     if (it->get() == channel) {
       if (channel->id() >= 0) {
         // After the closing procedure is done, it's safe to use this ID for
@@ -352,12 +346,138 @@
       }
       // Since this method is triggered by a signal from the DataChannel,
       // we can't free it directly here; we need to free it asynchronously.
-      pc_->sctp_data_channels_to_free_.push_back(*it);
-      pc_->sctp_data_channels_.erase(it);
+      sctp_data_channels_to_free_.push_back(*it);
+      sctp_data_channels_.erase(it);
       pc_->SignalFreeDataChannels();
       return;
     }
   }
 }
 
+void DataChannelController::OnTransportChannelClosed() {
+  RTC_DCHECK_RUN_ON(signaling_thread());
+  // Use a temporary copy of the RTP/SCTP DataChannel list because the
+  // DataChannel may callback to us and try to modify the list.
+  std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
+  temp_rtp_dcs.swap(rtp_data_channels_);
+  for (const auto& kv : temp_rtp_dcs) {
+    kv.second->OnTransportChannelClosed();
+  }
+
+  std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
+  temp_sctp_dcs.swap(sctp_data_channels_);
+  for (const auto& channel : temp_sctp_dcs) {
+    channel->OnTransportChannelClosed();
+  }
+}
+
+DataChannel* DataChannelController::FindDataChannelBySid(int sid) const {
+  RTC_DCHECK_RUN_ON(signaling_thread());
+  for (const auto& channel : sctp_data_channels_) {
+    if (channel->id() == sid) {
+      return channel;
+    }
+  }
+  return nullptr;
+}
+
+void DataChannelController::UpdateLocalRtpDataChannels(
+    const cricket::StreamParamsVec& streams) {
+  std::vector<std::string> existing_channels;
+
+  RTC_DCHECK_RUN_ON(signaling_thread());
+  // Find new and active data channels.
+  for (const cricket::StreamParams& params : streams) {
+    // |it->sync_label| is actually the data channel label. The reason is that
+    // we use the same naming of data channels as we do for
+    // MediaStreams and Tracks.
+    // For MediaStreams, the sync_label is the MediaStream label and the
+    // track label is the same as |streamid|.
+    const std::string& channel_label = params.first_stream_id();
+    auto data_channel_it = rtp_data_channels()->find(channel_label);
+    if (data_channel_it == rtp_data_channels()->end()) {
+      RTC_LOG(LS_ERROR) << "channel label not found";
+      continue;
+    }
+    // Set the SSRC the data channel should use for sending.
+    data_channel_it->second->SetSendSsrc(params.first_ssrc());
+    existing_channels.push_back(data_channel_it->first);
+  }
+
+  UpdateClosingRtpDataChannels(existing_channels, true);
+}
+
+void DataChannelController::UpdateRemoteRtpDataChannels(
+    const cricket::StreamParamsVec& streams) {
+  std::vector<std::string> existing_channels;
+
+  RTC_DCHECK_RUN_ON(signaling_thread());
+  // Find new and active data channels.
+  for (const cricket::StreamParams& params : streams) {
+    // The data channel label is either the mslabel or the SSRC if the mslabel
+    // does not exist. Ex a=ssrc:444330170 mslabel:test1.
+    std::string label = params.first_stream_id().empty()
+                            ? rtc::ToString(params.first_ssrc())
+                            : params.first_stream_id();
+    auto data_channel_it = rtp_data_channels()->find(label);
+    if (data_channel_it == rtp_data_channels()->end()) {
+      // This is a new data channel.
+      CreateRemoteRtpDataChannel(label, params.first_ssrc());
+    } else {
+      data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
+    }
+    existing_channels.push_back(label);
+  }
+
+  UpdateClosingRtpDataChannels(existing_channels, false);
+}
+
+void DataChannelController::UpdateClosingRtpDataChannels(
+    const std::vector<std::string>& active_channels,
+    bool is_local_update) {
+  auto it = rtp_data_channels_.begin();
+  while (it != rtp_data_channels_.end()) {
+    DataChannel* data_channel = it->second;
+    if (absl::c_linear_search(active_channels, data_channel->label())) {
+      ++it;
+      continue;
+    }
+
+    if (is_local_update) {
+      data_channel->SetSendSsrc(0);
+    } else {
+      data_channel->RemotePeerRequestClose();
+    }
+
+    if (data_channel->state() == DataChannel::kClosed) {
+      rtp_data_channels_.erase(it);
+      it = rtp_data_channels_.begin();
+    } else {
+      ++it;
+    }
+  }
+}
+
+void DataChannelController::CreateRemoteRtpDataChannel(const std::string& label,
+                                                       uint32_t remote_ssrc) {
+  rtc::scoped_refptr<DataChannel> channel(
+      InternalCreateDataChannel(label, nullptr));
+  if (!channel.get()) {
+    RTC_LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
+                           "CreateDataChannel failed.";
+    return;
+  }
+  channel->SetReceiveSsrc(remote_ssrc);
+  rtc::scoped_refptr<DataChannelInterface> proxy_channel =
+      DataChannelProxy::Create(signaling_thread(), channel);
+  pc_->Observer()->OnDataChannel(std::move(proxy_channel));
+}
+
+rtc::Thread* DataChannelController::network_thread() const {
+  return pc_->network_thread();
+}
+rtc::Thread* DataChannelController::signaling_thread() const {
+  return pc_->signaling_thread();
+}
+
 }  // namespace webrtc
diff --git a/pc/data_channel_controller.h b/pc/data_channel_controller.h
new file mode 100644
index 0000000..bfce16c
--- /dev/null
+++ b/pc/data_channel_controller.h
@@ -0,0 +1,214 @@
+/*
+ *  Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef PC_DATA_CHANNEL_CONTROLLER_H_
+#define PC_DATA_CHANNEL_CONTROLLER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "pc/channel.h"
+#include "pc/data_channel.h"
+
+namespace webrtc {
+
+class PeerConnection;
+
+class DataChannelController : public DataChannelProviderInterface,
+                              public DataChannelSink {
+ public:
+  explicit DataChannelController(PeerConnection* pc) : pc_(pc) {}
+
+  // Implements DataChannelProviderInterface.
+  bool SendData(const cricket::SendDataParams& params,
+                const rtc::CopyOnWriteBuffer& payload,
+                cricket::SendDataResult* result) override;
+  bool ConnectDataChannel(DataChannel* webrtc_data_channel) override;
+  void DisconnectDataChannel(DataChannel* webrtc_data_channel) override;
+  void AddSctpDataStream(int sid) override;
+  void RemoveSctpDataStream(int sid) override;
+  bool ReadyToSendData() const override;
+
+  // Implements DataChannelSink.
+  void OnDataReceived(int channel_id,
+                      DataMessageType type,
+                      const rtc::CopyOnWriteBuffer& buffer) override;
+  void OnChannelClosing(int channel_id) override;
+  void OnChannelClosed(int channel_id) override;
+  void OnReadyToSend() override;
+
+  // Called from PeerConnection::SetupDataChannelTransport_n
+  void SetupDataChannelTransport_n();
+  // Called from PeerConnection::TeardownDataChannelTransport_n
+  void TeardownDataChannelTransport_n();
+
+  // Called from PeerConnection::OnTransportChanged
+  // to make required changes to datachannels' transports.
+  void OnTransportChanged(
+      DataChannelTransportInterface* data_channel_transport);
+
+  // Creates channel and adds it to the collection of DataChannels that will
+  // be offered in a SessionDescription.
+  rtc::scoped_refptr<DataChannel> InternalCreateDataChannel(
+      const std::string& label,
+      const InternalDataChannelInit*
+          config) /* RTC_RUN_ON(signaling_thread()) */;
+  void AllocateSctpSids(rtc::SSLRole role);
+
+  DataChannel* FindDataChannelBySid(int sid) const;
+
+  // Checks if any data channel has been added.
+  bool HasDataChannels() const;
+  bool HasSctpDataChannels() const {
+    RTC_DCHECK_RUN_ON(signaling_thread());
+    return !sctp_data_channels_.empty();
+  }
+  bool HasRtpDataChannels() const {
+    RTC_DCHECK_RUN_ON(signaling_thread());
+    return !rtp_data_channels_.empty();
+  }
+
+  // Called when it's appropriate to delete released datachannels.
+  void FreeDataChannels() {
+    RTC_DCHECK_RUN_ON(signaling_thread());
+    sctp_data_channels_to_free_.clear();
+  }
+
+  void UpdateLocalRtpDataChannels(const cricket::StreamParamsVec& streams);
+  void UpdateRemoteRtpDataChannels(const cricket::StreamParamsVec& streams);
+
+  // Accessors
+  cricket::DataChannelType data_channel_type() const {
+    return data_channel_type_;
+  }
+  void set_data_channel_type(cricket::DataChannelType type) {
+    data_channel_type_ = type;
+  }
+  cricket::RtpDataChannel* rtp_data_channel() const {
+    return rtp_data_channel_;
+  }
+  void set_rtp_data_channel(cricket::RtpDataChannel* channel) {
+    rtp_data_channel_ = channel;
+  }
+  DataChannelTransportInterface* data_channel_transport() const {
+    return data_channel_transport_;
+  }
+  void set_data_channel_transport(DataChannelTransportInterface* transport) {
+    data_channel_transport_ = transport;
+  }
+  const std::map<std::string, rtc::scoped_refptr<DataChannel>>*
+  rtp_data_channels() const {
+    RTC_DCHECK_RUN_ON(signaling_thread());
+    return &rtp_data_channels_;
+  }
+  const std::vector<rtc::scoped_refptr<DataChannel>>* sctp_data_channels()
+      const {
+    RTC_DCHECK_RUN_ON(signaling_thread());
+    return &sctp_data_channels_;
+  }
+
+  sigslot::signal1<DataChannel*>& SignalDataChannelCreated() {
+    RTC_DCHECK_RUN_ON(signaling_thread());
+    return SignalDataChannelCreated_;
+  }
+  // Called when the transport for the data channels is closed or destroyed.
+  void OnTransportChannelClosed();
+
+  void OnSctpDataChannelClosed(DataChannel* channel);
+
+ private:
+  // Parses and handles open messages.  Returns true if the message is an open
+  // message, false otherwise.
+  bool HandleOpenMessage_s(const cricket::ReceiveDataParams& params,
+                           const rtc::CopyOnWriteBuffer& buffer)
+      RTC_RUN_ON(signaling_thread());
+  // Called when a valid data channel OPEN message is received.
+  void OnDataChannelOpenMessage(const std::string& label,
+                                const InternalDataChannelInit& config)
+      RTC_RUN_ON(signaling_thread());
+
+  void CreateRemoteRtpDataChannel(const std::string& label,
+                                  uint32_t remote_ssrc)
+      RTC_RUN_ON(signaling_thread());
+
+  void UpdateClosingRtpDataChannels(
+      const std::vector<std::string>& active_channels,
+      bool is_local_update) RTC_RUN_ON(signaling_thread());
+
+  rtc::Thread* network_thread() const;
+  rtc::Thread* signaling_thread() const;
+
+  // Specifies which kind of data channel is allowed. This is controlled
+  // by the chrome command-line flag and constraints:
+  // 1. If chrome command-line switch 'enable-sctp-data-channels' is enabled,
+  // constraint kEnableDtlsSrtp is true, and constaint kEnableRtpDataChannels is
+  // not set or false, SCTP is allowed (DCT_SCTP);
+  // 2. If constraint kEnableRtpDataChannels is true, RTP is allowed (DCT_RTP);
+  // 3. If both 1&2 are false, data channel is not allowed (DCT_NONE).
+  cricket::DataChannelType data_channel_type_ =
+      cricket::DCT_NONE;  // TODO(bugs.webrtc.org/9987): Accessed on both
+                          // signaling and network thread.
+
+  // Plugin transport used for data channels.  Pointer may be accessed and
+  // checked from any thread, but the object may only be touched on the
+  // network thread.
+  // TODO(bugs.webrtc.org/9987): Accessed on both signaling and network
+  // thread.
+  DataChannelTransportInterface* data_channel_transport_ = nullptr;
+
+  // Cached value of whether the data channel transport is ready to send.
+  bool data_channel_transport_ready_to_send_
+      RTC_GUARDED_BY(signaling_thread()) = false;
+
+  // |rtp_data_channel_| is used if in RTP data channel mode,
+  // |data_channel_transport_| when using SCTP.
+  cricket::RtpDataChannel* rtp_data_channel_ = nullptr;
+  // TODO(bugs.webrtc.org/9987): Accessed on both
+  // signaling and some other thread.
+
+  SctpSidAllocator sid_allocator_ /* RTC_GUARDED_BY(signaling_thread()) */;
+  std::vector<rtc::scoped_refptr<DataChannel>> sctp_data_channels_
+      RTC_GUARDED_BY(signaling_thread());
+  std::vector<rtc::scoped_refptr<DataChannel>> sctp_data_channels_to_free_
+      RTC_GUARDED_BY(signaling_thread());
+
+  // Map of label -> DataChannel
+  std::map<std::string, rtc::scoped_refptr<DataChannel>> rtp_data_channels_
+      RTC_GUARDED_BY(signaling_thread());
+
+  // Signals from |data_channel_transport_|.  These are invoked on the
+  // signaling thread.
+  sigslot::signal1<bool> SignalDataChannelTransportWritable_s
+      RTC_GUARDED_BY(signaling_thread());
+  sigslot::signal2<const cricket::ReceiveDataParams&,
+                   const rtc::CopyOnWriteBuffer&>
+      SignalDataChannelTransportReceivedData_s
+          RTC_GUARDED_BY(signaling_thread());
+  sigslot::signal1<int> SignalDataChannelTransportChannelClosing_s
+      RTC_GUARDED_BY(signaling_thread());
+  sigslot::signal1<int> SignalDataChannelTransportChannelClosed_s
+      RTC_GUARDED_BY(signaling_thread());
+
+  sigslot::signal1<DataChannel*> SignalDataChannelCreated_
+      RTC_GUARDED_BY(signaling_thread());
+
+  // Used to invoke data channel transport signals on the signaling thread.
+  std::unique_ptr<rtc::AsyncInvoker> data_channel_transport_invoker_
+      RTC_GUARDED_BY(network_thread());
+
+  // Owning PeerConnection.
+  PeerConnection* const pc_;
+};
+
+}  // namespace webrtc
+
+#endif  // PC_DATA_CHANNEL_CONTROLLER_H_
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
index 0f632ab..855df75 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -1306,21 +1306,23 @@
     }
     if (configuration.enable_dtls_srtp && !*configuration.enable_dtls_srtp) {
       RTC_LOG(LS_INFO) << "Using data channel transport with no fallback";
-      data_channel_type_ = cricket::DCT_DATA_CHANNEL_TRANSPORT;
+      data_channel_controller_.set_data_channel_type(
+          cricket::DCT_DATA_CHANNEL_TRANSPORT);
     } else {
       RTC_LOG(LS_INFO) << "Using data channel transport with fallback to SCTP";
-      data_channel_type_ = cricket::DCT_DATA_CHANNEL_TRANSPORT_SCTP;
+      data_channel_controller_.set_data_channel_type(
+          cricket::DCT_DATA_CHANNEL_TRANSPORT_SCTP);
       config.sctp_factory = sctp_factory_.get();
     }
   } else if (configuration.enable_rtp_data_channel) {
     // Enable creation of RTP data channels if the kEnableRtpDataChannels is
     // set. It takes precendence over the disable_sctp_data_channels
     // PeerConnectionFactoryInterface::Options.
-    data_channel_type_ = cricket::DCT_RTP;
+    data_channel_controller_.set_data_channel_type(cricket::DCT_RTP);
   } else {
     // DTLS has to be enabled to use SCTP.
     if (!options.disable_sctp_data_channels && dtls_enabled_) {
-      data_channel_type_ = cricket::DCT_SCTP;
+      data_channel_controller_.set_data_channel_type(cricket::DCT_SCTP);
       config.sctp_factory = sctp_factory_.get();
     }
   }
@@ -2159,7 +2161,7 @@
   RTC_DCHECK_RUN_ON(signaling_thread());
   TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel");
 
-  bool first_datachannel = !HasDataChannels();
+  bool first_datachannel = !data_channel_controller_.HasDataChannels();
 
   std::unique_ptr<InternalDataChannelInit> internal_config;
   if (config) {
@@ -2766,7 +2768,7 @@
   // If setting the description decided our SSL role, allocate any necessary
   // SCTP sids.
   rtc::SSLRole role;
-  if (DataChannel::IsSctpLike(data_channel_type_) && GetSctpSslRole(&role)) {
+  if (DataChannel::IsSctpLike(data_channel_type()) && GetSctpSslRole(&role)) {
     data_channel_controller_.AllocateSctpSids(role);
   }
 
@@ -2830,7 +2832,8 @@
         data_content->media_description()->as_rtp_data();
     // rtp_data_desc will be null if this is an SCTP description.
     if (rtp_data_desc) {
-      UpdateLocalRtpDataChannels(rtp_data_desc->streams());
+      data_channel_controller_.UpdateLocalRtpDataChannels(
+          rtp_data_desc->streams());
     }
   }
 
@@ -3204,7 +3207,7 @@
   // If setting the description decided our SSL role, allocate any necessary
   // SCTP sids.
   rtc::SSLRole role;
-  if (DataChannel::IsSctpLike(data_channel_type_) && GetSctpSslRole(&role)) {
+  if (DataChannel::IsSctpLike(data_channel_type()) && GetSctpSslRole(&role)) {
     data_channel_controller_.AllocateSctpSids(role);
   }
 
@@ -3385,7 +3388,8 @@
     // If this is an RTP data transport, update the DataChannels with the
     // information from the remote peer.
     if (rtp_data_desc) {
-      UpdateRemoteRtpDataChannels(GetActiveStreams(rtp_data_desc));
+      data_channel_controller_.UpdateRemoteRtpDataChannels(
+          GetActiveStreams(rtp_data_desc));
     }
 
     // Iterate new_streams and notify the observer about new MediaStreams.
@@ -3584,7 +3588,7 @@
     cricket::ContentSource source,
     const cricket::ContentInfo& content,
     const cricket::ContentGroup* bundle_group) {
-  if (data_channel_type_ == cricket::DCT_NONE) {
+  if (data_channel_type() == cricket::DCT_NONE) {
     // If data channels are disabled, ignore this media section. CreateAnswer
     // will take care of rejecting it.
     return RTCError::OK();
@@ -3604,7 +3608,8 @@
     if (source == cricket::CS_REMOTE) {
       const MediaContentDescription* data_desc = content.media_description();
       if (data_desc && cricket::IsRtpProtocol(data_desc->protocol())) {
-        UpdateRemoteRtpDataChannels(GetActiveStreams(data_desc));
+        data_channel_controller_.UpdateRemoteRtpDataChannels(
+            GetActiveStreams(data_desc));
       }
     }
   }
@@ -4492,7 +4497,7 @@
       break;
     }
     case MSG_FREE_DATACHANNELS: {
-      sctp_data_channels_to_free_.clear();
+      data_channel_controller_.FreeDataChannels();
       break;
     }
     case MSG_REPORT_USAGE_PATTERN: {
@@ -4874,7 +4879,8 @@
   // negotiated by default and the unit tests in WebRtcDataBrowserTest will fail
   // when building with chromium. We want to leave RTP data channels broken, so
   // people won't try to use them.
-  if (!rtp_data_channels_.empty() || data_channel_type() != cricket::DCT_RTP) {
+  if (data_channel_controller_.HasRtpDataChannels() ||
+      data_channel_type() != cricket::DCT_RTP) {
     session_options->data_channel_type = data_channel_type();
   }
 
@@ -4937,7 +4943,7 @@
   // By default, only offer a new m= section if we have media to send with it.
   bool offer_new_audio_description = send_audio;
   bool offer_new_video_description = send_video;
-  bool offer_new_data_description = HasDataChannels();
+  bool offer_new_data_description = data_channel_controller_.HasDataChannels();
 
   // The "offer_to_receive_X" options allow those defaults to be overridden.
   if (offer_answer_options.offer_to_receive_audio !=
@@ -5175,7 +5181,7 @@
   }
   // Lastly, add a m-section if we have local data channels and an m section
   // does not already exist.
-  if (!GetDataMid() && HasDataChannels()) {
+  if (!GetDataMid() && data_channel_controller_.HasDataChannels()) {
     session_options->media_description_options.push_back(
         GetMediaDescriptionOptionsForActiveData(mid_generator_()));
   }
@@ -5196,7 +5202,8 @@
   // the RTP data channels would be successfully negotiated by default and the
   // unit tests in WebRtcDataBrowserTest will fail when building with chromium.
   // We want to leave RTP data channels broken, so people won't try to use them.
-  if (!rtp_data_channels_.empty() || data_channel_type() != cricket::DCT_RTP) {
+  if (data_channel_controller_.HasRtpDataChannels() ||
+      data_channel_type() != cricket::DCT_RTP) {
     session_options->data_channel_type = data_channel_type();
   }
 
@@ -5303,7 +5310,7 @@
       // Reject all data sections if data channels are disabled.
       // Reject a data section if it has already been rejected.
       // Reject all data sections except for the first one.
-      if (data_channel_type_ == cricket::DCT_NONE || content.rejected ||
+      if (data_channel_type() == cricket::DCT_NONE || content.rejected ||
           content.name != *GetDataMid()) {
         session_options->media_description_options.push_back(
             GetMediaDescriptionOptionsForRejectedData(content.name));
@@ -5378,7 +5385,8 @@
   cricket::MediaDescriptionOptions options(cricket::MEDIA_TYPE_DATA, mid,
                                            RtpTransceiverDirection::kSendRecv,
                                            /*stopped=*/false);
-  AddRtpDataChannelOptions(rtp_data_channels_, &options);
+  AddRtpDataChannelOptions(*data_channel_controller_.rtp_data_channels(),
+                           &options);
   return options;
 }
 
@@ -5388,12 +5396,13 @@
   cricket::MediaDescriptionOptions options(cricket::MEDIA_TYPE_DATA, mid,
                                            RtpTransceiverDirection::kInactive,
                                            /*stopped=*/true);
-  AddRtpDataChannelOptions(rtp_data_channels_, &options);
+  AddRtpDataChannelOptions(*data_channel_controller_.rtp_data_channels(),
+                           &options);
   return options;
 }
 
 absl::optional<std::string> PeerConnection::GetDataMid() const {
-  switch (data_channel_type_) {
+  switch (data_channel_type()) {
     case cricket::DCT_RTP:
       if (!data_channel_controller_.rtp_data_channel()) {
         return absl::nullopt;
@@ -5661,100 +5670,6 @@
   sender->internal()->SetSsrc(0);
 }
 
-void PeerConnection::UpdateLocalRtpDataChannels(
-    const cricket::StreamParamsVec& streams) {
-  std::vector<std::string> existing_channels;
-
-  // Find new and active data channels.
-  for (const cricket::StreamParams& params : streams) {
-    // |it->sync_label| is actually the data channel label. The reason is that
-    // we use the same naming of data channels as we do for
-    // MediaStreams and Tracks.
-    // For MediaStreams, the sync_label is the MediaStream label and the
-    // track label is the same as |streamid|.
-    const std::string& channel_label = params.first_stream_id();
-    auto data_channel_it = rtp_data_channels_.find(channel_label);
-    if (data_channel_it == rtp_data_channels_.end()) {
-      RTC_LOG(LS_ERROR) << "channel label not found";
-      continue;
-    }
-    // Set the SSRC the data channel should use for sending.
-    data_channel_it->second->SetSendSsrc(params.first_ssrc());
-    existing_channels.push_back(data_channel_it->first);
-  }
-
-  UpdateClosingRtpDataChannels(existing_channels, true);
-}
-
-void PeerConnection::UpdateRemoteRtpDataChannels(
-    const cricket::StreamParamsVec& streams) {
-  std::vector<std::string> existing_channels;
-
-  // Find new and active data channels.
-  for (const cricket::StreamParams& params : streams) {
-    // The data channel label is either the mslabel or the SSRC if the mslabel
-    // does not exist. Ex a=ssrc:444330170 mslabel:test1.
-    std::string label = params.first_stream_id().empty()
-                            ? rtc::ToString(params.first_ssrc())
-                            : params.first_stream_id();
-    auto data_channel_it = rtp_data_channels_.find(label);
-    if (data_channel_it == rtp_data_channels_.end()) {
-      // This is a new data channel.
-      CreateRemoteRtpDataChannel(label, params.first_ssrc());
-    } else {
-      data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
-    }
-    existing_channels.push_back(label);
-  }
-
-  UpdateClosingRtpDataChannels(existing_channels, false);
-}
-
-void PeerConnection::UpdateClosingRtpDataChannels(
-    const std::vector<std::string>& active_channels,
-    bool is_local_update) {
-  auto it = rtp_data_channels_.begin();
-  while (it != rtp_data_channels_.end()) {
-    DataChannel* data_channel = it->second;
-    if (absl::c_linear_search(active_channels, data_channel->label())) {
-      ++it;
-      continue;
-    }
-
-    if (is_local_update) {
-      data_channel->SetSendSsrc(0);
-    } else {
-      data_channel->RemotePeerRequestClose();
-    }
-
-    if (data_channel->state() == DataChannel::kClosed) {
-      rtp_data_channels_.erase(it);
-      it = rtp_data_channels_.begin();
-    } else {
-      ++it;
-    }
-  }
-}
-
-void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
-                                                uint32_t remote_ssrc) {
-  rtc::scoped_refptr<DataChannel> channel(
-      data_channel_controller_.InternalCreateDataChannel(label, nullptr));
-  if (!channel.get()) {
-    RTC_LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
-                           "CreateDataChannel failed.";
-    return;
-  }
-  channel->SetReceiveSsrc(remote_ssrc);
-  rtc::scoped_refptr<DataChannelInterface> proxy_channel =
-      DataChannelProxy::Create(signaling_thread(), channel);
-  Observer()->OnDataChannel(std::move(proxy_channel));
-}
-
-bool PeerConnection::HasDataChannels() const {
-  return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
-}
-
 void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
   // Since data_channel_controller doesn't do signals, this
   // signal is relayed here.
@@ -5765,22 +5680,6 @@
   signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FREE_DATACHANNELS, nullptr);
 }
 
-void PeerConnection::OnTransportChannelClosed() {
-  // Use a temporary copy of the RTP/SCTP DataChannel list because the
-  // DataChannel may callback to us and try to modify the list.
-  std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
-  temp_rtp_dcs.swap(rtp_data_channels_);
-  for (const auto& kv : temp_rtp_dcs) {
-    kv.second->OnTransportChannelClosed();
-  }
-
-  std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
-  temp_sctp_dcs.swap(sctp_data_channels_);
-  for (const auto& channel : temp_sctp_dcs) {
-    channel->OnTransportChannelClosed();
-  }
-}
-
 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
 PeerConnection::GetAudioTransceiver() const {
   // This method only works with Plan B SDP, where there is a single
@@ -5891,12 +5790,7 @@
 }
 
 DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
-  for (const auto& channel : sctp_data_channels_) {
-    if (channel->id() == sid) {
-      return channel;
-    }
-  }
-  return nullptr;
+  return data_channel_controller_.FindDataChannelBySid(sid);
 }
 
 PeerConnection::InitializePortAllocatorResult
@@ -6370,7 +6264,7 @@
 }
 
 cricket::DataChannelType PeerConnection::data_channel_type() const {
-  return data_channel_type_;
+  return data_channel_controller_.data_channel_type();
 }
 
 bool PeerConnection::IceRestartPending(const std::string& content_name) const {
@@ -6692,7 +6586,7 @@
   }
 
   const cricket::ContentInfo* data = cricket::GetFirstDataContent(&desc);
-  if (data_channel_type_ != cricket::DCT_NONE && data && !data->rejected &&
+  if (data_channel_type() != cricket::DCT_NONE && data && !data->rejected &&
       !data_channel_controller_.rtp_data_channel() &&
       !data_channel_controller_.data_channel_transport()) {
     if (!CreateDataChannel(data->name)) {
@@ -6752,7 +6646,7 @@
 }
 
 bool PeerConnection::CreateDataChannel(const std::string& mid) {
-  switch (data_channel_type_) {
+  switch (data_channel_type()) {
     case cricket::DCT_SCTP:
     case cricket::DCT_DATA_CHANNEL_TRANSPORT_SCTP:
     case cricket::DCT_DATA_CHANNEL_TRANSPORT:
@@ -6764,7 +6658,8 @@
       }
 
       // All non-RTP data channels must initialize |sctp_data_channels_|.
-      for (const auto& channel : sctp_data_channels_) {
+      for (const auto& channel :
+           *data_channel_controller_.sctp_data_channels()) {
         channel->OnTransportChannelCreated();
       }
       return true;
@@ -7379,7 +7274,7 @@
 
 void PeerConnection::DestroyDataChannelTransport() {
   if (data_channel_controller_.rtp_data_channel()) {
-    OnTransportChannelClosed();
+    data_channel_controller_.OnTransportChannelClosed();
     DestroyChannelInterface(data_channel_controller_.rtp_data_channel());
     data_channel_controller_.set_rtp_data_channel(nullptr);
   }
@@ -7391,7 +7286,7 @@
   // rtc::Bind will cause "Pure virtual function called" error to appear.
 
   if (sctp_mid_) {
-    OnTransportChannelClosed();
+    data_channel_controller_.OnTransportChannelClosed();
     network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
       RTC_DCHECK_RUN_ON(network_thread());
       TeardownDataChannelTransport_n();
@@ -7445,12 +7340,8 @@
 }
 
 PeerConnectionObserver* PeerConnection::Observer() const {
-  // In earlier production code, the pointer was not cleared on close,
-  // which might have led to undefined behavior if the observer was not
-  // deallocated, or strange crashes if it was.
-  // We use CHECK in order to catch such behavior if it exists.
-  // TODO(hta): Remove or replace with DCHECK if nothing is found.
-  RTC_CHECK(observer_);
+  RTC_DCHECK_RUN_ON(signaling_thread());
+  RTC_DCHECK(observer_);
   return observer_;
 }
 
@@ -7534,7 +7425,7 @@
 
   // 4. If connection has created any RTCDataChannels, and no m= section in
   // description has been negotiated yet for data, return true.
-  if (!sctp_data_channels_.empty()) {
+  if (data_channel_controller_.HasSctpDataChannels()) {
     if (!cricket::GetFirstDataContent(description->description()->contents()))
       return true;
   }
diff --git a/pc/peer_connection.h b/pc/peer_connection.h
index 7a15766..941b744 100644
--- a/pc/peer_connection.h
+++ b/pc/peer_connection.h
@@ -21,6 +21,7 @@
 #include "api/peer_connection_interface.h"
 #include "api/transport/data_channel_transport_interface.h"
 #include "api/turn_customizer.h"
+#include "pc/data_channel_controller.h"
 #include "pc/ice_server_parsing.h"
 #include "pc/jsep_transport_controller.h"
 #include "pc/peer_connection_factory.h"
@@ -269,7 +270,7 @@
   }
 
   sigslot::signal1<DataChannel*>& SignalDataChannelCreated() override {
-    return SignalDataChannelCreated_;
+    return data_channel_controller_.SignalDataChannelCreated();
   }
 
   cricket::RtpDataChannel* rtp_data_channel() const override {
@@ -279,7 +280,7 @@
   std::vector<rtc::scoped_refptr<DataChannel>> sctp_data_channels()
       const override {
     RTC_DCHECK_RUN_ON(signaling_thread());
-    return sctp_data_channels_;
+    return *data_channel_controller_.sctp_data_channels();
   }
 
   absl::optional<std::string> sctp_content_name() const override {
@@ -304,6 +305,22 @@
   bool NeedsIceRestart(const std::string& content_name) const override;
   bool GetSslRole(const std::string& content_name, rtc::SSLRole* role) override;
 
+  // Functions needed by DataChannelController
+  void NoteDataAddedEvent() { NoteUsageEvent(UsageEvent::DATA_ADDED); }
+  // Returns the observer. Will crash on CHECK if the observer is removed.
+  PeerConnectionObserver* Observer() const;
+  bool IsClosed() const {
+    RTC_DCHECK_RUN_ON(signaling_thread());
+    return signaling_state_ == PeerConnectionInterface::kClosed;
+  }
+  // Get current SSL role used by SCTP's underlying transport.
+  bool GetSctpSslRole(rtc::SSLRole* role);
+  // Handler for the "channel closed" signal
+  void OnSctpDataChannelClosed(DataChannel* channel);
+  // Sends the MSG_FREE_DATACHANNELS signal
+  void SignalFreeDataChannels();
+
+  // Functions made public for testing.
   void ReturnHistogramVeryQuicklyForTesting() {
     RTC_DCHECK_RUN_ON(signaling_thread());
     return_histogram_very_quickly_ = true;
@@ -318,6 +335,7 @@
   friend class ImplicitCreateSessionDescriptionObserver;
   class SetRemoteDescriptionObserverAdapter;
   friend class SetRemoteDescriptionObserverAdapter;
+
   // Represents the [[LocalIceCredentialsToReplace]] internal slot in the spec.
   // It makes the next CreateOffer() produce new ICE credentials even if
   // RTCOfferAnswerOptions::ice_restart is false.
@@ -395,120 +413,6 @@
     FieldTrialFlag receive_only;
   };
 
-  // Controller for datachannels. Intended to be separated out; placed here as a
-  // first stage in refactoring.
-  class DataChannelController : public DataChannelProviderInterface,
-                                public DataChannelSink {
-   public:
-    explicit DataChannelController(PeerConnection* pc) : pc_(pc) {}
-    ~DataChannelController() { data_channel_transport_invoker_.reset(); }
-
-    // Implements DataChannelProviderInterface.
-    bool SendData(const cricket::SendDataParams& params,
-                  const rtc::CopyOnWriteBuffer& payload,
-                  cricket::SendDataResult* result) override;
-    bool ConnectDataChannel(DataChannel* webrtc_data_channel) override;
-    void DisconnectDataChannel(DataChannel* webrtc_data_channel) override;
-    void AddSctpDataStream(int sid) override;
-    void RemoveSctpDataStream(int sid) override;
-    bool ReadyToSendData() const override;
-
-    // Implements DataChannelSink.
-    void OnDataReceived(int channel_id,
-                        DataMessageType type,
-                        const rtc::CopyOnWriteBuffer& buffer) override;
-    void OnChannelClosing(int channel_id) override;
-    void OnChannelClosed(int channel_id) override;
-    void OnReadyToSend() override;
-
-    // Called from PeerConnection::SetupDataChannelTransport_n
-    void SetupDataChannelTransport_n();
-    // Called from PeerConnection::TeardownDataChannelTransport_n
-    void TeardownDataChannelTransport_n();
-
-    // Called from PeerConnection::OnTransportChanged
-    // to make required changes to datachannels' transports.
-    void OnTransportChanged(
-        DataChannelTransportInterface* data_channel_transport);
-
-    // Parses and handles open messages.  Returns true if the message is an open
-    // message, false otherwise.
-    bool HandleOpenMessage_s(const cricket::ReceiveDataParams& params,
-                             const rtc::CopyOnWriteBuffer& buffer)
-        RTC_RUN_ON(signaling_thread());
-    // Called when a valid data channel OPEN message is received.
-    void OnDataChannelOpenMessage(const std::string& label,
-                                  const InternalDataChannelInit& config)
-        RTC_RUN_ON(signaling_thread());
-
-    // Creates channel and adds it to the collection of DataChannels that will
-    // be offered in a SessionDescription.
-    rtc::scoped_refptr<DataChannel> InternalCreateDataChannel(
-        const std::string& label,
-        const InternalDataChannelInit*
-            config) /* RTC_RUN_ON(signaling_thread()) */;
-    void AllocateSctpSids(
-        rtc::SSLRole role) /* RTC_RUN_ON(signaling_thread()) */;
-    void OnSctpDataChannelClosed(DataChannel* channel);
-    /* RTC_RUN_ON(signaling_thread() */
-
-    // Accessors
-    cricket::RtpDataChannel* rtp_data_channel() const {
-      return rtp_data_channel_;
-    }
-    void set_rtp_data_channel(cricket::RtpDataChannel* channel) {
-      rtp_data_channel_ = channel;
-    }
-    DataChannelTransportInterface* data_channel_transport() const {
-      return data_channel_transport_;
-    }
-    void set_data_channel_transport(DataChannelTransportInterface* transport) {
-      data_channel_transport_ = transport;
-    }
-
-   private:
-    rtc::Thread* network_thread() const { return pc_->network_thread(); }
-    rtc::Thread* signaling_thread() const { return pc_->signaling_thread(); }
-    // Plugin transport used for data channels.  Pointer may be accessed and
-    // checked from any thread, but the object may only be touched on the
-    // network thread.
-    // TODO(bugs.webrtc.org/9987): Accessed on both signaling and network
-    // thread.
-    DataChannelTransportInterface* data_channel_transport_ = nullptr;
-
-    // Cached value of whether the data channel transport is ready to send.
-    bool data_channel_transport_ready_to_send_
-        RTC_GUARDED_BY(signaling_thread()) = false;
-
-    // |rtp_data_channel_| is used if in RTP data channel mode,
-    // |data_channel_transport_| when using SCTP.
-    cricket::RtpDataChannel* rtp_data_channel_ = nullptr;
-    // TODO(bugs.webrtc.org/9987): Accessed on both
-    // signaling and some other thread.
-
-    SctpSidAllocator sid_allocator_ /* RTC_GUARDED_BY(signaling_thread()) */;
-
-    // Signals from |data_channel_transport_|.  These are invoked on the
-    // signaling thread.
-    sigslot::signal1<bool> SignalDataChannelTransportWritable_s
-        RTC_GUARDED_BY(signaling_thread());
-    sigslot::signal2<const cricket::ReceiveDataParams&,
-                     const rtc::CopyOnWriteBuffer&>
-        SignalDataChannelTransportReceivedData_s
-            RTC_GUARDED_BY(signaling_thread());
-    sigslot::signal1<int> SignalDataChannelTransportChannelClosing_s
-        RTC_GUARDED_BY(signaling_thread());
-    sigslot::signal1<int> SignalDataChannelTransportChannelClosed_s
-        RTC_GUARDED_BY(signaling_thread());
-
-    // Used to invoke data channel transport signals on the signaling thread.
-    std::unique_ptr<rtc::AsyncInvoker> data_channel_transport_invoker_
-        RTC_GUARDED_BY(network_thread());
-
-    // Owning PeerConnection.
-    PeerConnection* pc_;
-  };
-
   // Captures partial state to be used for rollback. Applicable only in
   // Unified Plan.
   class TransceiverStableState {
@@ -807,11 +711,6 @@
 
   void OnNegotiationNeeded();
 
-  bool IsClosed() const {
-    RTC_DCHECK_RUN_ON(signaling_thread());
-    return signaling_state_ == PeerConnectionInterface::kClosed;
-  }
-
   // Returns a MediaSessionOptions struct with options decided by |options|,
   // the local MediaStreams and DataChannels.
   void GetOptionsForOffer(const PeerConnectionInterface::RTCOfferAnswerOptions&
@@ -944,27 +843,6 @@
                             cricket::MediaType media_type)
       RTC_RUN_ON(signaling_thread());
 
-  void UpdateLocalRtpDataChannels(const cricket::StreamParamsVec& streams)
-      RTC_RUN_ON(signaling_thread());
-  void UpdateRemoteRtpDataChannels(const cricket::StreamParamsVec& streams)
-      RTC_RUN_ON(signaling_thread());
-  void UpdateClosingRtpDataChannels(
-      const std::vector<std::string>& active_channels,
-      bool is_local_update) RTC_RUN_ON(signaling_thread());
-  void CreateRemoteRtpDataChannel(const std::string& label,
-                                  uint32_t remote_ssrc)
-      RTC_RUN_ON(signaling_thread());
-
-  // Checks if any data channel has been added.
-  bool HasDataChannels() const RTC_RUN_ON(signaling_thread());
-  // Handler for the "channel closed" signal
-  void OnSctpDataChannelClosed(DataChannel* channel);
-  // Sends the MSG_FREE_DATACHANNELS signal
-  void SignalFreeDataChannels();
-
-  // Called when the transport for the data channels is closed or destroyed.
-  void OnTransportChannelClosed() RTC_RUN_ON(signaling_thread());
-
   // Returns true if the PeerConnection is configured to use Unified Plan
   // semantics for creating offers/answers and setting local/remote
   // descriptions. If this is true the RtpTransceiver API will also be available
@@ -1065,9 +943,6 @@
 
   cricket::ChannelInterface* GetChannel(const std::string& content_name);
 
-  // Get current SSL role used by SCTP's underlying transport.
-  bool GetSctpSslRole(rtc::SSLRole* role);
-
   cricket::IceConfig ParseIceConfig(
       const PeerConnectionInterface::RTCConfiguration& config) const;
 
@@ -1283,9 +1158,6 @@
   // RtpSenderBase::SetStreamsObserver override.
   void OnSetStreams() override;
 
-  // Returns the observer. Will crash on CHECK if the observer is removed.
-  PeerConnectionObserver* Observer() const RTC_RUN_ON(signaling_thread());
-
   // Returns the CryptoOptions for this PeerConnection. This will always
   // return the RTCConfiguration.crypto_options if set and will only default
   // back to the PeerConnectionFactory settings if nothing was set.
@@ -1305,9 +1177,6 @@
   // | sdp_type | is the type of the SDP that caused the rollback.
   RTCError Rollback(SdpType sdp_type);
 
-  sigslot::signal1<DataChannel*> SignalDataChannelCreated_
-      RTC_GUARDED_BY(signaling_thread());
-
   // Storing the factory as a scoped reference pointer ensures that the memory
   // in the PeerConnectionFactoryImpl remains available as long as the
   // PeerConnection is running. It is passed to PeerConnection as a raw pointer.
@@ -1406,14 +1275,6 @@
   std::vector<RtpSenderInfo> local_video_sender_infos_
       RTC_GUARDED_BY(signaling_thread());
 
-  // label -> DataChannel
-  std::map<std::string, rtc::scoped_refptr<DataChannel>> rtp_data_channels_
-      RTC_GUARDED_BY(signaling_thread());
-  std::vector<rtc::scoped_refptr<DataChannel>> sctp_data_channels_
-      RTC_GUARDED_BY(signaling_thread());
-  std::vector<rtc::scoped_refptr<DataChannel>> sctp_data_channels_to_free_
-      RTC_GUARDED_BY(signaling_thread());
-
   bool remote_peer_supports_msid_ RTC_GUARDED_BY(signaling_thread()) = false;
 
   // The unique_ptr belongs to the worker thread, but the Call object manages
@@ -1489,16 +1350,6 @@
   std::unique_ptr<SessionDescriptionInterface> pending_remote_description_
       RTC_GUARDED_BY(signaling_thread());
   bool dtls_enabled_ RTC_GUARDED_BY(signaling_thread()) = false;
-  // Specifies which kind of data channel is allowed. This is controlled
-  // by the chrome command-line flag and constraints:
-  // 1. If chrome command-line switch 'enable-sctp-data-channels' is enabled,
-  // constraint kEnableDtlsSrtp is true, and constaint kEnableRtpDataChannels is
-  // not set or false, SCTP is allowed (DCT_SCTP);
-  // 2. If constraint kEnableRtpDataChannels is true, RTP is allowed (DCT_RTP);
-  // 3. If both 1&2 are false, data channel is not allowed (DCT_NONE).
-  cricket::DataChannelType data_channel_type_ =
-      cricket::DCT_NONE;  // TODO(bugs.webrtc.org/9987): Accessed on both
-                          // signaling and network thread.
 
   // List of content names for which the remote side triggered an ICE restart.
   std::set<std::string> pending_ice_restarts_