Use new TransportController implementation in PeerConnection.

The TransportController will be replaced by the JsepTransportController
and JsepTransport will be replace be JsepTransport2.

The JsepTransportController will take the entire SessionDescription
and handle the RtcpMux, Sdes and BUNDLE internally.

The ownership model is also changed. The P2P layer transports are not
ref-counted and will be owned by the JsepTransport2.

In ORTC aspect, RtpTransportAdapter is now a wrapper over RtpTransport
or SrtpTransport and it implements the public and internal interface
by calling the transport underneath.

Bug: webrtc:8587
Change-Id: Ia7fa61288a566f211f8560072ea0eecaf19e48df
Reviewed-on: https://webrtc-review.googlesource.com/59586
Commit-Queue: Zhi Huang <zhihuang@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22693}
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 907d199..b59de48 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -42,8 +42,6 @@
     "dtlssrtptransport.h",
     "externalhmac.cc",
     "externalhmac.h",
-    "jseptransport.cc",
-    "jseptransport.h",
     "jseptransport2.cc",
     "jseptransport2.h",
     "jseptransportcontroller.cc",
@@ -66,8 +64,6 @@
     "srtpsession.h",
     "srtptransport.cc",
     "srtptransport.h",
-    "transportcontroller.cc",
-    "transportcontroller.h",
     "transportstats.cc",
     "transportstats.h",
   ]
@@ -280,7 +276,6 @@
       "currentspeakermonitor_unittest.cc",
       "dtlssrtptransport_unittest.cc",
       "jseptransport2_unittest.cc",
-      "jseptransport_unittest.cc",
       "jseptransportcontroller_unittest.cc",
       "mediasession_unittest.cc",
       "rtcpmuxfilter_unittest.cc",
@@ -290,7 +285,6 @@
       "srtpsession_unittest.cc",
       "srtptestutil.h",
       "srtptransport_unittest.cc",
-      "transportcontroller_unittest.cc",
     ]
 
     include_dirs = [ "//third_party/libsrtp/srtp" ]
@@ -350,7 +344,6 @@
       "test/fakeperiodicvideosource.h",
       "test/fakertccertificategenerator.h",
       "test/fakesctptransport.h",
-      "test/faketransportcontroller.h",
       "test/fakevideotrackrenderer.h",
       "test/fakevideotracksource.h",
       "test/mock_datachannel.h",
diff --git a/pc/channel.cc b/pc/channel.cc
index 358cb77..6da6470 100644
--- a/pc/channel.cc
+++ b/pc/channel.cc
@@ -98,20 +98,16 @@
                          rtc::Thread* signaling_thread,
                          std::unique_ptr<MediaChannel> media_channel,
                          const std::string& content_name,
-                         bool rtcp_mux_required,
-                         bool srtp_required)
+                         bool srtp_required,
+                         rtc::CryptoOptions crypto_options)
     : worker_thread_(worker_thread),
       network_thread_(network_thread),
       signaling_thread_(signaling_thread),
       content_name_(content_name),
-      rtcp_mux_required_(rtcp_mux_required),
-      unencrypted_rtp_transport_(
-          rtc::MakeUnique<webrtc::RtpTransport>(rtcp_mux_required)),
       srtp_required_(srtp_required),
+      crypto_options_(crypto_options),
       media_channel_(std::move(media_channel)) {
   RTC_DCHECK_RUN_ON(worker_thread_);
-  rtp_transport_ = unencrypted_rtp_transport_.get();
-  ConnectToRtpTransport();
   RTC_LOG(LS_INFO) << "Created channel for " << content_name;
 }
 
@@ -162,33 +158,10 @@
   rtp_transport_->SetMetricsObserver(nullptr);
 }
 
-void BaseChannel::Init_w(DtlsTransportInternal* rtp_dtls_transport,
-                         DtlsTransportInternal* rtcp_dtls_transport,
-                         rtc::PacketTransportInternal* rtp_packet_transport,
-                         rtc::PacketTransportInternal* rtcp_packet_transport) {
-  RTC_DCHECK_RUN_ON(worker_thread_);
-  network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
-    SetTransports_n(rtp_dtls_transport, rtcp_dtls_transport,
-                    rtp_packet_transport, rtcp_packet_transport);
-
-    if (rtcp_mux_required_) {
-      rtcp_mux_filter_.SetActive();
-    }
-  });
-
-  // Both RTP and RTCP channels should be set, we can call SetInterface on
-  // the media channel and it can set network options.
-  media_channel_->SetInterface(this);
-}
-
 void BaseChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport) {
   RTC_DCHECK_RUN_ON(worker_thread_);
   network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
     SetRtpTransport(rtp_transport);
-
-    if (rtcp_mux_required_) {
-      rtcp_mux_filter_.SetActive();
-    }
   });
 
   // Both RTP and RTCP channels should be set, we can call SetInterface on
@@ -205,11 +178,8 @@
   network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
     FlushRtcpMessages_n();
 
-    if (dtls_srtp_transport_) {
-      dtls_srtp_transport_->SetDtlsTransports(nullptr, nullptr);
-    } else {
-      rtp_transport_->SetRtpPacketTransport(nullptr);
-      rtp_transport_->SetRtcpPacketTransport(nullptr);
+    if (rtp_transport_) {
+      DisconnectFromRtpTransport();
     }
     // Clear pending read packets/messages.
     network_thread_->Clear(&invoker_);
@@ -221,143 +191,34 @@
   if (!network_thread_->IsCurrent()) {
     network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
       SetRtpTransport(rtp_transport);
-      return;
     });
+    return;
   }
 
-  RTC_DCHECK(rtp_transport);
-
   if (rtp_transport_) {
     DisconnectFromRtpTransport();
   }
+
   rtp_transport_ = rtp_transport;
-  RTC_LOG(LS_INFO) << "Setting the RtpTransport for " << content_name();
-  ConnectToRtpTransport();
+  if (rtp_transport_) {
+    RTC_DCHECK(rtp_transport_->rtp_packet_transport());
+    transport_name_ = rtp_transport_->rtp_packet_transport()->transport_name();
 
-  UpdateWritableState_n();
-}
+    ConnectToRtpTransport();
+    OnTransportReadyToSend(rtp_transport_->IsReadyToSend());
+    UpdateWritableState_n();
 
-void BaseChannel::SetTransports(DtlsTransportInternal* rtp_dtls_transport,
-                                DtlsTransportInternal* rtcp_dtls_transport) {
-  network_thread_->Invoke<void>(
-      RTC_FROM_HERE,
-      Bind(&BaseChannel::SetTransports_n, this, rtp_dtls_transport,
-           rtcp_dtls_transport, rtp_dtls_transport, rtcp_dtls_transport));
-}
-
-void BaseChannel::SetTransports(
-    rtc::PacketTransportInternal* rtp_packet_transport,
-    rtc::PacketTransportInternal* rtcp_packet_transport) {
-  network_thread_->Invoke<void>(
-      RTC_FROM_HERE, Bind(&BaseChannel::SetTransports_n, this, nullptr, nullptr,
-                          rtp_packet_transport, rtcp_packet_transport));
-}
-
-void BaseChannel::SetTransports_n(
-    DtlsTransportInternal* rtp_dtls_transport,
-    DtlsTransportInternal* rtcp_dtls_transport,
-    rtc::PacketTransportInternal* rtp_packet_transport,
-    rtc::PacketTransportInternal* rtcp_packet_transport) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  // Validate some assertions about the input.
-  RTC_DCHECK(rtp_packet_transport);
-  RTC_DCHECK_EQ(NeedsRtcpTransport(), rtcp_packet_transport != nullptr);
-  if (rtp_dtls_transport || rtcp_dtls_transport) {
-    // DTLS/non-DTLS pointers should be to the same object.
-    RTC_DCHECK(rtp_dtls_transport == rtp_packet_transport);
-    RTC_DCHECK(rtcp_dtls_transport == rtcp_packet_transport);
-    // Can't go from non-DTLS to DTLS.
-    RTC_DCHECK(!rtp_transport_->rtp_packet_transport() || rtp_dtls_transport_);
-  } else {
-    // Can't go from DTLS to non-DTLS.
-    RTC_DCHECK(!rtp_dtls_transport_);
-  }
-  // Transport names should be the same.
-  if (rtp_dtls_transport && rtcp_dtls_transport) {
-    RTC_DCHECK(rtp_dtls_transport->transport_name() ==
-               rtcp_dtls_transport->transport_name());
-  }
-
-  if (rtp_packet_transport == rtp_transport_->rtp_packet_transport()) {
-    // Nothing to do if transport isn't changing.
-    return;
-  }
-
-  std::string debug_name;
-  if (rtp_dtls_transport) {
-    transport_name_ = rtp_dtls_transport->transport_name();
-    debug_name = transport_name_;
-  } else {
-    debug_name = rtp_packet_transport->transport_name();
-  }
-  // If this BaseChannel doesn't require RTCP mux and we haven't fully
-  // negotiated RTCP mux, we need an RTCP transport.
-  if (rtcp_packet_transport) {
-    RTC_LOG(LS_INFO) << "Setting RTCP Transport for " << content_name()
-                     << " on " << debug_name << " transport "
-                     << rtcp_packet_transport;
-    SetTransport_n(/*rtcp=*/true, rtcp_dtls_transport, rtcp_packet_transport);
-  }
-
-  RTC_LOG(LS_INFO) << "Setting RTP Transport for " << content_name() << " on "
-                   << debug_name << " transport " << rtp_packet_transport;
-  SetTransport_n(/*rtcp=*/false, rtp_dtls_transport, rtp_packet_transport);
-
-  // Set DtlsTransport/PacketTransport for RTP-level transport.
-  if ((rtp_dtls_transport_ || rtcp_dtls_transport_) && dtls_srtp_transport_) {
-    // When setting the transport with non-null |dtls_srtp_transport_|, we are
-    // using DTLS-SRTP. This could happen for bundling. If the
-    // |dtls_srtp_transport| is null, we cannot tell if it doing DTLS-SRTP or
-    // SDES until the description is set. So don't call |EnableDtlsSrtp_n| here.
-    dtls_srtp_transport_->SetDtlsTransports(rtp_dtls_transport,
-                                            rtcp_dtls_transport);
-  } else {
-    rtp_transport_->SetRtpPacketTransport(rtp_packet_transport);
-    rtp_transport_->SetRtcpPacketTransport(rtcp_packet_transport);
-  }
-
-  // Update aggregate writable/ready-to-send state between RTP and RTCP upon
-  // setting new transport channels.
-  UpdateWritableState_n();
-}
-
-void BaseChannel::SetTransport_n(
-    bool rtcp,
-    DtlsTransportInternal* new_dtls_transport,
-    rtc::PacketTransportInternal* new_packet_transport) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  if (new_dtls_transport) {
-    RTC_DCHECK(new_dtls_transport == new_packet_transport);
-  }
-  DtlsTransportInternal*& old_dtls_transport =
-      rtcp ? rtcp_dtls_transport_ : rtp_dtls_transport_;
-  rtc::PacketTransportInternal* old_packet_transport =
-      rtcp ? rtp_transport_->rtcp_packet_transport()
-           : rtp_transport_->rtp_packet_transport();
-
-  if (!old_packet_transport && !new_packet_transport) {
-    // Nothing to do.
-    return;
-  }
-
-  RTC_DCHECK(old_packet_transport != new_packet_transport);
-
-  old_dtls_transport = new_dtls_transport;
-
-  // If there's no new transport, we're done.
-  if (!new_packet_transport) {
-    return;
-  }
-
-  if (rtcp && new_dtls_transport) {
-    RTC_CHECK(!(ShouldSetupDtlsSrtp_n() && srtp_active()))
-        << "Setting RTCP for DTLS/SRTP after the DTLS is active "
-        << "should never happen.";
-  }
-
-  auto& socket_options = rtcp ? rtcp_socket_options_ : socket_options_;
-  for (const auto& pair : socket_options) {
-    new_packet_transport->SetOption(pair.first, pair.second);
+    // Set the cached socket options.
+    for (const auto& pair : socket_options_) {
+      rtp_transport_->rtp_packet_transport()->SetOption(pair.first,
+                                                        pair.second);
+    }
+    if (rtp_transport_->rtcp_packet_transport()) {
+      for (const auto& pair : rtcp_socket_options_) {
+        rtp_transport_->rtp_packet_transport()->SetOption(pair.first,
+                                                          pair.second);
+      }
+    }
   }
 }
 
@@ -416,12 +277,6 @@
       Bind(&BaseChannel::SetRemoteContent_w, this, content, type, error_desc));
 }
 
-bool BaseChannel::NeedsRtcpTransport() {
-  // If this BaseChannel doesn't require RTCP mux and we haven't fully
-  // negotiated RTCP mux, we need an RTCP transport.
-  return !rtcp_mux_required_ && !rtcp_mux_filter_.IsFullyActive();
-}
-
 bool BaseChannel::IsReadyToReceiveMedia_w() const {
   // Receive data if we are enabled and have local content,
   return enabled() &&
@@ -440,7 +295,7 @@
   return enabled() &&
          webrtc::RtpTransceiverDirectionHasRecv(remote_content_direction_) &&
          webrtc::RtpTransceiverDirectionHasSend(local_content_direction_) &&
-         was_ever_writable() && (srtp_active() || !ShouldSetupDtlsSrtp_n());
+         was_ever_writable() && (srtp_active() || encryption_disabled_);
 }
 
 bool BaseChannel::SendPacket(rtc::CopyOnWriteBuffer* packet,
@@ -463,6 +318,7 @@
                              rtc::Socket::Option opt,
                              int value) {
   RTC_DCHECK(network_thread_->IsCurrent());
+  RTC_DCHECK(rtp_transport_);
   rtc::PacketTransportInternal* transport = nullptr;
   switch (type) {
     case ST_RTP:
@@ -482,11 +338,6 @@
 void BaseChannel::OnWritableState(bool writable) {
   RTC_DCHECK(network_thread_->IsCurrent());
   if (writable) {
-    // This is used to cover the scenario when the DTLS handshake is completed
-    // and DtlsTransport becomes writable before the remote description is set.
-    if (ShouldSetupDtlsSrtp_n()) {
-      EnableDtlsSrtp_n();
-    }
     ChannelWritable_n();
   } else {
     ChannelNotWritable_n();
@@ -533,13 +384,14 @@
     network_thread_->Post(RTC_FROM_HERE, this, message_id, data);
     return true;
   }
+
   TRACE_EVENT0("webrtc", "BaseChannel::SendPacket");
 
   // Now that we are on the correct thread, ensure we have a place to send this
   // packet before doing anything. (We might get RTCP packets that we don't
   // intend to send.) If we've negotiated RTCP mux, send RTCP over the RTP
   // transport.
-  if (!rtp_transport_->IsWritable(rtcp)) {
+  if (!rtp_transport_ || !rtp_transport_->IsWritable(rtcp)) {
     return false;
   }
 
@@ -571,18 +423,15 @@
     std::string packet_type = rtcp ? "RTCP" : "RTP";
     RTC_LOG(LS_WARNING) << "Sending an " << packet_type
                         << " packet without encryption.";
-  } else {
-    // Make sure we didn't accidentally send any packets without encryption.
-    RTC_DCHECK(rtp_transport_ == sdes_transport_.get() ||
-               rtp_transport_ == dtls_srtp_transport_.get());
   }
+
   // Bon voyage.
   return rtcp ? rtp_transport_->SendRtcpPacket(packet, options, PF_SRTP_BYPASS)
               : rtp_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS);
 }
 
 bool BaseChannel::HandlesPayloadType(int packet_type) const {
-  return rtp_transport_->HandlesPayloadType(packet_type);
+  return bundle_filter_.FindPayloadType(packet_type);
 }
 
 void BaseChannel::OnPacketReceived(bool rtcp,
@@ -593,6 +442,11 @@
     signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED);
   }
 
+  // Filter out the packet this channel cannot handle.
+  if (!rtcp && !bundle_filter_.DemuxPacket(packet->data(), packet->size())) {
+    return;
+  }
+
   if (!srtp_active() && srtp_required_) {
     // Our session description indicates that SRTP is required, but we got a
     // packet before our SRTP filter is active. This means either that
@@ -652,12 +506,8 @@
 }
 
 void BaseChannel::UpdateWritableState_n() {
-  rtc::PacketTransportInternal* rtp_packet_transport =
-      rtp_transport_->rtp_packet_transport();
-  rtc::PacketTransportInternal* rtcp_packet_transport =
-      rtp_transport_->rtcp_packet_transport();
-  if (rtp_packet_transport && rtp_packet_transport->writable() &&
-      (!rtcp_packet_transport || rtcp_packet_transport->writable())) {
+  if (rtp_transport_->IsWritable(/*rtcp=*/true) &&
+      rtp_transport_->IsWritable(/*rtcp=*/false)) {
     ChannelWritable_n();
   } else {
     ChannelNotWritable_n();
@@ -678,11 +528,6 @@
   UpdateMediaSendRecvState();
 }
 
-bool BaseChannel::ShouldSetupDtlsSrtp_n() const {
-  // Since DTLS is applied to all transports, checking RTP should be enough.
-  return rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive();
-}
-
 void BaseChannel::ChannelNotWritable_n() {
   RTC_DCHECK(network_thread_->IsCurrent());
   if (!writable_)
@@ -693,238 +538,6 @@
   UpdateMediaSendRecvState();
 }
 
-bool BaseChannel::SetRtpTransportParameters(
-    const MediaContentDescription* content,
-    SdpType type,
-    ContentSource src,
-    const RtpHeaderExtensions& extensions,
-    std::string* error_desc) {
-  std::vector<int> encrypted_extension_ids;
-  for (const webrtc::RtpExtension& extension : extensions) {
-    if (extension.encrypt) {
-      RTC_LOG(LS_INFO) << "Using " << (src == CS_LOCAL ? "local" : "remote")
-                       << " encrypted extension: " << extension.ToString();
-      encrypted_extension_ids.push_back(extension.id);
-    }
-  }
-
-  // Cache srtp_required_ for belt and suspenders check on SendPacket
-  return network_thread_->Invoke<bool>(
-      RTC_FROM_HERE,
-      Bind(&BaseChannel::SetRtpTransportParameters_n, this, content, type, src,
-           encrypted_extension_ids, error_desc));
-}
-
-bool BaseChannel::SetRtpTransportParameters_n(
-    const MediaContentDescription* content,
-    SdpType type,
-    ContentSource src,
-    const std::vector<int>& encrypted_extension_ids,
-    std::string* error_desc) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  if (!SetSrtp_n(content->cryptos(), type, src, encrypted_extension_ids,
-                 error_desc)) {
-    return false;
-  }
-
-  if (!SetRtcpMux_n(content->rtcp_mux(), type, src, error_desc)) {
-    return false;
-  }
-
-  return true;
-}
-
-// |dtls| will be set to true if DTLS is active for transport and crypto is
-// empty.
-bool BaseChannel::CheckSrtpConfig_n(const std::vector<CryptoParams>& cryptos,
-                                    bool* dtls,
-                                    std::string* error_desc) {
-  *dtls = rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive();
-  if (*dtls && !cryptos.empty()) {
-    SafeSetError("Cryptos must be empty when DTLS is active.", error_desc);
-    return false;
-  }
-  return true;
-}
-
-void BaseChannel::EnableSdes_n() {
-  if (sdes_transport_) {
-    return;
-  }
-  // DtlsSrtpTransport and SrtpTransport shouldn't be enabled at the same
-  // time.
-  RTC_DCHECK(!dtls_srtp_transport_);
-  RTC_DCHECK(unencrypted_rtp_transport_);
-  sdes_transport_ = rtc::MakeUnique<webrtc::SrtpTransport>(
-      std::move(unencrypted_rtp_transport_));
-#if defined(ENABLE_EXTERNAL_AUTH)
-  sdes_transport_->EnableExternalAuth();
-#endif
-  SetRtpTransport(sdes_transport_.get());
-  RTC_LOG(LS_INFO) << "Wrapping RtpTransport in SrtpTransport.";
-}
-
-void BaseChannel::EnableDtlsSrtp_n() {
-  if (dtls_srtp_transport_) {
-    return;
-  }
-  // DtlsSrtpTransport and SrtpTransport shouldn't be enabled at the same
-  // time.
-  RTC_DCHECK(!sdes_transport_);
-  RTC_DCHECK(unencrypted_rtp_transport_);
-
-  auto srtp_transport = rtc::MakeUnique<webrtc::SrtpTransport>(
-      std::move(unencrypted_rtp_transport_));
-#if defined(ENABLE_EXTERNAL_AUTH)
-  srtp_transport->EnableExternalAuth();
-#endif
-  dtls_srtp_transport_ =
-      rtc::MakeUnique<webrtc::DtlsSrtpTransport>(std::move(srtp_transport));
-
-  SetRtpTransport(dtls_srtp_transport_.get());
-  if (cached_send_extension_ids_) {
-    dtls_srtp_transport_->UpdateSendEncryptedHeaderExtensionIds(
-        *cached_send_extension_ids_);
-  }
-  if (cached_recv_extension_ids_) {
-    dtls_srtp_transport_->UpdateRecvEncryptedHeaderExtensionIds(
-        *cached_recv_extension_ids_);
-  }
-  // Set the DtlsTransport and the |dtls_srtp_transport_| will handle the DTLS
-  // relate signal internally.
-  RTC_DCHECK(rtp_dtls_transport_);
-  dtls_srtp_transport_->SetDtlsTransports(rtp_dtls_transport_,
-                                          rtcp_dtls_transport_);
-
-  RTC_LOG(LS_INFO) << "Wrapping SrtpTransport in DtlsSrtpTransport.";
-}
-
-bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& cryptos,
-                            SdpType type,
-                            ContentSource src,
-                            const std::vector<int>& encrypted_extension_ids,
-                            std::string* error_desc) {
-  TRACE_EVENT0("webrtc", "BaseChannel::SetSrtp_w");
-  bool ret = false;
-  bool dtls = false;
-  ret = CheckSrtpConfig_n(cryptos, &dtls, error_desc);
-  if (!ret) {
-    return false;
-  }
-
-  // If SRTP was not required, but we're setting a description that uses SDES,
-  // we need to upgrade to an SrtpTransport.
-  if (!sdes_transport_ && !dtls && !cryptos.empty()) {
-    EnableSdes_n();
-  }
-
-  if ((type == SdpType::kAnswer || type == SdpType::kPrAnswer) && dtls) {
-    EnableDtlsSrtp_n();
-  }
-
-  UpdateEncryptedHeaderExtensionIds(src, encrypted_extension_ids);
-
-  if (!dtls) {
-    switch (type) {
-      case SdpType::kOffer:
-        ret = sdes_negotiator_.SetOffer(cryptos, src);
-        break;
-      case SdpType::kPrAnswer:
-        ret = sdes_negotiator_.SetProvisionalAnswer(cryptos, src);
-        break;
-      case SdpType::kAnswer:
-        ret = sdes_negotiator_.SetAnswer(cryptos, src);
-        break;
-      default:
-        break;
-    }
-
-    // If setting an SDES answer succeeded, apply the negotiated parameters
-    // to the SRTP transport.
-    if ((type == SdpType::kPrAnswer || type == SdpType::kAnswer) && ret) {
-      if (sdes_negotiator_.send_cipher_suite() &&
-          sdes_negotiator_.recv_cipher_suite()) {
-        RTC_DCHECK(cached_send_extension_ids_);
-        RTC_DCHECK(cached_recv_extension_ids_);
-        ret = sdes_transport_->SetRtpParams(
-            *(sdes_negotiator_.send_cipher_suite()),
-            sdes_negotiator_.send_key().data(),
-            static_cast<int>(sdes_negotiator_.send_key().size()),
-            *(cached_send_extension_ids_),
-            *(sdes_negotiator_.recv_cipher_suite()),
-            sdes_negotiator_.recv_key().data(),
-            static_cast<int>(sdes_negotiator_.recv_key().size()),
-            *(cached_recv_extension_ids_));
-      } else {
-        RTC_LOG(LS_INFO) << "No crypto keys are provided for SDES.";
-        if (type == SdpType::kAnswer && sdes_transport_) {
-          // Explicitly reset the |sdes_transport_| if no crypto param is
-          // provided in the answer. No need to call |ResetParams()| for
-          // |sdes_negotiator_| because it resets the params inside |SetAnswer|.
-          sdes_transport_->ResetParams();
-        }
-      }
-    }
-  }
-
-  if (!ret) {
-    SafeSetError("Failed to setup SRTP.", error_desc);
-    return false;
-  }
-  return true;
-}
-
-bool BaseChannel::SetRtcpMux_n(bool enable,
-                               SdpType type,
-                               ContentSource src,
-                               std::string* error_desc) {
-  // Provide a more specific error message for the RTCP mux "require" policy
-  // case.
-  if (rtcp_mux_required_ && !enable) {
-    SafeSetError(
-        "rtcpMuxPolicy is 'require', but media description does not "
-        "contain 'a=rtcp-mux'.",
-        error_desc);
-    return false;
-  }
-  bool ret = false;
-  switch (type) {
-    case SdpType::kOffer:
-      ret = rtcp_mux_filter_.SetOffer(enable, src);
-      break;
-    case SdpType::kPrAnswer:
-      // This may activate RTCP muxing, but we don't yet destroy the transport
-      // because the final answer may deactivate it.
-      ret = rtcp_mux_filter_.SetProvisionalAnswer(enable, src);
-      break;
-    case SdpType::kAnswer:
-      ret = rtcp_mux_filter_.SetAnswer(enable, src);
-      if (ret && rtcp_mux_filter_.IsActive()) {
-        ActivateRtcpMux();
-      }
-      break;
-    default:
-      break;
-  }
-  if (!ret) {
-    SafeSetError("Failed to setup RTCP mux filter.", error_desc);
-    return false;
-  }
-  rtp_transport_->SetRtcpMuxEnabled(rtcp_mux_filter_.IsActive());
-  // |rtcp_mux_filter_| can be active if |action| is SdpType::kPrAnswer or
-  // SdpType::kAnswer, but we only want to tear down the RTCP transport if we
-  // received a final answer.
-  if (rtcp_mux_filter_.IsActive()) {
-    // If the RTP transport is already writable, then so are we.
-    if (rtp_transport_->rtp_packet_transport()->writable()) {
-      ChannelWritable_n();
-    }
-  }
-
-  return true;
-}
-
 bool BaseChannel::AddRecvStream_w(const StreamParams& sp) {
   RTC_DCHECK(worker_thread() == rtc::Thread::Current());
   return media_channel()->AddRecvStream(sp);
@@ -1008,9 +621,8 @@
 
 RtpHeaderExtensions BaseChannel::GetFilteredRtpHeaderExtensions(
     const RtpHeaderExtensions& extensions) {
-  if (!rtp_dtls_transport_ ||
-      !rtp_dtls_transport_->crypto_options()
-          .enable_encrypted_rtp_header_extensions) {
+  RTC_DCHECK(rtp_transport_);
+  if (crypto_options_.enable_encrypted_rtp_header_extensions) {
     RtpHeaderExtensions filtered;
     auto pred = [](const webrtc::RtpExtension& extension) {
         return !extension.encrypt;
@@ -1023,39 +635,6 @@
   return webrtc::RtpExtension::FilterDuplicateNonEncrypted(extensions);
 }
 
-void BaseChannel::MaybeCacheRtpAbsSendTimeHeaderExtension_w(
-    const std::vector<webrtc::RtpExtension>& extensions) {
-// Absolute Send Time extension id is used only with external auth,
-// so do not bother searching for it and making asyncronious call to set
-// something that is not used.
-#if defined(ENABLE_EXTERNAL_AUTH)
-  const webrtc::RtpExtension* send_time_extension =
-      webrtc::RtpExtension::FindHeaderExtensionByUri(
-          extensions, webrtc::RtpExtension::kAbsSendTimeUri);
-  int rtp_abs_sendtime_extn_id =
-      send_time_extension ? send_time_extension->id : -1;
-  invoker_.AsyncInvoke<void>(
-      RTC_FROM_HERE, network_thread_,
-      Bind(&BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n, this,
-           rtp_abs_sendtime_extn_id));
-#endif
-}
-
-void BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n(
-    int rtp_abs_sendtime_extn_id) {
-  if (sdes_transport_) {
-    sdes_transport_->CacheRtpAbsSendTimeHeaderExtension(
-        rtp_abs_sendtime_extn_id);
-  } else if (dtls_srtp_transport_) {
-    dtls_srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(
-        rtp_abs_sendtime_extn_id);
-  } else {
-    RTC_LOG(LS_WARNING)
-        << "Trying to cache the Absolute Send Time extension id "
-           "but the SRTP is not active.";
-  }
-}
-
 void BaseChannel::OnMessage(rtc::Message *pmsg) {
   TRACE_EVENT0("webrtc", "BaseChannel::OnMessage");
   switch (pmsg->message_id) {
@@ -1077,7 +656,7 @@
 }
 
 void BaseChannel::AddHandledPayloadType(int payload_type) {
-  rtp_transport_->AddHandledPayloadType(payload_type);
+  bundle_filter_.AddPayloadType(payload_type);
 }
 
 void BaseChannel::FlushRtcpMessages_n() {
@@ -1104,47 +683,6 @@
   SignalSentPacket(sent_packet);
 }
 
-void BaseChannel::UpdateEncryptedHeaderExtensionIds(
-    cricket::ContentSource source,
-    const std::vector<int>& extension_ids) {
-  if (source == ContentSource::CS_LOCAL) {
-    cached_recv_extension_ids_ = std::move(extension_ids);
-    if (dtls_srtp_transport_) {
-      dtls_srtp_transport_->UpdateRecvEncryptedHeaderExtensionIds(
-          extension_ids);
-    }
-  } else {
-    cached_send_extension_ids_ = std::move(extension_ids);
-    if (dtls_srtp_transport_) {
-      dtls_srtp_transport_->UpdateSendEncryptedHeaderExtensionIds(
-          extension_ids);
-    }
-  }
-}
-
-void BaseChannel::ActivateRtcpMux() {
-  // We permanently activated RTCP muxing; signal that we no longer need
-  // the RTCP transport.
-  std::string debug_name =
-      transport_name_.empty()
-          ? rtp_transport_->rtp_packet_transport()->transport_name()
-          : transport_name_;
-  RTC_LOG(LS_INFO) << "Enabling rtcp-mux for " << content_name()
-                   << "; no longer need RTCP transport for " << debug_name;
-  if (rtp_transport_->rtcp_packet_transport()) {
-    SetTransport_n(/*rtcp=*/true, nullptr, nullptr);
-    if (dtls_srtp_transport_) {
-      RTC_DCHECK(rtp_dtls_transport_);
-      dtls_srtp_transport_->SetDtlsTransports(rtp_dtls_transport_,
-                                              /*rtcp_dtls_transport_=*/nullptr);
-    } else {
-      rtp_transport_->SetRtcpPacketTransport(nullptr);
-    }
-    SignalRtcpMuxFullyActive(transport_name_);
-  }
-  UpdateWritableState_n();
-}
-
 VoiceChannel::VoiceChannel(rtc::Thread* worker_thread,
                            rtc::Thread* network_thread,
                            rtc::Thread* signaling_thread,
@@ -1152,21 +690,20 @@
                            MediaEngineInterface* /* media_engine */,
                            std::unique_ptr<VoiceMediaChannel> media_channel,
                            const std::string& content_name,
-                           bool rtcp_mux_required,
-                           bool srtp_required)
+                           bool srtp_required,
+                           rtc::CryptoOptions crypto_options)
     : BaseChannel(worker_thread,
                   network_thread,
                   signaling_thread,
                   std::move(media_channel),
                   content_name,
-                  rtcp_mux_required,
-                  srtp_required) {}
+                  srtp_required,
+                  crypto_options) {}
 
 VoiceChannel::~VoiceChannel() {
   TRACE_EVENT0("webrtc", "VoiceChannel::~VoiceChannel");
   // this can't be done in the base class, since it calls a virtual
   DisableMedia_w();
-  Deinit();
 }
 
 void BaseChannel::UpdateMediaSendRecvState() {
@@ -1208,11 +745,6 @@
   RtpHeaderExtensions rtp_header_extensions =
       GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions());
 
-  if (!SetRtpTransportParameters(content, type, CS_LOCAL, rtp_header_extensions,
-                                 error_desc)) {
-    return false;
-  }
-
   AudioRecvParameters recv_params = last_recv_params_;
   RtpParametersFromMediaDescription(audio, rtp_header_extensions, &recv_params);
   if (!media_channel()->SetRecvParameters(recv_params)) {
@@ -1257,11 +789,6 @@
   RtpHeaderExtensions rtp_header_extensions =
       GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions());
 
-  if (!SetRtpTransportParameters(content, type, CS_REMOTE,
-                                 rtp_header_extensions, error_desc)) {
-    return false;
-  }
-
   AudioSendParameters send_params = last_send_params_;
   RtpSendParametersFromMediaDescription(audio, rtp_header_extensions,
       &send_params);
@@ -1284,10 +811,6 @@
     return false;
   }
 
-  if (audio->rtp_header_extensions_set()) {
-    MaybeCacheRtpAbsSendTimeHeaderExtension_w(rtp_header_extensions);
-  }
-
   set_remote_content_direction(content->direction());
   UpdateMediaSendRecvState_w();
   return true;
@@ -1298,22 +821,20 @@
                            rtc::Thread* signaling_thread,
                            std::unique_ptr<VideoMediaChannel> media_channel,
                            const std::string& content_name,
-                           bool rtcp_mux_required,
-                           bool srtp_required)
+                           bool srtp_required,
+                           rtc::CryptoOptions crypto_options)
     : BaseChannel(worker_thread,
                   network_thread,
                   signaling_thread,
                   std::move(media_channel),
                   content_name,
-                  rtcp_mux_required,
-                  srtp_required) {}
+                  srtp_required,
+                  crypto_options) {}
 
 VideoChannel::~VideoChannel() {
   TRACE_EVENT0("webrtc", "VideoChannel::~VideoChannel");
   // this can't be done in the base class, since it calls a virtual
   DisableMedia_w();
-
-  Deinit();
 }
 
 void VideoChannel::UpdateMediaSendRecvState_w() {
@@ -1351,11 +872,6 @@
   RtpHeaderExtensions rtp_header_extensions =
       GetFilteredRtpHeaderExtensions(video->rtp_header_extensions());
 
-  if (!SetRtpTransportParameters(content, type, CS_LOCAL, rtp_header_extensions,
-                                 error_desc)) {
-    return false;
-  }
-
   VideoRecvParameters recv_params = last_recv_params_;
   RtpParametersFromMediaDescription(video, rtp_header_extensions, &recv_params);
   if (!media_channel()->SetRecvParameters(recv_params)) {
@@ -1400,11 +916,6 @@
   RtpHeaderExtensions rtp_header_extensions =
       GetFilteredRtpHeaderExtensions(video->rtp_header_extensions());
 
-  if (!SetRtpTransportParameters(content, type, CS_REMOTE,
-                                 rtp_header_extensions, error_desc)) {
-    return false;
-  }
-
   VideoSendParameters send_params = last_send_params_;
   RtpSendParametersFromMediaDescription(video, rtp_header_extensions,
       &send_params);
@@ -1430,11 +941,6 @@
     SafeSetError("Failed to set remote video description streams.", error_desc);
     return false;
   }
-
-  if (video->rtp_header_extensions_set()) {
-    MaybeCacheRtpAbsSendTimeHeaderExtension_w(rtp_header_extensions);
-  }
-
   set_remote_content_direction(content->direction());
   UpdateMediaSendRecvState_w();
   return true;
@@ -1445,36 +951,20 @@
                                rtc::Thread* signaling_thread,
                                std::unique_ptr<DataMediaChannel> media_channel,
                                const std::string& content_name,
-                               bool rtcp_mux_required,
-                               bool srtp_required)
+                               bool srtp_required,
+                               rtc::CryptoOptions crypto_options)
     : BaseChannel(worker_thread,
                   network_thread,
                   signaling_thread,
                   std::move(media_channel),
                   content_name,
-                  rtcp_mux_required,
-                  srtp_required) {}
+                  srtp_required,
+                  crypto_options) {}
 
 RtpDataChannel::~RtpDataChannel() {
   TRACE_EVENT0("webrtc", "RtpDataChannel::~RtpDataChannel");
   // this can't be done in the base class, since it calls a virtual
   DisableMedia_w();
-
-  Deinit();
-}
-
-void RtpDataChannel::Init_w(
-    DtlsTransportInternal* rtp_dtls_transport,
-    DtlsTransportInternal* rtcp_dtls_transport,
-    rtc::PacketTransportInternal* rtp_packet_transport,
-    rtc::PacketTransportInternal* rtcp_packet_transport) {
-  BaseChannel::Init_w(rtp_dtls_transport, rtcp_dtls_transport,
-                      rtp_packet_transport, rtcp_packet_transport);
-
-  media_channel()->SignalDataReceived.connect(this,
-                                              &RtpDataChannel::OnDataReceived);
-  media_channel()->SignalReadyToSend.connect(
-      this, &RtpDataChannel::OnDataChannelReadyToSend);
 }
 
 void RtpDataChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport) {
@@ -1529,11 +1019,6 @@
   RtpHeaderExtensions rtp_header_extensions =
       GetFilteredRtpHeaderExtensions(data->rtp_header_extensions());
 
-  if (!SetRtpTransportParameters(content, type, CS_LOCAL, rtp_header_extensions,
-                                 error_desc)) {
-    return false;
-  }
-
   DataRecvParameters recv_params = last_recv_params_;
   RtpParametersFromMediaDescription(data, rtp_header_extensions, &recv_params);
   if (!media_channel()->SetRecvParameters(recv_params)) {
@@ -1588,11 +1073,6 @@
       GetFilteredRtpHeaderExtensions(data->rtp_header_extensions());
 
   RTC_LOG(LS_INFO) << "Setting remote data description";
-  if (!SetRtpTransportParameters(content, type, CS_REMOTE,
-                                 rtp_header_extensions, error_desc)) {
-    return false;
-  }
-
   DataSendParameters send_params = last_send_params_;
   RtpSendParametersFromMediaDescription<DataCodec>(data, rtp_header_extensions,
       &send_params);
diff --git a/pc/channel.h b/pc/channel.h
index 6a8367a..cf04b5c 100644
--- a/pc/channel.h
+++ b/pc/channel.h
@@ -29,13 +29,12 @@
 #include "p2p/base/dtlstransportinternal.h"
 #include "p2p/base/packettransportinternal.h"
 #include "pc/audiomonitor.h"
+#include "pc/bundlefilter.h"
 #include "pc/dtlssrtptransport.h"
 #include "pc/mediasession.h"
-#include "pc/rtcpmuxfilter.h"
 #include "pc/rtptransport.h"
 #include "pc/srtpfilter.h"
 #include "pc/srtptransport.h"
-#include "pc/transportcontroller.h"
 #include "rtc_base/asyncinvoker.h"
 #include "rtc_base/asyncudpsocket.h"
 #include "rtc_base/criticalsection.h"
@@ -75,20 +74,16 @@
  public:
   // If |srtp_required| is true, the channel will not send or receive any
   // RTP/RTCP packets without using SRTP (either using SDES or DTLS-SRTP).
+  // TODO(zhihuang:) Create a BaseChannel::Config struct for the parameter lists
+  // which will make it easier to change the constructor.
   BaseChannel(rtc::Thread* worker_thread,
               rtc::Thread* network_thread,
               rtc::Thread* signaling_thread,
               std::unique_ptr<MediaChannel> media_channel,
               const std::string& content_name,
-              bool rtcp_mux_required,
-              bool srtp_required);
+              bool srtp_required,
+              rtc::CryptoOptions crypto_options);
   virtual ~BaseChannel();
-  // TODO(zhihuang): Remove this once the RtpTransport can be shared between
-  // BaseChannels.
-  void Init_w(DtlsTransportInternal* rtp_dtls_transport,
-              DtlsTransportInternal* rtcp_dtls_transport,
-              rtc::PacketTransportInternal* rtp_packet_transport,
-              rtc::PacketTransportInternal* rtcp_packet_transport);
   void Init_w(webrtc::RtpTransportInternal* rtp_transport);
 
   // Deinit may be called multiple times and is simply ignored if it's already
@@ -102,16 +97,10 @@
   const std::string& transport_name() const { return transport_name_; }
   bool enabled() const { return enabled_; }
 
-  // This function returns true if we are using SDES.
-  bool sdes_active() const {
-    return sdes_transport_ && sdes_negotiator_.IsActive();
-  }
-  // The following function returns true if we are using DTLS-based keying.
-  bool dtls_active() const {
-    return dtls_srtp_transport_ && dtls_srtp_transport_->IsActive();
-  }
   // This function returns true if using SRTP (DTLS-based keying or SDES).
-  bool srtp_active() const { return sdes_active() || dtls_active(); }
+  bool srtp_active() const {
+    return rtp_transport_ && rtp_transport_->IsSrtpActive();
+  }
 
   bool writable() const { return writable_; }
 
@@ -121,20 +110,6 @@
   // internally. It would replace the |SetTransports| and its variants.
   void SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport);
 
-  // Set the transport(s), and update writability and "ready-to-send" state.
-  // |rtp_transport| must be non-null.
-  // |rtcp_transport| must be supplied if NeedsRtcpTransport() is true (meaning
-  // RTCP muxing is not fully active yet).
-  // |rtp_transport| and |rtcp_transport| must share the same transport name as
-  // well.
-  // Can not start with "rtc::PacketTransportInternal" and switch to
-  // "DtlsTransportInternal", or vice-versa.
-  // TODO(zhihuang): Remove these two once the RtpTransport can be shared
-  // between BaseChannels.
-  void SetTransports(DtlsTransportInternal* rtp_dtls_transport,
-                     DtlsTransportInternal* rtcp_dtls_transport);
-  void SetTransports(rtc::PacketTransportInternal* rtp_packet_transport,
-                     rtc::PacketTransportInternal* rtcp_packet_transport);
   // Channel control
   bool SetLocalContent(const MediaContentDescription* content,
                        webrtc::SdpType type,
@@ -173,15 +148,19 @@
   // Fired on the network thread.
   sigslot::signal1<const std::string&> SignalRtcpMuxFullyActive;
 
-  // Only public for unit tests.  Otherwise, consider private.
-  DtlsTransportInternal* rtp_dtls_transport() const {
-    return rtp_dtls_transport_;
-  }
-  DtlsTransportInternal* rtcp_dtls_transport() const {
-    return rtcp_dtls_transport_;
+  rtc::PacketTransportInternal* rtp_packet_transport() {
+    if (rtp_transport_) {
+      return rtp_transport_->rtp_packet_transport();
+    }
+    return nullptr;
   }
 
-  bool NeedsRtcpTransport();
+  rtc::PacketTransportInternal* rtcp_packet_transport() {
+    if (rtp_transport_) {
+      return rtp_transport_->rtcp_packet_transport();
+    }
+    return nullptr;
+  }
 
   // From RtpTransport - public for testing only
   void OnTransportReadyToSend(bool ready);
@@ -207,22 +186,11 @@
   void SetMetricsObserver(
       rtc::scoped_refptr<webrtc::MetricsObserverInterface> metrics_observer);
 
+  void DisableEncryption(bool disabled) { encryption_disabled_ = disabled; }
+
  protected:
   virtual MediaChannel* media_channel() const { return media_channel_.get(); }
 
-  void SetTransports_n(DtlsTransportInternal* rtp_dtls_transport,
-                       DtlsTransportInternal* rtcp_dtls_transport,
-                       rtc::PacketTransportInternal* rtp_packet_transport,
-                       rtc::PacketTransportInternal* rtcp_packet_transport);
-
-  // This does not update writability or "ready-to-send" state; it just
-  // disconnects from the old channel and connects to the new one.
-  // TODO(zhihuang): Remove this once the RtpTransport can be shared between
-  // BaseChannels.
-  void SetTransport_n(bool rtcp,
-                      DtlsTransportInternal* new_dtls_transport,
-                      rtc::PacketTransportInternal* new_packet_transport);
-
   bool was_ever_writable() const { return was_ever_writable_; }
   void set_local_content_direction(webrtc::RtpTransceiverDirection direction) {
     local_content_direction_ = direction;
@@ -289,11 +257,6 @@
   bool RemoveRecvStream_w(uint32_t ssrc);
   bool AddSendStream_w(const StreamParams& sp);
   bool RemoveSendStream_w(uint32_t ssrc);
-  bool ShouldSetupDtlsSrtp_n() const;
-  // Do the DTLS key expansion and impose it on the SRTP/SRTCP filters.
-  // |rtcp_channel| indicates whether to set up the RTP or RTCP filter.
-  bool SetupDtlsSrtp_n(bool rtcp);
-  void MaybeSetupDtlsSrtp_n();
 
   // Should be called whenever the conditions for
   // IsReadyToReceiveMedia/IsReadyToSendMedia are satisfied (or unsatisfied).
@@ -313,18 +276,6 @@
   virtual bool SetRemoteContent_w(const MediaContentDescription* content,
                                   webrtc::SdpType type,
                                   std::string* error_desc) = 0;
-  bool SetRtpTransportParameters(const MediaContentDescription* content,
-                                 webrtc::SdpType type,
-                                 ContentSource src,
-                                 const RtpHeaderExtensions& extensions,
-                                 std::string* error_desc);
-  bool SetRtpTransportParameters_n(
-      const MediaContentDescription* content,
-      webrtc::SdpType type,
-      ContentSource src,
-      const std::vector<int>& encrypted_extension_ids,
-      std::string* error_desc);
-
   // Return a list of RTP header extensions with the non-encrypted extensions
   // removed depending on the current crypto_options_ and only if both the
   // non-encrypted and encrypted extension is present for the same URI.
@@ -336,19 +287,6 @@
   void MaybeCacheRtpAbsSendTimeHeaderExtension_w(
       const std::vector<webrtc::RtpExtension>& extensions);
 
-  bool CheckSrtpConfig_n(const std::vector<CryptoParams>& cryptos,
-                         bool* dtls,
-                         std::string* error_desc);
-  bool SetSrtp_n(const std::vector<CryptoParams>& params,
-                 webrtc::SdpType type,
-                 ContentSource src,
-                 const std::vector<int>& encrypted_extension_ids,
-                 std::string* error_desc);
-  bool SetRtcpMux_n(bool enable,
-                    webrtc::SdpType type,
-                    ContentSource src,
-                    std::string* error_desc);
-
   // From MessageHandler
   void OnMessage(rtc::Message* pmsg) override;
 
@@ -366,26 +304,6 @@
   void SignalSentPacket_n(const rtc::SentPacket& sent_packet);
   void SignalSentPacket_w(const rtc::SentPacket& sent_packet);
   bool IsReadyToSendMedia_n() const;
-  void CacheRtpAbsSendTimeHeaderExtension_n(int rtp_abs_sendtime_extn_id);
-  // Wraps the existing RtpTransport in an SrtpTransport.
-  void EnableSdes_n();
-
-  // Wraps the existing RtpTransport in a new SrtpTransport and wraps that in a
-  // new DtlsSrtpTransport.
-  void EnableDtlsSrtp_n();
-
-  // Update the encrypted header extension IDs when setting the local/remote
-  // description and use them later together with other crypto parameters from
-  // DtlsTransport. If DTLS-SRTP is enabled, it also update the encrypted header
-  // extension IDs for DtlsSrtpTransport.
-  void UpdateEncryptedHeaderExtensionIds(cricket::ContentSource source,
-                                         const std::vector<int>& extension_ids);
-
-  // Permanently enable RTCP muxing. Set null RTCP PacketTransport for
-  // BaseChannel and RtpTransport. If using DTLS-SRTP, set null DtlsTransport
-  // for DtlsSrtpTransport.
-  void ActivateRtcpMux();
-
   rtc::Thread* const worker_thread_;
   rtc::Thread* const network_thread_;
   rtc::Thread* const signaling_thread_;
@@ -396,16 +314,8 @@
   // Won't be set when using raw packet transports. SDP-specific thing.
   std::string transport_name_;
 
-  const bool rtcp_mux_required_;
-
   rtc::scoped_refptr<webrtc::MetricsObserverInterface> metrics_observer_;
 
-  // Separate DTLS/non-DTLS pointers to support using BaseChannel without DTLS.
-  // Temporary measure until more refactoring is done.
-  // If non-null, "X_dtls_transport_" will always equal "X_packet_transport_".
-  DtlsTransportInternal* rtp_dtls_transport_ = nullptr;
-  DtlsTransportInternal* rtcp_dtls_transport_ = nullptr;
-
   webrtc::RtpTransportInternal* rtp_transport_ = nullptr;
   // Only one of these transports is non-null at a time. One for DTLS-SRTP, one
   // for SDES and one for unencrypted RTP.
@@ -415,12 +325,11 @@
 
   std::vector<std::pair<rtc::Socket::Option, int> > socket_options_;
   std::vector<std::pair<rtc::Socket::Option, int> > rtcp_socket_options_;
-  SrtpFilter sdes_negotiator_;
-  RtcpMuxFilter rtcp_mux_filter_;
   bool writable_ = false;
   bool was_ever_writable_ = false;
   bool has_received_packet_ = false;
   const bool srtp_required_ = true;
+  rtc::CryptoOptions crypto_options_;
 
   // MediaChannel related members that should be accessed from the worker
   // thread.
@@ -439,6 +348,11 @@
   // The cached encrypted header extension IDs.
   rtc::Optional<std::vector<int>> cached_send_extension_ids_;
   rtc::Optional<std::vector<int>> cached_recv_extension_ids_;
+
+  // TODO(zhihuang): These two variables can be removed once switching to
+  // RtpDemuxer.
+  BundleFilter bundle_filter_;
+  bool encryption_disabled_ = false;
 };
 
 // VoiceChannel is a specialization that adds support for early media, DTMF,
@@ -451,8 +365,8 @@
                MediaEngineInterface* media_engine,
                std::unique_ptr<VoiceMediaChannel> channel,
                const std::string& content_name,
-               bool rtcp_mux_required,
-               bool srtp_required);
+               bool srtp_required,
+               rtc::CryptoOptions crypto_options);
   ~VoiceChannel();
 
   // downcasts a MediaChannel
@@ -491,8 +405,8 @@
                rtc::Thread* signaling_thread,
                std::unique_ptr<VideoMediaChannel> media_channel,
                const std::string& content_name,
-               bool rtcp_mux_required,
-               bool srtp_required);
+               bool srtp_required,
+               rtc::CryptoOptions crypto_options);
   ~VideoChannel();
 
   // downcasts a MediaChannel
@@ -530,8 +444,8 @@
                  rtc::Thread* signaling_thread,
                  std::unique_ptr<DataMediaChannel> channel,
                  const std::string& content_name,
-                 bool rtcp_mux_required,
-                 bool srtp_required);
+                 bool srtp_required,
+                 rtc::CryptoOptions crypto_options);
   ~RtpDataChannel();
   // TODO(zhihuang): Remove this once the RtpTransport can be shared between
   // BaseChannels.
diff --git a/pc/channel_unittest.cc b/pc/channel_unittest.cc
index 7ee3501..c398f07 100644
--- a/pc/channel_unittest.cc
+++ b/pc/channel_unittest.cc
@@ -91,15 +91,11 @@
  public:
   enum Flags {
     RTCP_MUX = 0x1,
-    RTCP_MUX_REQUIRED = 0x2,
-    SECURE = 0x4,
     SSRC_MUX = 0x8,
     DTLS = 0x10,
     // Use BaseChannel with PacketTransportInternal rather than
     // DtlsTransportInternal.
     RAW_PACKET_TRANSPORT = 0x20,
-    GCM_CIPHER = 0x40,
-    ENCRYPTED_HEADERS = 0x80,
   };
 
   ChannelTest(bool verify_playout,
@@ -135,9 +131,7 @@
     if (network_thread_keeper_) {
       network_thread_keeper_->Start();
     }
-    // Make sure RTCP_MUX_REQUIRED isn't set without RTCP_MUX.
-    RTC_DCHECK_NE(RTCP_MUX_REQUIRED, flags1 & (RTCP_MUX | RTCP_MUX_REQUIRED));
-    RTC_DCHECK_NE(RTCP_MUX_REQUIRED, flags2 & (RTCP_MUX | RTCP_MUX_REQUIRED));
+
     // Make sure if using raw packet transports, they're used for both
     // channels.
     RTC_DCHECK_EQ(flags1 & RAW_PACKET_TRANSPORT, flags2 & RAW_PACKET_TRANSPORT);
@@ -153,7 +147,7 @@
       fake_rtp_packet_transport1_.reset(
           new rtc::FakePacketTransport("channel1_rtp"));
       rtp1 = fake_rtp_packet_transport1_.get();
-      if (!(flags1 & RTCP_MUX_REQUIRED)) {
+      if (!(flags1 & RTCP_MUX)) {
         fake_rtcp_packet_transport1_.reset(
             new rtc::FakePacketTransport("channel1_rtcp"));
         rtcp1 = fake_rtcp_packet_transport1_.get();
@@ -163,7 +157,7 @@
       fake_rtp_dtls_transport1_.reset(new cricket::FakeDtlsTransport(
           "channel1", cricket::ICE_CANDIDATE_COMPONENT_RTP));
       rtp1 = fake_rtp_dtls_transport1_.get();
-      if (!(flags1 & RTCP_MUX_REQUIRED)) {
+      if (!(flags1 & RTCP_MUX)) {
         fake_rtcp_dtls_transport1_.reset(new cricket::FakeDtlsTransport(
             "channel1", cricket::ICE_CANDIDATE_COMPONENT_RTCP));
         rtcp1 = fake_rtcp_dtls_transport1_.get();
@@ -177,29 +171,13 @@
           fake_rtcp_dtls_transport1_->SetLocalCertificate(cert1);
         }
       }
-      if (flags1 & ENCRYPTED_HEADERS) {
-        rtc::CryptoOptions crypto_options;
-        crypto_options.enable_encrypted_rtp_header_extensions = true;
-        fake_rtp_dtls_transport1_->SetCryptoOptions(crypto_options);
-        if (fake_rtcp_dtls_transport1_) {
-          fake_rtcp_dtls_transport1_->SetCryptoOptions(crypto_options);
-        }
-      }
-      if (flags1 & GCM_CIPHER) {
-        fake_rtp_dtls_transport1_->SetSrtpCryptoSuite(
-            rtc::SRTP_AEAD_AES_256_GCM);
-        if (fake_rtcp_dtls_transport1_) {
-          fake_rtcp_dtls_transport1_->SetSrtpCryptoSuite(
-              rtc::SRTP_AEAD_AES_256_GCM);
-        }
-      }
     }
     // Based on flags, create fake DTLS or raw packet transports.
     if (flags2 & RAW_PACKET_TRANSPORT) {
       fake_rtp_packet_transport2_.reset(
           new rtc::FakePacketTransport("channel2_rtp"));
       rtp2 = fake_rtp_packet_transport2_.get();
-      if (!(flags2 & RTCP_MUX_REQUIRED)) {
+      if (!(flags2 & RTCP_MUX)) {
         fake_rtcp_packet_transport2_.reset(
             new rtc::FakePacketTransport("channel2_rtcp"));
         rtcp2 = fake_rtcp_packet_transport2_.get();
@@ -209,7 +187,7 @@
       fake_rtp_dtls_transport2_.reset(new cricket::FakeDtlsTransport(
           "channel2", cricket::ICE_CANDIDATE_COMPONENT_RTP));
       rtp2 = fake_rtp_dtls_transport2_.get();
-      if (!(flags2 & RTCP_MUX_REQUIRED)) {
+      if (!(flags2 & RTCP_MUX)) {
         fake_rtcp_dtls_transport2_.reset(new cricket::FakeDtlsTransport(
             "channel2", cricket::ICE_CANDIDATE_COMPONENT_RTCP));
         rtcp2 = fake_rtcp_dtls_transport2_.get();
@@ -223,39 +201,24 @@
           fake_rtcp_dtls_transport2_->SetLocalCertificate(cert2);
         }
       }
-      if (flags2 & ENCRYPTED_HEADERS) {
-        rtc::CryptoOptions crypto_options;
-        crypto_options.enable_encrypted_rtp_header_extensions = true;
-        fake_rtp_dtls_transport2_->SetCryptoOptions(crypto_options);
-        if (fake_rtcp_dtls_transport2_) {
-          fake_rtcp_dtls_transport2_->SetCryptoOptions(crypto_options);
-        }
-      }
-      if (flags2 & GCM_CIPHER) {
-        fake_rtp_dtls_transport2_->SetSrtpCryptoSuite(
-            rtc::SRTP_AEAD_AES_256_GCM);
-        if (fake_rtcp_dtls_transport2_) {
-          fake_rtcp_dtls_transport2_->SetSrtpCryptoSuite(
-              rtc::SRTP_AEAD_AES_256_GCM);
-        }
-      }
     }
-    channel1_ =
-        CreateChannel(worker_thread, network_thread_, &media_engine_,
-                      std::move(ch1), fake_rtp_dtls_transport1_.get(),
-                      fake_rtcp_dtls_transport1_.get(), rtp1, rtcp1, flags1);
-    channel2_ =
-        CreateChannel(worker_thread, network_thread_, &media_engine_,
-                      std::move(ch2), fake_rtp_dtls_transport2_.get(),
-                      fake_rtcp_dtls_transport2_.get(), rtp2, rtcp2, flags2);
+    rtp_transport1_ = CreateRtpTransportBasedOnFlags(
+        fake_rtp_packet_transport1_.get(), fake_rtcp_packet_transport1_.get(),
+        fake_rtp_dtls_transport1_.get(), fake_rtcp_dtls_transport1_.get(),
+        flags1);
+    rtp_transport2_ = CreateRtpTransportBasedOnFlags(
+        fake_rtp_packet_transport2_.get(), fake_rtcp_packet_transport2_.get(),
+        fake_rtp_dtls_transport2_.get(), fake_rtcp_dtls_transport2_.get(),
+        flags2);
+
+    channel1_ = CreateChannel(worker_thread, network_thread_, &media_engine_,
+                              std::move(ch1), rtp_transport1_.get(), flags1);
+    channel2_ = CreateChannel(worker_thread, network_thread_, &media_engine_,
+                              std::move(ch2), rtp_transport2_.get(), flags2);
     channel1_->SignalRtcpMuxFullyActive.connect(
         this, &ChannelTest<T>::OnRtcpMuxFullyActive1);
     channel2_->SignalRtcpMuxFullyActive.connect(
         this, &ChannelTest<T>::OnRtcpMuxFullyActive2);
-    if ((flags1 & DTLS) && (flags2 & DTLS)) {
-      flags1 = (flags1 & ~SECURE);
-      flags2 = (flags2 & ~SECURE);
-    }
     CreateContent(flags1, kPcmuCodec, kH264Codec,
                   &local_media_content1_);
     CreateContent(flags2, kPcmuCodec, kH264Codec,
@@ -276,30 +239,81 @@
     if (flags2 & SSRC_MUX) {
       AddLegacyStreamInContent(kSsrc2, flags2, &remote_media_content2_);
     }
+
+    if (!(flags1 & DTLS)) {
+      channel1_->DisableEncryption(true);
+    }
+    if (!(flags2 & DTLS)) {
+      channel2_->DisableEncryption(true);
+    }
   }
   std::unique_ptr<typename T::Channel> CreateChannel(
       rtc::Thread* worker_thread,
       rtc::Thread* network_thread,
       cricket::MediaEngineInterface* engine,
       std::unique_ptr<typename T::MediaChannel> ch,
-      cricket::DtlsTransportInternal* fake_rtp_dtls_transport,
-      cricket::DtlsTransportInternal* fake_rtcp_dtls_transport,
-      rtc::PacketTransportInternal* fake_rtp_packet_transport,
-      rtc::PacketTransportInternal* fake_rtcp_packet_transport,
+      webrtc::RtpTransportInternal* rtp_transport,
       int flags) {
     rtc::Thread* signaling_thread = rtc::Thread::Current();
     auto channel = rtc::MakeUnique<typename T::Channel>(
         worker_thread, network_thread, signaling_thread, engine, std::move(ch),
-        cricket::CN_AUDIO, (flags & RTCP_MUX_REQUIRED) != 0,
-        (flags & SECURE) != 0);
-    if (!channel->NeedsRtcpTransport()) {
-      fake_rtcp_dtls_transport = nullptr;
-    }
-    channel->Init_w(fake_rtp_dtls_transport, fake_rtcp_dtls_transport,
-                    fake_rtp_packet_transport, fake_rtcp_packet_transport);
+        cricket::CN_AUDIO, (flags & DTLS) != 0, rtc::CryptoOptions());
+    channel->Init_w(rtp_transport);
     return channel;
   }
 
+  std::unique_ptr<webrtc::RtpTransportInternal> CreateRtpTransportBasedOnFlags(
+      rtc::PacketTransportInternal* rtp_packet_transport,
+      rtc::PacketTransportInternal* rtcp_packet_transport,
+      DtlsTransportInternal* rtp_dtls_transport,
+      DtlsTransportInternal* rtcp_dtls_transport,
+      int flags) {
+    if (flags & RTCP_MUX) {
+      rtcp_packet_transport = nullptr;
+      rtcp_dtls_transport = nullptr;
+    }
+
+    if (flags & DTLS) {
+      return CreateDtlsSrtpTransport(rtp_dtls_transport, rtcp_dtls_transport);
+    } else {
+      if (flags & RAW_PACKET_TRANSPORT) {
+        return CreateUnencryptedTransport(rtp_packet_transport,
+                                          rtcp_packet_transport);
+      } else {
+        return CreateUnencryptedTransport(rtp_dtls_transport,
+                                          rtcp_dtls_transport);
+      }
+    }
+  }
+
+  std::unique_ptr<webrtc::RtpTransport> CreateUnencryptedTransport(
+      rtc::PacketTransportInternal* rtp_packet_transport,
+      rtc::PacketTransportInternal* rtcp_packet_transport) {
+    bool rtcp_mux_enabled = (rtcp_packet_transport == nullptr);
+    auto rtp_transport =
+        rtc::MakeUnique<webrtc::RtpTransport>(rtcp_mux_enabled);
+
+    rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
+    if (rtcp_packet_transport) {
+      rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
+    }
+    return rtp_transport;
+  }
+
+  std::unique_ptr<webrtc::DtlsSrtpTransport> CreateDtlsSrtpTransport(
+      cricket::DtlsTransportInternal* rtp_dtls_transport,
+      cricket::DtlsTransportInternal* rtcp_dtls_transport) {
+    bool rtcp_mux_enabled = (rtcp_dtls_transport == nullptr);
+    auto srtp_transport =
+        rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_mux_enabled);
+    auto dtls_srtp_transport =
+        rtc::MakeUnique<webrtc::DtlsSrtpTransport>(std::move(srtp_transport));
+
+    dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
+                                           rtcp_dtls_transport);
+    return dtls_srtp_transport;
+  }
+
   void ConnectFakeTransports() {
     network_thread_->Invoke<void>(RTC_FROM_HERE, [this] {
       bool asymmetric = false;
@@ -507,7 +521,7 @@
   // kPcmuCodec is used as audio codec and kH264Codec is used as video codec.
   typename T::Content* CreateMediaContentWithStream(uint32_t ssrc) {
     typename T::Content* content = new typename T::Content();
-    CreateContent(SECURE, kPcmuCodec, kH264Codec, content);
+    CreateContent(0, kPcmuCodec, kH264Codec, content);
     AddLegacyStreamInContent(ssrc, 0, content);
     return content;
   }
@@ -693,7 +707,7 @@
 
     // Let channel 2 update the content by sending |stream2| and enable SRTP.
     typename T::Content content3;
-    CreateContent(SECURE, kPcmuCodec, kH264Codec, &content3);
+    CreateContent(0, kPcmuCodec, kH264Codec, &content3);
     content3.AddStream(stream2);
     EXPECT_TRUE(channel2_->SetLocalContent(&content3, SdpType::kOffer, NULL));
     ASSERT_EQ(1u, media_channel2_->send_streams().size());
@@ -705,197 +719,18 @@
 
     // Channel 1 replies but stop sending stream1.
     typename T::Content content4;
-    CreateContent(SECURE, kPcmuCodec, kH264Codec, &content4);
+    CreateContent(0, kPcmuCodec, kH264Codec, &content4);
     EXPECT_TRUE(channel1_->SetLocalContent(&content4, SdpType::kAnswer, NULL));
     EXPECT_EQ(0u, media_channel1_->send_streams().size());
 
     EXPECT_TRUE(channel2_->SetRemoteContent(&content4, SdpType::kAnswer, NULL));
     EXPECT_EQ(0u, media_channel2_->recv_streams().size());
 
-    EXPECT_TRUE(channel1_->srtp_active());
-    EXPECT_TRUE(channel2_->srtp_active());
     SendCustomRtp2(kSsrc2, 0);
     WaitForThreads();
     EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0));
   }
 
-  enum EncryptedHeaderTestScenario {
-    // Offer/Answer are processed before DTLS completes.
-    DEFAULT,
-    // DTLS completes before any Offer/Answer have been sent.
-    DTLS_BEFORE_OFFER_ANSWER,
-    // DTLS completes after channel 2 has processed (remote) Offer and (local)
-    // Answer.
-    DTLS_AFTER_CHANNEL2_READY,
-  };
-
-  // Test that encrypted header extensions are working and can be changed when
-  // sending a new OFFER/ANSWER.
-  void TestChangeEncryptedHeaderExtensions(int flags,
-      EncryptedHeaderTestScenario scenario = DEFAULT) {
-    RTC_CHECK(scenario == 0 || (flags & DTLS));
-    struct PacketListener : public sigslot::has_slots<> {
-      PacketListener() {}
-      void OnReadPacket(rtc::PacketTransportInternal* transport,
-          const char* data, size_t size, const rtc::PacketTime& time,
-          int flags) {
-        CompareHeaderExtensions(
-            reinterpret_cast<const char*>(kPcmuFrameWithExtensions),
-            sizeof(kPcmuFrameWithExtensions), data, size, encrypted_headers,
-            false);
-      }
-      std::vector<int> encrypted_headers;
-    } packet_listener1, packet_listener2;
-
-    cricket::StreamParams stream1;
-    stream1.groupid = "group1";
-    stream1.id = "stream1";
-    stream1.ssrcs.push_back(kSsrc1);
-    stream1.cname = "stream1_cname";
-
-    cricket::StreamParams stream2;
-    stream2.groupid = "group1";
-    stream2.id = "stream2";
-    stream2.ssrcs.push_back(kSsrc2);
-    stream2.cname = "stream2_cname";
-
-    // Use SRTP when testing encrypted extensions.
-    int channel_flags = flags | SECURE | ENCRYPTED_HEADERS;
-    // Enable SDES if channel is not using DTLS.
-    int content_flags = (channel_flags & DTLS) == 0 ? SECURE : 0;
-
-    // kPcmuFrameWithExtensions contains RTP extension headers with ids 1-4.
-    // Make sure to use URIs that are supported for encryption.
-    cricket::RtpHeaderExtensions extensions1;
-    extensions1.push_back(
-        RtpExtension(RtpExtension::kAudioLevelUri, 10));
-    extensions1.push_back(
-        RtpExtension(RtpExtension::kAudioLevelUri, 1, true));
-
-    cricket::RtpHeaderExtensions extensions2;
-    extensions2.push_back(
-        RtpExtension(RtpExtension::kAudioLevelUri, 10));
-    extensions2.push_back(
-        RtpExtension(RtpExtension::kAudioLevelUri, 2, true));
-    extensions2.push_back(
-        RtpExtension(RtpExtension::kVideoRotationUri, 3));
-    extensions2.push_back(
-        RtpExtension(RtpExtension::kTimestampOffsetUri, 4, true));
-
-    // Setup a call where channel 1 send |stream1| to channel 2.
-    CreateChannels(channel_flags, channel_flags);
-    fake_rtp_dtls_transport1_->fake_ice_transport()->SignalReadPacket.connect(
-        &packet_listener1, &PacketListener::OnReadPacket);
-    fake_rtp_dtls_transport2_->fake_ice_transport()->SignalReadPacket.connect(
-        &packet_listener2, &PacketListener::OnReadPacket);
-
-    if (scenario == DTLS_BEFORE_OFFER_ANSWER) {
-      ConnectFakeTransports();
-      WaitForThreads();
-    }
-
-    typename T::Content content1;
-    CreateContent(content_flags, kPcmuCodec, kH264Codec, &content1);
-    content1.AddStream(stream1);
-    content1.set_rtp_header_extensions(extensions1);
-    EXPECT_TRUE(channel1_->SetLocalContent(&content1, SdpType::kOffer, NULL));
-    EXPECT_TRUE(channel1_->Enable(true));
-    EXPECT_EQ(1u, media_channel1_->send_streams().size());
-    packet_listener1.encrypted_headers.push_back(1);
-
-    EXPECT_TRUE(channel2_->SetRemoteContent(&content1, SdpType::kOffer, NULL));
-    EXPECT_EQ(1u, media_channel2_->recv_streams().size());
-
-    // Channel 2 sends back |stream2|.
-    typename T::Content content2;
-    CreateContent(content_flags, kPcmuCodec, kH264Codec, &content2);
-    content2.AddStream(stream2);
-    content2.set_rtp_header_extensions(extensions1);
-    EXPECT_TRUE(channel2_->SetLocalContent(&content2, SdpType::kAnswer, NULL));
-    EXPECT_TRUE(channel2_->Enable(true));
-    EXPECT_EQ(1u, media_channel2_->send_streams().size());
-    packet_listener2.encrypted_headers.push_back(1);
-
-    if (scenario == DTLS_AFTER_CHANNEL2_READY) {
-      ConnectFakeTransports();
-      WaitForThreads();
-    }
-
-    if (scenario == DTLS_BEFORE_OFFER_ANSWER ||
-        scenario == DTLS_AFTER_CHANNEL2_READY) {
-      // In both scenarios with partially completed Offer/Answer, sending
-      // packets from Channel 2 to Channel 1 should work.
-      SendCustomRtp2(kSsrc2, 0);
-      WaitForThreads();
-      EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0));
-    }
-
-    EXPECT_TRUE(channel1_->SetRemoteContent(&content2, SdpType::kAnswer, NULL));
-    EXPECT_EQ(1u, media_channel1_->recv_streams().size());
-
-    if (scenario == DEFAULT) {
-      ConnectFakeTransports();
-      WaitForThreads();
-    }
-
-    SendCustomRtp1(kSsrc1, 0);
-    SendCustomRtp2(kSsrc2, 0);
-    WaitForThreads();
-    EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0));
-    EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0));
-
-    // Let channel 2 update the encrypted header extensions.
-    typename T::Content content3;
-    CreateContent(content_flags, kPcmuCodec, kH264Codec, &content3);
-    content3.AddStream(stream2);
-    content3.set_rtp_header_extensions(extensions2);
-    EXPECT_TRUE(channel2_->SetLocalContent(&content3, SdpType::kOffer, NULL));
-    ASSERT_EQ(1u, media_channel2_->send_streams().size());
-    EXPECT_EQ(stream2, media_channel2_->send_streams()[0]);
-    packet_listener2.encrypted_headers.clear();
-    packet_listener2.encrypted_headers.push_back(2);
-    packet_listener2.encrypted_headers.push_back(4);
-
-    EXPECT_TRUE(channel1_->SetRemoteContent(&content3, SdpType::kOffer, NULL));
-    ASSERT_EQ(1u, media_channel1_->recv_streams().size());
-    EXPECT_EQ(stream2, media_channel1_->recv_streams()[0]);
-
-    // Channel 1 is already sending the new encrypted extensions. These
-    // can be decrypted by channel 2. Channel 2 is still sending the old
-    // encrypted extensions (which can be decrypted by channel 1).
-
-    if (flags & DTLS) {
-      // DTLS supports updating the encrypted extensions with only the OFFER
-      // being processed. For SDES both the OFFER and ANSWER must have been
-      // processed to update encrypted extensions, so we can't check this case.
-      SendCustomRtp1(kSsrc1, 0);
-      SendCustomRtp2(kSsrc2, 0);
-      WaitForThreads();
-      EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0));
-      EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0));
-    }
-
-    // Channel 1 replies with the same extensions.
-    typename T::Content content4;
-    CreateContent(content_flags, kPcmuCodec, kH264Codec, &content4);
-    content4.AddStream(stream1);
-    content4.set_rtp_header_extensions(extensions2);
-    EXPECT_TRUE(channel1_->SetLocalContent(&content4, SdpType::kAnswer, NULL));
-    EXPECT_EQ(1u, media_channel1_->send_streams().size());
-    packet_listener1.encrypted_headers.clear();
-    packet_listener1.encrypted_headers.push_back(2);
-    packet_listener1.encrypted_headers.push_back(4);
-
-    EXPECT_TRUE(channel2_->SetRemoteContent(&content4, SdpType::kAnswer, NULL));
-    EXPECT_EQ(1u, media_channel2_->recv_streams().size());
-
-    SendCustomRtp1(kSsrc1, 0);
-    SendCustomRtp2(kSsrc2, 0);
-    WaitForThreads();
-    EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0));
-    EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0));
-  }
-
   // Test that we only start playout and sending at the right times.
   void TestPlayoutAndSendingStates() {
     CreateChannels(0, 0);
@@ -1122,11 +957,11 @@
 
   // Send voice RTP data to the other side and ensure it gets there.
   void SendRtpToRtp() {
-    CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX | RTCP_MUX_REQUIRED);
+    CreateChannels(RTCP_MUX, RTCP_MUX);
     EXPECT_TRUE(SendInitiate());
     EXPECT_TRUE(SendAccept());
-    EXPECT_FALSE(channel1_->NeedsRtcpTransport());
-    EXPECT_FALSE(channel2_->NeedsRtcpTransport());
+    EXPECT_EQ(nullptr, channel1_->rtcp_packet_transport());
+    EXPECT_EQ(nullptr, channel2_->rtcp_packet_transport());
     SendRtp1();
     SendRtp2();
     WaitForThreads();
@@ -1154,8 +989,8 @@
     CreateChannels(0, 0);
     EXPECT_TRUE(SendInitiate());
     EXPECT_TRUE(SendAccept());
-    EXPECT_TRUE(channel1_->NeedsRtcpTransport());
-    EXPECT_TRUE(channel2_->NeedsRtcpTransport());
+    EXPECT_NE(nullptr, channel1_->rtcp_packet_transport());
+    EXPECT_NE(nullptr, channel2_->rtcp_packet_transport());
     SendRtcp1();
     SendRtcp2();
     WaitForThreads();
@@ -1165,205 +1000,8 @@
     EXPECT_TRUE(CheckNoRtcp2());
   }
 
-  // Check that RTCP is transmitted if only the initiator supports mux.
-  void SendRtcpMuxToRtcp() {
-    CreateChannels(RTCP_MUX, 0);
-    EXPECT_TRUE(SendInitiate());
-    EXPECT_TRUE(SendAccept());
-    EXPECT_TRUE(channel1_->NeedsRtcpTransport());
-    EXPECT_TRUE(channel2_->NeedsRtcpTransport());
-    SendRtcp1();
-    SendRtcp2();
-    WaitForThreads();
-    EXPECT_TRUE(CheckRtcp1());
-    EXPECT_TRUE(CheckRtcp2());
-    EXPECT_TRUE(CheckNoRtcp1());
-    EXPECT_TRUE(CheckNoRtcp2());
-  }
-
-  // Check that RTP and RTCP are transmitted ok when both sides support mux.
-  void SendRtcpMuxToRtcpMux() {
-    CreateChannels(RTCP_MUX, RTCP_MUX);
-    EXPECT_TRUE(SendInitiate());
-    EXPECT_TRUE(channel1_->NeedsRtcpTransport());
-    EXPECT_FALSE(channel2_->NeedsRtcpTransport());
-    EXPECT_EQ(0, rtcp_mux_activated_callbacks1_);
-    EXPECT_TRUE(SendAccept());
-    EXPECT_FALSE(channel1_->NeedsRtcpTransport());
-    EXPECT_EQ(1, rtcp_mux_activated_callbacks1_);
-    SendRtp1();
-    SendRtp2();
-    SendRtcp1();
-    SendRtcp2();
-    WaitForThreads();
-    EXPECT_TRUE(CheckRtp1());
-    EXPECT_TRUE(CheckRtp2());
-    EXPECT_TRUE(CheckNoRtp1());
-    EXPECT_TRUE(CheckNoRtp2());
-    EXPECT_TRUE(CheckRtcp1());
-    EXPECT_TRUE(CheckRtcp2());
-    EXPECT_TRUE(CheckNoRtcp1());
-    EXPECT_TRUE(CheckNoRtcp2());
-  }
-
-  // Check that RTP and RTCP are transmitted ok when both sides
-  // support mux and one the offerer requires mux.
-  void SendRequireRtcpMuxToRtcpMux() {
-    CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX);
-    EXPECT_TRUE(SendInitiate());
-    EXPECT_FALSE(channel1_->NeedsRtcpTransport());
-    EXPECT_FALSE(channel2_->NeedsRtcpTransport());
-    EXPECT_TRUE(SendAccept());
-    SendRtp1();
-    SendRtp2();
-    SendRtcp1();
-    SendRtcp2();
-    WaitForThreads();
-    EXPECT_TRUE(CheckRtp1());
-    EXPECT_TRUE(CheckRtp2());
-    EXPECT_TRUE(CheckNoRtp1());
-    EXPECT_TRUE(CheckNoRtp2());
-    EXPECT_TRUE(CheckRtcp1());
-    EXPECT_TRUE(CheckRtcp2());
-    EXPECT_TRUE(CheckNoRtcp1());
-    EXPECT_TRUE(CheckNoRtcp2());
-  }
-
-  // Check that RTP and RTCP are transmitted ok when both sides
-  // support mux and only the answerer requires rtcp mux.
-  void SendRtcpMuxToRequireRtcpMux() {
-    CreateChannels(RTCP_MUX, RTCP_MUX | RTCP_MUX_REQUIRED);
-    EXPECT_TRUE(SendInitiate());
-    EXPECT_TRUE(channel1_->NeedsRtcpTransport());
-    EXPECT_FALSE(channel2_->NeedsRtcpTransport());
-    EXPECT_EQ(0, rtcp_mux_activated_callbacks1_);
-    EXPECT_TRUE(SendAccept());
-    EXPECT_FALSE(channel1_->NeedsRtcpTransport());
-    EXPECT_EQ(1, rtcp_mux_activated_callbacks1_);
-    SendRtp1();
-    SendRtp2();
-    SendRtcp1();
-    SendRtcp2();
-    WaitForThreads();
-    EXPECT_TRUE(CheckRtp1());
-    EXPECT_TRUE(CheckRtp2());
-    EXPECT_TRUE(CheckNoRtp1());
-    EXPECT_TRUE(CheckNoRtp2());
-    EXPECT_TRUE(CheckRtcp1());
-    EXPECT_TRUE(CheckRtcp2());
-    EXPECT_TRUE(CheckNoRtcp1());
-    EXPECT_TRUE(CheckNoRtcp2());
-  }
-
-  // Check that RTP and RTCP are transmitted ok when both sides
-  // require mux.
-  void SendRequireRtcpMuxToRequireRtcpMux() {
-    CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX | RTCP_MUX_REQUIRED);
-    EXPECT_TRUE(SendInitiate());
-    EXPECT_FALSE(channel1_->NeedsRtcpTransport());
-    EXPECT_FALSE(channel2_->NeedsRtcpTransport());
-    EXPECT_TRUE(SendAccept());
-    EXPECT_FALSE(channel1_->NeedsRtcpTransport());
-    SendRtp1();
-    SendRtp2();
-    SendRtcp1();
-    SendRtcp2();
-    WaitForThreads();
-    EXPECT_TRUE(CheckRtp1());
-    EXPECT_TRUE(CheckRtp2());
-    EXPECT_TRUE(CheckNoRtp1());
-    EXPECT_TRUE(CheckNoRtp2());
-    EXPECT_TRUE(CheckRtcp1());
-    EXPECT_TRUE(CheckRtcp2());
-    EXPECT_TRUE(CheckNoRtcp1());
-    EXPECT_TRUE(CheckNoRtcp2());
-  }
-
-  // Check that SendAccept fails if the answerer doesn't support mux
-  // and the offerer requires it.
-  void SendRequireRtcpMuxToNoRtcpMux() {
-    CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, 0);
-    EXPECT_TRUE(SendInitiate());
-    EXPECT_FALSE(channel1_->NeedsRtcpTransport());
-    EXPECT_TRUE(channel2_->NeedsRtcpTransport());
-    EXPECT_FALSE(SendAccept());
-  }
-
-  // Check that RTCP data sent by the initiator before the accept is not muxed.
-  void SendEarlyRtcpMuxToRtcp() {
-    CreateChannels(RTCP_MUX, 0);
-    EXPECT_TRUE(SendInitiate());
-    EXPECT_TRUE(channel1_->NeedsRtcpTransport());
-    EXPECT_TRUE(channel2_->NeedsRtcpTransport());
-
-    // RTCP can be sent before the call is accepted, if the transport is ready.
-    // It should not be muxed though, as the remote side doesn't support mux.
-    SendRtcp1();
-    WaitForThreads();
-    EXPECT_TRUE(CheckNoRtp2());
-    EXPECT_TRUE(CheckRtcp2());
-
-    // Send RTCP packet from callee and verify that it is received.
-    SendRtcp2();
-    WaitForThreads();
-    EXPECT_TRUE(CheckNoRtp1());
-    EXPECT_TRUE(CheckRtcp1());
-
-    // Complete call setup and ensure everything is still OK.
-    EXPECT_TRUE(SendAccept());
-    EXPECT_TRUE(channel1_->NeedsRtcpTransport());
-    SendRtcp1();
-    SendRtcp2();
-    WaitForThreads();
-    EXPECT_TRUE(CheckRtcp2());
-    EXPECT_TRUE(CheckRtcp1());
-  }
-
-
-  // Check that RTCP data is not muxed until both sides have enabled muxing,
-  // but that we properly demux before we get the accept message, since there
-  // is a race between RTP data and the jingle accept.
-  void SendEarlyRtcpMuxToRtcpMux() {
-    CreateChannels(RTCP_MUX, RTCP_MUX);
-    EXPECT_TRUE(SendInitiate());
-    EXPECT_TRUE(channel1_->NeedsRtcpTransport());
-    EXPECT_FALSE(channel2_->NeedsRtcpTransport());
-
-    // RTCP can't be sent yet, since the RTCP transport isn't writable, and
-    // we haven't yet received the accept that says we should mux.
-    SendRtcp1();
-    WaitForThreads();
-    EXPECT_TRUE(CheckNoRtcp2());
-
-    // Send muxed RTCP packet from callee and verify that it is received.
-    SendRtcp2();
-    WaitForThreads();
-    EXPECT_TRUE(CheckNoRtp1());
-    EXPECT_TRUE(CheckRtcp1());
-
-    // Complete call setup and ensure everything is still OK.
-    EXPECT_EQ(0, rtcp_mux_activated_callbacks1_);
-    EXPECT_TRUE(SendAccept());
-    EXPECT_FALSE(channel1_->NeedsRtcpTransport());
-    EXPECT_EQ(1, rtcp_mux_activated_callbacks1_);
-    SendRtcp1();
-    SendRtcp2();
-    WaitForThreads();
-    EXPECT_TRUE(CheckRtcp2());
-    EXPECT_TRUE(CheckRtcp1());
-  }
-
-  // Test that we properly send SRTP with RTCP in both directions.
-  // You can pass in DTLS, RTCP_MUX, and RAW_PACKET_TRANSPORT as flags.
-  void SendSrtpToSrtp(int flags1_in = 0, int flags2_in = 0) {
-    RTC_CHECK((flags1_in & ~(RTCP_MUX | DTLS | RAW_PACKET_TRANSPORT)) == 0);
-    RTC_CHECK((flags2_in & ~(RTCP_MUX | DTLS | RAW_PACKET_TRANSPORT)) == 0);
-
-    int flags1 = SECURE | flags1_in;
-    int flags2 = SECURE | flags2_in;
-    bool dtls1 = !!(flags1_in & DTLS);
-    bool dtls2 = !!(flags2_in & DTLS);
-    CreateChannels(flags1, flags2);
+  void SendDtlsSrtpToDtlsSrtp(int flags1, int flags2) {
+    CreateChannels(flags1 | DTLS, flags2 | DTLS);
     EXPECT_FALSE(channel1_->srtp_active());
     EXPECT_FALSE(channel2_->srtp_active());
     EXPECT_TRUE(SendInitiate());
@@ -1373,43 +1011,6 @@
     EXPECT_TRUE(SendAccept());
     EXPECT_TRUE(channel1_->srtp_active());
     EXPECT_TRUE(channel2_->srtp_active());
-    EXPECT_EQ(dtls1 && dtls2, channel1_->dtls_active());
-    EXPECT_EQ(dtls1 && dtls2, channel2_->dtls_active());
-    SendRtp1();
-    SendRtp2();
-    SendRtcp1();
-    SendRtcp2();
-    WaitForThreads();
-    EXPECT_TRUE(CheckRtp1());
-    EXPECT_TRUE(CheckRtp2());
-    EXPECT_TRUE(CheckNoRtp1());
-    EXPECT_TRUE(CheckNoRtp2());
-    EXPECT_TRUE(CheckRtcp1());
-    EXPECT_TRUE(CheckRtcp2());
-    EXPECT_TRUE(CheckNoRtcp1());
-    EXPECT_TRUE(CheckNoRtcp2());
-  }
-
-  // Test that the DTLS to SDES fallback is not supported and the negotiation
-  // between DTLS to SDES end points will fail.
-  void SendDtlsToSdesNotSupported() {
-    int flags1 = SECURE | DTLS;
-    int flags2 = SECURE;
-    CreateChannels(flags1, flags2);
-    EXPECT_FALSE(channel1_->srtp_active());
-    EXPECT_FALSE(channel2_->srtp_active());
-    EXPECT_FALSE(SendInitiate());
-  }
-
-  // Test that we properly handling SRTP negotiating down to RTP.
-  void SendSrtpToRtp() {
-    CreateChannels(SECURE, 0);
-    EXPECT_FALSE(channel1_->srtp_active());
-    EXPECT_FALSE(channel2_->srtp_active());
-    EXPECT_TRUE(SendInitiate());
-    EXPECT_TRUE(SendAccept());
-    EXPECT_FALSE(channel1_->srtp_active());
-    EXPECT_FALSE(channel2_->srtp_active());
     SendRtp1();
     SendRtp2();
     SendRtcp1();
@@ -1430,14 +1031,13 @@
   void SendEarlyMediaUsingRtcpMuxSrtp() {
       int sequence_number1_1 = 0, sequence_number2_2 = 0;
 
-      CreateChannels(SSRC_MUX | RTCP_MUX | SECURE,
-                     SSRC_MUX | RTCP_MUX | SECURE);
+      CreateChannels(SSRC_MUX | RTCP_MUX | DTLS, SSRC_MUX | RTCP_MUX | DTLS);
       EXPECT_TRUE(SendOffer());
       EXPECT_TRUE(SendProvisionalAnswer());
       EXPECT_TRUE(channel1_->srtp_active());
       EXPECT_TRUE(channel2_->srtp_active());
-      EXPECT_TRUE(channel1_->NeedsRtcpTransport());
-      EXPECT_TRUE(channel2_->NeedsRtcpTransport());
+      EXPECT_EQ(nullptr, channel1_->rtcp_packet_transport());
+      EXPECT_EQ(nullptr, channel2_->rtcp_packet_transport());
       WaitForThreads();  // Wait for 'sending' flag go through network thread.
       SendCustomRtcp1(kSsrc1);
       SendCustomRtp1(kSsrc1, ++sequence_number1_1);
@@ -1453,13 +1053,7 @@
       EXPECT_TRUE(CheckCustomRtp1(kSsrc2, sequence_number2_2));
 
       // Complete call setup and ensure everything is still OK.
-      EXPECT_EQ(0, rtcp_mux_activated_callbacks1_);
-      EXPECT_EQ(0, rtcp_mux_activated_callbacks2_);
       EXPECT_TRUE(SendFinalAnswer());
-      EXPECT_FALSE(channel1_->NeedsRtcpTransport());
-      EXPECT_FALSE(channel2_->NeedsRtcpTransport());
-      EXPECT_EQ(1, rtcp_mux_activated_callbacks1_);
-      EXPECT_EQ(1, rtcp_mux_activated_callbacks2_);
       EXPECT_TRUE(channel1_->srtp_active());
       EXPECT_TRUE(channel2_->srtp_active());
       SendCustomRtcp1(kSsrc1);
@@ -1496,37 +1090,14 @@
     EXPECT_TRUE(CheckNoRtcp2());
   }
 
-  // Test that we properly send SRTP with RTCP from a thread.
-  void SendSrtpToSrtpOnThread() {
-    CreateChannels(SECURE, SECURE);
-    EXPECT_TRUE(SendInitiate());
-    EXPECT_TRUE(SendAccept());
-    ScopedCallThread send_rtp1([this] { SendRtp1(); });
-    ScopedCallThread send_rtp2([this] { SendRtp2(); });
-    ScopedCallThread send_rtcp1([this] { SendRtcp1(); });
-    ScopedCallThread send_rtcp2([this] { SendRtcp2(); });
-    rtc::Thread* involved_threads[] = {send_rtp1.thread(), send_rtp2.thread(),
-                                       send_rtcp1.thread(),
-                                       send_rtcp2.thread()};
-    WaitForThreads(involved_threads);
-    EXPECT_TRUE(CheckRtp1());
-    EXPECT_TRUE(CheckRtp2());
-    EXPECT_TRUE(CheckNoRtp1());
-    EXPECT_TRUE(CheckNoRtp2());
-    EXPECT_TRUE(CheckRtcp1());
-    EXPECT_TRUE(CheckRtcp2());
-    EXPECT_TRUE(CheckNoRtcp1());
-    EXPECT_TRUE(CheckNoRtcp2());
-  }
-
   // Test that the mediachannel retains its sending state after the transport
   // becomes non-writable.
   void SendWithWritabilityLoss() {
-    CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX | RTCP_MUX_REQUIRED);
+    CreateChannels(RTCP_MUX, RTCP_MUX);
     EXPECT_TRUE(SendInitiate());
     EXPECT_TRUE(SendAccept());
-    EXPECT_FALSE(channel1_->NeedsRtcpTransport());
-    EXPECT_FALSE(channel2_->NeedsRtcpTransport());
+    EXPECT_EQ(nullptr, channel1_->rtcp_packet_transport());
+    EXPECT_EQ(nullptr, channel2_->rtcp_packet_transport());
     SendRtp1();
     SendRtp2();
     WaitForThreads();
@@ -1598,17 +1169,14 @@
     int pl_type1 = pl_types[0];
     int pl_type2 = pl_types[1];
     int flags = SSRC_MUX;
-    if (secure) flags |= SECURE;
+    if (secure)
+      flags |= DTLS;
     if (rtcp_mux) {
       flags |= RTCP_MUX;
     }
     CreateChannels(flags, flags);
     EXPECT_TRUE(SendInitiate());
-    EXPECT_TRUE(channel1_->NeedsRtcpTransport());
-    EXPECT_EQ(rtcp_mux, !channel2_->NeedsRtcpTransport());
     EXPECT_TRUE(SendAccept());
-    EXPECT_EQ(rtcp_mux, !channel1_->NeedsRtcpTransport());
-    EXPECT_EQ(rtcp_mux, !channel2_->NeedsRtcpTransport());
     EXPECT_TRUE(channel1_->HandlesPayloadType(pl_type1));
     EXPECT_TRUE(channel2_->HandlesPayloadType(pl_type1));
     EXPECT_FALSE(channel1_->HandlesPayloadType(pl_type2));
@@ -1623,13 +1191,13 @@
     EXPECT_TRUE(CheckNoRtp1());
     EXPECT_TRUE(CheckNoRtp2());
 
-    // RTCP test
     SendCustomRtp1(kSsrc1, ++sequence_number1_1, pl_type2);
     SendCustomRtp2(kSsrc2, ++sequence_number2_2, pl_type2);
     WaitForThreads();
     EXPECT_FALSE(CheckCustomRtp2(kSsrc1, sequence_number1_1, pl_type2));
     EXPECT_FALSE(CheckCustomRtp1(kSsrc2, sequence_number2_2, pl_type2));
 
+    // RTCP test
     SendCustomRtcp1(kSsrc1);
     SendCustomRtcp2(kSsrc2);
     WaitForThreads();
@@ -1766,8 +1334,8 @@
     CreateChannels(0, 0);
     EXPECT_TRUE(SendInitiate());
     EXPECT_TRUE(SendAccept());
-    EXPECT_TRUE(channel1_->NeedsRtcpTransport());
-    EXPECT_TRUE(channel2_->NeedsRtcpTransport());
+    EXPECT_NE(nullptr, channel1_->rtcp_packet_transport());
+    EXPECT_NE(nullptr, channel2_->rtcp_packet_transport());
 
     // Send RTCP1 from a different thread.
     ScopedCallThread send_rtcp([this] { SendRtcp1(); });
@@ -1796,33 +1364,6 @@
     EXPECT_FALSE(media_channel1_->ready_to_send());
   }
 
-  void TestOnTransportReadyToSendWithRtcpMux() {
-    CreateChannels(0, 0);
-    typename T::Content content;
-    CreateContent(0, kPcmuCodec, kH264Codec, &content);
-    // Both sides agree on mux. Should signal that RTCP mux is fully active.
-    content.set_rtcp_mux(true);
-    EXPECT_TRUE(channel1_->SetLocalContent(&content, SdpType::kOffer, NULL));
-    EXPECT_EQ(0, rtcp_mux_activated_callbacks1_);
-    EXPECT_TRUE(channel1_->SetRemoteContent(&content, SdpType::kAnswer, NULL));
-    EXPECT_EQ(1, rtcp_mux_activated_callbacks1_);
-    cricket::FakeDtlsTransport* rtp = fake_rtp_dtls_transport1_.get();
-    EXPECT_FALSE(media_channel1_->ready_to_send());
-    // In the case of rtcp mux, the SignalReadyToSend() from rtp channel
-    // should trigger the MediaChannel's OnReadyToSend.
-    network_thread_->Invoke<void>(RTC_FROM_HERE,
-                                  [rtp] { rtp->SignalReadyToSend(rtp); });
-    WaitForThreads();
-    EXPECT_TRUE(media_channel1_->ready_to_send());
-
-    // TODO(zstein): Find a way to test this without making
-    // OnTransportReadyToSend public.
-    network_thread_->Invoke<void>(
-        RTC_FROM_HERE, [this] { channel1_->OnTransportReadyToSend(false); });
-    WaitForThreads();
-    EXPECT_FALSE(media_channel1_->ready_to_send());
-  }
-
   bool SetRemoteContentWithBitrateLimit(int remote_limit) {
     typename T::Content content;
     CreateContent(0, kPcmuCodec, kH264Codec, &content);
@@ -1853,9 +1394,10 @@
                      rtc::nullopt);
   }
 
-  // Test that when a channel gets new transports with a call to
-  // |SetTransports|, the socket options from the old transports are merged with
-  // the options on the new transport.
+  // Test that when a channel gets new RtpTransport with a call to
+  // |SetRtpTransport|, the socket options from the old RtpTransport is merged
+  // with the options on the new one.
+
   // For example, audio and video may use separate socket options, but initially
   // be unbundled, then later become bundled. When this happens, their preferred
   // socket options should be merged to the underlying transport they share.
@@ -1863,22 +1405,27 @@
     constexpr int kSndBufSize = 4000;
     constexpr int kRcvBufSize = 8000;
 
-    CreateChannels(0, 0);
+    CreateChannels(DTLS, DTLS);
 
     channel1_->SetOption(cricket::BaseChannel::ST_RTP,
                          rtc::Socket::Option::OPT_SNDBUF, kSndBufSize);
     channel2_->SetOption(cricket::BaseChannel::ST_RTP,
                          rtc::Socket::Option::OPT_RCVBUF, kRcvBufSize);
 
-    channel1_->SetTransports(channel2_->rtp_dtls_transport(),
-                             channel2_->rtcp_dtls_transport());
+    new_rtp_transport_ = CreateDtlsSrtpTransport(
+        static_cast<DtlsTransportInternal*>(channel2_->rtp_packet_transport()),
+        static_cast<DtlsTransportInternal*>(
+            channel2_->rtcp_packet_transport()));
+    channel1_->SetRtpTransport(new_rtp_transport_.get());
 
     int option_val;
-    ASSERT_TRUE(channel1_->rtp_dtls_transport()->GetOption(
-        rtc::Socket::Option::OPT_SNDBUF, &option_val));
+    ASSERT_TRUE(
+        static_cast<DtlsTransportInternal*>(channel1_->rtp_packet_transport())
+            ->GetOption(rtc::Socket::Option::OPT_SNDBUF, &option_val));
     EXPECT_EQ(kSndBufSize, option_val);
-    ASSERT_TRUE(channel1_->rtp_dtls_transport()->GetOption(
-        rtc::Socket::Option::OPT_RCVBUF, &option_val));
+    ASSERT_TRUE(
+        static_cast<DtlsTransportInternal*>(channel1_->rtp_packet_transport())
+            ->GetOption(rtc::Socket::Option::OPT_RCVBUF, &option_val));
     EXPECT_EQ(kRcvBufSize, option_val);
   }
 
@@ -1918,6 +1465,9 @@
   std::unique_ptr<rtc::FakePacketTransport> fake_rtcp_packet_transport1_;
   std::unique_ptr<rtc::FakePacketTransport> fake_rtp_packet_transport2_;
   std::unique_ptr<rtc::FakePacketTransport> fake_rtcp_packet_transport2_;
+  std::unique_ptr<webrtc::RtpTransportInternal> rtp_transport1_;
+  std::unique_ptr<webrtc::RtpTransportInternal> rtp_transport2_;
+  std::unique_ptr<webrtc::RtpTransportInternal> new_rtp_transport_;
   cricket::FakeMediaEngine media_engine_;
   // The media channels are owned by the voice channel objects below.
   typename T::MediaChannel* media_channel1_ = nullptr;
@@ -1944,11 +1494,6 @@
     cricket::AudioContentDescription* audio) {
   audio->AddCodec(audio_codec);
   audio->set_rtcp_mux((flags & RTCP_MUX) != 0);
-  if ((flags & SECURE) && !(flags & DTLS)) {
-    audio->AddCrypto(cricket::CryptoParams(
-        1, rtc::CS_AES_CM_128_HMAC_SHA1_32,
-        "inline:" + rtc::CreateRandomString(40), std::string()));
-  }
 }
 
 template<>
@@ -2012,21 +1557,13 @@
     rtc::Thread* network_thread,
     cricket::MediaEngineInterface* engine,
     std::unique_ptr<cricket::FakeVideoMediaChannel> ch,
-    cricket::DtlsTransportInternal* fake_rtp_dtls_transport,
-    cricket::DtlsTransportInternal* fake_rtcp_dtls_transport,
-    rtc::PacketTransportInternal* fake_rtp_packet_transport,
-    rtc::PacketTransportInternal* fake_rtcp_packet_transport,
+    webrtc::RtpTransportInternal* rtp_transport,
     int flags) {
   rtc::Thread* signaling_thread = rtc::Thread::Current();
   auto channel = rtc::MakeUnique<cricket::VideoChannel>(
       worker_thread, network_thread, signaling_thread, std::move(ch),
-      cricket::CN_VIDEO, (flags & RTCP_MUX_REQUIRED) != 0,
-      (flags & SECURE) != 0);
-  if (!channel->NeedsRtcpTransport()) {
-    fake_rtcp_dtls_transport = nullptr;
-  }
-  channel->Init_w(fake_rtp_dtls_transport, fake_rtcp_dtls_transport,
-                  fake_rtp_packet_transport, fake_rtcp_packet_transport);
+      cricket::CN_VIDEO, (flags & DTLS) != 0, rtc::CryptoOptions());
+  channel->Init_w(rtp_transport);
   return channel;
 }
 
@@ -2044,11 +1581,6 @@
     cricket::VideoContentDescription* video) {
   video->AddCodec(video_codec);
   video->set_rtcp_mux((flags & RTCP_MUX) != 0);
-  if (flags & SECURE) {
-    video->AddCrypto(cricket::CryptoParams(
-        1, rtc::CS_AES_CM_128_HMAC_SHA1_80,
-        "inline:" + rtc::CreateRandomString(40), std::string()));
-  }
 }
 
 template<>
@@ -2120,48 +1652,6 @@
   Base::TestChangeStreamParamsInContent();
 }
 
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtls) {
-  int flags = DTLS;
-  Base::TestChangeEncryptedHeaderExtensions(flags);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtlsScenario1) {
-  int flags = DTLS;
-  Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtlsScenario2) {
-  int flags = DTLS;
-  Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtlsGcm) {
-  int flags = DTLS | GCM_CIPHER;
-  Base::TestChangeEncryptedHeaderExtensions(flags);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtlsGcmScenario1) {
-  int flags = DTLS | GCM_CIPHER;
-  Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtlsGcmScenario2) {
-  int flags = DTLS | GCM_CIPHER;
-  Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest,
-    TestChangeEncryptedHeaderExtensionsSDES) {
-  int flags = 0;
-  Base::TestChangeEncryptedHeaderExtensions(flags);
-}
-
 TEST_F(VoiceChannelSingleThreadTest, TestPlayoutAndSendingStates) {
   Base::TestPlayoutAndSendingStates();
 }
@@ -2190,66 +1680,12 @@
   Base::SendRtcpToRtcp();
 }
 
-TEST_F(VoiceChannelSingleThreadTest, SendRtcpMuxToRtcp) {
-  Base::SendRtcpMuxToRtcp();
-}
-
-TEST_F(VoiceChannelSingleThreadTest, SendRtcpMuxToRtcpMux) {
-  Base::SendRtcpMuxToRtcpMux();
-}
-
-TEST_F(VoiceChannelSingleThreadTest, SendRequireRtcpMuxToRtcpMux) {
-  Base::SendRequireRtcpMuxToRtcpMux();
-}
-
-TEST_F(VoiceChannelSingleThreadTest, SendRtcpMuxToRequireRtcpMux) {
-  Base::SendRtcpMuxToRequireRtcpMux();
-}
-
-TEST_F(VoiceChannelSingleThreadTest, SendRequireRtcpMuxToRequireRtcpMux) {
-  Base::SendRequireRtcpMuxToRequireRtcpMux();
-}
-
-TEST_F(VoiceChannelSingleThreadTest, SendRequireRtcpMuxToNoRtcpMux) {
-  Base::SendRequireRtcpMuxToNoRtcpMux();
-}
-
-TEST_F(VoiceChannelSingleThreadTest, SendEarlyRtcpMuxToRtcp) {
-  Base::SendEarlyRtcpMuxToRtcp();
-}
-
-TEST_F(VoiceChannelSingleThreadTest, SendEarlyRtcpMuxToRtcpMux) {
-  Base::SendEarlyRtcpMuxToRtcpMux();
-}
-
-TEST_F(VoiceChannelSingleThreadTest, SendSrtpToSrtpRtcpMux) {
-  Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX);
-}
-
-TEST_F(VoiceChannelSingleThreadTest, SendSrtpToRtp) {
-  Base::SendSrtpToSrtp();
-}
-
-TEST_F(VoiceChannelSingleThreadTest, SendSrtcpMux) {
-  Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX);
-}
-
-TEST_F(VoiceChannelSingleThreadTest, SendDtlsSrtpToSrtp) {
-  Base::SendDtlsToSdesNotSupported();
-}
-
 TEST_F(VoiceChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtp) {
-  Base::SendSrtpToSrtp(DTLS, DTLS);
+  Base::SendDtlsSrtpToDtlsSrtp(0, 0);
 }
 
 TEST_F(VoiceChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtpRtcpMux) {
-  Base::SendSrtpToSrtp(DTLS | RTCP_MUX, DTLS | RTCP_MUX);
-}
-
-// Test using the channel with a raw packet interface, as opposed to a DTLS
-// transport interface.
-TEST_F(VoiceChannelSingleThreadTest, SendSrtpToSrtpWithRawPacketTransport) {
-  Base::SendSrtpToSrtp(RAW_PACKET_TRANSPORT, RAW_PACKET_TRANSPORT);
+  Base::SendDtlsSrtpToDtlsSrtp(RTCP_MUX, RTCP_MUX);
 }
 
 TEST_F(VoiceChannelSingleThreadTest, SendEarlyMediaUsingRtcpMuxSrtp) {
@@ -2260,9 +1696,6 @@
   Base::SendRtpToRtpOnThread();
 }
 
-TEST_F(VoiceChannelSingleThreadTest, SendSrtpToSrtpOnThread) {
-  Base::SendSrtpToSrtpOnThread();
-}
 
 TEST_F(VoiceChannelSingleThreadTest, SendWithWritabilityLoss) {
   Base::SendWithWritabilityLoss();
@@ -2296,10 +1729,6 @@
   Base::TestOnTransportReadyToSend();
 }
 
-TEST_F(VoiceChannelSingleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
-  Base::TestOnTransportReadyToSendWithRtcpMux();
-}
-
 TEST_F(VoiceChannelSingleThreadTest, SendBundleToBundle) {
   Base::SendBundleToBundle(kAudioPts, arraysize(kAudioPts), false, false);
 }
@@ -2359,48 +1788,6 @@
   Base::TestChangeStreamParamsInContent();
 }
 
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtls) {
-  int flags = DTLS;
-  Base::TestChangeEncryptedHeaderExtensions(flags);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtlsScenario1) {
-  int flags = DTLS;
-  Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtlsScenario2) {
-  int flags = DTLS;
-  Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtlsGcm) {
-  int flags = DTLS | GCM_CIPHER;
-  Base::TestChangeEncryptedHeaderExtensions(flags);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtlsGcmScenario1) {
-  int flags = DTLS | GCM_CIPHER;
-  Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
-    TestChangeEncryptedHeaderExtensionsDtlsGcmScenario2) {
-  int flags = DTLS | GCM_CIPHER;
-  Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY);
-}
-
-TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest,
-    TestChangeEncryptedHeaderExtensionsSDES) {
-  int flags = 0;
-  Base::TestChangeEncryptedHeaderExtensions(flags);
-}
-
 TEST_F(VoiceChannelDoubleThreadTest, TestPlayoutAndSendingStates) {
   Base::TestPlayoutAndSendingStates();
 }
@@ -2429,66 +1816,12 @@
   Base::SendRtcpToRtcp();
 }
 
-TEST_F(VoiceChannelDoubleThreadTest, SendRtcpMuxToRtcp) {
-  Base::SendRtcpMuxToRtcp();
-}
-
-TEST_F(VoiceChannelDoubleThreadTest, SendRtcpMuxToRtcpMux) {
-  Base::SendRtcpMuxToRtcpMux();
-}
-
-TEST_F(VoiceChannelDoubleThreadTest, SendRequireRtcpMuxToRtcpMux) {
-  Base::SendRequireRtcpMuxToRtcpMux();
-}
-
-TEST_F(VoiceChannelDoubleThreadTest, SendRtcpMuxToRequireRtcpMux) {
-  Base::SendRtcpMuxToRequireRtcpMux();
-}
-
-TEST_F(VoiceChannelDoubleThreadTest, SendRequireRtcpMuxToRequireRtcpMux) {
-  Base::SendRequireRtcpMuxToRequireRtcpMux();
-}
-
-TEST_F(VoiceChannelDoubleThreadTest, SendRequireRtcpMuxToNoRtcpMux) {
-  Base::SendRequireRtcpMuxToNoRtcpMux();
-}
-
-TEST_F(VoiceChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcp) {
-  Base::SendEarlyRtcpMuxToRtcp();
-}
-
-TEST_F(VoiceChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcpMux) {
-  Base::SendEarlyRtcpMuxToRtcpMux();
-}
-
-TEST_F(VoiceChannelDoubleThreadTest, SendSrtpToSrtpRtcpMux) {
-  Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX);
-}
-
-TEST_F(VoiceChannelDoubleThreadTest, SendSrtpToRtp) {
-  Base::SendSrtpToSrtp();
-}
-
-TEST_F(VoiceChannelDoubleThreadTest, SendSrtcpMux) {
-  Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX);
-}
-
-TEST_F(VoiceChannelDoubleThreadTest, SendDtlsSrtpToSrtp) {
-  Base::SendDtlsToSdesNotSupported();
-}
-
 TEST_F(VoiceChannelDoubleThreadTest, SendDtlsSrtpToDtlsSrtp) {
-  Base::SendSrtpToSrtp(DTLS, DTLS);
+  Base::SendDtlsSrtpToDtlsSrtp(0, 0);
 }
 
 TEST_F(VoiceChannelDoubleThreadTest, SendDtlsSrtpToDtlsSrtpRtcpMux) {
-  Base::SendSrtpToSrtp(DTLS | RTCP_MUX, DTLS | RTCP_MUX);
-}
-
-// Test using the channel with a raw packet interface, as opposed to a DTLS
-// transport interface.
-TEST_F(VoiceChannelDoubleThreadTest, SendSrtpToSrtpWithRawPacketTransport) {
-  Base::SendSrtpToSrtp(RAW_PACKET_TRANSPORT, RAW_PACKET_TRANSPORT);
+  Base::SendDtlsSrtpToDtlsSrtp(RTCP_MUX, RTCP_MUX);
 }
 
 TEST_F(VoiceChannelDoubleThreadTest, SendEarlyMediaUsingRtcpMuxSrtp) {
@@ -2499,10 +1832,6 @@
   Base::SendRtpToRtpOnThread();
 }
 
-TEST_F(VoiceChannelDoubleThreadTest, SendSrtpToSrtpOnThread) {
-  Base::SendSrtpToSrtpOnThread();
-}
-
 TEST_F(VoiceChannelDoubleThreadTest, SendWithWritabilityLoss) {
   Base::SendWithWritabilityLoss();
 }
@@ -2535,10 +1864,6 @@
   Base::TestOnTransportReadyToSend();
 }
 
-TEST_F(VoiceChannelDoubleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
-  Base::TestOnTransportReadyToSendWithRtcpMux();
-}
-
 TEST_F(VoiceChannelDoubleThreadTest, SendBundleToBundle) {
   Base::SendBundleToBundle(kAudioPts, arraysize(kAudioPts), false, false);
 }
@@ -2624,66 +1949,12 @@
   Base::SendRtcpToRtcp();
 }
 
-TEST_F(VideoChannelSingleThreadTest, SendRtcpMuxToRtcp) {
-  Base::SendRtcpMuxToRtcp();
-}
-
-TEST_F(VideoChannelSingleThreadTest, SendRtcpMuxToRtcpMux) {
-  Base::SendRtcpMuxToRtcpMux();
-}
-
-TEST_F(VideoChannelSingleThreadTest, SendRequireRtcpMuxToRtcpMux) {
-  Base::SendRequireRtcpMuxToRtcpMux();
-}
-
-TEST_F(VideoChannelSingleThreadTest, SendRtcpMuxToRequireRtcpMux) {
-  Base::SendRtcpMuxToRequireRtcpMux();
-}
-
-TEST_F(VideoChannelSingleThreadTest, SendRequireRtcpMuxToRequireRtcpMux) {
-  Base::SendRequireRtcpMuxToRequireRtcpMux();
-}
-
-TEST_F(VideoChannelSingleThreadTest, SendRequireRtcpMuxToNoRtcpMux) {
-  Base::SendRequireRtcpMuxToNoRtcpMux();
-}
-
-TEST_F(VideoChannelSingleThreadTest, SendEarlyRtcpMuxToRtcp) {
-  Base::SendEarlyRtcpMuxToRtcp();
-}
-
-TEST_F(VideoChannelSingleThreadTest, SendEarlyRtcpMuxToRtcpMux) {
-  Base::SendEarlyRtcpMuxToRtcpMux();
-}
-
-TEST_F(VideoChannelSingleThreadTest, SendSrtpToSrtp) {
-  Base::SendSrtpToSrtp();
-}
-
-TEST_F(VideoChannelSingleThreadTest, SendSrtpToRtp) {
-  Base::SendSrtpToSrtp();
-}
-
-TEST_F(VideoChannelSingleThreadTest, SendDtlsSrtpToSrtp) {
-  Base::SendDtlsToSdesNotSupported();
-}
-
 TEST_F(VideoChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtp) {
-  Base::SendSrtpToSrtp(DTLS, DTLS);
+  Base::SendDtlsSrtpToDtlsSrtp(0, 0);
 }
 
 TEST_F(VideoChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtpRtcpMux) {
-  Base::SendSrtpToSrtp(DTLS | RTCP_MUX, DTLS | RTCP_MUX);
-}
-
-// Test using the channel with a raw packet interface, as opposed to a DTLS
-// transport interface.
-TEST_F(VideoChannelSingleThreadTest, SendSrtpToSrtpWithRawPacketTransport) {
-  Base::SendSrtpToSrtp(RAW_PACKET_TRANSPORT, RAW_PACKET_TRANSPORT);
-}
-
-TEST_F(VideoChannelSingleThreadTest, SendSrtcpMux) {
-  Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX);
+  Base::SendDtlsSrtpToDtlsSrtp(RTCP_MUX, RTCP_MUX);
 }
 
 TEST_F(VideoChannelSingleThreadTest, SendEarlyMediaUsingRtcpMuxSrtp) {
@@ -2694,10 +1965,6 @@
   Base::SendRtpToRtpOnThread();
 }
 
-TEST_F(VideoChannelSingleThreadTest, SendSrtpToSrtpOnThread) {
-  Base::SendSrtpToSrtpOnThread();
-}
-
 TEST_F(VideoChannelSingleThreadTest, SendWithWritabilityLoss) {
   Base::SendWithWritabilityLoss();
 }
@@ -2746,10 +2013,6 @@
   Base::TestOnTransportReadyToSend();
 }
 
-TEST_F(VideoChannelSingleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
-  Base::TestOnTransportReadyToSendWithRtcpMux();
-}
-
 TEST_F(VideoChannelSingleThreadTest, DefaultMaxBitrateIsUnlimited) {
   Base::DefaultMaxBitrateIsUnlimited();
 }
@@ -2819,66 +2082,12 @@
   Base::SendRtcpToRtcp();
 }
 
-TEST_F(VideoChannelDoubleThreadTest, SendRtcpMuxToRtcp) {
-  Base::SendRtcpMuxToRtcp();
-}
-
-TEST_F(VideoChannelDoubleThreadTest, SendRtcpMuxToRtcpMux) {
-  Base::SendRtcpMuxToRtcpMux();
-}
-
-TEST_F(VideoChannelDoubleThreadTest, SendRequireRtcpMuxToRtcpMux) {
-  Base::SendRequireRtcpMuxToRtcpMux();
-}
-
-TEST_F(VideoChannelDoubleThreadTest, SendRtcpMuxToRequireRtcpMux) {
-  Base::SendRtcpMuxToRequireRtcpMux();
-}
-
-TEST_F(VideoChannelDoubleThreadTest, SendRequireRtcpMuxToRequireRtcpMux) {
-  Base::SendRequireRtcpMuxToRequireRtcpMux();
-}
-
-TEST_F(VideoChannelDoubleThreadTest, SendRequireRtcpMuxToNoRtcpMux) {
-  Base::SendRequireRtcpMuxToNoRtcpMux();
-}
-
-TEST_F(VideoChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcp) {
-  Base::SendEarlyRtcpMuxToRtcp();
-}
-
-TEST_F(VideoChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcpMux) {
-  Base::SendEarlyRtcpMuxToRtcpMux();
-}
-
-TEST_F(VideoChannelDoubleThreadTest, SendSrtpToSrtp) {
-  Base::SendSrtpToSrtp();
-}
-
-TEST_F(VideoChannelDoubleThreadTest, SendSrtpToRtp) {
-  Base::SendSrtpToSrtp();
-}
-
-TEST_F(VideoChannelDoubleThreadTest, SendDtlsSrtpToSrtp) {
-  Base::SendDtlsToSdesNotSupported();
-}
-
 TEST_F(VideoChannelDoubleThreadTest, SendDtlsSrtpToDtlsSrtp) {
-  Base::SendSrtpToSrtp(DTLS, DTLS);
+  Base::SendDtlsSrtpToDtlsSrtp(0, 0);
 }
 
 TEST_F(VideoChannelDoubleThreadTest, SendDtlsSrtpToDtlsSrtpRtcpMux) {
-  Base::SendSrtpToSrtp(DTLS | RTCP_MUX, DTLS | RTCP_MUX);
-}
-
-// Test using the channel with a raw packet interface, as opposed to a DTLS
-// transport interface.
-TEST_F(VideoChannelDoubleThreadTest, SendSrtpToSrtpWithRawPacketTransport) {
-  Base::SendSrtpToSrtp(RAW_PACKET_TRANSPORT, RAW_PACKET_TRANSPORT);
-}
-
-TEST_F(VideoChannelDoubleThreadTest, SendSrtcpMux) {
-  Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX);
+  Base::SendDtlsSrtpToDtlsSrtp(RTCP_MUX, RTCP_MUX);
 }
 
 TEST_F(VideoChannelDoubleThreadTest, SendEarlyMediaUsingRtcpMuxSrtp) {
@@ -2889,10 +2098,6 @@
   Base::SendRtpToRtpOnThread();
 }
 
-TEST_F(VideoChannelDoubleThreadTest, SendSrtpToSrtpOnThread) {
-  Base::SendSrtpToSrtpOnThread();
-}
-
 TEST_F(VideoChannelDoubleThreadTest, SendWithWritabilityLoss) {
   Base::SendWithWritabilityLoss();
 }
@@ -2941,10 +2146,6 @@
   Base::TestOnTransportReadyToSend();
 }
 
-TEST_F(VideoChannelDoubleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
-  Base::TestOnTransportReadyToSendWithRtcpMux();
-}
-
 TEST_F(VideoChannelDoubleThreadTest, DefaultMaxBitrateIsUnlimited) {
   Base::DefaultMaxBitrateIsUnlimited();
 }
@@ -2976,21 +2177,13 @@
     rtc::Thread* network_thread,
     cricket::MediaEngineInterface* engine,
     std::unique_ptr<cricket::FakeDataMediaChannel> ch,
-    cricket::DtlsTransportInternal* fake_rtp_dtls_transport,
-    cricket::DtlsTransportInternal* fake_rtcp_dtls_transport,
-    rtc::PacketTransportInternal* fake_rtp_packet_transport,
-    rtc::PacketTransportInternal* fake_rtcp_packet_transport,
+    webrtc::RtpTransportInternal* rtp_transport,
     int flags) {
   rtc::Thread* signaling_thread = rtc::Thread::Current();
   auto channel = rtc::MakeUnique<cricket::RtpDataChannel>(
       worker_thread, network_thread, signaling_thread, std::move(ch),
-      cricket::CN_DATA, (flags & RTCP_MUX_REQUIRED) != 0,
-      (flags & SECURE) != 0);
-  if (!channel->NeedsRtcpTransport()) {
-    fake_rtcp_dtls_transport = nullptr;
-  }
-  channel->Init_w(fake_rtp_dtls_transport, fake_rtcp_dtls_transport,
-                  fake_rtp_packet_transport, fake_rtcp_packet_transport);
+      cricket::CN_DATA, (flags & DTLS) != 0, rtc::CryptoOptions());
+  channel->Init_w(rtp_transport);
   return channel;
 }
 
@@ -3002,11 +2195,6 @@
     cricket::DataContentDescription* data) {
   data->AddCodec(kGoogleDataCodec);
   data->set_rtcp_mux((flags & RTCP_MUX) != 0);
-  if (flags & SECURE) {
-    data->AddCrypto(cricket::CryptoParams(
-        1, rtc::CS_AES_CM_128_HMAC_SHA1_32,
-        "inline:" + rtc::CreateRandomString(40), std::string()));
-  }
 }
 
 template <>
@@ -3079,10 +2267,6 @@
   Base::TestOnTransportReadyToSend();
 }
 
-TEST_F(RtpDataChannelSingleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
-  Base::TestOnTransportReadyToSendWithRtcpMux();
-}
-
 TEST_F(RtpDataChannelSingleThreadTest, SendRtpToRtp) {
   Base::SendRtpToRtp();
 }
@@ -3091,42 +2275,10 @@
   Base::SendRtcpToRtcp();
 }
 
-TEST_F(RtpDataChannelSingleThreadTest, SendRtcpMuxToRtcp) {
-  Base::SendRtcpMuxToRtcp();
-}
-
-TEST_F(RtpDataChannelSingleThreadTest, SendRtcpMuxToRtcpMux) {
-  Base::SendRtcpMuxToRtcpMux();
-}
-
-TEST_F(RtpDataChannelSingleThreadTest, SendEarlyRtcpMuxToRtcp) {
-  Base::SendEarlyRtcpMuxToRtcp();
-}
-
-TEST_F(RtpDataChannelSingleThreadTest, SendEarlyRtcpMuxToRtcpMux) {
-  Base::SendEarlyRtcpMuxToRtcpMux();
-}
-
-TEST_F(RtpDataChannelSingleThreadTest, SendSrtpToSrtp) {
-  Base::SendSrtpToSrtp();
-}
-
-TEST_F(RtpDataChannelSingleThreadTest, SendSrtpToRtp) {
-  Base::SendSrtpToSrtp();
-}
-
-TEST_F(RtpDataChannelSingleThreadTest, SendSrtcpMux) {
-  Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX);
-}
-
 TEST_F(RtpDataChannelSingleThreadTest, SendRtpToRtpOnThread) {
   Base::SendRtpToRtpOnThread();
 }
 
-TEST_F(RtpDataChannelSingleThreadTest, SendSrtpToSrtpOnThread) {
-  Base::SendSrtpToSrtpOnThread();
-}
-
 TEST_F(RtpDataChannelSingleThreadTest, SendWithWritabilityLoss) {
   Base::SendWithWritabilityLoss();
 }
@@ -3199,10 +2351,6 @@
   Base::TestOnTransportReadyToSend();
 }
 
-TEST_F(RtpDataChannelDoubleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
-  Base::TestOnTransportReadyToSendWithRtcpMux();
-}
-
 TEST_F(RtpDataChannelDoubleThreadTest, SendRtpToRtp) {
   Base::SendRtpToRtp();
 }
@@ -3211,42 +2359,10 @@
   Base::SendRtcpToRtcp();
 }
 
-TEST_F(RtpDataChannelDoubleThreadTest, SendRtcpMuxToRtcp) {
-  Base::SendRtcpMuxToRtcp();
-}
-
-TEST_F(RtpDataChannelDoubleThreadTest, SendRtcpMuxToRtcpMux) {
-  Base::SendRtcpMuxToRtcpMux();
-}
-
-TEST_F(RtpDataChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcp) {
-  Base::SendEarlyRtcpMuxToRtcp();
-}
-
-TEST_F(RtpDataChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcpMux) {
-  Base::SendEarlyRtcpMuxToRtcpMux();
-}
-
-TEST_F(RtpDataChannelDoubleThreadTest, SendSrtpToSrtp) {
-  Base::SendSrtpToSrtp();
-}
-
-TEST_F(RtpDataChannelDoubleThreadTest, SendSrtpToRtp) {
-  Base::SendSrtpToSrtp();
-}
-
-TEST_F(RtpDataChannelDoubleThreadTest, SendSrtcpMux) {
-  Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX);
-}
-
 TEST_F(RtpDataChannelDoubleThreadTest, SendRtpToRtpOnThread) {
   Base::SendRtpToRtpOnThread();
 }
 
-TEST_F(RtpDataChannelDoubleThreadTest, SendSrtpToSrtpOnThread) {
-  Base::SendSrtpToSrtpOnThread();
-}
-
 TEST_F(RtpDataChannelDoubleThreadTest, SendWithWritabilityLoss) {
   Base::SendWithWritabilityLoss();
 }
@@ -3273,107 +2389,4 @@
   EXPECT_EQ("foo", media_channel1_->last_sent_data());
 }
 
-#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
-
-// Verifies some DCHECKs are in place.
-// Uses VoiceChannel, but any BaseChannel subclass would work.
-class BaseChannelDeathTest : public testing::Test {
- public:
-  BaseChannelDeathTest()
-      : fake_rtp_dtls_transport_("foo", cricket::ICE_CANDIDATE_COMPONENT_RTP),
-        fake_rtcp_dtls_transport_("foo", cricket::ICE_CANDIDATE_COMPONENT_RTCP),
-        // RTCP mux not required, SRTP required.
-        voice_channel_(rtc::Thread::Current(),
-                       rtc::Thread::Current(),
-                       rtc::Thread::Current(),
-                       &fake_media_engine_,
-                       rtc::MakeUnique<cricket::FakeVoiceMediaChannel>(
-                           nullptr,
-                           cricket::AudioOptions()),
-                       cricket::CN_AUDIO,
-                       false,
-                       true) {}
-
- protected:
-  cricket::FakeMediaEngine fake_media_engine_;
-  cricket::FakeDtlsTransport fake_rtp_dtls_transport_;
-  cricket::FakeDtlsTransport fake_rtcp_dtls_transport_;
-  cricket::VoiceChannel voice_channel_;
-};
-
-TEST_F(BaseChannelDeathTest, SetTransportsWithNullRtpTransport) {
-  voice_channel_.Init_w(&fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_,
-                        &fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_);
-  cricket::FakeDtlsTransport new_rtcp_transport(
-      "bar", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-  EXPECT_DEATH(voice_channel_.SetTransports(nullptr, &new_rtcp_transport), "");
-}
-
-TEST_F(BaseChannelDeathTest, SetTransportsWithMissingRtcpTransport) {
-  voice_channel_.Init_w(&fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_,
-                        &fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_);
-  cricket::FakeDtlsTransport new_rtp_transport(
-      "bar", cricket::ICE_CANDIDATE_COMPONENT_RTP);
-  EXPECT_DEATH(voice_channel_.SetTransports(&new_rtp_transport, nullptr), "");
-}
-
-TEST_F(BaseChannelDeathTest, SetTransportsWithUnneededRtcpTransport) {
-  voice_channel_.Init_w(&fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_,
-                        &fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_);
-  // Activate RTCP muxing, simulating offer/answer negotiation.
-  cricket::AudioContentDescription content;
-  content.set_rtcp_mux(true);
-  ASSERT_TRUE(
-      voice_channel_.SetLocalContent(&content, SdpType::kOffer, nullptr));
-  ASSERT_TRUE(
-      voice_channel_.SetRemoteContent(&content, SdpType::kAnswer, nullptr));
-  cricket::FakeDtlsTransport new_rtp_transport(
-      "bar", cricket::ICE_CANDIDATE_COMPONENT_RTP);
-  cricket::FakeDtlsTransport new_rtcp_transport(
-      "bar", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-  // After muxing is enabled, no RTCP transport should be passed in here.
-  EXPECT_DEATH(
-      voice_channel_.SetTransports(&new_rtp_transport, &new_rtcp_transport),
-      "");
-}
-
-// This test will probably go away if/when we move the transport name out of
-// the transport classes and into their parent classes.
-TEST_F(BaseChannelDeathTest, SetTransportsWithMismatchingTransportNames) {
-  voice_channel_.Init_w(&fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_,
-                        &fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_);
-  cricket::FakeDtlsTransport new_rtp_transport(
-      "bar", cricket::ICE_CANDIDATE_COMPONENT_RTP);
-  cricket::FakeDtlsTransport new_rtcp_transport(
-      "baz", cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-  EXPECT_DEATH(
-      voice_channel_.SetTransports(&new_rtp_transport, &new_rtcp_transport),
-      "");
-}
-
-// Not expected to support going from DtlsTransportInternal to
-// PacketTransportInternal.
-TEST_F(BaseChannelDeathTest, SetTransportsDtlsToNonDtls) {
-  voice_channel_.Init_w(&fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_,
-                        &fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_);
-  EXPECT_DEATH(
-      voice_channel_.SetTransports(
-          static_cast<rtc::PacketTransportInternal*>(&fake_rtp_dtls_transport_),
-          static_cast<rtc::PacketTransportInternal*>(
-              &fake_rtp_dtls_transport_)),
-      "");
-}
-
-// Not expected to support going from PacketTransportInternal to
-// DtlsTransportInternal.
-TEST_F(BaseChannelDeathTest, SetTransportsNonDtlsToDtls) {
-  voice_channel_.Init_w(nullptr, nullptr, &fake_rtp_dtls_transport_,
-                        &fake_rtcp_dtls_transport_);
-  EXPECT_DEATH(voice_channel_.SetTransports(&fake_rtp_dtls_transport_,
-                                            &fake_rtp_dtls_transport_),
-               "");
-}
-
-#endif  // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
-
 // TODO(pthatcher): TestSetReceiver?
diff --git a/pc/channelmanager.cc b/pc/channelmanager.cc
index ead1da9..e32f56a 100644
--- a/pc/channelmanager.cc
+++ b/pc/channelmanager.cc
@@ -155,48 +155,17 @@
 VoiceChannel* ChannelManager::CreateVoiceChannel(
     webrtc::Call* call,
     const cricket::MediaConfig& media_config,
-    DtlsTransportInternal* rtp_transport,
-    DtlsTransportInternal* rtcp_transport,
-    rtc::Thread* signaling_thread,
-    const std::string& content_name,
-    bool srtp_required,
-    const AudioOptions& options) {
-  return worker_thread_->Invoke<VoiceChannel*>(RTC_FROM_HERE, [&] {
-    return CreateVoiceChannel_w(
-        call, media_config, rtp_transport, rtcp_transport, rtp_transport,
-        rtcp_transport, signaling_thread, content_name, srtp_required, options);
-  });
-}
-
-VoiceChannel* ChannelManager::CreateVoiceChannel(
-    webrtc::Call* call,
-    const cricket::MediaConfig& media_config,
-    rtc::PacketTransportInternal* rtp_transport,
-    rtc::PacketTransportInternal* rtcp_transport,
-    rtc::Thread* signaling_thread,
-    const std::string& content_name,
-    bool srtp_required,
-    const AudioOptions& options) {
-  return worker_thread_->Invoke<VoiceChannel*>(RTC_FROM_HERE, [&] {
-    return CreateVoiceChannel_w(call, media_config, nullptr, nullptr,
-                                rtp_transport, rtcp_transport, signaling_thread,
-                                content_name, srtp_required, options);
-  });
-}
-
-VoiceChannel* ChannelManager::CreateVoiceChannel(
-    webrtc::Call* call,
-    const cricket::MediaConfig& media_config,
     webrtc::RtpTransportInternal* rtp_transport,
     rtc::Thread* signaling_thread,
     const std::string& content_name,
     bool srtp_required,
+    const rtc::CryptoOptions& crypto_options,
     const AudioOptions& options) {
   if (!worker_thread_->IsCurrent()) {
     return worker_thread_->Invoke<VoiceChannel*>(RTC_FROM_HERE, [&] {
       return CreateVoiceChannel(call, media_config, rtp_transport,
                                 signaling_thread, content_name, srtp_required,
-                                options);
+                                crypto_options, options);
     });
   }
 
@@ -215,8 +184,8 @@
 
   auto voice_channel = rtc::MakeUnique<VoiceChannel>(
       worker_thread_, network_thread_, signaling_thread, media_engine_.get(),
-      rtc::WrapUnique(media_channel), content_name,
-      rtp_transport->rtcp_packet_transport() == nullptr, srtp_required);
+      rtc::WrapUnique(media_channel), content_name, srtp_required,
+      crypto_options);
 
   voice_channel->Init_w(rtp_transport);
 
@@ -225,41 +194,6 @@
   return voice_channel_ptr;
 }
 
-VoiceChannel* ChannelManager::CreateVoiceChannel_w(
-    webrtc::Call* call,
-    const cricket::MediaConfig& media_config,
-    DtlsTransportInternal* rtp_dtls_transport,
-    DtlsTransportInternal* rtcp_dtls_transport,
-    rtc::PacketTransportInternal* rtp_packet_transport,
-    rtc::PacketTransportInternal* rtcp_packet_transport,
-    rtc::Thread* signaling_thread,
-    const std::string& content_name,
-    bool srtp_required,
-    const AudioOptions& options) {
-  RTC_DCHECK_RUN_ON(worker_thread_);
-  RTC_DCHECK(initialized_);
-  RTC_DCHECK(call);
-  if (!media_engine_) {
-    return nullptr;
-  }
-
-  VoiceMediaChannel* media_channel = media_engine_->CreateChannel(
-      call, media_config, options);
-  if (!media_channel) {
-    return nullptr;
-  }
-
-  auto voice_channel = rtc::MakeUnique<VoiceChannel>(
-      worker_thread_, network_thread_, signaling_thread, media_engine_.get(),
-      rtc::WrapUnique(media_channel), content_name,
-      rtcp_packet_transport == nullptr, srtp_required);
-  voice_channel->Init_w(rtp_dtls_transport, rtcp_dtls_transport,
-                        rtp_packet_transport, rtcp_packet_transport);
-
-  VoiceChannel* voice_channel_ptr = voice_channel.get();
-  voice_channels_.push_back(std::move(voice_channel));
-  return voice_channel_ptr;
-}
 
 void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
   TRACE_EVENT0("webrtc", "ChannelManager::DestroyVoiceChannel");
@@ -289,48 +223,17 @@
 VideoChannel* ChannelManager::CreateVideoChannel(
     webrtc::Call* call,
     const cricket::MediaConfig& media_config,
-    DtlsTransportInternal* rtp_transport,
-    DtlsTransportInternal* rtcp_transport,
-    rtc::Thread* signaling_thread,
-    const std::string& content_name,
-    bool srtp_required,
-    const VideoOptions& options) {
-  return worker_thread_->Invoke<VideoChannel*>(RTC_FROM_HERE, [&] {
-    return CreateVideoChannel_w(
-        call, media_config, rtp_transport, rtcp_transport, rtp_transport,
-        rtcp_transport, signaling_thread, content_name, srtp_required, options);
-  });
-}
-
-VideoChannel* ChannelManager::CreateVideoChannel(
-    webrtc::Call* call,
-    const cricket::MediaConfig& media_config,
-    rtc::PacketTransportInternal* rtp_transport,
-    rtc::PacketTransportInternal* rtcp_transport,
-    rtc::Thread* signaling_thread,
-    const std::string& content_name,
-    bool srtp_required,
-    const VideoOptions& options) {
-  return worker_thread_->Invoke<VideoChannel*>(RTC_FROM_HERE, [&] {
-    return CreateVideoChannel_w(call, media_config, nullptr, nullptr,
-                                rtp_transport, rtcp_transport, signaling_thread,
-                                content_name, srtp_required, options);
-  });
-}
-
-VideoChannel* ChannelManager::CreateVideoChannel(
-    webrtc::Call* call,
-    const cricket::MediaConfig& media_config,
     webrtc::RtpTransportInternal* rtp_transport,
     rtc::Thread* signaling_thread,
     const std::string& content_name,
     bool srtp_required,
+    const rtc::CryptoOptions& crypto_options,
     const VideoOptions& options) {
   if (!worker_thread_->IsCurrent()) {
     return worker_thread_->Invoke<VideoChannel*>(RTC_FROM_HERE, [&] {
       return CreateVideoChannel(call, media_config, rtp_transport,
                                 signaling_thread, content_name, srtp_required,
-                                options);
+                                crypto_options, options);
     });
   }
 
@@ -349,8 +252,8 @@
 
   auto video_channel = rtc::MakeUnique<VideoChannel>(
       worker_thread_, network_thread_, signaling_thread,
-      rtc::WrapUnique(media_channel), content_name,
-      rtp_transport->rtcp_packet_transport() == nullptr, srtp_required);
+      rtc::WrapUnique(media_channel), content_name, srtp_required,
+      crypto_options);
   video_channel->Init_w(rtp_transport);
 
   VideoChannel* video_channel_ptr = video_channel.get();
@@ -358,41 +261,7 @@
   return video_channel_ptr;
 }
 
-VideoChannel* ChannelManager::CreateVideoChannel_w(
-    webrtc::Call* call,
-    const cricket::MediaConfig& media_config,
-    DtlsTransportInternal* rtp_dtls_transport,
-    DtlsTransportInternal* rtcp_dtls_transport,
-    rtc::PacketTransportInternal* rtp_packet_transport,
-    rtc::PacketTransportInternal* rtcp_packet_transport,
-    rtc::Thread* signaling_thread,
-    const std::string& content_name,
-    bool srtp_required,
-    const VideoOptions& options) {
-  RTC_DCHECK_RUN_ON(worker_thread_);
-  RTC_DCHECK(initialized_);
-  RTC_DCHECK(call);
-  if (!media_engine_) {
-    return nullptr;
-  }
 
-  VideoMediaChannel* media_channel = media_engine_->CreateVideoChannel(
-      call, media_config, options);
-  if (!media_channel) {
-    return nullptr;
-  }
-
-  auto video_channel = rtc::MakeUnique<VideoChannel>(
-      worker_thread_, network_thread_, signaling_thread,
-      rtc::WrapUnique(media_channel), content_name,
-      rtcp_packet_transport == nullptr, srtp_required);
-  video_channel->Init_w(rtp_dtls_transport, rtcp_dtls_transport,
-                        rtp_packet_transport, rtcp_packet_transport);
-
-  VideoChannel* video_channel_ptr = video_channel.get();
-  video_channels_.push_back(std::move(video_channel));
-  return video_channel_ptr;
-}
 
 void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
   TRACE_EVENT0("webrtc", "ChannelManager::DestroyVideoChannel");
@@ -421,49 +290,15 @@
 
 RtpDataChannel* ChannelManager::CreateRtpDataChannel(
     const cricket::MediaConfig& media_config,
-    DtlsTransportInternal* rtp_transport,
-    DtlsTransportInternal* rtcp_transport,
-    rtc::Thread* signaling_thread,
-    const std::string& content_name,
-    bool srtp_required) {
-  if (!worker_thread_->IsCurrent()) {
-    return worker_thread_->Invoke<RtpDataChannel*>(RTC_FROM_HERE, [&] {
-      return CreateRtpDataChannel(media_config, rtp_transport, rtcp_transport,
-                                  signaling_thread, content_name,
-                                  srtp_required);
-    });
-  }
-
-  // This is ok to alloc from a thread other than the worker thread.
-  RTC_DCHECK(initialized_);
-  DataMediaChannel* media_channel = data_engine_->CreateChannel(media_config);
-  if (!media_channel) {
-    RTC_LOG(LS_WARNING) << "Failed to create RTP data channel.";
-    return nullptr;
-  }
-
-  auto data_channel = rtc::MakeUnique<RtpDataChannel>(
-      worker_thread_, network_thread_, signaling_thread,
-      rtc::WrapUnique(media_channel), content_name, rtcp_transport == nullptr,
-      srtp_required);
-  data_channel->Init_w(rtp_transport, rtcp_transport, rtp_transport,
-                       rtcp_transport);
-
-  RtpDataChannel* data_channel_ptr = data_channel.get();
-  data_channels_.push_back(std::move(data_channel));
-  return data_channel_ptr;
-}
-
-RtpDataChannel* ChannelManager::CreateRtpDataChannel(
-    const cricket::MediaConfig& media_config,
     webrtc::RtpTransportInternal* rtp_transport,
     rtc::Thread* signaling_thread,
     const std::string& content_name,
-    bool srtp_required) {
+    bool srtp_required,
+    const rtc::CryptoOptions& crypto_options) {
   if (!worker_thread_->IsCurrent()) {
     return worker_thread_->Invoke<RtpDataChannel*>(RTC_FROM_HERE, [&] {
       return CreateRtpDataChannel(media_config, rtp_transport, signaling_thread,
-                                  content_name, srtp_required);
+                                  content_name, srtp_required, crypto_options);
     });
   }
 
@@ -477,8 +312,8 @@
 
   auto data_channel = rtc::MakeUnique<RtpDataChannel>(
       worker_thread_, network_thread_, signaling_thread,
-      rtc::WrapUnique(media_channel), content_name,
-      rtp_transport->rtcp_packet_transport() == nullptr, srtp_required);
+      rtc::WrapUnique(media_channel), content_name, srtp_required,
+      crypto_options);
   data_channel->Init_w(rtp_transport);
 
   RtpDataChannel* data_channel_ptr = data_channel.get();
diff --git a/pc/channelmanager.h b/pc/channelmanager.h
index 72d218a..c6b601e 100644
--- a/pc/channelmanager.h
+++ b/pc/channelmanager.h
@@ -80,90 +80,38 @@
   // call the appropriate Destroy*Channel method when done.
 
   // Creates a voice channel, to be associated with the specified session.
-  // TODO(zhihuang): Replace this with the method taking an
-  // RtpTransportInternal*;
-  VoiceChannel* CreateVoiceChannel(
-      webrtc::Call* call,
-      const cricket::MediaConfig& media_config,
-      DtlsTransportInternal* rtp_transport,
-      DtlsTransportInternal* rtcp_transport,
-      rtc::Thread* signaling_thread,
-      const std::string& content_name,
-      bool srtp_required,
-      const AudioOptions& options);
-  // Version of the above that takes PacketTransportInternal.
-  // TODO(zhihuang): Replace this with the method taking an
-  // RtpTransportInternal*;
-  VoiceChannel* CreateVoiceChannel(
-      webrtc::Call* call,
-      const cricket::MediaConfig& media_config,
-      rtc::PacketTransportInternal* rtp_transport,
-      rtc::PacketTransportInternal* rtcp_transport,
-      rtc::Thread* signaling_thread,
-      const std::string& content_name,
-      bool srtp_required,
-      const AudioOptions& options);
-
   VoiceChannel* CreateVoiceChannel(webrtc::Call* call,
                                    const cricket::MediaConfig& media_config,
                                    webrtc::RtpTransportInternal* rtp_transport,
                                    rtc::Thread* signaling_thread,
                                    const std::string& content_name,
                                    bool srtp_required,
+                                   const rtc::CryptoOptions& crypto_options,
                                    const AudioOptions& options);
   // Destroys a voice channel created by CreateVoiceChannel.
   void DestroyVoiceChannel(VoiceChannel* voice_channel);
 
   // Creates a video channel, synced with the specified voice channel, and
   // associated with the specified session.
-  // TODO(zhihuang): Replace this with the method taking an
-  // RtpTransportInternal*;
-  VideoChannel* CreateVideoChannel(
-      webrtc::Call* call,
-      const cricket::MediaConfig& media_config,
-      DtlsTransportInternal* rtp_transport,
-      DtlsTransportInternal* rtcp_transport,
-      rtc::Thread* signaling_thread,
-      const std::string& content_name,
-      bool srtp_required,
-      const VideoOptions& options);
   // Version of the above that takes PacketTransportInternal.
-  // TODO(zhihuang): Replace this with the method taking an
-  // RtpTransportInternal*;
-  VideoChannel* CreateVideoChannel(
-      webrtc::Call* call,
-      const cricket::MediaConfig& media_config,
-      rtc::PacketTransportInternal* rtp_transport,
-      rtc::PacketTransportInternal* rtcp_transport,
-      rtc::Thread* signaling_thread,
-      const std::string& content_name,
-      bool srtp_required,
-      const VideoOptions& options);
   VideoChannel* CreateVideoChannel(webrtc::Call* call,
                                    const cricket::MediaConfig& media_config,
                                    webrtc::RtpTransportInternal* rtp_transport,
                                    rtc::Thread* signaling_thread,
                                    const std::string& content_name,
                                    bool srtp_required,
+                                   const rtc::CryptoOptions& crypto_options,
                                    const VideoOptions& options);
   // Destroys a video channel created by CreateVideoChannel.
   void DestroyVideoChannel(VideoChannel* video_channel);
 
-  // TODO(zhihuang): Replace this with the method taking an
-  // RtpTransportInternal*;
-  RtpDataChannel* CreateRtpDataChannel(
-      const cricket::MediaConfig& media_config,
-      DtlsTransportInternal* rtp_transport,
-      DtlsTransportInternal* rtcp_transport,
-      rtc::Thread* signaling_thread,
-      const std::string& content_name,
-      bool srtp_required);
   RtpDataChannel* CreateRtpDataChannel(
       const cricket::MediaConfig& media_config,
       webrtc::RtpTransportInternal* rtp_transport,
       rtc::Thread* signaling_thread,
       const std::string& content_name,
-      bool srtp_required);
+      bool srtp_required,
+      const rtc::CryptoOptions& crypto_options);
   // Destroys a data channel created by CreateRtpDataChannel.
   void DestroyRtpDataChannel(RtpDataChannel* data_channel);
 
@@ -191,29 +139,6 @@
   void StopAecDump();
 
  private:
-  VoiceChannel* CreateVoiceChannel_w(
-      webrtc::Call* call,
-      const cricket::MediaConfig& media_config,
-      DtlsTransportInternal* rtp_dtls_transport,
-      DtlsTransportInternal* rtcp_dtls_transport,
-      rtc::PacketTransportInternal* rtp_packet_transport,
-      rtc::PacketTransportInternal* rtcp_packet_transport,
-      rtc::Thread* signaling_thread,
-      const std::string& content_name,
-      bool srtp_required,
-      const AudioOptions& options);
-  VideoChannel* CreateVideoChannel_w(
-      webrtc::Call* call,
-      const cricket::MediaConfig& media_config,
-      DtlsTransportInternal* rtp_dtls_transport,
-      DtlsTransportInternal* rtcp_dtls_transport,
-      rtc::PacketTransportInternal* rtp_packet_transport,
-      rtc::PacketTransportInternal* rtcp_packet_transport,
-      rtc::Thread* signaling_thread,
-      const std::string& content_name,
-      bool srtp_required,
-      const VideoOptions& options);
-
   std::unique_ptr<MediaEngineInterface> media_engine_;  // Nullable.
   std::unique_ptr<DataEngineInterface> data_engine_;    // Non-null.
   bool initialized_ = false;
diff --git a/pc/channelmanager_unittest.cc b/pc/channelmanager_unittest.cc
index d318ac5..38da139 100644
--- a/pc/channelmanager_unittest.cc
+++ b/pc/channelmanager_unittest.cc
@@ -15,8 +15,8 @@
 #include "media/base/fakevideocapturer.h"
 #include "media/base/testutils.h"
 #include "media/engine/fakewebrtccall.h"
+#include "p2p/base/fakedtlstransport.h"
 #include "pc/channelmanager.h"
-#include "pc/test/faketransportcontroller.h"
 #include "rtc_base/gunit.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/thread.h"
@@ -47,13 +47,47 @@
             std::unique_ptr<DataEngineInterface>(fdme_),
             rtc::Thread::Current(),
             rtc::Thread::Current())),
-        fake_call_(),
-        transport_controller_(
-            new cricket::FakeTransportController(ICEROLE_CONTROLLING)) {
+        fake_call_() {
     fme_->SetAudioCodecs(MAKE_VECTOR(kAudioCodecs));
     fme_->SetVideoCodecs(MAKE_VECTOR(kVideoCodecs));
   }
 
+  std::unique_ptr<webrtc::RtpTransportInternal> CreateDtlsSrtpTransport() {
+    rtp_dtls_transport_ = rtc::MakeUnique<FakeDtlsTransport>(
+        "fake_dtls_transport", cricket::ICE_CANDIDATE_COMPONENT_RTP);
+    auto rtp_transport =
+        rtc::MakeUnique<webrtc::RtpTransport>(/*rtcp_mux_required=*/true);
+    auto srtp_transport =
+        rtc::MakeUnique<webrtc::SrtpTransport>(std::move(rtp_transport));
+    auto dtls_srtp_transport =
+        rtc::MakeUnique<webrtc::DtlsSrtpTransport>(std::move(srtp_transport));
+    dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport_.get(),
+                                           /*rtcp_dtls_transport=*/nullptr);
+    return dtls_srtp_transport;
+  }
+
+  void TestCreateDestroyChannels(webrtc::RtpTransportInternal* rtp_transport) {
+    cricket::VoiceChannel* voice_channel = cm_->CreateVoiceChannel(
+        &fake_call_, cricket::MediaConfig(), rtp_transport,
+        rtc::Thread::Current(), cricket::CN_AUDIO, kDefaultSrtpRequired,
+        rtc::CryptoOptions(), AudioOptions());
+    EXPECT_TRUE(voice_channel != nullptr);
+    cricket::VideoChannel* video_channel = cm_->CreateVideoChannel(
+        &fake_call_, cricket::MediaConfig(), rtp_transport,
+        rtc::Thread::Current(), cricket::CN_VIDEO, kDefaultSrtpRequired,
+        rtc::CryptoOptions(), VideoOptions());
+    EXPECT_TRUE(video_channel != nullptr);
+    cricket::RtpDataChannel* rtp_data_channel = cm_->CreateRtpDataChannel(
+        cricket::MediaConfig(), rtp_transport, rtc::Thread::Current(),
+        cricket::CN_DATA, kDefaultSrtpRequired, rtc::CryptoOptions());
+    EXPECT_TRUE(rtp_data_channel != nullptr);
+    cm_->DestroyVideoChannel(video_channel);
+    cm_->DestroyVoiceChannel(voice_channel);
+    cm_->DestroyRtpDataChannel(rtp_data_channel);
+    cm_->Terminate();
+  }
+
+  std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport_;
   std::unique_ptr<rtc::Thread> network_;
   std::unique_ptr<rtc::Thread> worker_;
   // |fme_| and |fdme_| are actually owned by |cm_|.
@@ -61,7 +95,6 @@
   cricket::FakeDataEngine* fdme_;
   std::unique_ptr<cricket::ChannelManager> cm_;
   cricket::FakeCall fake_call_;
-  std::unique_ptr<cricket::FakeTransportController> transport_controller_;
 };
 
 // Test that we startup/shutdown properly.
@@ -93,68 +126,6 @@
   EXPECT_FALSE(cm_->initialized());
 }
 
-// Test that we can create and destroy a voice and video channel.
-TEST_F(ChannelManagerTest, CreateDestroyChannels) {
-  EXPECT_TRUE(cm_->Init());
-  cricket::DtlsTransportInternal* rtp_transport =
-      transport_controller_->CreateDtlsTransport(
-          cricket::CN_AUDIO, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-  cricket::VoiceChannel* voice_channel = cm_->CreateVoiceChannel(
-      &fake_call_, cricket::MediaConfig(),
-      rtp_transport, nullptr /*rtcp_transport*/,
-      rtc::Thread::Current(), cricket::CN_AUDIO, kDefaultSrtpRequired,
-      AudioOptions());
-  EXPECT_TRUE(voice_channel != nullptr);
-  cricket::VideoChannel* video_channel = cm_->CreateVideoChannel(
-      &fake_call_, cricket::MediaConfig(),
-      rtp_transport, nullptr /*rtcp_transport*/,
-      rtc::Thread::Current(), cricket::CN_VIDEO, kDefaultSrtpRequired,
-      VideoOptions());
-  EXPECT_TRUE(video_channel != nullptr);
-  cricket::RtpDataChannel* rtp_data_channel = cm_->CreateRtpDataChannel(
-      cricket::MediaConfig(), rtp_transport, nullptr /*rtcp_transport*/,
-      rtc::Thread::Current(), cricket::CN_DATA, kDefaultSrtpRequired);
-  EXPECT_TRUE(rtp_data_channel != nullptr);
-  cm_->DestroyVideoChannel(video_channel);
-  cm_->DestroyVoiceChannel(voice_channel);
-  cm_->DestroyRtpDataChannel(rtp_data_channel);
-  cm_->Terminate();
-}
-
-// Test that we can create and destroy a voice and video channel with a worker.
-TEST_F(ChannelManagerTest, CreateDestroyChannelsOnThread) {
-  network_->Start();
-  worker_->Start();
-  EXPECT_TRUE(cm_->set_worker_thread(worker_.get()));
-  EXPECT_TRUE(cm_->set_network_thread(network_.get()));
-  EXPECT_TRUE(cm_->Init());
-  transport_controller_.reset(new cricket::FakeTransportController(
-      network_.get(), ICEROLE_CONTROLLING));
-  cricket::DtlsTransportInternal* rtp_transport =
-      transport_controller_->CreateDtlsTransport(
-          cricket::CN_AUDIO, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-  cricket::VoiceChannel* voice_channel = cm_->CreateVoiceChannel(
-      &fake_call_, cricket::MediaConfig(),
-      rtp_transport, nullptr /*rtcp_transport*/,
-      rtc::Thread::Current(), cricket::CN_AUDIO, kDefaultSrtpRequired,
-      AudioOptions());
-  EXPECT_TRUE(voice_channel != nullptr);
-  cricket::VideoChannel* video_channel = cm_->CreateVideoChannel(
-      &fake_call_, cricket::MediaConfig(),
-      rtp_transport, nullptr /*rtcp_transport*/,
-      rtc::Thread::Current(), cricket::CN_VIDEO, kDefaultSrtpRequired,
-      VideoOptions());
-  EXPECT_TRUE(video_channel != nullptr);
-  cricket::RtpDataChannel* rtp_data_channel = cm_->CreateRtpDataChannel(
-      cricket::MediaConfig(), rtp_transport, nullptr /*rtcp_transport*/,
-      rtc::Thread::Current(), cricket::CN_DATA, kDefaultSrtpRequired);
-  EXPECT_TRUE(rtp_data_channel != nullptr);
-  cm_->DestroyVideoChannel(video_channel);
-  cm_->DestroyVoiceChannel(voice_channel);
-  cm_->DestroyRtpDataChannel(rtp_data_channel);
-  cm_->Terminate();
-}
-
 TEST_F(ChannelManagerTest, SetVideoRtxEnabled) {
   std::vector<VideoCodec> codecs;
   const VideoCodec rtx_codec(96, "rtx");
@@ -185,89 +156,20 @@
   EXPECT_TRUE(ContainsMatchingCodec(codecs, rtx_codec));
 }
 
-enum class RTPTransportType { kRtp, kSrtp, kDtlsSrtp };
-
-class ChannelManagerTestWithRtpTransport
-    : public ChannelManagerTest,
-      public ::testing::WithParamInterface<RTPTransportType> {
- public:
-  std::unique_ptr<webrtc::RtpTransportInternal> CreateRtpTransport() {
-    RTPTransportType type = GetParam();
-    switch (type) {
-      case RTPTransportType::kRtp:
-        return CreatePlainRtpTransport();
-      case RTPTransportType::kSrtp:
-        return CreateSrtpTransport();
-      case RTPTransportType::kDtlsSrtp:
-        return CreateDtlsSrtpTransport();
-    }
-    return nullptr;
-  }
-
-  void TestCreateDestroyChannels(webrtc::RtpTransportInternal* rtp_transport) {
-    cricket::VoiceChannel* voice_channel = cm_->CreateVoiceChannel(
-        &fake_call_, cricket::MediaConfig(), rtp_transport,
-        rtc::Thread::Current(), cricket::CN_AUDIO, kDefaultSrtpRequired,
-        AudioOptions());
-    EXPECT_TRUE(voice_channel != nullptr);
-    cricket::VideoChannel* video_channel = cm_->CreateVideoChannel(
-        &fake_call_, cricket::MediaConfig(), rtp_transport,
-        rtc::Thread::Current(), cricket::CN_VIDEO, kDefaultSrtpRequired,
-        VideoOptions());
-    EXPECT_TRUE(video_channel != nullptr);
-    cricket::RtpDataChannel* rtp_data_channel = cm_->CreateRtpDataChannel(
-        cricket::MediaConfig(), rtp_transport, rtc::Thread::Current(),
-        cricket::CN_DATA, kDefaultSrtpRequired);
-    EXPECT_TRUE(rtp_data_channel != nullptr);
-    cm_->DestroyVideoChannel(video_channel);
-    cm_->DestroyVoiceChannel(voice_channel);
-    cm_->DestroyRtpDataChannel(rtp_data_channel);
-    cm_->Terminate();
-  }
-
- private:
-  std::unique_ptr<webrtc::RtpTransportInternal> CreatePlainRtpTransport() {
-    return rtc::MakeUnique<webrtc::RtpTransport>(/*rtcp_mux_required=*/true);
-  }
-
-  std::unique_ptr<webrtc::RtpTransportInternal> CreateSrtpTransport() {
-    auto rtp_transport =
-        rtc::MakeUnique<webrtc::RtpTransport>(/*rtcp_mux_required=*/true);
-    auto srtp_transport =
-        rtc::MakeUnique<webrtc::SrtpTransport>(std::move(rtp_transport));
-    return srtp_transport;
-  }
-
-  std::unique_ptr<webrtc::RtpTransportInternal> CreateDtlsSrtpTransport() {
-    auto rtp_transport =
-        rtc::MakeUnique<webrtc::RtpTransport>(/*rtcp_mux_required=*/true);
-    auto srtp_transport =
-        rtc::MakeUnique<webrtc::SrtpTransport>(std::move(rtp_transport));
-    auto dtls_srtp_transport_ =
-        rtc::MakeUnique<webrtc::DtlsSrtpTransport>(std::move(srtp_transport));
-    return dtls_srtp_transport_;
-  }
-};
-
-TEST_P(ChannelManagerTestWithRtpTransport, CreateDestroyChannels) {
+TEST_F(ChannelManagerTest, CreateDestroyChannels) {
   EXPECT_TRUE(cm_->Init());
-  auto rtp_transport = CreateRtpTransport();
+  auto rtp_transport = CreateDtlsSrtpTransport();
   TestCreateDestroyChannels(rtp_transport.get());
 }
 
-TEST_P(ChannelManagerTestWithRtpTransport, CreateDestroyChannelsOnThread) {
+TEST_F(ChannelManagerTest, CreateDestroyChannelsOnThread) {
   network_->Start();
   worker_->Start();
   EXPECT_TRUE(cm_->set_worker_thread(worker_.get()));
   EXPECT_TRUE(cm_->set_network_thread(network_.get()));
   EXPECT_TRUE(cm_->Init());
-  auto rtp_transport = CreateRtpTransport();
+  auto rtp_transport = CreateDtlsSrtpTransport();
   TestCreateDestroyChannels(rtp_transport.get());
 }
 
-INSTANTIATE_TEST_CASE_P(ChannelManagerTest,
-                        ChannelManagerTestWithRtpTransport,
-                        ::testing::Values(RTPTransportType::kRtp,
-                                          RTPTransportType::kSrtp,
-                                          RTPTransportType::kDtlsSrtp));
 }  // namespace cricket
diff --git a/pc/dtlssrtptransport.cc b/pc/dtlssrtptransport.cc
index 0b98a96..f40c96f 100644
--- a/pc/dtlssrtptransport.cc
+++ b/pc/dtlssrtptransport.cc
@@ -53,7 +53,7 @@
   // When using DTLS-SRTP, we must reset the SrtpTransport every time the
   // DtlsTransport changes and wait until the DTLS handshake is complete to set
   // the newly negotiated parameters.
-  if (IsActive()) {
+  if (IsSrtpActive()) {
     srtp_transport_->ResetParams();
   }
 
@@ -62,7 +62,7 @@
 
   // This would only be possible if using BUNDLE but not rtcp-mux, which isn't
   // allowed according to the BUNDLE spec.
-  RTC_CHECK(!(IsActive()))
+  RTC_CHECK(!(IsSrtpActive()))
       << "Setting RTCP for DTLS/SRTP after the DTLS is active "
          "should never happen.";
 
@@ -140,7 +140,7 @@
 }
 
 void DtlsSrtpTransport::MaybeSetupDtlsSrtp() {
-  if (IsActive() || !DtlsHandshakeCompleted()) {
+  if (IsSrtpActive() || !DtlsHandshakeCompleted()) {
     return;
   }
 
@@ -184,7 +184,7 @@
   // Return if the DTLS-SRTP is active because the encrypted header extension
   // IDs don't need to be updated for RTCP and the crypto params don't need to
   // be reset.
-  if (IsActive()) {
+  if (IsSrtpActive()) {
     return;
   }
 
diff --git a/pc/dtlssrtptransport.h b/pc/dtlssrtptransport.h
index 02002b0..889bd22 100644
--- a/pc/dtlssrtptransport.h
+++ b/pc/dtlssrtptransport.h
@@ -45,7 +45,7 @@
   void UpdateRecvEncryptedHeaderExtensionIds(
       const std::vector<int>& recv_extension_ids);
 
-  bool IsActive() { return srtp_transport_->IsActive(); }
+  bool IsSrtpActive() const override { return srtp_transport_->IsSrtpActive(); }
 
   // Cache RTP Absoulute SendTime extension header ID. This is only used when
   // external authentication is enabled.
@@ -54,11 +54,17 @@
         rtp_abs_sendtime_extn_id);
   }
 
-  // TODO(zhihuang): Remove this when we remove RtpTransportAdapter.
-  RtpTransportAdapter* GetInternal() override { return nullptr; }
-
   sigslot::signal2<DtlsSrtpTransport*, bool> SignalDtlsSrtpSetupFailure;
 
+  RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override {
+    return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
+                    "Set SRTP keys for DTLS-SRTP is not supported.");
+  }
+  RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) override {
+    return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
+                    "Set SRTP keys for DTLS-SRTP is not supported.");
+  }
+
  private:
   bool IsDtlsActive();
   bool IsDtlsConnected();
diff --git a/pc/dtlssrtptransport_unittest.cc b/pc/dtlssrtptransport_unittest.cc
index 08a8151..f0e4f28 100644
--- a/pc/dtlssrtptransport_unittest.cc
+++ b/pc/dtlssrtptransport_unittest.cc
@@ -70,9 +70,6 @@
       bool rtcp_mux_enabled) {
     auto rtp_transport = rtc::MakeUnique<RtpTransport>(rtcp_mux_enabled);
 
-    rtp_transport->AddHandledPayloadType(0x00);
-    rtp_transport->AddHandledPayloadType(0xc9);
-
     auto srtp_transport =
         rtc::MakeUnique<SrtpTransport>(std::move(rtp_transport));
     auto dtls_srtp_transport =
@@ -118,8 +115,8 @@
   void SendRecvRtpPackets() {
     ASSERT_TRUE(dtls_srtp_transport1_);
     ASSERT_TRUE(dtls_srtp_transport2_);
-    ASSERT_TRUE(dtls_srtp_transport1_->IsActive());
-    ASSERT_TRUE(dtls_srtp_transport2_->IsActive());
+    ASSERT_TRUE(dtls_srtp_transport1_->IsSrtpActive());
+    ASSERT_TRUE(dtls_srtp_transport2_->IsSrtpActive());
 
     size_t rtp_len = sizeof(kPcmuFrame);
     size_t packet_size = rtp_len + kRtpAuthTagLen;
@@ -181,8 +178,8 @@
       const std::vector<int>& encrypted_header_ids) {
     ASSERT_TRUE(dtls_srtp_transport1_);
     ASSERT_TRUE(dtls_srtp_transport2_);
-    ASSERT_TRUE(dtls_srtp_transport1_->IsActive());
-    ASSERT_TRUE(dtls_srtp_transport2_->IsActive());
+    ASSERT_TRUE(dtls_srtp_transport1_->IsSrtpActive());
+    ASSERT_TRUE(dtls_srtp_transport2_->IsSrtpActive());
 
     size_t rtp_len = sizeof(kPcmuFrameWithExtensions);
     size_t packet_size = rtp_len + kRtpAuthTagLen;
@@ -353,8 +350,8 @@
                          rtcp_dtls2.get(), /*rtcp_mux_enabled=*/false);
 
   CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
-  EXPECT_FALSE(dtls_srtp_transport1_->IsActive());
-  EXPECT_FALSE(dtls_srtp_transport2_->IsActive());
+  EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive());
+  EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive());
   CompleteDtlsHandshake(rtcp_dtls1.get(), rtcp_dtls2.get());
   SendRecvPackets();
 }
@@ -372,8 +369,8 @@
                          /*rtcp_mux_enabled=*/true);
 
   CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
-  EXPECT_TRUE(dtls_srtp_transport1_->IsActive());
-  EXPECT_TRUE(dtls_srtp_transport2_->IsActive());
+  EXPECT_TRUE(dtls_srtp_transport1_->IsSrtpActive());
+  EXPECT_TRUE(dtls_srtp_transport2_->IsSrtpActive());
 
   auto rtp_dtls3 = rtc::MakeUnique<FakeDtlsTransport>(
       "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
@@ -383,8 +380,8 @@
   // The previous context is reset.
   dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls3.get(), nullptr);
   dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls4.get(), nullptr);
-  EXPECT_FALSE(dtls_srtp_transport1_->IsActive());
-  EXPECT_FALSE(dtls_srtp_transport2_->IsActive());
+  EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive());
+  EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive());
 
   // Re-setup.
   CompleteDtlsHandshake(rtp_dtls3.get(), rtp_dtls4.get());
@@ -409,8 +406,8 @@
 
   CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get());
   // Inactive because the RTCP transport handshake didn't complete.
-  EXPECT_FALSE(dtls_srtp_transport1_->IsActive());
-  EXPECT_FALSE(dtls_srtp_transport2_->IsActive());
+  EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive());
+  EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive());
 
   dtls_srtp_transport1_->SetRtcpMuxEnabled(true);
   dtls_srtp_transport2_->SetRtcpMuxEnabled(true);
diff --git a/pc/jseptransport.cc b/pc/jseptransport.cc
deleted file mode 100644
index 0127d84..0000000
--- a/pc/jseptransport.cc
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- *  Copyright 2004 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.
- */
-
-#include "pc/jseptransport.h"
-
-#include <memory>
-#include <utility>  // for std::pair
-
-#include "api/candidate.h"
-#include "p2p/base/p2pconstants.h"
-#include "p2p/base/p2ptransportchannel.h"
-#include "p2p/base/port.h"
-#include "rtc_base/bind.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-
-using webrtc::SdpType;
-
-namespace cricket {
-
-static bool BadTransportDescription(const std::string& desc,
-                                    std::string* err_desc) {
-  if (err_desc) {
-    *err_desc = desc;
-  }
-  RTC_LOG(LS_ERROR) << desc;
-  return false;
-}
-
-static bool VerifyIceParams(const TransportDescription& desc) {
-  // For legacy protocols.
-  if (desc.ice_ufrag.empty() && desc.ice_pwd.empty())
-    return true;
-
-  if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH ||
-      desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) {
-    return false;
-  }
-  if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH ||
-      desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) {
-    return false;
-  }
-  return true;
-}
-
-JsepTransport::JsepTransport(
-    const std::string& mid,
-    const rtc::scoped_refptr<rtc::RTCCertificate>& certificate)
-    : mid_(mid), certificate_(certificate) {}
-
-JsepTransport::~JsepTransport() = default;
-
-bool JsepTransport::AddChannel(DtlsTransportInternal* dtls, int component) {
-  if (channels_.find(component) != channels_.end()) {
-    RTC_LOG(LS_ERROR) << "Adding channel for component " << component
-                      << " twice.";
-    return false;
-  }
-  channels_[component] = dtls;
-  // Something's wrong if a channel is being added after a description is set.
-  // This may currently occur if rtcp-mux is negotiated, then a new m= section
-  // is added in a later offer/answer. But this is suboptimal and should be
-  // changed; we shouldn't support going from muxed to non-muxed.
-  // TODO(deadbeef): Once this is fixed, make the warning an error, and remove
-  // the calls to "ApplyXTransportDescription" below.
-  if (local_description_set_ || remote_description_set_) {
-    RTC_LOG(LS_WARNING) << "Adding new transport channel after "
-                           "transport description already applied.";
-  }
-  bool ret = true;
-  std::string err;
-  if (local_description_set_) {
-    ret &= ApplyLocalTransportDescription(channels_[component], &err);
-  }
-  if (remote_description_set_) {
-    ret &= ApplyRemoteTransportDescription(channels_[component], &err);
-  }
-  if (local_description_set_ && remote_description_set_) {
-    ret &= ApplyNegotiatedTransportDescription(channels_[component], &err);
-  }
-  return ret;
-}
-
-bool JsepTransport::RemoveChannel(int component) {
-  auto it = channels_.find(component);
-  if (it == channels_.end()) {
-    RTC_LOG(LS_ERROR) << "Trying to remove channel for component " << component
-                      << ", which doesn't exist.";
-    return false;
-  }
-  channels_.erase(component);
-  return true;
-}
-
-bool JsepTransport::HasChannels() const {
-  return !channels_.empty();
-}
-
-void JsepTransport::SetLocalCertificate(
-    const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
-  certificate_ = certificate;
-}
-
-bool JsepTransport::GetLocalCertificate(
-    rtc::scoped_refptr<rtc::RTCCertificate>* certificate) const {
-  if (!certificate_) {
-    return false;
-  }
-
-  *certificate = certificate_;
-  return true;
-}
-
-bool JsepTransport::SetLocalTransportDescription(
-    const TransportDescription& description,
-    SdpType type,
-    std::string* error_desc) {
-  bool ret = true;
-
-  if (!VerifyIceParams(description)) {
-    return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
-                                   error_desc);
-  }
-
-  bool ice_restarting =
-      local_description_set_ &&
-      IceCredentialsChanged(local_description_->ice_ufrag,
-                            local_description_->ice_pwd, description.ice_ufrag,
-                            description.ice_pwd);
-  local_description_.reset(new TransportDescription(description));
-
-  rtc::SSLFingerprint* local_fp =
-      local_description_->identity_fingerprint.get();
-
-  if (!local_fp) {
-    certificate_ = nullptr;
-  } else if (!VerifyCertificateFingerprint(certificate_.get(), local_fp,
-                                           error_desc)) {
-    return false;
-  }
-
-  for (const auto& kv : channels_) {
-    ret &= ApplyLocalTransportDescription(kv.second, error_desc);
-  }
-  if (!ret) {
-    return false;
-  }
-
-  // If PRANSWER/ANSWER is set, we should decide transport protocol type.
-  if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
-    ret &= NegotiateTransportDescription(type, error_desc);
-  }
-  if (!ret) {
-    return false;
-  }
-
-  if (needs_ice_restart_ && ice_restarting) {
-    needs_ice_restart_ = false;
-    RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag cleared for transport "
-                        << mid();
-  }
-
-  local_description_set_ = true;
-  return true;
-}
-
-bool JsepTransport::SetRemoteTransportDescription(
-    const TransportDescription& description,
-    SdpType type,
-    std::string* error_desc) {
-  bool ret = true;
-
-  if (!VerifyIceParams(description)) {
-    return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
-                                   error_desc);
-  }
-
-  remote_description_.reset(new TransportDescription(description));
-  for (const auto& kv : channels_) {
-    ret &= ApplyRemoteTransportDescription(kv.second, error_desc);
-  }
-
-  // If PRANSWER/ANSWER is set, we should decide transport protocol type.
-  if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
-    ret = NegotiateTransportDescription(SdpType::kOffer, error_desc);
-  }
-  if (ret) {
-    remote_description_set_ = true;
-  }
-
-  return ret;
-}
-
-void JsepTransport::SetNeedsIceRestartFlag() {
-  if (!needs_ice_restart_) {
-    needs_ice_restart_ = true;
-    RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag set for transport " << mid();
-  }
-}
-
-bool JsepTransport::NeedsIceRestart() const {
-  return needs_ice_restart_;
-}
-
-rtc::Optional<rtc::SSLRole> JsepTransport::GetSslRole() const {
-  return ssl_role_;
-}
-
-bool JsepTransport::GetStats(TransportStats* stats) {
-  stats->transport_name = mid();
-  stats->channel_stats.clear();
-  for (auto& kv : channels_) {
-    DtlsTransportInternal* dtls_transport = kv.second;
-    TransportChannelStats substats;
-    substats.component = kv.first;
-    dtls_transport->GetSrtpCryptoSuite(&substats.srtp_crypto_suite);
-    dtls_transport->GetSslCipherSuite(&substats.ssl_cipher_suite);
-    substats.dtls_state = dtls_transport->dtls_state();
-    if (!dtls_transport->ice_transport()->GetStats(
-            &substats.connection_infos, &substats.candidate_stats_list)) {
-      return false;
-    }
-    stats->channel_stats.push_back(substats);
-  }
-  return true;
-}
-
-bool JsepTransport::VerifyCertificateFingerprint(
-    const rtc::RTCCertificate* certificate,
-    const rtc::SSLFingerprint* fingerprint,
-    std::string* error_desc) const {
-  if (!fingerprint) {
-    return BadTransportDescription("No fingerprint.", error_desc);
-  }
-  if (!certificate) {
-    return BadTransportDescription(
-        "Fingerprint provided but no identity available.", error_desc);
-  }
-  std::unique_ptr<rtc::SSLFingerprint> fp_tmp(rtc::SSLFingerprint::Create(
-      fingerprint->algorithm, certificate->identity()));
-  RTC_DCHECK(fp_tmp.get() != NULL);
-  if (*fp_tmp == *fingerprint) {
-    return true;
-  }
-  std::ostringstream desc;
-  desc << "Local fingerprint does not match identity. Expected: ";
-  desc << fp_tmp->ToString();
-  desc << " Got: " << fingerprint->ToString();
-  return BadTransportDescription(desc.str(), error_desc);
-}
-
-bool JsepTransport::ApplyLocalTransportDescription(
-    DtlsTransportInternal* dtls_transport,
-    std::string* error_desc) {
-  dtls_transport->ice_transport()->SetIceParameters(
-      local_description_->GetIceParameters());
-  return true;
-}
-
-bool JsepTransport::ApplyRemoteTransportDescription(
-    DtlsTransportInternal* dtls_transport,
-    std::string* error_desc) {
-  dtls_transport->ice_transport()->SetRemoteIceParameters(
-      remote_description_->GetIceParameters());
-  dtls_transport->ice_transport()->SetRemoteIceMode(
-      remote_description_->ice_mode);
-  return true;
-}
-
-bool JsepTransport::ApplyNegotiatedTransportDescription(
-    DtlsTransportInternal* dtls_transport,
-    std::string* error_desc) {
-  // Set SSL role. Role must be set before fingerprint is applied, which
-  // initiates DTLS setup.
-  if (ssl_role_ && !dtls_transport->SetDtlsRole(*ssl_role_)) {
-    return BadTransportDescription("Failed to set SSL role for the channel.",
-                                   error_desc);
-  }
-  // Apply remote fingerprint.
-  if (!dtls_transport->SetRemoteFingerprint(
-          remote_fingerprint_->algorithm,
-          reinterpret_cast<const uint8_t*>(remote_fingerprint_->digest.data()),
-          remote_fingerprint_->digest.size())) {
-    return BadTransportDescription("Failed to apply remote fingerprint.",
-                                   error_desc);
-  }
-  return true;
-}
-
-bool JsepTransport::NegotiateTransportDescription(
-    SdpType local_description_type,
-    std::string* error_desc) {
-  if (!local_description_ || !remote_description_) {
-    const std::string msg =
-        "Applying an answer transport description "
-        "without applying any offer.";
-    return BadTransportDescription(msg, error_desc);
-  }
-  rtc::SSLFingerprint* local_fp =
-      local_description_->identity_fingerprint.get();
-  rtc::SSLFingerprint* remote_fp =
-      remote_description_->identity_fingerprint.get();
-  if (remote_fp && local_fp) {
-    remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp));
-    if (!NegotiateRole(local_description_type, error_desc)) {
-      return false;
-    }
-  } else if (local_fp && (local_description_type == SdpType::kAnswer)) {
-    return BadTransportDescription(
-        "Local fingerprint supplied when caller didn't offer DTLS.",
-        error_desc);
-  } else {
-    // We are not doing DTLS
-    remote_fingerprint_.reset(new rtc::SSLFingerprint("", nullptr, 0));
-  }
-  // Now that we have negotiated everything, push it downward.
-  // Note that we cache the result so that if we have race conditions
-  // between future SetRemote/SetLocal invocations and new channel
-  // creation, we have the negotiation state saved until a new
-  // negotiation happens.
-  for (const auto& kv : channels_) {
-    if (!ApplyNegotiatedTransportDescription(kv.second, error_desc)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-bool JsepTransport::NegotiateRole(SdpType local_description_type,
-                                  std::string* error_desc) {
-  if (!local_description_ || !remote_description_) {
-    const std::string msg =
-        "Local and Remote description must be set before "
-        "transport descriptions are negotiated";
-    return BadTransportDescription(msg, error_desc);
-  }
-
-  // From RFC 4145, section-4.1, The following are the values that the
-  // 'setup' attribute can take in an offer/answer exchange:
-  //       Offer      Answer
-  //      ________________
-  //      active     passive / holdconn
-  //      passive    active / holdconn
-  //      actpass    active / passive / holdconn
-  //      holdconn   holdconn
-  //
-  // Set the role that is most conformant with RFC 5763, Section 5, bullet 1
-  // The endpoint MUST use the setup attribute defined in [RFC4145].
-  // The endpoint that is the offerer MUST use the setup attribute
-  // value of setup:actpass and be prepared to receive a client_hello
-  // before it receives the answer.  The answerer MUST use either a
-  // setup attribute value of setup:active or setup:passive.  Note that
-  // if the answerer uses setup:passive, then the DTLS handshake will
-  // not begin until the answerer is received, which adds additional
-  // latency. setup:active allows the answer and the DTLS handshake to
-  // occur in parallel.  Thus, setup:active is RECOMMENDED.  Whichever
-  // party is active MUST initiate a DTLS handshake by sending a
-  // ClientHello over each flow (host/port quartet).
-  // IOW - actpass and passive modes should be treated as server and
-  // active as client.
-  ConnectionRole local_connection_role = local_description_->connection_role;
-  ConnectionRole remote_connection_role = remote_description_->connection_role;
-
-  bool is_remote_server = false;
-  if (local_description_type == SdpType::kOffer) {
-    if (local_connection_role != CONNECTIONROLE_ACTPASS) {
-      return BadTransportDescription(
-          "Offerer must use actpass value for setup attribute.", error_desc);
-    }
-
-    if (remote_connection_role == CONNECTIONROLE_ACTIVE ||
-        remote_connection_role == CONNECTIONROLE_PASSIVE ||
-        remote_connection_role == CONNECTIONROLE_NONE) {
-      is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE);
-    } else {
-      const std::string msg =
-          "Answerer must use either active or passive value "
-          "for setup attribute.";
-      return BadTransportDescription(msg, error_desc);
-    }
-    // If remote is NONE or ACTIVE it will act as client.
-  } else {
-    if (remote_connection_role != CONNECTIONROLE_ACTPASS &&
-        remote_connection_role != CONNECTIONROLE_NONE) {
-      // Accept a remote role attribute that's not "actpass", but matches the
-      // current negotiated role. This is allowed by dtls-sdp, though our
-      // implementation will never generate such an offer as it's not
-      // recommended.
-      //
-      // See https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-dtls-sdp,
-      // section 5.5.
-      if (!ssl_role_ ||
-          (*ssl_role_ == rtc::SSL_CLIENT &&
-           remote_connection_role == CONNECTIONROLE_ACTIVE) ||
-          (*ssl_role_ == rtc::SSL_SERVER &&
-           remote_connection_role == CONNECTIONROLE_PASSIVE)) {
-        return BadTransportDescription(
-            "Offerer must use actpass value or current negotiated role for "
-            "setup attribute.",
-            error_desc);
-      }
-    }
-
-    if (local_connection_role == CONNECTIONROLE_ACTIVE ||
-        local_connection_role == CONNECTIONROLE_PASSIVE) {
-      is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE);
-    } else {
-      const std::string msg =
-          "Answerer must use either active or passive value "
-          "for setup attribute.";
-      return BadTransportDescription(msg, error_desc);
-    }
-
-    // If local is passive, local will act as server.
-  }
-
-  ssl_role_.emplace(is_remote_server ? rtc::SSL_CLIENT : rtc::SSL_SERVER);
-  return true;
-}
-
-}  // namespace cricket
diff --git a/pc/jseptransport.h b/pc/jseptransport.h
deleted file mode 100644
index 4a8aec8..0000000
--- a/pc/jseptransport.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- *  Copyright 2004 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_JSEPTRANSPORT_H_
-#define PC_JSEPTRANSPORT_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "api/candidate.h"
-#include "api/jsep.h"
-#include "api/optional.h"
-#include "p2p/base/dtlstransport.h"
-#include "p2p/base/p2pconstants.h"
-#include "p2p/base/transportinfo.h"
-#include "pc/sessiondescription.h"
-#include "pc/transportstats.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/messagequeue.h"
-#include "rtc_base/rtccertificate.h"
-#include "rtc_base/sigslot.h"
-#include "rtc_base/sslstreamadapter.h"
-
-namespace cricket {
-
-class DtlsTransportInternal;
-
-// Helper class used by TransportController that processes
-// TransportDescriptions. A TransportDescription represents the
-// transport-specific properties of an SDP m= section, processed according to
-// JSEP. Each transport consists of DTLS and ICE transport channels for RTP
-// (and possibly RTCP, if rtcp-mux isn't used).
-//
-// On Threading:  Transport performs work solely on the network thread, and so
-// its methods should only be called on the network thread.
-class JsepTransport : public sigslot::has_slots<> {
- public:
-  // |mid| is just used for log statements in order to identify the Transport.
-  // Note that |certificate| is allowed to be null since a remote description
-  // may be set before a local certificate is generated.
-  JsepTransport(const std::string& mid,
-                const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
-  ~JsepTransport() override;
-
-  // Returns the MID of this transport.
-  const std::string& mid() const { return mid_; }
-
-  // Add or remove channel that is affected when a local/remote transport
-  // description is set on this transport. Need to add all channels before
-  // setting a transport description.
-  bool AddChannel(DtlsTransportInternal* dtls, int component);
-  bool RemoveChannel(int component);
-  bool HasChannels() const;
-
-  bool ready_for_remote_candidates() const {
-    return local_description_set_ && remote_description_set_;
-  }
-
-  // Must be called before applying local session description.
-  // Needed in order to verify the local fingerprint.
-  void SetLocalCertificate(
-      const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
-
-  // Get a copy of the local certificate provided by SetLocalCertificate.
-  bool GetLocalCertificate(
-      rtc::scoped_refptr<rtc::RTCCertificate>* certificate) const;
-
-  // Set the local TransportDescription to be used by DTLS and ICE channels
-  // that are part of this Transport.
-  bool SetLocalTransportDescription(const TransportDescription& description,
-                                    webrtc::SdpType type,
-                                    std::string* error_desc);
-
-  // Set the remote TransportDescription to be used by DTLS and ICE channels
-  // that are part of this Transport.
-  bool SetRemoteTransportDescription(const TransportDescription& description,
-                                     webrtc::SdpType type,
-                                     std::string* error_desc);
-
-  // Set the "needs-ice-restart" flag as described in JSEP. After the flag is
-  // set, offers should generate new ufrags/passwords until an ICE restart
-  // occurs.
-  //
-  // This and the below method can be called safely from any thread as long as
-  // SetXTransportDescription is not in progress.
-  void SetNeedsIceRestartFlag();
-  // Returns true if the ICE restart flag above was set, and no ICE restart has
-  // occurred yet for this transport (by applying a local description with
-  // changed ufrag/password).
-  bool NeedsIceRestart() const;
-
-  // Returns role if negotiated, or empty Optional if it hasn't been negotiated
-  // yet.
-  rtc::Optional<rtc::SSLRole> GetSslRole() const;
-
-  // TODO(deadbeef): Make this const. See comment in transportcontroller.h.
-  bool GetStats(TransportStats* stats);
-
-  // The current local transport description, possibly used
-  // by the transport controller.
-  const TransportDescription* local_description() const {
-    return local_description_.get();
-  }
-
-  // The current remote transport description, possibly used
-  // by the transport controller.
-  const TransportDescription* remote_description() const {
-    return remote_description_.get();
-  }
-
-  // TODO(deadbeef): The methods below are only public for testing. Should make
-  // them utility functions or objects so they can be tested independently from
-  // this class.
-
-  // Returns false if the certificate's identity does not match the fingerprint,
-  // or either is NULL.
-  bool VerifyCertificateFingerprint(const rtc::RTCCertificate* certificate,
-                                    const rtc::SSLFingerprint* fingerprint,
-                                    std::string* error_desc) const;
-
- private:
-  // Negotiates the transport parameters based on the current local and remote
-  // transport description, such as the ICE role to use, and whether DTLS
-  // should be activated.
-  //
-  // Called when an answer TransportDescription is applied.
-  bool NegotiateTransportDescription(webrtc::SdpType local_description_type,
-                                     std::string* error_desc);
-
-  // Negotiates the SSL role based off the offer and answer as specified by
-  // RFC 4145, section-4.1. Returns false if the SSL role cannot be determined
-  // from the local description and remote description.
-  bool NegotiateRole(webrtc::SdpType local_description_type,
-                     std::string* error_desc);
-
-  // Pushes down the transport parameters from the local description, such
-  // as the ICE ufrag and pwd.
-  bool ApplyLocalTransportDescription(DtlsTransportInternal* dtls_transport,
-                                      std::string* error_desc);
-
-  // Pushes down the transport parameters from the remote description to the
-  // transport channel.
-  bool ApplyRemoteTransportDescription(DtlsTransportInternal* dtls_transport,
-                                       std::string* error_desc);
-
-  // Pushes down the transport parameters obtained via negotiation.
-  bool ApplyNegotiatedTransportDescription(
-      DtlsTransportInternal* dtls_transport,
-      std::string* error_desc);
-
-  const std::string mid_;
-  // needs-ice-restart bit as described in JSEP.
-  bool needs_ice_restart_ = false;
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
-  rtc::Optional<rtc::SSLRole> ssl_role_;
-  std::unique_ptr<rtc::SSLFingerprint> remote_fingerprint_;
-  std::unique_ptr<TransportDescription> local_description_;
-  std::unique_ptr<TransportDescription> remote_description_;
-  bool local_description_set_ = false;
-  bool remote_description_set_ = false;
-
-  // Candidate component => DTLS channel
-  std::map<int, DtlsTransportInternal*> channels_;
-
-  RTC_DISALLOW_COPY_AND_ASSIGN(JsepTransport);
-};
-
-}  // namespace cricket
-
-#endif  // PC_JSEPTRANSPORT_H_
diff --git a/pc/jseptransport2.cc b/pc/jseptransport2.cc
index 11f9438..a4a0348 100644
--- a/pc/jseptransport2.cc
+++ b/pc/jseptransport2.cc
@@ -54,10 +54,12 @@
     bool rtcp_mux_enabled,
     const std::vector<CryptoParams>& cryptos,
     const std::vector<int>& encrypted_header_extension_ids,
+    int rtp_abs_sendtime_extn_id,
     const TransportDescription& transport_desc)
     : rtcp_mux_enabled(rtcp_mux_enabled),
       cryptos(cryptos),
       encrypted_header_extension_ids(encrypted_header_extension_ids),
+      rtp_abs_sendtime_extn_id(rtp_abs_sendtime_extn_id),
       transport_desc(transport_desc) {}
 
 JsepTransportDescription::JsepTransportDescription(
@@ -65,6 +67,7 @@
     : rtcp_mux_enabled(from.rtcp_mux_enabled),
       cryptos(from.cryptos),
       encrypted_header_extension_ids(from.encrypted_header_extension_ids),
+      rtp_abs_sendtime_extn_id(from.rtp_abs_sendtime_extn_id),
       transport_desc(from.transport_desc) {}
 
 JsepTransportDescription::~JsepTransportDescription() = default;
@@ -77,6 +80,7 @@
   rtcp_mux_enabled = from.rtcp_mux_enabled;
   cryptos = from.cryptos;
   encrypted_header_extension_ids = from.encrypted_header_extension_ids;
+  rtp_abs_sendtime_extn_id = from.rtp_abs_sendtime_extn_id;
   transport_desc = from.transport_desc;
 
   return *this;
@@ -218,11 +222,15 @@
       return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                               "Failed to setup SDES crypto parameters.");
     }
+    sdes_transport_->CacheRtpAbsSendTimeHeaderExtension(
+        jsep_description.rtp_abs_sendtime_extn_id);
   } else if (dtls_srtp_transport_) {
     RTC_DCHECK(!unencrypted_rtp_transport_);
     RTC_DCHECK(!sdes_transport_);
     dtls_srtp_transport_->UpdateSendEncryptedHeaderExtensionIds(
         jsep_description.encrypted_header_extension_ids);
+    dtls_srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(
+        jsep_description.rtp_abs_sendtime_extn_id);
   }
 
   remote_description_.reset(new JsepTransportDescription(jsep_description));
diff --git a/pc/jseptransport2.h b/pc/jseptransport2.h
index 16a20b9..8656cf5 100644
--- a/pc/jseptransport2.h
+++ b/pc/jseptransport2.h
@@ -46,6 +46,7 @@
       bool rtcp_mux_enabled,
       const std::vector<CryptoParams>& cryptos,
       const std::vector<int>& encrypted_header_extension_ids,
+      int rtp_abs_sendtime_extn_id,
       const TransportDescription& transport_description);
   JsepTransportDescription(const JsepTransportDescription& from);
   ~JsepTransportDescription();
@@ -55,6 +56,7 @@
   bool rtcp_mux_enabled = true;
   std::vector<CryptoParams> cryptos;
   std::vector<int> encrypted_header_extension_ids;
+  int rtp_abs_sendtime_extn_id = -1;
   // TODO(zhihuang): Add the ICE and DTLS related variables and methods from
   // TransportDescription and remove this extra layer of abstraction.
   TransportDescription transport_desc;
diff --git a/pc/jseptransport2_unittest.cc b/pc/jseptransport2_unittest.cc
index fc098ae..2f015cdc 100644
--- a/pc/jseptransport2_unittest.cc
+++ b/pc/jseptransport2_unittest.cc
@@ -9,8 +9,10 @@
  */
 
 #include <memory>
+#include <tuple>
 #include <utility>
 
+#include "media/base/fakertp.h"
 #include "p2p/base/fakedtlstransport.h"
 #include "p2p/base/fakeicetransport.h"
 #include "pc/jseptransport2.h"
@@ -40,7 +42,6 @@
 class JsepTransport2Test : public testing::Test, public sigslot::has_slots<> {
  protected:
   std::unique_ptr<webrtc::SrtpTransport> CreateSdesTransport(
-      const std::string& transport_name,
       rtc::PacketTransportInternal* rtp_packet_transport,
       rtc::PacketTransportInternal* rtcp_packet_transport) {
     bool rtcp_mux_enabled = (rtcp_packet_transport == nullptr);
@@ -55,7 +56,6 @@
   }
 
   std::unique_ptr<webrtc::DtlsSrtpTransport> CreateDtlsSrtpTransport(
-      const std::string& transport_name,
       cricket::DtlsTransportInternal* rtp_dtls_transport,
       cricket::DtlsTransportInternal* rtcp_dtls_transport) {
     bool rtcp_mux_enabled = (rtcp_dtls_transport == nullptr);
@@ -71,7 +71,8 @@
 
   // Create a new JsepTransport2 with a FakeDtlsTransport and a
   // FakeIceTransport.
-  void CreateJsepTransport2(bool rtcp_mux_enabled, SrtpMode srtp_mode) {
+  std::unique_ptr<JsepTransport2> CreateJsepTransport2(bool rtcp_mux_enabled,
+                                                       SrtpMode srtp_mode) {
     auto ice = rtc::MakeUnique<FakeIceTransport>(kTransportName,
                                                  ICE_CANDIDATE_COMPONENT_RTP);
     auto rtp_dtls_transport =
@@ -89,29 +90,28 @@
     std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport;
     switch (srtp_mode) {
       case SrtpMode::kSdes:
-        sdes_transport =
-            CreateSdesTransport(kTransportName, rtp_dtls_transport.get(),
-                                rtcp_dtls_transport.get());
+        sdes_transport = CreateSdesTransport(rtp_dtls_transport.get(),
+                                             rtcp_dtls_transport.get());
         sdes_transport_ = sdes_transport.get();
         break;
       case SrtpMode::kDtlsSrtp:
-        dtls_srtp_transport =
-            CreateDtlsSrtpTransport(kTransportName, rtp_dtls_transport.get(),
-                                    rtcp_dtls_transport.get());
+        dtls_srtp_transport = CreateDtlsSrtpTransport(
+            rtp_dtls_transport.get(), rtcp_dtls_transport.get());
         break;
       default:
         RTC_NOTREACHED();
     }
 
-    jsep_transport_ = rtc::MakeUnique<JsepTransport2>(
+    auto jsep_transport = rtc::MakeUnique<JsepTransport2>(
         kTransportName, /*local_certificate=*/nullptr,
         std::move(unencrypted_rtp_transport), std::move(sdes_transport),
         std::move(dtls_srtp_transport), std::move(rtp_dtls_transport),
         std::move(rtcp_dtls_transport));
 
     signal_rtcp_mux_active_received_ = false;
-    jsep_transport_->SignalRtcpMuxActive.connect(
+    jsep_transport->SignalRtcpMuxActive.connect(
         this, &JsepTransport2Test::OnRtcpMuxActive);
+    return jsep_transport;
   }
 
   JsepTransportDescription MakeJsepTransportDescription(
@@ -159,7 +159,7 @@
 // This test verifies the ICE parameters are properly applied to the transports.
 TEST_P(JsepTransport2WithRtcpMux, SetIceParameters) {
   bool rtcp_mux_enabled = GetParam();
-  CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+  jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
 
   JsepTransportDescription jsep_description;
   jsep_description.transport_desc = TransportDescription(kIceUfrag1, kIcePwd1);
@@ -205,7 +205,7 @@
 // Similarly, test DTLS parameters are properly applied to the transports.
 TEST_P(JsepTransport2WithRtcpMux, SetDtlsParameters) {
   bool rtcp_mux_enabled = GetParam();
-  CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+  jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
 
   // Create certificates.
   rtc::scoped_refptr<rtc::RTCCertificate> local_cert =
@@ -256,7 +256,7 @@
 // CONNECTIONROLE_PASSIVE, expecting SSL_CLIENT role.
 TEST_P(JsepTransport2WithRtcpMux, SetDtlsParametersWithPassiveAnswer) {
   bool rtcp_mux_enabled = GetParam();
-  CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+  jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
 
   // Create certificates.
   rtc::scoped_refptr<rtc::RTCCertificate> local_cert =
@@ -308,7 +308,7 @@
 // only starts returning "false" once an ICE restart has been initiated.
 TEST_P(JsepTransport2WithRtcpMux, NeedsIceRestart) {
   bool rtcp_mux_enabled = GetParam();
-  CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+  jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
 
   // Use the same JsepTransportDescription for both offer and answer.
   JsepTransportDescription description;
@@ -353,7 +353,7 @@
 
 TEST_P(JsepTransport2WithRtcpMux, GetStats) {
   bool rtcp_mux_enabled = GetParam();
-  CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+  jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
 
   size_t expected_stats_size = rtcp_mux_enabled ? 1u : 2u;
   TransportStats stats;
@@ -369,7 +369,7 @@
 // certificate matches the fingerprint.
 TEST_P(JsepTransport2WithRtcpMux, VerifyCertificateFingerprint) {
   bool rtcp_mux_enabled = GetParam();
-  CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+  jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
 
   EXPECT_FALSE(
       jsep_transport_->VerifyCertificateFingerprint(nullptr, nullptr).ok());
@@ -436,7 +436,8 @@
        SdpType::kPrAnswer}};
 
   for (auto& param : valid_client_params) {
-    CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+    jsep_transport_ =
+        CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
     jsep_transport_->SetLocalCertificate(certificate);
 
     local_description.transport_desc.connection_role = param.local_role;
@@ -477,7 +478,8 @@
        SdpType::kPrAnswer}};
 
   for (auto& param : valid_server_params) {
-    CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+    jsep_transport_ =
+        CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
     jsep_transport_->SetLocalCertificate(certificate);
 
     local_description.transport_desc.connection_role = param.local_role;
@@ -548,7 +550,8 @@
        SdpType::kPrAnswer}};
 
   for (auto& param : duplicate_params) {
-    CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+    jsep_transport_ =
+        CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
     jsep_transport_->SetLocalCertificate(certificate);
 
     local_description.transport_desc.connection_role = param.local_role;
@@ -603,7 +606,8 @@
        SdpType::kPrAnswer}};
 
   for (auto& param : offerer_without_actpass_params) {
-    CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+    jsep_transport_ =
+        CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
     jsep_transport_->SetLocalCertificate(certificate);
 
     local_description.transport_desc.connection_role = param.local_role;
@@ -645,7 +649,7 @@
       rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
           rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
   bool rtcp_mux_enabled = true;
-  CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+  jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
   jsep_transport_->SetLocalCertificate(certificate);
 
   JsepTransportDescription local_offer =
@@ -692,7 +696,7 @@
       rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
           rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
   bool rtcp_mux_enabled = true;
-  CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+  jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
   jsep_transport_->SetLocalCertificate(certificate);
 
   JsepTransportDescription local_offer =
@@ -738,7 +742,7 @@
       rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
           rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
   bool rtcp_mux_enabled = true;
-  CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+  jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
   jsep_transport_->SetLocalCertificate(certificate);
 
   JsepTransportDescription remote_desc =
@@ -783,7 +787,7 @@
       rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
           rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
   bool rtcp_mux_enabled = true;
-  CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+  jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
   jsep_transport_->SetLocalCertificate(certificate);
 
   JsepTransportDescription remote_desc =
@@ -828,7 +832,7 @@
       rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
           rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
   bool rtcp_mux_enabled = true;
-  CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
+  jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp);
   jsep_transport_->SetLocalCertificate(certificate);
 
   JsepTransportDescription remote_desc =
@@ -860,7 +864,8 @@
 // Tests that when the RTCP mux is successfully negotiated, the RTCP transport
 // will be destroyed and the SignalRtpMuxActive will be fired.
 TEST_F(JsepTransport2Test, RtcpMuxNegotiation) {
-  CreateJsepTransport2(/*rtcp_mux_enabled=*/false, SrtpMode::kDtlsSrtp);
+  jsep_transport_ =
+      CreateJsepTransport2(/*rtcp_mux_enabled=*/false, SrtpMode::kDtlsSrtp);
   JsepTransportDescription local_desc;
   local_desc.rtcp_mux_enabled = true;
   EXPECT_NE(nullptr, jsep_transport_->rtcp_dtls_transport());
@@ -882,7 +887,8 @@
   EXPECT_TRUE(signal_rtcp_mux_active_received_);
 
   // The remote side doesn't support RTCP-mux.
-  CreateJsepTransport2(/*rtcp_mux_enabled=*/false, SrtpMode::kDtlsSrtp);
+  jsep_transport_ =
+      CreateJsepTransport2(/*rtcp_mux_enabled=*/false, SrtpMode::kDtlsSrtp);
   signal_rtcp_mux_active_received_ = false;
   remote_desc.rtcp_mux_enabled = false;
   ASSERT_TRUE(
@@ -899,9 +905,10 @@
 }
 
 TEST_F(JsepTransport2Test, SdesNegotiation) {
-  CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes);
+  jsep_transport_ =
+      CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes);
   ASSERT_TRUE(sdes_transport_);
-  EXPECT_FALSE(sdes_transport_->IsActive());
+  EXPECT_FALSE(sdes_transport_->IsSrtpActive());
 
   JsepTransportDescription offer_desc;
   offer_desc.cryptos.push_back(cricket::CryptoParams(
@@ -920,13 +927,14 @@
       jsep_transport_
           ->SetRemoteJsepTransportDescription(answer_desc, SdpType::kAnswer)
           .ok());
-  EXPECT_TRUE(sdes_transport_->IsActive());
+  EXPECT_TRUE(sdes_transport_->IsSrtpActive());
 }
 
 TEST_F(JsepTransport2Test, SdesNegotiationWithEmptyCryptosInAnswer) {
-  CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes);
+  jsep_transport_ =
+      CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes);
   ASSERT_TRUE(sdes_transport_);
-  EXPECT_FALSE(sdes_transport_->IsActive());
+  EXPECT_FALSE(sdes_transport_->IsSrtpActive());
 
   JsepTransportDescription offer_desc;
   offer_desc.cryptos.push_back(cricket::CryptoParams(
@@ -943,13 +951,14 @@
           ->SetRemoteJsepTransportDescription(answer_desc, SdpType::kAnswer)
           .ok());
   // SRTP is not active because the crypto parameter is answer is empty.
-  EXPECT_FALSE(sdes_transport_->IsActive());
+  EXPECT_FALSE(sdes_transport_->IsSrtpActive());
 }
 
 TEST_F(JsepTransport2Test, SdesNegotiationWithMismatchedCryptos) {
-  CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes);
+  jsep_transport_ =
+      CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes);
   ASSERT_TRUE(sdes_transport_);
-  EXPECT_FALSE(sdes_transport_->IsActive());
+  EXPECT_FALSE(sdes_transport_->IsSrtpActive());
 
   JsepTransportDescription offer_desc;
   offer_desc.cryptos.push_back(cricket::CryptoParams(
@@ -974,7 +983,8 @@
 // Tests that the remote candidates can be added to the transports after both
 // local and remote descriptions are set.
 TEST_F(JsepTransport2Test, AddRemoteCandidates) {
-  CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kDtlsSrtp);
+  jsep_transport_ =
+      CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kDtlsSrtp);
   auto fake_ice_transport = static_cast<FakeIceTransport*>(
       jsep_transport_->rtp_dtls_transport()->ice_transport());
 
@@ -997,4 +1007,237 @@
   EXPECT_EQ(candidates.size(), fake_ice_transport->remote_candidates().size());
 }
 
+enum class Scenario {
+  kSdes,
+  kDtlsBeforeCallerSendOffer,
+  kDtlsBeforeCallerSetAnswer,
+  kDtlsAfterCallerSetAnswer,
+};
+
+class JsepTransport2HeaderExtensionTest
+    : public JsepTransport2Test,
+      public ::testing::WithParamInterface<std::tuple<Scenario, bool>> {
+ protected:
+  JsepTransport2HeaderExtensionTest() {}
+
+  void CreateJsepTransportPair(SrtpMode mode) {
+    jsep_transport1_ = CreateJsepTransport2(/*rtcp_mux_enabled=*/true, mode);
+    jsep_transport2_ = CreateJsepTransport2(/*rtcp_mux_enabled=*/true, mode);
+
+    auto fake_dtls1 =
+        static_cast<FakeDtlsTransport*>(jsep_transport1_->rtp_dtls_transport());
+    auto fake_dtls2 =
+        static_cast<FakeDtlsTransport*>(jsep_transport2_->rtp_dtls_transport());
+
+    fake_dtls1->fake_ice_transport()->SignalReadPacket.connect(
+        this, &JsepTransport2HeaderExtensionTest::OnReadPacket1);
+    fake_dtls2->fake_ice_transport()->SignalReadPacket.connect(
+        this, &JsepTransport2HeaderExtensionTest::OnReadPacket2);
+
+    if (mode == SrtpMode::kDtlsSrtp) {
+      auto cert1 =
+          rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
+              rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
+      jsep_transport1_->rtp_dtls_transport()->SetLocalCertificate(cert1);
+      auto cert2 =
+          rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
+              rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
+      jsep_transport2_->rtp_dtls_transport()->SetLocalCertificate(cert2);
+    }
+  }
+
+  void OnReadPacket1(rtc::PacketTransportInternal* transport,
+                     const char* data,
+                     size_t size,
+                     const rtc::PacketTime& time,
+                     int flags) {
+    RTC_LOG(LS_INFO) << "JsepTransport 1 Received a packet.";
+    CompareHeaderExtensions(
+        reinterpret_cast<const char*>(kPcmuFrameWithExtensions),
+        sizeof(kPcmuFrameWithExtensions), data, size, recv_encrypted_headers1_,
+        false);
+    received_packet_count_++;
+  }
+
+  void OnReadPacket2(rtc::PacketTransportInternal* transport,
+                     const char* data,
+                     size_t size,
+                     const rtc::PacketTime& time,
+                     int flags) {
+    RTC_LOG(LS_INFO) << "JsepTransport 2 Received a packet.";
+    CompareHeaderExtensions(
+        reinterpret_cast<const char*>(kPcmuFrameWithExtensions),
+        sizeof(kPcmuFrameWithExtensions), data, size, recv_encrypted_headers2_,
+        false);
+    received_packet_count_++;
+  }
+
+  void ConnectTransport() {
+    auto rtp_dtls_transport1 =
+        static_cast<FakeDtlsTransport*>(jsep_transport1_->rtp_dtls_transport());
+    auto rtp_dtls_transport2 =
+        static_cast<FakeDtlsTransport*>(jsep_transport2_->rtp_dtls_transport());
+    rtp_dtls_transport1->SetDestination(rtp_dtls_transport2);
+  }
+
+  int GetRtpAuthLen() {
+    bool use_gcm = std::get<1>(GetParam());
+    if (use_gcm) {
+      return 16;
+    }
+    return 10;
+  }
+
+  void TestSendRecvPacketWithEncryptedHeaderExtension() {
+    TestOneWaySendRecvPacketWithEncryptedHeaderExtension(
+        jsep_transport1_.get());
+    TestOneWaySendRecvPacketWithEncryptedHeaderExtension(
+        jsep_transport2_.get());
+  }
+
+  void TestOneWaySendRecvPacketWithEncryptedHeaderExtension(
+      JsepTransport2* sender_transport) {
+    size_t rtp_len = sizeof(kPcmuFrameWithExtensions);
+    size_t packet_size = rtp_len + GetRtpAuthLen();
+    rtc::Buffer rtp_packet_buffer(packet_size);
+    char* rtp_packet_data = rtp_packet_buffer.data<char>();
+    memcpy(rtp_packet_data, kPcmuFrameWithExtensions, rtp_len);
+    // In order to be able to run this test function multiple times we can not
+    // use the same sequence number twice. Increase the sequence number by one.
+    rtc::SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_data) + 2,
+                 ++sequence_number_);
+    rtc::CopyOnWriteBuffer rtp_packet(rtp_packet_data, rtp_len, packet_size);
+
+    int packet_count_before = received_packet_count_;
+    rtc::PacketOptions options;
+    // Send a packet and verify that the packet can be successfully received and
+    // decrypted.
+    ASSERT_TRUE(sender_transport->rtp_transport()->SendRtpPacket(
+        &rtp_packet, options, cricket::PF_SRTP_BYPASS));
+    EXPECT_EQ(packet_count_before + 1, received_packet_count_);
+  }
+
+  int sequence_number_ = 0;
+  int received_packet_count_ = 0;
+  std::unique_ptr<JsepTransport2> jsep_transport1_;
+  std::unique_ptr<JsepTransport2> jsep_transport2_;
+  std::vector<int> recv_encrypted_headers1_;
+  std::vector<int> recv_encrypted_headers2_;
+};
+
+// Test that the encrypted header extension works and can be changed in
+// different scenarios.
+TEST_P(JsepTransport2HeaderExtensionTest, EncryptedHeaderExtensionNegotiation) {
+  Scenario scenario = std::get<0>(GetParam());
+  bool use_gcm = std::get<1>(GetParam());
+  SrtpMode mode = SrtpMode ::kDtlsSrtp;
+  if (scenario == Scenario::kSdes) {
+    mode = SrtpMode::kSdes;
+  }
+  CreateJsepTransportPair(mode);
+  recv_encrypted_headers1_.push_back(kHeaderExtensionIDs[0]);
+  recv_encrypted_headers2_.push_back(kHeaderExtensionIDs[1]);
+
+  cricket::CryptoParams sdes_param(1, rtc::CS_AES_CM_128_HMAC_SHA1_80,
+                                   "inline:" + rtc::CreateRandomString(40),
+                                   std::string());
+  if (use_gcm) {
+    auto fake_dtls1 =
+        static_cast<FakeDtlsTransport*>(jsep_transport1_->rtp_dtls_transport());
+    auto fake_dtls2 =
+        static_cast<FakeDtlsTransport*>(jsep_transport2_->rtp_dtls_transport());
+
+    fake_dtls1->SetSrtpCryptoSuite(rtc::SRTP_AEAD_AES_256_GCM);
+    fake_dtls2->SetSrtpCryptoSuite(rtc::SRTP_AEAD_AES_256_GCM);
+  }
+
+  if (scenario == Scenario::kDtlsBeforeCallerSendOffer) {
+    ConnectTransport();
+  }
+
+  JsepTransportDescription offer_desc;
+  offer_desc.encrypted_header_extension_ids = recv_encrypted_headers1_;
+  if (scenario == Scenario::kSdes) {
+    offer_desc.cryptos.push_back(sdes_param);
+  }
+  ASSERT_TRUE(
+      jsep_transport1_
+          ->SetLocalJsepTransportDescription(offer_desc, SdpType::kOffer)
+          .ok());
+  ASSERT_TRUE(
+      jsep_transport2_
+          ->SetRemoteJsepTransportDescription(offer_desc, SdpType::kOffer)
+          .ok());
+
+  JsepTransportDescription answer_desc;
+  answer_desc.encrypted_header_extension_ids = recv_encrypted_headers2_;
+  if (scenario == Scenario::kSdes) {
+    answer_desc.cryptos.push_back(sdes_param);
+  }
+  ASSERT_TRUE(
+      jsep_transport2_
+          ->SetLocalJsepTransportDescription(answer_desc, SdpType::kAnswer)
+          .ok());
+
+  if (scenario == Scenario::kDtlsBeforeCallerSetAnswer) {
+    ConnectTransport();
+    // Sending packet from transport2 to transport1 should work when they are
+    // partially configured.
+    TestOneWaySendRecvPacketWithEncryptedHeaderExtension(
+        /*sender_transport=*/jsep_transport2_.get());
+  }
+
+  ASSERT_TRUE(
+      jsep_transport1_
+          ->SetRemoteJsepTransportDescription(answer_desc, SdpType::kAnswer)
+          .ok());
+
+  if (scenario == Scenario::kDtlsAfterCallerSetAnswer ||
+      scenario == Scenario::kSdes) {
+    ConnectTransport();
+  }
+  EXPECT_TRUE(jsep_transport1_->rtp_transport()->IsSrtpActive());
+  EXPECT_TRUE(jsep_transport2_->rtp_transport()->IsSrtpActive());
+  TestSendRecvPacketWithEncryptedHeaderExtension();
+
+  // Change the encrypted header extension in a new offer/answer exchange.
+  recv_encrypted_headers1_.clear();
+  recv_encrypted_headers2_.clear();
+  recv_encrypted_headers1_.push_back(kHeaderExtensionIDs[1]);
+  recv_encrypted_headers2_.push_back(kHeaderExtensionIDs[0]);
+  offer_desc.encrypted_header_extension_ids = recv_encrypted_headers1_;
+  answer_desc.encrypted_header_extension_ids = recv_encrypted_headers2_;
+  ASSERT_TRUE(
+      jsep_transport1_
+          ->SetLocalJsepTransportDescription(offer_desc, SdpType::kOffer)
+          .ok());
+  ASSERT_TRUE(
+      jsep_transport2_
+          ->SetRemoteJsepTransportDescription(offer_desc, SdpType::kOffer)
+          .ok());
+  ASSERT_TRUE(
+      jsep_transport2_
+          ->SetLocalJsepTransportDescription(answer_desc, SdpType::kAnswer)
+          .ok());
+  ASSERT_TRUE(
+      jsep_transport1_
+          ->SetRemoteJsepTransportDescription(answer_desc, SdpType::kAnswer)
+          .ok());
+  EXPECT_TRUE(jsep_transport1_->rtp_transport()->IsSrtpActive());
+  EXPECT_TRUE(jsep_transport2_->rtp_transport()->IsSrtpActive());
+  TestSendRecvPacketWithEncryptedHeaderExtension();
+}
+
+INSTANTIATE_TEST_CASE_P(
+    JsepTransport2Test,
+    JsepTransport2HeaderExtensionTest,
+    ::testing::Values(
+        std::make_tuple(Scenario::kSdes, false),
+        std::make_tuple(Scenario::kDtlsBeforeCallerSendOffer, true),
+        std::make_tuple(Scenario::kDtlsBeforeCallerSetAnswer, true),
+        std::make_tuple(Scenario::kDtlsAfterCallerSetAnswer, true),
+        std::make_tuple(Scenario::kDtlsBeforeCallerSendOffer, false),
+        std::make_tuple(Scenario::kDtlsBeforeCallerSetAnswer, false),
+        std::make_tuple(Scenario::kDtlsAfterCallerSetAnswer, false)));
+
 }  // namespace cricket
diff --git a/pc/jseptransport_unittest.cc b/pc/jseptransport_unittest.cc
deleted file mode 100644
index a40312f..0000000
--- a/pc/jseptransport_unittest.cc
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
- *  Copyright 2011 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.
- */
-#include "pc/jseptransport.h"
-
-#include <memory>
-
-#include "p2p/base/fakedtlstransport.h"
-#include "p2p/base/fakeicetransport.h"
-#include "rtc_base/fakesslidentity.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/network.h"
-
-namespace cricket {
-
-using rtc::SocketAddress;
-using webrtc::SdpType;
-
-static const char kIceUfrag1[] = "TESTICEUFRAG0001";
-static const char kIcePwd1[] = "TESTICEPWD00000000000001";
-
-static const char kIceUfrag2[] = "TESTICEUFRAG0002";
-static const char kIcePwd2[] = "TESTICEPWD00000000000002";
-
-TransportDescription MakeTransportDescription(
-    const char* ufrag,
-    const char* pwd,
-    const rtc::scoped_refptr<rtc::RTCCertificate>& cert,
-    ConnectionRole role = CONNECTIONROLE_NONE) {
-  std::unique_ptr<rtc::SSLFingerprint> fingerprint;
-  if (cert) {
-    fingerprint.reset(rtc::SSLFingerprint::CreateFromCertificate(cert));
-  }
-  return TransportDescription(std::vector<std::string>(), ufrag, pwd,
-                              ICEMODE_FULL, role, fingerprint.get());
-}
-
-class JsepTransportTest : public testing::Test, public sigslot::has_slots<> {
- public:
-  JsepTransportTest() { RecreateTransport(); }
-
-  bool SetupFakeTransports(int component) {
-    fake_ice_transports_.emplace_back(
-        new FakeIceTransport(transport_->mid(), component));
-    fake_dtls_transports_.emplace_back(
-        new FakeDtlsTransport(fake_ice_transports_.back().get()));
-    return transport_->AddChannel(fake_dtls_transports_.back().get(),
-                                  component);
-  }
-
-  void DestroyChannel(int component) { transport_->RemoveChannel(component); }
-
-  void RecreateTransport() {
-    transport_.reset(new JsepTransport("test content name", nullptr));
-  }
-
-  bool IceCredentialsChanged(const std::string& old_ufrag,
-                             const std::string& old_pwd,
-                             const std::string& new_ufrag,
-                             const std::string& new_pwd) {
-    return (old_ufrag != new_ufrag) || (old_pwd != new_pwd);
-  }
-
- protected:
-  std::vector<std::unique_ptr<FakeDtlsTransport>> fake_dtls_transports_;
-  std::vector<std::unique_ptr<FakeIceTransport>> fake_ice_transports_;
-  std::unique_ptr<JsepTransport> transport_;
-};
-
-// This test verifies transports are created with proper ICE ufrag/password
-// after a transport description is applied.
-TEST_F(JsepTransportTest, TestIceTransportParameters) {
-  EXPECT_TRUE(SetupFakeTransports(1));
-  TransportDescription local_desc(kIceUfrag1, kIcePwd1);
-  ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc,
-                                                       SdpType::kOffer, NULL));
-  EXPECT_EQ(ICEMODE_FULL, fake_ice_transports_[0]->remote_ice_mode());
-  EXPECT_EQ(kIceUfrag1, fake_ice_transports_[0]->ice_ufrag());
-  EXPECT_EQ(kIcePwd1, fake_ice_transports_[0]->ice_pwd());
-
-  TransportDescription remote_desc(kIceUfrag2, kIcePwd2);
-  ASSERT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_desc, SdpType::kAnswer, NULL));
-  EXPECT_EQ(ICEMODE_FULL, fake_ice_transports_[0]->remote_ice_mode());
-  EXPECT_EQ(kIceUfrag2, fake_ice_transports_[0]->remote_ice_ufrag());
-  EXPECT_EQ(kIcePwd2, fake_ice_transports_[0]->remote_ice_pwd());
-}
-
-// Similarly, test that DTLS parameters are applied after a transport
-// description is applied.
-TEST_F(JsepTransportTest, TestDtlsTransportParameters) {
-  EXPECT_TRUE(SetupFakeTransports(1));
-
-  // Create certificates.
-  rtc::scoped_refptr<rtc::RTCCertificate> local_cert =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("local", rtc::KT_DEFAULT)));
-  rtc::scoped_refptr<rtc::RTCCertificate> remote_cert =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("remote", rtc::KT_DEFAULT)));
-  transport_->SetLocalCertificate(local_cert);
-
-  // Apply offer/answer.
-  TransportDescription local_desc = MakeTransportDescription(
-      kIceUfrag1, kIcePwd1, local_cert, CONNECTIONROLE_ACTPASS);
-  ASSERT_TRUE(transport_->SetLocalTransportDescription(
-      local_desc, SdpType::kOffer, nullptr));
-  TransportDescription remote_desc = MakeTransportDescription(
-      kIceUfrag2, kIcePwd2, remote_cert, CONNECTIONROLE_ACTIVE);
-  ASSERT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_desc, SdpType::kAnswer, nullptr));
-
-  // Verify that SSL role and remote fingerprint were set correctly based on
-  // transport descriptions.
-  rtc::SSLRole role;
-  EXPECT_TRUE(fake_dtls_transports_[0]->GetDtlsRole(&role));
-  EXPECT_EQ(rtc::SSL_SERVER, role);  // Because remote description was "active".
-  EXPECT_EQ(remote_desc.identity_fingerprint->ToString(),
-            fake_dtls_transports_[0]->dtls_fingerprint().ToString());
-}
-
-// Same as above test, but with remote transport description using
-// CONNECTIONROLE_PASSIVE, expecting SSL_CLIENT role.
-TEST_F(JsepTransportTest, TestDtlsTransportParametersWithPassiveAnswer) {
-  EXPECT_TRUE(SetupFakeTransports(1));
-
-  // Create certificates.
-  rtc::scoped_refptr<rtc::RTCCertificate> local_cert =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("local", rtc::KT_DEFAULT)));
-  rtc::scoped_refptr<rtc::RTCCertificate> remote_cert =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("remote", rtc::KT_DEFAULT)));
-  transport_->SetLocalCertificate(local_cert);
-
-  // Apply offer/answer.
-  TransportDescription local_desc = MakeTransportDescription(
-      kIceUfrag1, kIcePwd1, local_cert, CONNECTIONROLE_ACTPASS);
-  ASSERT_TRUE(transport_->SetLocalTransportDescription(
-      local_desc, SdpType::kOffer, nullptr));
-  TransportDescription remote_desc = MakeTransportDescription(
-      kIceUfrag2, kIcePwd2, remote_cert, CONNECTIONROLE_PASSIVE);
-  ASSERT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_desc, SdpType::kAnswer, nullptr));
-
-  // Verify that SSL role and remote fingerprint were set correctly based on
-  // transport descriptions.
-  rtc::SSLRole role;
-  EXPECT_TRUE(fake_dtls_transports_[0]->GetDtlsRole(&role));
-  EXPECT_EQ(rtc::SSL_CLIENT,
-            role);  // Because remote description was "passive".
-  EXPECT_EQ(remote_desc.identity_fingerprint->ToString(),
-            fake_dtls_transports_[0]->dtls_fingerprint().ToString());
-}
-
-// Add two DtlsTransports/IceTransports and make sure parameters are applied to
-// both of them. Applicable when RTP/RTCP are not multiplexed, so they share
-// the same parameters but different connections.
-TEST_F(JsepTransportTest, TestTransportParametersAppliedToTwoComponents) {
-  EXPECT_TRUE(SetupFakeTransports(1));
-  EXPECT_TRUE(SetupFakeTransports(2));
-
-  // Create certificates.
-  rtc::scoped_refptr<rtc::RTCCertificate> local_cert =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("local", rtc::KT_DEFAULT)));
-  rtc::scoped_refptr<rtc::RTCCertificate> remote_cert =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("remote", rtc::KT_DEFAULT)));
-  transport_->SetLocalCertificate(local_cert);
-
-  // Apply offer/answer.
-  TransportDescription local_desc = MakeTransportDescription(
-      kIceUfrag1, kIcePwd1, local_cert, CONNECTIONROLE_ACTPASS);
-  ASSERT_TRUE(transport_->SetLocalTransportDescription(
-      local_desc, SdpType::kOffer, nullptr));
-  TransportDescription remote_desc = MakeTransportDescription(
-      kIceUfrag2, kIcePwd2, remote_cert, CONNECTIONROLE_ACTIVE);
-  ASSERT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_desc, SdpType::kAnswer, nullptr));
-
-  for (int i = 0; i < 1; ++i) {
-    // Verify parameters of ICE transports.
-    EXPECT_EQ(ICEMODE_FULL, fake_ice_transports_[i]->remote_ice_mode());
-    EXPECT_EQ(kIceUfrag1, fake_ice_transports_[i]->ice_ufrag());
-    EXPECT_EQ(kIcePwd1, fake_ice_transports_[i]->ice_pwd());
-    EXPECT_EQ(kIceUfrag2, fake_ice_transports_[i]->remote_ice_ufrag());
-    EXPECT_EQ(kIcePwd2, fake_ice_transports_[i]->remote_ice_pwd());
-    // Verify parameters of DTLS transports.
-    rtc::SSLRole role;
-    EXPECT_TRUE(fake_dtls_transports_[i]->GetDtlsRole(&role));
-    EXPECT_EQ(rtc::SSL_SERVER,
-              role);  // Because remote description was "active".
-    EXPECT_EQ(remote_desc.identity_fingerprint->ToString(),
-              fake_dtls_transports_[i]->dtls_fingerprint().ToString());
-  }
-}
-
-// Verifies that IceCredentialsChanged returns true when either ufrag or pwd
-// changed, and false in other cases.
-TEST_F(JsepTransportTest, TestIceCredentialsChanged) {
-  EXPECT_TRUE(IceCredentialsChanged("u1", "p1", "u2", "p2"));
-  EXPECT_TRUE(IceCredentialsChanged("u1", "p1", "u2", "p1"));
-  EXPECT_TRUE(IceCredentialsChanged("u1", "p1", "u1", "p2"));
-  EXPECT_FALSE(IceCredentialsChanged("u1", "p1", "u1", "p1"));
-}
-
-// Tests SetNeedsIceRestartFlag and NeedsIceRestart, ensuring NeedsIceRestart
-// only starts returning "false" once an ICE restart has been initiated.
-TEST_F(JsepTransportTest, NeedsIceRestart) {
-  // Do initial offer/answer so there's something to restart.
-  TransportDescription local_desc(kIceUfrag1, kIcePwd1);
-  TransportDescription remote_desc(kIceUfrag1, kIcePwd1);
-  ASSERT_TRUE(transport_->SetLocalTransportDescription(
-      local_desc, SdpType::kOffer, nullptr));
-  ASSERT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_desc, SdpType::kAnswer, nullptr));
-
-  // Flag initially should be false.
-  EXPECT_FALSE(transport_->NeedsIceRestart());
-
-  // After setting flag, it should be true.
-  transport_->SetNeedsIceRestartFlag();
-  EXPECT_TRUE(transport_->NeedsIceRestart());
-
-  // Doing an identical offer/answer shouldn't clear the flag.
-  ASSERT_TRUE(transport_->SetLocalTransportDescription(
-      local_desc, SdpType::kOffer, nullptr));
-  ASSERT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_desc, SdpType::kAnswer, nullptr));
-  EXPECT_TRUE(transport_->NeedsIceRestart());
-
-  // Doing an offer/answer that restarts ICE should clear the flag.
-  TransportDescription ice_restart_local_desc(kIceUfrag2, kIcePwd2);
-  TransportDescription ice_restart_remote_desc(kIceUfrag2, kIcePwd2);
-  ASSERT_TRUE(transport_->SetLocalTransportDescription(
-      ice_restart_local_desc, SdpType::kOffer, nullptr));
-  ASSERT_TRUE(transport_->SetRemoteTransportDescription(
-      ice_restart_remote_desc, SdpType::kAnswer, nullptr));
-  EXPECT_FALSE(transport_->NeedsIceRestart());
-}
-
-TEST_F(JsepTransportTest, TestGetStats) {
-  EXPECT_TRUE(SetupFakeTransports(1));
-  TransportStats stats;
-  EXPECT_TRUE(transport_->GetStats(&stats));
-  // Note that this tests the behavior of a FakeIceTransport.
-  ASSERT_EQ(1U, stats.channel_stats.size());
-  EXPECT_EQ(1, stats.channel_stats[0].component);
-  // Set local transport description for FakeTransport before connecting.
-  TransportDescription faketransport_desc(
-      std::vector<std::string>(), rtc::CreateRandomString(ICE_UFRAG_LENGTH),
-      rtc::CreateRandomString(ICE_PWD_LENGTH), ICEMODE_FULL,
-      CONNECTIONROLE_NONE, nullptr);
-  transport_->SetLocalTransportDescription(faketransport_desc, SdpType::kOffer,
-                                           nullptr);
-  EXPECT_TRUE(transport_->GetStats(&stats));
-  ASSERT_EQ(1U, stats.channel_stats.size());
-  EXPECT_EQ(1, stats.channel_stats[0].component);
-}
-
-// Tests that VerifyCertificateFingerprint only returns true when the
-// certificate matches the fingerprint.
-TEST_F(JsepTransportTest, TestVerifyCertificateFingerprint) {
-  std::string error_desc;
-  EXPECT_FALSE(
-      transport_->VerifyCertificateFingerprint(nullptr, nullptr, &error_desc));
-  rtc::KeyType key_types[] = {rtc::KT_RSA, rtc::KT_ECDSA};
-
-  for (auto& key_type : key_types) {
-    rtc::scoped_refptr<rtc::RTCCertificate> certificate =
-        rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-            rtc::SSLIdentity::Generate("testing", key_type)));
-    ASSERT_NE(nullptr, certificate);
-
-    std::string digest_algorithm;
-    ASSERT_TRUE(certificate->ssl_certificate().GetSignatureDigestAlgorithm(
-        &digest_algorithm));
-    ASSERT_FALSE(digest_algorithm.empty());
-    std::unique_ptr<rtc::SSLFingerprint> good_fingerprint(
-        rtc::SSLFingerprint::Create(digest_algorithm, certificate->identity()));
-    ASSERT_NE(nullptr, good_fingerprint);
-
-    EXPECT_TRUE(transport_->VerifyCertificateFingerprint(
-        certificate.get(), good_fingerprint.get(), &error_desc));
-    EXPECT_FALSE(transport_->VerifyCertificateFingerprint(
-        certificate.get(), nullptr, &error_desc));
-    EXPECT_FALSE(transport_->VerifyCertificateFingerprint(
-        nullptr, good_fingerprint.get(), &error_desc));
-
-    rtc::SSLFingerprint bad_fingerprint = *good_fingerprint;
-    bad_fingerprint.digest.AppendData("0", 1);
-    EXPECT_FALSE(transport_->VerifyCertificateFingerprint(
-        certificate.get(), &bad_fingerprint, &error_desc));
-  }
-}
-
-// Tests the logic of DTLS role negotiation for an initial offer/answer.
-TEST_F(JsepTransportTest, DtlsRoleNegotiation) {
-  // Just use the same certificate for both sides; doesn't really matter in a
-  // non end-to-end test.
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
-
-  TransportDescription local_desc =
-      MakeTransportDescription(kIceUfrag1, kIcePwd1, certificate);
-  TransportDescription remote_desc =
-      MakeTransportDescription(kIceUfrag2, kIcePwd2, certificate);
-
-  struct NegotiateRoleParams {
-    ConnectionRole local_role;
-    ConnectionRole remote_role;
-    SdpType local_type;
-    SdpType remote_type;
-  };
-
-  std::string error_desc;
-
-  // Parameters which set the SSL role to SSL_CLIENT.
-  NegotiateRoleParams valid_client_params[] = {
-      {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTPASS, SdpType::kAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTPASS, SdpType::kPrAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_PASSIVE, SdpType::kOffer,
-       SdpType::kAnswer},
-      {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_PASSIVE, SdpType::kOffer,
-       SdpType::kPrAnswer}};
-
-  for (auto& param : valid_client_params) {
-    RecreateTransport();
-    transport_->SetLocalCertificate(certificate);
-
-    local_desc.connection_role = param.local_role;
-    remote_desc.connection_role = param.remote_role;
-
-    // Set the offer first.
-    if (param.local_type == SdpType::kOffer) {
-      EXPECT_TRUE(transport_->SetLocalTransportDescription(
-          local_desc, param.local_type, nullptr));
-      EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-          remote_desc, param.remote_type, nullptr));
-    } else {
-      EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-          remote_desc, param.remote_type, nullptr));
-      EXPECT_TRUE(transport_->SetLocalTransportDescription(
-          local_desc, param.local_type, nullptr));
-    }
-    EXPECT_EQ(rtc::SSL_CLIENT, *transport_->GetSslRole());
-  }
-
-  // Parameters which set the SSL role to SSL_SERVER.
-  NegotiateRoleParams valid_server_params[] = {
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTPASS, SdpType::kAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTPASS, SdpType::kPrAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTIVE, SdpType::kOffer,
-       SdpType::kAnswer},
-      {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTIVE, SdpType::kOffer,
-       SdpType::kPrAnswer}};
-
-  for (auto& param : valid_server_params) {
-    RecreateTransport();
-    transport_->SetLocalCertificate(certificate);
-
-    local_desc.connection_role = param.local_role;
-    remote_desc.connection_role = param.remote_role;
-
-    // Set the offer first.
-    if (param.local_type == SdpType::kOffer) {
-      EXPECT_TRUE(transport_->SetLocalTransportDescription(
-          local_desc, param.local_type, nullptr));
-      EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-          remote_desc, param.remote_type, nullptr));
-    } else {
-      EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-          remote_desc, param.remote_type, nullptr));
-      EXPECT_TRUE(transport_->SetLocalTransportDescription(
-          local_desc, param.local_type, nullptr));
-    }
-    EXPECT_EQ(rtc::SSL_SERVER, *transport_->GetSslRole());
-  }
-
-  // Invalid parameters due to both peers having a duplicate role.
-  NegotiateRoleParams duplicate_params[] = {
-      {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTIVE, SdpType::kAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTPASS, SdpType::kAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_PASSIVE, SdpType::kAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTIVE, SdpType::kPrAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTPASS, SdpType::kPrAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_PASSIVE, SdpType::kPrAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTIVE, SdpType::kOffer,
-       SdpType::kAnswer},
-      {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTPASS, SdpType::kOffer,
-       SdpType::kAnswer},
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_PASSIVE, SdpType::kOffer,
-       SdpType::kAnswer},
-      {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTIVE, SdpType::kOffer,
-       SdpType::kPrAnswer},
-      {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTPASS, SdpType::kOffer,
-       SdpType::kPrAnswer},
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_PASSIVE, SdpType::kOffer,
-       SdpType::kPrAnswer}};
-
-  for (auto& param : duplicate_params) {
-    RecreateTransport();
-    transport_->SetLocalCertificate(certificate);
-
-    local_desc.connection_role = param.local_role;
-    remote_desc.connection_role = param.remote_role;
-
-    // Set the offer first.
-    if (param.local_type == SdpType::kOffer) {
-      EXPECT_TRUE(transport_->SetLocalTransportDescription(
-          local_desc, param.local_type, nullptr));
-      EXPECT_FALSE(transport_->SetRemoteTransportDescription(
-          remote_desc, param.remote_type, nullptr));
-    } else {
-      EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-          remote_desc, param.remote_type, nullptr));
-      EXPECT_FALSE(transport_->SetLocalTransportDescription(
-          local_desc, param.local_type, nullptr));
-    }
-  }
-
-  // Invalid parameters due to the offerer not using ACTPASS.
-  NegotiateRoleParams offerer_without_actpass_params[] = {
-      {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_PASSIVE, SdpType::kAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTIVE, SdpType::kAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_PASSIVE, SdpType::kAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_PASSIVE, SdpType::kPrAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTIVE, SdpType::kPrAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_PASSIVE, SdpType::kPrAnswer,
-       SdpType::kOffer},
-      {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_PASSIVE, SdpType::kOffer,
-       SdpType::kAnswer},
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTIVE, SdpType::kOffer,
-       SdpType::kAnswer},
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTPASS, SdpType::kOffer,
-       SdpType::kAnswer},
-      {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_PASSIVE, SdpType::kOffer,
-       SdpType::kPrAnswer},
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTIVE, SdpType::kOffer,
-       SdpType::kPrAnswer},
-      {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTPASS, SdpType::kOffer,
-       SdpType::kPrAnswer}};
-
-  for (auto& param : offerer_without_actpass_params) {
-    RecreateTransport();
-    transport_->SetLocalCertificate(certificate);
-
-    local_desc.connection_role = param.local_role;
-    remote_desc.connection_role = param.remote_role;
-
-    // Set the offer first.
-    // TODO(deadbeef): Really this should fail as soon as the offer is
-    // attempted to be applied, and not when the answer is applied.
-    if (param.local_type == SdpType::kOffer) {
-      EXPECT_TRUE(transport_->SetLocalTransportDescription(
-          local_desc, param.local_type, nullptr));
-      EXPECT_FALSE(transport_->SetRemoteTransportDescription(
-          remote_desc, param.remote_type, nullptr));
-    } else {
-      EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-          remote_desc, param.remote_type, nullptr));
-      EXPECT_FALSE(transport_->SetLocalTransportDescription(
-          local_desc, param.local_type, nullptr));
-    }
-  }
-}
-
-// Test that a reoffer in the opposite direction is successful as long as the
-// role isn't changing. Doesn't test every possible combination like the test
-// above.
-TEST_F(JsepTransportTest, ValidDtlsReofferFromAnswerer) {
-  // Just use the same certificate for both sides; doesn't really matter in a
-  // non end-to-end test.
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
-  transport_->SetLocalCertificate(certificate);
-
-  TransportDescription local_offer = MakeTransportDescription(
-      kIceUfrag1, kIcePwd1, certificate, CONNECTIONROLE_ACTPASS);
-  TransportDescription remote_answer = MakeTransportDescription(
-      kIceUfrag2, kIcePwd2, certificate, CONNECTIONROLE_ACTIVE);
-
-  EXPECT_TRUE(transport_->SetLocalTransportDescription(
-      local_offer, SdpType::kOffer, nullptr));
-  EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_answer, SdpType::kAnswer, nullptr));
-
-  // We were actpass->active previously, now in the other direction it's
-  // actpass->passive.
-  TransportDescription remote_offer = MakeTransportDescription(
-      kIceUfrag2, kIcePwd2, certificate, CONNECTIONROLE_ACTPASS);
-  TransportDescription local_answer = MakeTransportDescription(
-      kIceUfrag1, kIcePwd1, certificate, CONNECTIONROLE_PASSIVE);
-
-  EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_offer, SdpType::kOffer, nullptr));
-  EXPECT_TRUE(transport_->SetLocalTransportDescription(
-      local_answer, SdpType::kAnswer, nullptr));
-}
-
-// Test that a reoffer in the opposite direction fails if the role changes.
-// Inverse of test above.
-TEST_F(JsepTransportTest, InvalidDtlsReofferFromAnswerer) {
-  // Just use the same certificate for both sides; doesn't really matter in a
-  // non end-to-end test.
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
-  transport_->SetLocalCertificate(certificate);
-
-  TransportDescription local_offer = MakeTransportDescription(
-      kIceUfrag1, kIcePwd1, certificate, CONNECTIONROLE_ACTPASS);
-  TransportDescription remote_answer = MakeTransportDescription(
-      kIceUfrag2, kIcePwd2, certificate, CONNECTIONROLE_ACTIVE);
-
-  EXPECT_TRUE(transport_->SetLocalTransportDescription(
-      local_offer, SdpType::kOffer, nullptr));
-  EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_answer, SdpType::kAnswer, nullptr));
-
-  // Changing role to passive here isn't allowed. Though for some reason this
-  // only fails in SetLocalTransportDescription.
-  TransportDescription remote_offer = MakeTransportDescription(
-      kIceUfrag2, kIcePwd2, certificate, CONNECTIONROLE_PASSIVE);
-  TransportDescription local_answer = MakeTransportDescription(
-      kIceUfrag1, kIcePwd1, certificate, CONNECTIONROLE_ACTIVE);
-
-  EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_offer, SdpType::kOffer, nullptr));
-  EXPECT_FALSE(transport_->SetLocalTransportDescription(
-      local_answer, SdpType::kAnswer, nullptr));
-}
-
-// Test that a remote offer with the current negotiated role can be accepted.
-// This is allowed by dtls-sdp, though we'll never generate such an offer,
-// since JSEP requires generating "actpass".
-TEST_F(JsepTransportTest, RemoteOfferWithCurrentNegotiatedDtlsRole) {
-  // Just use the same certificate in both descriptions; the remote fingerprint
-  // doesn't matter in a non end-to-end test.
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
-  transport_->SetLocalCertificate(certificate);
-
-  TransportDescription remote_desc = MakeTransportDescription(
-      kIceUfrag1, kIcePwd1, certificate, CONNECTIONROLE_ACTPASS);
-  TransportDescription local_desc = MakeTransportDescription(
-      kIceUfrag2, kIcePwd2, certificate, CONNECTIONROLE_ACTIVE);
-
-  // Normal initial offer/answer with "actpass" in the offer and "active" in
-  // the answer.
-  ASSERT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_desc, SdpType::kOffer, nullptr));
-  ASSERT_TRUE(transport_->SetLocalTransportDescription(
-      local_desc, SdpType::kAnswer, nullptr));
-
-  // Sanity check that role was actually negotiated.
-  rtc::Optional<rtc::SSLRole> role = transport_->GetSslRole();
-  ASSERT_TRUE(role);
-  EXPECT_EQ(rtc::SSL_CLIENT, *role);
-
-  // Subsequent offer with current negotiated role of "passive".
-  remote_desc.connection_role = CONNECTIONROLE_PASSIVE;
-  EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_desc, SdpType::kOffer, nullptr));
-  EXPECT_TRUE(transport_->SetLocalTransportDescription(
-      local_desc, SdpType::kAnswer, nullptr));
-}
-
-// Test that a remote offer with the inverse of the current negotiated DTLS
-// role is rejected.
-TEST_F(JsepTransportTest, RemoteOfferThatChangesNegotiatedDtlsRole) {
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
-  std::unique_ptr<rtc::SSLFingerprint> fingerprint(
-      rtc::SSLFingerprint::CreateFromCertificate(certificate));
-  transport_->SetLocalCertificate(certificate);
-
-  TransportDescription local_desc(kIceUfrag1, kIcePwd1);
-  TransportDescription remote_desc(kIceUfrag2, kIcePwd2);
-  // Just use the same fingerprint in both descriptions; the remote fingerprint
-  // doesn't matter in a non end-to-end test.
-  local_desc.identity_fingerprint.reset(
-      TransportDescription::CopyFingerprint(fingerprint.get()));
-  remote_desc.identity_fingerprint.reset(
-      TransportDescription::CopyFingerprint(fingerprint.get()));
-
-  remote_desc.connection_role = CONNECTIONROLE_ACTPASS;
-  local_desc.connection_role = CONNECTIONROLE_ACTIVE;
-
-  // Normal initial offer/answer with "actpass" in the offer and "active" in
-  // the answer.
-  ASSERT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_desc, SdpType::kOffer, nullptr));
-  ASSERT_TRUE(transport_->SetLocalTransportDescription(
-      local_desc, SdpType::kAnswer, nullptr));
-
-  // Sanity check that role was actually negotiated.
-  rtc::Optional<rtc::SSLRole> role = transport_->GetSslRole();
-  ASSERT_TRUE(role);
-  EXPECT_EQ(rtc::SSL_CLIENT, *role);
-
-  // Subsequent offer with "active", which is the opposite of the remote
-  // endpoint's negotiated role.
-  // TODO(deadbeef): Really this should fail as soon as the offer is
-  // attempted to be applied, and not when the answer is applied.
-  remote_desc.connection_role = CONNECTIONROLE_ACTIVE;
-  EXPECT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_desc, SdpType::kOffer, nullptr));
-  EXPECT_FALSE(transport_->SetLocalTransportDescription(
-      local_desc, SdpType::kAnswer, nullptr));
-}
-
-// Testing that a legacy client that doesn't use the setup attribute will be
-// interpreted as having an active role.
-TEST_F(JsepTransportTest, TestDtlsSetupWithLegacyAsAnswerer) {
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
-  std::unique_ptr<rtc::SSLFingerprint> fingerprint(
-      rtc::SSLFingerprint::CreateFromCertificate(certificate));
-  transport_->SetLocalCertificate(certificate);
-
-  TransportDescription local_desc(kIceUfrag1, kIcePwd1);
-  TransportDescription remote_desc(kIceUfrag2, kIcePwd2);
-  // Just use the same fingerprint in both descriptions; the remote fingerprint
-  // doesn't matter in a non end-to-end test.
-  local_desc.identity_fingerprint.reset(
-      TransportDescription::CopyFingerprint(fingerprint.get()));
-  remote_desc.identity_fingerprint.reset(
-      TransportDescription::CopyFingerprint(fingerprint.get()));
-
-  local_desc.connection_role = CONNECTIONROLE_ACTPASS;
-  ASSERT_TRUE(transport_->SetLocalTransportDescription(
-      local_desc, SdpType::kOffer, nullptr));
-  // Use CONNECTIONROLE_NONE to simulate legacy endpoint.
-  remote_desc.connection_role = CONNECTIONROLE_NONE;
-  ASSERT_TRUE(transport_->SetRemoteTransportDescription(
-      remote_desc, SdpType::kAnswer, nullptr));
-
-  rtc::Optional<rtc::SSLRole> role = transport_->GetSslRole();
-  ASSERT_TRUE(role);
-  // Since legacy answer ommitted setup atribute, and we offered actpass, we
-  // should act as passive (server).
-  EXPECT_EQ(rtc::SSL_SERVER, *role);
-}
-
-}  // namespace cricket
diff --git a/pc/jseptransportcontroller.cc b/pc/jseptransportcontroller.cc
index 5235791..1a1fce8 100644
--- a/pc/jseptransportcontroller.cc
+++ b/pc/jseptransportcontroller.cc
@@ -136,7 +136,7 @@
 
 RtpTransportInternal* JsepTransportController::GetRtpTransport(
     const std::string& mid) const {
-  auto jsep_transport = GetJsepTransport(mid);
+  auto jsep_transport = GetJsepTransportForMid(mid);
   if (!jsep_transport) {
     return nullptr;
   }
@@ -145,7 +145,7 @@
 
 cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
     const std::string& mid) const {
-  auto jsep_transport = GetJsepTransport(mid);
+  auto jsep_transport = GetJsepTransportForMid(mid);
   if (!jsep_transport) {
     return nullptr;
   }
@@ -154,7 +154,7 @@
 
 cricket::DtlsTransportInternal* JsepTransportController::GetRtcpDtlsTransport(
     const std::string& mid) const {
-  auto jsep_transport = GetJsepTransport(mid);
+  auto jsep_transport = GetJsepTransportForMid(mid);
   if (!jsep_transport) {
     return nullptr;
   }
@@ -174,14 +174,15 @@
 }
 
 void JsepTransportController::SetNeedsIceRestartFlag() {
-  for (auto& kv : jsep_transports_by_mid_) {
+  for (auto& kv : jsep_transports_by_name_) {
     kv.second->SetNeedsIceRestartFlag();
   }
 }
 
 bool JsepTransportController::NeedsIceRestart(
     const std::string& transport_name) const {
-  const cricket::JsepTransport2* transport = GetJsepTransport(transport_name);
+  const cricket::JsepTransport2* transport =
+      GetJsepTransportByName(transport_name);
   if (!transport) {
     return false;
   }
@@ -189,13 +190,13 @@
 }
 
 rtc::Optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
-    const std::string& transport_name) const {
+    const std::string& mid) const {
   if (!network_thread_->IsCurrent()) {
     return network_thread_->Invoke<rtc::Optional<rtc::SSLRole>>(
-        RTC_FROM_HERE, [&] { return GetDtlsRole(transport_name); });
+        RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
   }
 
-  const cricket::JsepTransport2* t = GetJsepTransport(transport_name);
+  const cricket::JsepTransport2* t = GetJsepTransportForMid(mid);
   if (!t) {
     return rtc::Optional<rtc::SSLRole>();
   }
@@ -218,7 +219,7 @@
   // Set certificate for JsepTransport, which verifies it matches the
   // fingerprint in SDP, and DTLS transport.
   // Fallback from DTLS to SDES is not supported.
-  for (auto& kv : jsep_transports_by_mid_) {
+  for (auto& kv : jsep_transports_by_name_) {
     kv.second->SetLocalCertificate(certificate_);
   }
   for (auto& dtls : GetDtlsTransports()) {
@@ -236,7 +237,7 @@
         RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
   }
 
-  const cricket::JsepTransport2* t = GetJsepTransport(transport_name);
+  const cricket::JsepTransport2* t = GetJsepTransportByName(transport_name);
   if (!t) {
     return nullptr;
   }
@@ -251,10 +252,14 @@
         RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
   }
 
-  // Get the certificate from the RTP channel's DTLS handshake. Should be
-  // identical to the RTCP channel's, since they were given the same remote
+  // Get the certificate from the RTP transport's DTLS handshake. Should be
+  // identical to the RTCP transport's, since they were given the same remote
   // fingerprint.
-  auto dtls = GetDtlsTransport(transport_name);
+  auto jsep_transport = GetJsepTransportByName(transport_name);
+  if (!jsep_transport) {
+    return nullptr;
+  }
+  auto dtls = jsep_transport->rtp_dtls_transport();
   if (!dtls) {
     return nullptr;
   }
@@ -288,13 +293,12 @@
   if (!error.ok()) {
     return error;
   }
-
-  cricket::JsepTransport2* jsep_transport = GetJsepTransport(transport_name);
+  auto jsep_transport = GetJsepTransportByName(transport_name);
   if (!jsep_transport) {
-    return RTCError(RTCErrorType::INVALID_PARAMETER,
-                    "The transport doesn't exist.");
+    RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
+                           "doesn't exist. Ignore it.";
+    return RTCError::OK();
   }
-
   return jsep_transport->AddRemoteCandidates(candidates);
 }
 
@@ -325,10 +329,12 @@
   for (const auto& kv : candidates_by_transport_name) {
     const std::string& transport_name = kv.first;
     const cricket::Candidates& candidates = kv.second;
-    cricket::JsepTransport2* jsep_transport = GetJsepTransport(transport_name);
+    cricket::JsepTransport2* jsep_transport =
+        GetJsepTransportByName(transport_name);
     if (!jsep_transport) {
-      return RTCError(RTCErrorType::INVALID_PARAMETER,
-                      "The transport doesn't exist.");
+      RTC_LOG(LS_WARNING)
+          << "Not removing candidate because the JsepTransport doesn't exist.";
+      continue;
     }
     for (const cricket::Candidate& candidate : candidates) {
       auto dtls = candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
@@ -349,7 +355,7 @@
         RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
   }
 
-  cricket::JsepTransport2* transport = GetJsepTransport(transport_name);
+  cricket::JsepTransport2* transport = GetJsepTransportByName(transport_name);
   if (!transport) {
     return false;
   }
@@ -427,23 +433,27 @@
     rtc::PacketTransportInternal* rtp_packet_transport,
     rtc::PacketTransportInternal* rtcp_packet_transport) {
   RTC_DCHECK(network_thread_->IsCurrent());
-  // TODO(zhihuang): Add support of unencrypted RTP for testing.
-  return nullptr;
+  auto unencrypted_rtp_transport =
+      rtc::MakeUnique<RtpTransport>(rtcp_packet_transport == nullptr);
+  unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
+  if (rtcp_packet_transport) {
+    unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
+  }
+  return unencrypted_rtp_transport;
 }
 
 std::unique_ptr<webrtc::SrtpTransport>
 JsepTransportController::CreateSdesTransport(
     const std::string& transport_name,
-    rtc::PacketTransportInternal* rtp_packet_transport,
-    rtc::PacketTransportInternal* rtcp_packet_transport) {
+    cricket::DtlsTransportInternal* rtp_dtls_transport,
+    cricket::DtlsTransportInternal* rtcp_dtls_transport) {
   RTC_DCHECK(network_thread_->IsCurrent());
-  bool rtcp_mux_enabled = rtcp_packet_transport == nullptr;
   auto srtp_transport =
-      rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_mux_enabled);
-  RTC_DCHECK(rtp_packet_transport);
-  srtp_transport->SetRtpPacketTransport(rtp_packet_transport);
-  if (rtcp_packet_transport) {
-    srtp_transport->SetRtcpPacketTransport(rtp_packet_transport);
+      rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
+  RTC_DCHECK(rtp_dtls_transport);
+  srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
+  if (rtcp_dtls_transport) {
+    srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
   }
   if (config_.enable_external_auth) {
     srtp_transport->EnableExternalAuth();
@@ -457,9 +467,8 @@
     cricket::DtlsTransportInternal* rtp_dtls_transport,
     cricket::DtlsTransportInternal* rtcp_dtls_transport) {
   RTC_DCHECK(network_thread_->IsCurrent());
-  bool rtcp_mux_enabled = rtcp_dtls_transport == nullptr;
   auto srtp_transport =
-      rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_mux_enabled);
+      rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
   if (config_.enable_external_auth) {
     srtp_transport->EnableExternalAuth();
   }
@@ -475,8 +484,8 @@
 std::vector<cricket::DtlsTransportInternal*>
 JsepTransportController::GetDtlsTransports() {
   std::vector<cricket::DtlsTransportInternal*> dtls_transports;
-  for (auto it = jsep_transports_by_mid_.begin();
-       it != jsep_transports_by_mid_.end(); ++it) {
+  for (auto it = jsep_transports_by_name_.begin();
+       it != jsep_transports_by_name_.end(); ++it) {
     auto jsep_transport = it->second.get();
     RTC_DCHECK(jsep_transport);
     if (jsep_transport->rtp_dtls_transport()) {
@@ -535,7 +544,18 @@
   }
 
   if (ShouldUpdateBundleGroup(type, description)) {
-    bundle_group_ = *description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
+    if (!description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
+      return RTCError(RTCErrorType::INVALID_PARAMETER,
+                      "max-bundle is used but no bundle group found.");
+    } else {
+      bundle_group_ = *description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
+    }
+  }
+
+  RTCError error;
+  error = ValidateBundleGroup(description);
+  if (!error.ok()) {
+    return error;
   }
 
   std::vector<int> merged_encrypted_extension_ids;
@@ -550,7 +570,10 @@
         (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
       continue;
     }
-    MaybeCreateJsepTransport(content_info.name, content_info);
+    error = MaybeCreateJsepTransport(content_info.name, content_info);
+    if (!error.ok()) {
+      return error;
+    }
   }
 
   RTC_DCHECK(description->contents().size() ==
@@ -569,6 +592,11 @@
       continue;
     }
 
+    error = ValidateContent(content_info);
+    if (!error.ok()) {
+      return error;
+    }
+
     std::vector<int> extension_ids;
     if (bundle_group_ && content_info.name == *bundled_mid()) {
       extension_ids = merged_encrypted_extension_ids;
@@ -576,15 +604,18 @@
       extension_ids = GetEncryptedHeaderExtensionIds(content_info);
     }
 
-    cricket::JsepTransport2* transport = GetJsepTransport(content_info.name);
+    int rtp_abs_sendtime_extn_id =
+        GetRtpAbsSendTimeHeaderExtensionId(content_info);
+
+    cricket::JsepTransport2* transport =
+        GetJsepTransportForMid(content_info.name);
     RTC_DCHECK(transport);
 
     SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
 
-    RTCError error;
     cricket::JsepTransportDescription jsep_description =
         CreateJsepTransportDescription(content_info, transport_info,
-                                       extension_ids);
+                                       extension_ids, rtp_abs_sendtime_extn_id);
     if (local) {
       error =
           transport->SetLocalJsepTransportDescription(jsep_description, type);
@@ -602,6 +633,51 @@
   return RTCError::OK();
 }
 
+RTCError JsepTransportController::ValidateBundleGroup(
+    const cricket::SessionDescription* description) {
+  RTC_DCHECK(description);
+
+  if (!bundled_mid()) {
+    return RTCError::OK();
+  }
+
+  auto bundled_content = description->GetContentByName(*bundled_mid());
+  if (!bundled_content) {
+    return RTCError(
+        RTCErrorType::INVALID_PARAMETER,
+        "An m= section associated with the BUNDLE-tag doesn't exist.");
+  }
+
+  // If the |bundled_content| is rejected, other contents in the bundle group
+  // should be rejected.
+  if (bundled_content->rejected) {
+    for (auto content_name : bundle_group_->content_names()) {
+      auto other_content = description->GetContentByName(content_name);
+      if (!other_content->rejected) {
+        return RTCError(
+            RTCErrorType::INVALID_PARAMETER,
+            "The m= section:" + content_name + " should be rejected.");
+      }
+    }
+  }
+
+  return RTCError::OK();
+}
+
+RTCError JsepTransportController::ValidateContent(
+    const cricket::ContentInfo& content_info) {
+  if (config_.rtcp_mux_policy ==
+          PeerConnectionInterface::kRtcpMuxPolicyRequire &&
+      content_info.type == cricket::MediaProtocolType::kRtp &&
+      !content_info.media_description()->rtcp_mux()) {
+    return RTCError(RTCErrorType::INVALID_PARAMETER,
+                    "The m= section:" + content_info.name +
+                        " is invalid. RTCP-MUX is not "
+                        "enabled when it is required.");
+  }
+  return RTCError::OK();
+}
+
 void JsepTransportController::HandleRejectedContent(
     const cricket::ContentInfo& content_info) {
   // If the content is rejected, let the
@@ -612,9 +688,24 @@
   } else {
     SignalDtlsTransportChanged(content_info.name, nullptr);
   }
-  // Remove the rejected content from the |bundle_group_|.
-  if (IsBundled(content_info.name)) {
+  // If the answerer rejects the first content, which other contents are bundled
+  // on, all the other contents in the bundle group will be rejected.
+  if (content_info.name == bundled_mid()) {
+    for (auto content_name : bundle_group_->content_names()) {
+      if (content_info.type == cricket::MediaProtocolType::kRtp) {
+        SignalRtpTransportChanged(content_name, nullptr);
+      } else {
+        SignalDtlsTransportChanged(content_name, nullptr);
+      }
+    }
+    bundle_group_.reset();
+  } else if (IsBundled(content_info.name)) {
+    // Remove the rejected content from the |bundle_group_|.
     bundle_group_->RemoveContentName(content_info.name);
+    // Reset the bundle group if nothing left.
+    if (!bundle_group_->FirstContentName()) {
+      bundle_group_.reset();
+    }
   }
   MaybeDestroyJsepTransport(content_info.name);
 }
@@ -626,11 +717,11 @@
   // then destroy the cricket::JsepTransport2.
   if (content_info.type == cricket::MediaProtocolType::kRtp) {
     auto rtp_transport =
-        jsep_transports_by_mid_[*bundled_mid()]->rtp_transport();
+        jsep_transports_by_name_[*bundled_mid()]->rtp_transport();
     SignalRtpTransportChanged(content_info.name, rtp_transport);
   } else {
     auto dtls_transport =
-        jsep_transports_by_mid_[*bundled_mid()]->rtp_dtls_transport();
+        jsep_transports_by_name_[*bundled_mid()]->rtp_dtls_transport();
     SignalDtlsTransportChanged(content_info.name, dtls_transport);
   }
   MaybeDestroyJsepTransport(content_info.name);
@@ -640,7 +731,8 @@
 JsepTransportController::CreateJsepTransportDescription(
     cricket::ContentInfo content_info,
     cricket::TransportInfo transport_info,
-    const std::vector<int>& encrypted_extension_ids) {
+    const std::vector<int>& encrypted_extension_ids,
+    int rtp_abs_sendtime_extn_id) {
   const cricket::MediaContentDescription* content_desc =
       static_cast<const cricket::MediaContentDescription*>(
           content_info.description);
@@ -651,7 +743,7 @@
 
   return cricket::JsepTransportDescription(
       rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
-      transport_info.description);
+      rtp_abs_sendtime_extn_id, transport_info.description);
 }
 
 bool JsepTransportController::ShouldUpdateBundleGroup(
@@ -721,47 +813,79 @@
   return merged_ids;
 }
 
-const cricket::JsepTransport2* JsepTransportController::GetJsepTransport(
-    const std::string& mid) const {
-  auto target_mid = mid;
-  if (IsBundled(mid)) {
-    target_mid = *bundled_mid();
-  }
-  auto it = jsep_transports_by_mid_.find(target_mid);
-  return (it == jsep_transports_by_mid_.end()) ? nullptr : it->second.get();
-}
-
-cricket::JsepTransport2* JsepTransportController::GetJsepTransport(
-    const std::string& mid) {
-  auto target_mid = mid;
-  if (IsBundled(mid)) {
-    target_mid = *bundled_mid();
-  }
-  auto it = jsep_transports_by_mid_.find(target_mid);
-  return (it == jsep_transports_by_mid_.end()) ? nullptr : it->second.get();
-}
-
-void JsepTransportController::MaybeCreateJsepTransport(
-    const std::string& mid,
+int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
     const cricket::ContentInfo& content_info) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  cricket::JsepTransport2* transport = GetJsepTransport(mid);
-  if (transport) {
-    return;
+  if (!config_.enable_external_auth) {
+    return -1;
   }
 
   const cricket::MediaContentDescription* content_desc =
       static_cast<const cricket::MediaContentDescription*>(
           content_info.description);
-  bool rtcp_mux_enabled =
-      content_desc->rtcp_mux() ||
-      config_.rtcp_mux_policy == PeerConnectionInterface::kRtcpMuxPolicyRequire;
+
+  const webrtc::RtpExtension* send_time_extension =
+      webrtc::RtpExtension::FindHeaderExtensionByUri(
+          content_desc->rtp_header_extensions(),
+          webrtc::RtpExtension::kAbsSendTimeUri);
+  return send_time_extension ? send_time_extension->id : -1;
+}
+
+const cricket::JsepTransport2* JsepTransportController::GetJsepTransportForMid(
+    const std::string& mid) const {
+  auto target_mid = mid;
+  if (IsBundled(mid)) {
+    target_mid = *bundled_mid();
+  }
+  auto it = jsep_transports_by_name_.find(target_mid);
+  return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
+}
+
+cricket::JsepTransport2* JsepTransportController::GetJsepTransportForMid(
+    const std::string& mid) {
+  auto target_mid = mid;
+  if (IsBundled(mid)) {
+    target_mid = *bundled_mid();
+  }
+  auto it = jsep_transports_by_name_.find(target_mid);
+  return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
+}
+
+const cricket::JsepTransport2* JsepTransportController::GetJsepTransportByName(
+    const std::string& transport_name) const {
+  auto it = jsep_transports_by_name_.find(transport_name);
+  return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
+}
+
+cricket::JsepTransport2* JsepTransportController::GetJsepTransportByName(
+    const std::string& transport_name) {
+  auto it = jsep_transports_by_name_.find(transport_name);
+  return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
+}
+
+RTCError JsepTransportController::MaybeCreateJsepTransport(
+    const std::string& mid,
+    const cricket::ContentInfo& content_info) {
+  RTC_DCHECK(network_thread_->IsCurrent());
+  cricket::JsepTransport2* transport = GetJsepTransportForMid(mid);
+  if (transport) {
+    return RTCError::OK();
+  }
+
+  const cricket::MediaContentDescription* content_desc =
+      static_cast<const cricket::MediaContentDescription*>(
+          content_info.description);
+  if (certificate_ && !content_desc->cryptos().empty()) {
+    return RTCError(RTCErrorType::INVALID_PARAMETER,
+                    "SDES and DTLS-SRTP cannot be enabled at the same time.");
+  }
+
   std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
-      CreateDtlsTransport(mid, /*rtcp = */ false);
+      CreateDtlsTransport(mid, /*rtcp =*/false);
   std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
-  if (!rtcp_mux_enabled) {
-    rtcp_dtls_transport = CreateDtlsTransport(mid, /*rtcp = */ true);
+  if (config_.rtcp_mux_policy !=
+          PeerConnectionInterface::kRtcpMuxPolicyRequire &&
+      content_info.type == cricket::MediaProtocolType::kRtp) {
+    rtcp_dtls_transport = CreateDtlsTransport(mid, /*rtcp =*/true);
   }
 
   std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
@@ -785,19 +909,21 @@
           std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport));
   jsep_transport->SignalRtcpMuxActive.connect(
       this, &JsepTransportController::UpdateAggregateStates_n);
-  jsep_transports_by_mid_[mid] = std::move(jsep_transport);
+  jsep_transports_by_name_[mid] = std::move(jsep_transport);
   UpdateAggregateStates_n();
+
+  return RTCError::OK();
 }
 
 void JsepTransportController::MaybeDestroyJsepTransport(
     const std::string& mid) {
-  jsep_transports_by_mid_.erase(mid);
+  jsep_transports_by_name_.erase(mid);
   UpdateAggregateStates_n();
 }
 
 void JsepTransportController::DestroyAllJsepTransports_n() {
   RTC_DCHECK(network_thread_->IsCurrent());
-  jsep_transports_by_mid_.clear();
+  jsep_transports_by_name_.clear();
 }
 
 void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
@@ -871,7 +997,7 @@
         jsep_transport->local_description()->transport_desc.ice_mode ==
             cricket::ICEMODE_LITE &&
         ice_role_ == cricket::ICEROLE_CONTROLLING &&
-        tdesc.ice_mode == cricket::ICEMODE_LITE) {
+        tdesc.ice_mode == cricket::ICEMODE_FULL) {
       ice_role = cricket::ICEROLE_CONTROLLED;
     }
   }
diff --git a/pc/jseptransportcontroller.h b/pc/jseptransportcontroller.h
index fffdd33..f533cf8 100644
--- a/pc/jseptransportcontroller.h
+++ b/pc/jseptransportcontroller.h
@@ -135,6 +135,7 @@
   bool GetStats(const std::string& mid, cricket::TransportStats* stats);
   void SetMetricsObserver(webrtc::MetricsObserverInterface* metrics_observer);
 
+  bool initial_offerer() const { return initial_offerer_ && *initial_offerer_; }
   // All of these signals are fired on the signaling thread.
 
   // If any transport failed => failed,
@@ -176,6 +177,8 @@
   RTCError ApplyDescription_n(bool local,
                               SdpType type,
                               const cricket::SessionDescription* description);
+  RTCError ValidateBundleGroup(const cricket::SessionDescription* description);
+  RTCError ValidateContent(const cricket::ContentInfo& content_info);
 
   void HandleRejectedContent(const cricket::ContentInfo& content_info);
   void HandleBundledContent(const cricket::ContentInfo& content_info);
@@ -183,7 +186,8 @@
   cricket::JsepTransportDescription CreateJsepTransportDescription(
       cricket::ContentInfo content_info,
       cricket::TransportInfo transport_info,
-      const std::vector<int>& encrypted_extension_ids);
+      const std::vector<int>& encrypted_extension_ids,
+      int rtp_abs_sendtime_extn_id);
 
   rtc::Optional<std::string> bundled_mid() const {
     rtc::Optional<std::string> bundled_mid;
@@ -202,15 +206,29 @@
 
   std::vector<int> MergeEncryptedHeaderExtensionIdsForBundle(
       const cricket::SessionDescription* description);
-
   std::vector<int> GetEncryptedHeaderExtensionIds(
       const cricket::ContentInfo& content_info);
 
-  const cricket::JsepTransport2* GetJsepTransport(const std::string& mid) const;
-  cricket::JsepTransport2* GetJsepTransport(const std::string& mid);
+  int GetRtpAbsSendTimeHeaderExtensionId(
+      const cricket::ContentInfo& content_info);
 
-  void MaybeCreateJsepTransport(const std::string& mid,
-                                const cricket::ContentInfo& content_info);
+  // This method takes the BUNDLE group into account. If the JsepTransport is
+  // destroyed because of BUNDLE, it would return the transport which other
+  // transports are bundled on (In current implementation, it is the first
+  // content in the BUNDLE group).
+  const cricket::JsepTransport2* GetJsepTransportForMid(
+      const std::string& mid) const;
+  cricket::JsepTransport2* GetJsepTransportForMid(const std::string& mid);
+
+  // Get the JsepTransport without considering the BUNDLE group. Return nullptr
+  // if the JsepTransport is destroyed.
+  const cricket::JsepTransport2* GetJsepTransportByName(
+      const std::string& transport_name) const;
+  cricket::JsepTransport2* GetJsepTransportByName(
+      const std::string& transport_name);
+
+  RTCError MaybeCreateJsepTransport(const std::string& mid,
+                                    const cricket::ContentInfo& content_info);
   void MaybeDestroyJsepTransport(const std::string& mid);
   void DestroyAllJsepTransports_n();
 
@@ -232,8 +250,8 @@
       rtc::PacketTransportInternal* rtcp_packet_transport);
   std::unique_ptr<webrtc::SrtpTransport> CreateSdesTransport(
       const std::string& transport_name,
-      rtc::PacketTransportInternal* rtp_packet_transport,
-      rtc::PacketTransportInternal* rtcp_packet_transport);
+      cricket::DtlsTransportInternal* rtp_dtls_transport,
+      cricket::DtlsTransportInternal* rtcp_dtls_transport);
   std::unique_ptr<webrtc::DtlsSrtpTransport> CreateDtlsSrtpTransport(
       const std::string& transport_name,
       cricket::DtlsTransportInternal* rtp_dtls_transport,
@@ -265,9 +283,9 @@
   cricket::PortAllocator* const port_allocator_ = nullptr;
 
   std::map<std::string, std::unique_ptr<cricket::JsepTransport2>>
-      jsep_transports_by_mid_;
+      jsep_transports_by_name_;
 
-  // Aggregate state for TransportChannelImpls.
+  // Aggregate state for Transports.
   cricket::IceConnectionState ice_connection_state_ =
       cricket::kIceConnectionConnecting;
   cricket::IceGatheringState ice_gathering_state_ = cricket::kIceGatheringNew;
diff --git a/pc/jseptransportcontroller_unittest.cc b/pc/jseptransportcontroller_unittest.cc
index 78f4986..73af35d 100644
--- a/pc/jseptransportcontroller_unittest.cc
+++ b/pc/jseptransportcontroller_unittest.cc
@@ -123,6 +123,8 @@
                        rtc::scoped_refptr<rtc::RTCCertificate> cert) {
     std::unique_ptr<cricket::AudioContentDescription> audio(
         new cricket::AudioContentDescription());
+    // Set RTCP-mux to be true because the default policy is "mux required".
+    audio->set_rtcp_mux(true);
     description->AddContent(mid, cricket::MediaProtocolType::kRtp,
                             /*rejected=*/false, audio.release());
     AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
@@ -137,6 +139,8 @@
                        rtc::scoped_refptr<rtc::RTCCertificate> cert) {
     std::unique_ptr<cricket::VideoContentDescription> video(
         new cricket::VideoContentDescription());
+    // Set RTCP-mux to be true because the default policy is "mux required".
+    video->set_rtcp_mux(true);
     description->AddContent(mid, cricket::MediaProtocolType::kRtp,
                             /*rejected=*/false, video.release());
     AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
@@ -152,6 +156,7 @@
                       rtc::scoped_refptr<rtc::RTCCertificate> cert) {
     std::unique_ptr<cricket::DataContentDescription> data(
         new cricket::DataContentDescription());
+    data->set_rtcp_mux(true);
     description->AddContent(mid, protocol_type,
                             /*rejected=*/false, data.release());
     AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
@@ -325,6 +330,20 @@
   EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
 }
 
+TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
+  JsepTransportController::Config config;
+  config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
+  CreateJsepTransportController(config);
+  auto description = CreateSessionDescriptionWithoutBundle();
+  EXPECT_TRUE(transport_controller_
+                  ->SetLocalDescription(SdpType::kOffer, description.get())
+                  .ok());
+  EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
+  EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
+  EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
+  EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
+}
+
 TEST_F(JsepTransportControllerTest, SetIceConfig) {
   CreateJsepTransportController(JsepTransportController::Config());
   auto description = CreateSessionDescriptionWithoutBundle();
@@ -1207,5 +1226,103 @@
                    ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
                    .ok());
 }
+// Test that rejecting only the first m= section of a BUNDLE group is treated as
+// an error, but rejecting all of them works as expected.
+TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
+  CreateJsepTransportController(JsepTransportController::Config());
+  cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
+  bundle_group.AddContentName(kAudioMid1);
+  bundle_group.AddContentName(kVideoMid1);
+  bundle_group.AddContentName(kDataMid1);
+
+  auto local_offer = rtc::MakeUnique<cricket::SessionDescription>();
+  AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
+                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
+                  nullptr);
+  AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
+                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
+                  nullptr);
+  AddDataSection(local_offer.get(), kDataMid1,
+                 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
+                 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
+                 nullptr);
+
+  auto remote_answer = rtc::MakeUnique<cricket::SessionDescription>();
+  AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
+                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
+                  nullptr);
+  AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
+                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
+                  nullptr);
+  AddDataSection(remote_answer.get(), kDataMid1,
+                 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
+                 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
+                 nullptr);
+  // Reject audio content in answer.
+  remote_answer->contents()[0].rejected = true;
+
+  local_offer->AddGroup(bundle_group);
+  remote_answer->AddGroup(bundle_group);
+
+  EXPECT_TRUE(transport_controller_
+                  ->SetLocalDescription(SdpType::kOffer, local_offer.get())
+                  .ok());
+  EXPECT_FALSE(transport_controller_
+                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
+                   .ok());
+
+  // Reject all the contents.
+  remote_answer->contents()[1].rejected = true;
+  remote_answer->contents()[2].rejected = true;
+  EXPECT_TRUE(transport_controller_
+                  ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
+                  .ok());
+  EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
+  EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
+  EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
+}
+
+// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
+// is used.
+TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
+  JsepTransportController::Config config;
+  config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
+  CreateJsepTransportController(config);
+  auto local_offer = rtc::MakeUnique<cricket::SessionDescription>();
+  AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
+                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
+                  nullptr);
+
+  local_offer->contents()[0].media_description()->set_rtcp_mux(false);
+  // Applying a non-RTCP-mux offer is expected to fail.
+  EXPECT_FALSE(transport_controller_
+                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
+                   .ok());
+}
+
+// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
+// is used.
+TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
+  JsepTransportController::Config config;
+  config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
+  CreateJsepTransportController(config);
+  auto local_offer = rtc::MakeUnique<cricket::SessionDescription>();
+  AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
+                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
+                  nullptr);
+  EXPECT_TRUE(transport_controller_
+                  ->SetLocalDescription(SdpType::kOffer, local_offer.get())
+                  .ok());
+
+  auto remote_answer = rtc::MakeUnique<cricket::SessionDescription>();
+  AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
+                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
+                  nullptr);
+  // Applying a non-RTCP-mux answer is expected to fail.
+  remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
+  EXPECT_FALSE(transport_controller_
+                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
+                   .ok());
+}
 
 }  // namespace webrtc
diff --git a/pc/mediasession.h b/pc/mediasession.h
index 9b118e1..72a756a 100644
--- a/pc/mediasession.h
+++ b/pc/mediasession.h
@@ -22,7 +22,7 @@
 #include "media/base/mediaconstants.h"
 #include "media/base/mediaengine.h"  // For DataChannelType
 #include "p2p/base/transportdescriptionfactory.h"
-#include "pc/jseptransport.h"
+#include "pc/jseptransport2.h"
 #include "pc/sessiondescription.h"
 
 namespace cricket {
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index eacfb83..ca54c44 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -89,7 +89,6 @@
     "Couldn't set up DTLS-SRTP on RTP channel.";
 const char kDtlsSrtpSetupFailureRtcp[] =
     "Couldn't set up DTLS-SRTP on RTCP channel.";
-const char kEnableBundleFailed[] = "Failed to enable BUNDLE.";
 
 namespace {
 
@@ -907,25 +906,40 @@
     return false;
   }
 
+  const PeerConnectionFactoryInterface::Options& options = factory_->options();
+
   // RFC 3264: The numeric value of the session id and version in the
   // o line MUST be representable with a "64 bit signed integer".
   // Due to this constraint session id |session_id_| is max limited to
   // LLONG_MAX.
   session_id_ = rtc::ToString(rtc::CreateRandomId64() & LLONG_MAX);
-  transport_controller_.reset(factory_->CreateTransportController(
-      port_allocator_.get(), configuration.redetermine_role_on_ice_restart,
-      event_log_.get()));
-  transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLED);
-  transport_controller_->SignalConnectionState.connect(
+  JsepTransportController::Config config;
+  config.redetermine_role_on_ice_restart =
+      configuration.redetermine_role_on_ice_restart;
+  config.ssl_max_version = factory_->options().ssl_max_version;
+  config.disable_encryption = options.disable_encryption;
+  config.bundle_policy = configuration.bundle_policy;
+  config.rtcp_mux_policy = configuration.rtcp_mux_policy;
+  config.crypto_options = options.crypto_options;
+#if defined(ENABLE_EXTERNAL_AUTH)
+  config.enable_external_auth = true;
+#endif
+  transport_controller_.reset(new JsepTransportController(
+      signaling_thread(), network_thread(), port_allocator_.get(), config));
+  transport_controller_->SignalIceConnectionState.connect(
       this, &PeerConnection::OnTransportControllerConnectionState);
-  transport_controller_->SignalGatheringState.connect(
+  transport_controller_->SignalIceGatheringState.connect(
       this, &PeerConnection::OnTransportControllerGatheringState);
-  transport_controller_->SignalCandidatesGathered.connect(
+  transport_controller_->SignalIceCandidatesGathered.connect(
       this, &PeerConnection::OnTransportControllerCandidatesGathered);
-  transport_controller_->SignalCandidatesRemoved.connect(
+  transport_controller_->SignalIceCandidatesRemoved.connect(
       this, &PeerConnection::OnTransportControllerCandidatesRemoved);
   transport_controller_->SignalDtlsHandshakeError.connect(
       this, &PeerConnection::OnTransportControllerDtlsHandshakeError);
+  transport_controller_->SignalRtpTransportChanged.connect(
+      this, &PeerConnection::OnRtpTransportChanged);
+  transport_controller_->SignalDtlsTransportChanged.connect(
+      this, &PeerConnection::OnDtlsTransportChanged);
 
   sctp_factory_ = factory_->CreateSctpTransportInternalFactory();
 
@@ -934,10 +948,6 @@
 
   configuration_ = configuration;
 
-  const PeerConnectionFactoryInterface::Options& options = factory_->options();
-
-  transport_controller_->SetSslMaxProtocolVersion(options.ssl_max_version);
-
   // Obtain a certificate from RTCConfiguration if any were provided (optional).
   rtc::scoped_refptr<rtc::RTCCertificate> certificate;
   if (!configuration.certificates.empty()) {
@@ -1975,17 +1985,6 @@
   // streams that might be removed by updating the session description.
   stats_->UpdateStats(kStatsOutputLevelStandard);
 
-  // Update the initial_offerer flag if this session is the initial_offerer.
-  SdpType type = desc->GetType();
-  if (!initial_offerer_.has_value()) {
-    initial_offerer_.emplace(type == SdpType::kOffer);
-    if (*initial_offerer_) {
-      transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING);
-    } else {
-      transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLED);
-    }
-  }
-
   // Take a reference to the old local description since it's used below to
   // compare against the new local description. When setting the new local
   // description, grab ownership of the replaced session description in case it
@@ -1994,6 +1993,7 @@
   const SessionDescriptionInterface* old_local_description =
       local_description();
   std::unique_ptr<SessionDescriptionInterface> replaced_local_description;
+  SdpType type = desc->GetType();
   if (type == SdpType::kAnswer) {
     replaced_local_description = pending_local_description_
                                      ? std::move(pending_local_description_)
@@ -2009,6 +2009,11 @@
   // |local_description()|.
   RTC_DCHECK(local_description());
 
+  RTCError error = PushdownTransportDescription(cricket::CS_LOCAL, type);
+  if (!error.ok()) {
+    return error;
+  }
+
   if (IsUnifiedPlan()) {
     RTCError error = UpdateTransceiversAndDataChannels(
         cricket::CS_LOCAL, *local_description(), old_local_description,
@@ -2031,7 +2036,8 @@
       }
     }
   } else {
-    // Transport and Media channels will be created only when offer is set.
+    // Media channels will be created only when offer is set. These may use new
+    // transports just created by PushdownTransportDescription.
     if (type == SdpType::kOffer) {
       // TODO(bugs.webrtc.org/4676) - Handle CreateChannel failure, as new local
       // description is applied. Restore back to old description.
@@ -2040,12 +2046,12 @@
         return error;
       }
     }
-
     // Remove unused channels if MediaContentDescription is rejected.
     RemoveUnusedChannels(local_description()->description());
   }
 
-  RTCError error = UpdateSessionState(type, cricket::CS_LOCAL);
+  error = UpdateSessionState(type, cricket::CS_LOCAL,
+                             local_description()->description());
   if (!error.ok()) {
     return error;
   }
@@ -2246,6 +2252,10 @@
   // |remote_description()|.
   RTC_DCHECK(remote_description());
 
+  RTCError error = PushdownTransportDescription(cricket::CS_REMOTE, type);
+  if (!error.ok()) {
+    return error;
+  }
   // Transport and Media channels will be created only when offer is set.
   if (IsUnifiedPlan()) {
     RTCError error = UpdateTransceiversAndDataChannels(
@@ -2255,22 +2265,24 @@
       return error;
     }
   } else {
+    // Media channels will be created only when offer is set. These may use new
+    // transports just created by PushdownTransportDescription.
     if (type == SdpType::kOffer) {
-      // TODO(bugs.webrtc.org/4676) - Handle CreateChannel failure, as new local
+      // TODO(mallinath) - Handle CreateChannel failure, as new local
       // description is applied. Restore back to old description.
       RTCError error = CreateChannels(*remote_description()->description());
       if (!error.ok()) {
         return error;
       }
     }
-
     // Remove unused channels if MediaContentDescription is rejected.
     RemoveUnusedChannels(remote_description()->description());
   }
 
-  // NOTE: Candidates allocation will be initiated only when SetLocalDescription
-  // is called.
-  RTCError error = UpdateSessionState(type, cricket::CS_REMOTE);
+  // NOTE: Candidates allocation will be initiated only when
+  // SetLocalDescription is called.
+  error = UpdateSessionState(type, cricket::CS_REMOTE,
+                             remote_description()->description());
   if (!error.ok()) {
     return error;
   }
@@ -2574,14 +2586,10 @@
   } else {
     if (!channel) {
       if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
-        channel = CreateVoiceChannel(
-            content.name,
-            GetTransportNameForMediaSection(content.name, bundle_group));
+        channel = CreateVoiceChannel(content.name);
       } else {
         RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, transceiver->media_type());
-        channel = CreateVideoChannel(
-            content.name,
-            GetTransportNameForMediaSection(content.name, bundle_group));
+        channel = CreateVideoChannel(content.name);
       }
       if (!channel) {
         LOG_AND_RETURN_ERROR(
@@ -2607,8 +2615,7 @@
     DestroyDataChannel();
   } else {
     if (!rtp_data_channel_ && !sctp_transport_) {
-      if (!CreateDataChannel(content.name, GetTransportNameForMediaSection(
-                                               content.name, bundle_group))) {
+      if (!CreateDataChannel(content.name)) {
         LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
                              "Failed to create data channel.");
       }
@@ -2919,10 +2926,10 @@
   }
 
   // Remove the candidates from the transport controller.
-  std::string error;
-  bool res = transport_controller_->RemoveRemoteCandidates(candidates, &error);
-  if (!res && !error.empty()) {
-    RTC_LOG(LS_ERROR) << "Error when removing remote candidates: " << error;
+  RTCError error = transport_controller_->RemoveRemoteCandidates(candidates);
+  if (!error.ok()) {
+    RTC_LOG(LS_ERROR) << "Error when removing remote candidates: "
+                      << error.message();
   }
   return true;
 }
@@ -3965,7 +3972,7 @@
       }
       return rtp_data_channel_->content_name();
     case cricket::DCT_SCTP:
-      return sctp_content_name_;
+      return sctp_mid_;
     default:
       return rtc::nullopt;
   }
@@ -4657,7 +4664,12 @@
     return false;
   }
 
-  return transport_controller_->GetSslRole(*sctp_transport_name_, role);
+  auto dtls_role = transport_controller_->GetDtlsRole(*sctp_mid_);
+  if (dtls_role) {
+    *role = *dtls_role;
+    return true;
+  }
+  return false;
 }
 
 bool PeerConnection::GetSslRole(const std::string& content_name,
@@ -4669,8 +4681,12 @@
     return false;
   }
 
-  return transport_controller_->GetSslRole(GetTransportName(content_name),
-                                           role);
+  auto dtls_role = transport_controller_->GetDtlsRole(content_name);
+  if (dtls_role) {
+    *role = *dtls_role;
+    return true;
+  }
+  return false;
 }
 
 void PeerConnection::SetSessionError(SessionError error,
@@ -4682,42 +4698,16 @@
   }
 }
 
-RTCError PeerConnection::UpdateSessionState(SdpType type,
-                                            cricket::ContentSource source) {
+RTCError PeerConnection::UpdateSessionState(
+    SdpType type,
+    cricket::ContentSource source,
+    const cricket::SessionDescription* description) {
   RTC_DCHECK_RUN_ON(signaling_thread());
 
   // If there's already a pending error then no state transition should happen.
   // But all call-sites should be verifying this before calling us!
   RTC_DCHECK(session_error() == SessionError::kNone);
 
-  // If this is an answer then we know whether to BUNDLE or not. If both the
-  // local and remote side have agreed to BUNDLE, go ahead and enable it.
-  if (type == SdpType::kAnswer) {
-    const cricket::ContentGroup* local_bundle =
-        local_description()->description()->GetGroupByName(
-            cricket::GROUP_TYPE_BUNDLE);
-    const cricket::ContentGroup* remote_bundle =
-        remote_description()->description()->GetGroupByName(
-            cricket::GROUP_TYPE_BUNDLE);
-    if (local_bundle && remote_bundle) {
-      // The answerer decides the transport to bundle on.
-      const cricket::ContentGroup* answer_bundle =
-          (source == cricket::CS_LOCAL ? local_bundle : remote_bundle);
-      if (!EnableBundle(*answer_bundle)) {
-        LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
-                             kEnableBundleFailed);
-      }
-    }
-  }
-
-  // Only push down the transport description after potentially enabling BUNDLE;
-  // we don't want to push down a description on a transport about to be
-  // destroyed.
-  RTCError error = PushdownTransportDescription(source, type);
-  if (!error.ok()) {
-    return error;
-  }
-
   // If this is answer-ish we're ready to let media flow.
   if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
     EnableSending();
@@ -4740,7 +4730,7 @@
 
   // Update internal objects according to the session description's media
   // descriptions.
-  error = PushdownMediaDescription(type, source);
+  RTCError error = PushdownMediaDescription(type, source);
   if (!error.ok()) {
     return error;
   }
@@ -4834,29 +4824,17 @@
     SdpType type) {
   RTC_DCHECK_RUN_ON(signaling_thread());
 
-  const SessionDescriptionInterface* sdesc =
-      (source == cricket::CS_LOCAL ? local_description()
-                                   : remote_description());
-  RTC_DCHECK(sdesc);
-  for (const cricket::TransportInfo& tinfo :
-       sdesc->description()->transport_infos()) {
-    std::string error;
-    bool success;
-    if (source == cricket::CS_LOCAL) {
-      success = transport_controller_->SetLocalTransportDescription(
-          tinfo.content_name, tinfo.description, type, &error);
-    } else {
-      success = transport_controller_->SetRemoteTransportDescription(
-          tinfo.content_name, tinfo.description, type, &error);
-    }
-    if (!success) {
-      LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
-                           "Failed to push down transport description for " +
-                               tinfo.content_name + ": " + error);
-    }
+  if (source == cricket::CS_LOCAL) {
+    const SessionDescriptionInterface* sdesc = local_description();
+    RTC_DCHECK(sdesc);
+    return transport_controller_->SetLocalDescription(type,
+                                                      sdesc->description());
+  } else {
+    const SessionDescriptionInterface* sdesc = remote_description();
+    RTC_DCHECK(sdesc);
+    return transport_controller_->SetRemoteDescription(type,
+                                                       sdesc->description());
   }
-
-  return RTCError::OK();
 }
 
 bool PeerConnection::GetTransportDescription(
@@ -4875,71 +4853,6 @@
   return true;
 }
 
-bool PeerConnection::EnableBundle(const cricket::ContentGroup& bundle) {
-  const std::string* first_content_name = bundle.FirstContentName();
-  if (!first_content_name) {
-    RTC_LOG(LS_WARNING) << "Tried to BUNDLE with no contents.";
-    return false;
-  }
-  const std::string& transport_name = *first_content_name;
-
-  auto maybe_set_transport = [this, bundle,
-                              transport_name](cricket::BaseChannel* ch) {
-    if (!ch || !bundle.HasContentName(ch->content_name())) {
-      return;
-    }
-
-    std::string old_transport_name = ch->transport_name();
-    if (old_transport_name == transport_name) {
-      RTC_LOG(LS_INFO) << "BUNDLE already enabled for " << ch->content_name()
-                       << " on " << transport_name << ".";
-      return;
-    }
-
-    cricket::DtlsTransportInternal* rtp_dtls_transport =
-        transport_controller_->CreateDtlsTransport(
-            transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-    bool need_rtcp = (ch->rtcp_dtls_transport() != nullptr);
-    cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr;
-    if (need_rtcp) {
-      rtcp_dtls_transport = transport_controller_->CreateDtlsTransport(
-          transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-    }
-
-    ch->SetTransports(rtp_dtls_transport, rtcp_dtls_transport);
-    RTC_LOG(LS_INFO) << "Enabled BUNDLE for " << ch->content_name() << " on "
-                     << transport_name << ".";
-    transport_controller_->DestroyDtlsTransport(
-        old_transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-    // If the channel needs rtcp, it means that the channel used to have a
-    // rtcp transport which needs to be deleted now.
-    if (need_rtcp) {
-      transport_controller_->DestroyDtlsTransport(
-          old_transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-    }
-  };
-
-  for (auto transceiver : transceivers_) {
-    maybe_set_transport(transceiver->internal()->channel());
-  }
-  maybe_set_transport(rtp_data_channel_);
-
-  // For SCTP, transport creation/deletion happens here instead of in the
-  // object itself.
-  if (sctp_transport_) {
-    RTC_DCHECK(sctp_transport_name_);
-    RTC_DCHECK(sctp_content_name_);
-    if (transport_name != *sctp_transport_name_ &&
-        bundle.HasContentName(*sctp_content_name_)) {
-      network_thread()->Invoke<void>(
-          RTC_FROM_HERE, rtc::Bind(&PeerConnection::ChangeSctpTransport_n, this,
-                                   transport_name));
-    }
-  }
-
-  return true;
-}
-
 cricket::IceConfig PeerConnection::ParseIceConfig(
     const PeerConnectionInterface::RTCConfiguration& config) const {
   cricket::ContinualGatheringPolicy gathering_policy;
@@ -5081,6 +4994,17 @@
          sctp_ready_to_send_data_;
 }
 
+rtc::Optional<std::string> PeerConnection::sctp_transport_name() const {
+  if (sctp_mid_ && transport_controller_) {
+    auto dtls_transport = transport_controller_->GetDtlsTransport(*sctp_mid_);
+    if (dtls_transport) {
+      return dtls_transport->transport_name();
+    }
+    return rtc::Optional<std::string>();
+  }
+  return rtc::Optional<std::string>();
+}
+
 cricket::CandidateStatsList PeerConnection::GetPooledCandidateStats() const {
   cricket::CandidateStatsList candidate_states_list;
   port_allocator_->GetCandidateStatsFromPooledSessions(&candidate_states_list);
@@ -5102,7 +5026,9 @@
         rtp_data_channel_->transport_name();
   }
   if (sctp_transport_) {
-    transport_names_by_mid[*sctp_content_name_] = *sctp_transport_name_;
+    rtc::Optional<std::string> transport_name = sctp_transport_name();
+    RTC_DCHECK(transport_name);
+    transport_names_by_mid[*sctp_mid_] = *transport_name;
   }
   return transport_names_by_mid;
 }
@@ -5134,8 +5060,11 @@
 bool PeerConnection::GetLocalCertificate(
     const std::string& transport_name,
     rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
-  return transport_controller_->GetLocalCertificate(transport_name,
-                                                    certificate);
+  if (!certificate) {
+    return false;
+  }
+  *certificate = transport_controller_->GetLocalCertificate(transport_name);
+  return *certificate != nullptr;
 }
 
 std::unique_ptr<rtc::SSLCertChain> PeerConnection::GetRemoteSSLCertChain(
@@ -5339,9 +5268,9 @@
   std::vector<cricket::Candidate> candidates;
   candidates.push_back(candidate->candidate());
   // Invoking BaseSession method to handle remote candidates.
-  std::string error;
-  if (transport_controller_->AddRemoteCandidates(content.name, candidates,
-                                                 &error)) {
+  RTCError error =
+      transport_controller_->AddRemoteCandidates(content.name, candidates);
+  if (error.ok()) {
     // Candidates successfully submitted for checking.
     if (ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew ||
         ice_connection_state_ ==
@@ -5357,10 +5286,8 @@
       SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking);
     }
     // TODO(bemasc): If state is Completed, go back to Connected.
-  } else {
-    if (!error.empty()) {
-      RTC_LOG(LS_WARNING) << error;
-    }
+  } else if (error.message()) {
+    RTC_LOG(LS_WARNING) << error.message();
   }
   return true;
 }
@@ -5384,25 +5311,6 @@
   }
 }
 
-std::string PeerConnection::GetTransportNameForMediaSection(
-    const std::string& mid,
-    const cricket::ContentGroup* bundle_group) const {
-  if (!bundle_group) {
-    return mid;
-  }
-  const std::string* first_content_name = bundle_group->FirstContentName();
-  if (!first_content_name) {
-    RTC_LOG(LS_WARNING) << "Tried to BUNDLE with no contents.";
-    return mid;
-  }
-  if (!bundle_group->HasContentName(mid)) {
-    RTC_LOG(LS_WARNING) << mid << " is not part of any bundle group";
-    return mid;
-  }
-  RTC_LOG(LS_INFO) << "Bundling " << mid << " on " << *first_content_name;
-  return *first_content_name;
-}
-
 RTCErrorOr<const cricket::ContentGroup*> PeerConnection::GetEarlyBundleGroup(
     const SessionDescription& desc) const {
   const cricket::ContentGroup* bundle_group = nullptr;
@@ -5419,19 +5327,12 @@
 }
 
 RTCError PeerConnection::CreateChannels(const SessionDescription& desc) {
-  auto bundle_group_or_error = GetEarlyBundleGroup(desc);
-  if (!bundle_group_or_error.ok()) {
-    return bundle_group_or_error.MoveError();
-  }
-  const cricket::ContentGroup* bundle_group = bundle_group_or_error.MoveValue();
-
-  // Creating the media channels and transport proxies.
+  // Creating the media channels. Transports should already have been created
+  // at this point.
   const cricket::ContentInfo* voice = cricket::GetFirstAudioContent(&desc);
   if (voice && !voice->rejected &&
       !GetAudioTransceiver()->internal()->channel()) {
-    cricket::VoiceChannel* voice_channel = CreateVoiceChannel(
-        voice->name,
-        GetTransportNameForMediaSection(voice->name, bundle_group));
+    cricket::VoiceChannel* voice_channel = CreateVoiceChannel(voice->name);
     if (!voice_channel) {
       LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
                            "Failed to create voice channel.");
@@ -5442,9 +5343,7 @@
   const cricket::ContentInfo* video = cricket::GetFirstVideoContent(&desc);
   if (video && !video->rejected &&
       !GetVideoTransceiver()->internal()->channel()) {
-    cricket::VideoChannel* video_channel = CreateVideoChannel(
-        video->name,
-        GetTransportNameForMediaSection(video->name, bundle_group));
+    cricket::VideoChannel* video_channel = CreateVideoChannel(video->name);
     if (!video_channel) {
       LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
                            "Failed to create video channel.");
@@ -5455,8 +5354,7 @@
   const cricket::ContentInfo* data = cricket::GetFirstDataContent(&desc);
   if (data_channel_type_ != cricket::DCT_NONE && data && !data->rejected &&
       !rtp_data_channel_ && !sctp_transport_) {
-    if (!CreateDataChannel(data->name, GetTransportNameForMediaSection(
-                                           data->name, bundle_group))) {
+    if (!CreateDataChannel(data->name)) {
       LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
                            "Failed to create data channel.");
     }
@@ -5467,37 +5365,25 @@
 
 // TODO(steveanton): Perhaps this should be managed by the RtpTransceiver.
 cricket::VoiceChannel* PeerConnection::CreateVoiceChannel(
-    const std::string& mid,
-    const std::string& transport_name) {
-  cricket::DtlsTransportInternal* rtp_dtls_transport =
-      transport_controller_->CreateDtlsTransport(
-          transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-  cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr;
-  if (configuration_.rtcp_mux_policy !=
-      PeerConnectionInterface::kRtcpMuxPolicyRequire) {
-    rtcp_dtls_transport = transport_controller_->CreateDtlsTransport(
-        transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-  }
-
+    const std::string& mid) {
+  RtpTransportInternal* rtp_transport =
+      transport_controller_->GetRtpTransport(mid);
+  RTC_DCHECK(rtp_transport);
   cricket::VoiceChannel* voice_channel = channel_manager()->CreateVoiceChannel(
-      call_.get(), configuration_.media_config, rtp_dtls_transport,
-      rtcp_dtls_transport, signaling_thread(), mid, SrtpRequired(),
-      audio_options_);
+      call_.get(), configuration_.media_config, rtp_transport,
+      signaling_thread(), mid, SrtpRequired(),
+      factory_->options().crypto_options, audio_options_);
   if (!voice_channel) {
-    transport_controller_->DestroyDtlsTransport(
-        transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-    if (rtcp_dtls_transport) {
-      transport_controller_->DestroyDtlsTransport(
-          transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-    }
     return nullptr;
   }
-  voice_channel->SignalRtcpMuxFullyActive.connect(
-      this, &PeerConnection::DestroyRtcpTransport_n);
   voice_channel->SignalDtlsSrtpSetupFailure.connect(
       this, &PeerConnection::OnDtlsSrtpSetupFailure);
   voice_channel->SignalSentPacket.connect(this,
                                           &PeerConnection::OnSentPacket_w);
+  voice_channel->SetRtpTransport(rtp_transport);
+  if (factory_->options().disable_encryption) {
+    voice_channel->DisableEncryption(true);
+  }
   if (uma_observer_) {
     voice_channel->SetMetricsObserver(uma_observer_);
   }
@@ -5507,38 +5393,25 @@
 
 // TODO(steveanton): Perhaps this should be managed by the RtpTransceiver.
 cricket::VideoChannel* PeerConnection::CreateVideoChannel(
-    const std::string& mid,
-    const std::string& transport_name) {
-  cricket::DtlsTransportInternal* rtp_dtls_transport =
-      transport_controller_->CreateDtlsTransport(
-          transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-  cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr;
-  if (configuration_.rtcp_mux_policy !=
-      PeerConnectionInterface::kRtcpMuxPolicyRequire) {
-    rtcp_dtls_transport = transport_controller_->CreateDtlsTransport(
-        transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-  }
-
+    const std::string& mid) {
+  RtpTransportInternal* rtp_transport =
+      transport_controller_->GetRtpTransport(mid);
+  RTC_DCHECK(rtp_transport);
   cricket::VideoChannel* video_channel = channel_manager()->CreateVideoChannel(
-      call_.get(), configuration_.media_config, rtp_dtls_transport,
-      rtcp_dtls_transport, signaling_thread(), mid, SrtpRequired(),
-      video_options_);
-
+      call_.get(), configuration_.media_config, rtp_transport,
+      signaling_thread(), mid, SrtpRequired(),
+      factory_->options().crypto_options, video_options_);
   if (!video_channel) {
-    transport_controller_->DestroyDtlsTransport(
-        transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-    if (rtcp_dtls_transport) {
-      transport_controller_->DestroyDtlsTransport(
-          transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-    }
     return nullptr;
   }
-  video_channel->SignalRtcpMuxFullyActive.connect(
-      this, &PeerConnection::DestroyRtcpTransport_n);
   video_channel->SignalDtlsSrtpSetupFailure.connect(
       this, &PeerConnection::OnDtlsSrtpSetupFailure);
   video_channel->SignalSentPacket.connect(this,
                                           &PeerConnection::OnSentPacket_w);
+  video_channel->SetRtpTransport(rtp_transport);
+  if (factory_->options().disable_encryption) {
+    video_channel->DisableEncryption(true);
+  }
   if (uma_observer_) {
     video_channel->SetMetricsObserver(uma_observer_);
   }
@@ -5546,8 +5419,7 @@
   return video_channel;
 }
 
-bool PeerConnection::CreateDataChannel(const std::string& mid,
-                                       const std::string& transport_name) {
+bool PeerConnection::CreateDataChannel(const std::string& mid) {
   bool sctp = (data_channel_type_ == cricket::DCT_SCTP);
   if (sctp) {
     if (!sctp_factory_) {
@@ -5557,44 +5429,31 @@
       return false;
     }
     if (!network_thread()->Invoke<bool>(
-            RTC_FROM_HERE, rtc::Bind(&PeerConnection::CreateSctpTransport_n,
-                                     this, mid, transport_name))) {
+            RTC_FROM_HERE,
+            rtc::Bind(&PeerConnection::CreateSctpTransport_n, this, mid))) {
       return false;
     }
     for (const auto& channel : sctp_data_channels_) {
       channel->OnTransportChannelCreated();
     }
   } else {
-    cricket::DtlsTransportInternal* rtp_dtls_transport =
-        transport_controller_->CreateDtlsTransport(
-            transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-    cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr;
-    if (configuration_.rtcp_mux_policy !=
-        PeerConnectionInterface::kRtcpMuxPolicyRequire) {
-      rtcp_dtls_transport = transport_controller_->CreateDtlsTransport(
-          transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-    }
-
+    RtpTransportInternal* rtp_transport =
+        transport_controller_->GetRtpTransport(mid);
+    RTC_DCHECK(rtp_transport);
     rtp_data_channel_ = channel_manager()->CreateRtpDataChannel(
-        configuration_.media_config, rtp_dtls_transport, rtcp_dtls_transport,
-        signaling_thread(), mid, SrtpRequired());
-
+        configuration_.media_config, rtp_transport, signaling_thread(), mid,
+        SrtpRequired(), factory_->options().crypto_options);
     if (!rtp_data_channel_) {
-      transport_controller_->DestroyDtlsTransport(
-          transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-      if (rtcp_dtls_transport) {
-        transport_controller_->DestroyDtlsTransport(
-            transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-      }
       return false;
     }
-
-    rtp_data_channel_->SignalRtcpMuxFullyActive.connect(
-        this, &PeerConnection::DestroyRtcpTransport_n);
     rtp_data_channel_->SignalDtlsSrtpSetupFailure.connect(
         this, &PeerConnection::OnDtlsSrtpSetupFailure);
     rtp_data_channel_->SignalSentPacket.connect(
         this, &PeerConnection::OnSentPacket_w);
+    rtp_data_channel_->SetRtpTransport(rtp_transport);
+    if (factory_->options().disable_encryption) {
+      rtp_data_channel_->DisableEncryption(true);
+    }
     if (uma_observer_) {
       rtp_data_channel_->SetMetricsObserver(uma_observer_);
     }
@@ -5615,13 +5474,12 @@
   }
 }
 
-bool PeerConnection::CreateSctpTransport_n(const std::string& content_name,
-                                           const std::string& transport_name) {
+bool PeerConnection::CreateSctpTransport_n(const std::string& mid) {
   RTC_DCHECK(network_thread()->IsCurrent());
   RTC_DCHECK(sctp_factory_);
   cricket::DtlsTransportInternal* tc =
-      transport_controller_->CreateDtlsTransport_n(
-          transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
+      transport_controller_->GetDtlsTransport(mid);
+  RTC_DCHECK(tc);
   sctp_transport_ = sctp_factory_->CreateSctpTransport(tc);
   RTC_DCHECK(sctp_transport_);
   sctp_invoker_.reset(new rtc::AsyncInvoker());
@@ -5631,32 +5489,15 @@
       this, &PeerConnection::OnSctpTransportDataReceived_n);
   sctp_transport_->SignalStreamClosedRemotely.connect(
       this, &PeerConnection::OnSctpStreamClosedRemotely_n);
-  sctp_transport_name_ = transport_name;
-  sctp_content_name_ = content_name;
-  return true;
-}
-
-void PeerConnection::ChangeSctpTransport_n(const std::string& transport_name) {
-  RTC_DCHECK(network_thread()->IsCurrent());
-  RTC_DCHECK(sctp_transport_);
-  RTC_DCHECK(sctp_transport_name_);
-  std::string old_sctp_transport_name = *sctp_transport_name_;
-  sctp_transport_name_ = transport_name;
-  cricket::DtlsTransportInternal* tc =
-      transport_controller_->CreateDtlsTransport_n(
-          transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
+  sctp_mid_ = mid;
   sctp_transport_->SetTransportChannel(tc);
-  transport_controller_->DestroyDtlsTransport_n(
-      old_sctp_transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
+  return true;
 }
 
 void PeerConnection::DestroySctpTransport_n() {
   RTC_DCHECK(network_thread()->IsCurrent());
   sctp_transport_.reset(nullptr);
-  transport_controller_->DestroyDtlsTransport_n(
-      *sctp_transport_name_, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-  sctp_content_name_.reset();
-  sctp_transport_name_.reset();
+  sctp_mid_.reset();
   sctp_invoker_.reset(nullptr);
   sctp_ready_to_send_data_ = false;
 }
@@ -5989,7 +5830,7 @@
   if (transport_name.empty()) {
     return false;
   }
-  return transport_controller_->ReadyForRemoteCandidates(transport_name);
+  return true;
 }
 
 bool PeerConnection::SrtpRequired() const {
@@ -6022,10 +5863,13 @@
     media_types_by_transport_name[rtp_data_channel()->transport_name()].insert(
         cricket::MEDIA_TYPE_DATA);
   }
-  if (sctp_transport_name_) {
-    media_types_by_transport_name[*sctp_transport_name_].insert(
+
+  rtc::Optional<std::string> transport_name = sctp_transport_name();
+  if (transport_name) {
+    media_types_by_transport_name[*transport_name].insert(
         cricket::MEDIA_TYPE_DATA);
   }
+
   for (const auto& entry : media_types_by_transport_name) {
     const std::string& transport_name = entry.first;
     const std::set<cricket::MediaType> media_types = entry.second;
@@ -6145,22 +5989,15 @@
     return channel->transport_name();
   }
   if (sctp_transport_) {
-    RTC_DCHECK(sctp_content_name_);
-    RTC_DCHECK(sctp_transport_name_);
-    if (content_name == *sctp_content_name_) {
-      return *sctp_transport_name_;
+    RTC_DCHECK(sctp_mid_);
+    if (content_name == *sctp_mid_) {
+      return *sctp_transport_name();
     }
   }
   // Return an empty string if failed to retrieve the transport name.
   return "";
 }
 
-void PeerConnection::DestroyRtcpTransport_n(const std::string& transport_name) {
-  RTC_DCHECK(network_thread()->IsCurrent());
-  transport_controller_->DestroyDtlsTransport_n(
-      transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-}
-
 void PeerConnection::DestroyTransceiverChannel(
     rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
         transceiver) {
@@ -6195,13 +6032,6 @@
 
 void PeerConnection::DestroyBaseChannel(cricket::BaseChannel* channel) {
   RTC_DCHECK(channel);
-  RTC_DCHECK(channel->rtp_dtls_transport());
-
-  // Need to cache these before destroying the base channel so that we do not
-  // access uninitialized memory.
-  const std::string transport_name =
-      channel->rtp_dtls_transport()->transport_name();
-  const bool need_to_delete_rtcp = (channel->rtcp_dtls_transport() != nullptr);
 
   switch (channel->media_type()) {
     case cricket::MEDIA_TYPE_AUDIO:
@@ -6220,14 +6050,23 @@
       RTC_NOTREACHED() << "Unknown media type: " << channel->media_type();
       break;
   }
+}
 
-  // |channel| can no longer be used.
+void PeerConnection::OnRtpTransportChanged(
+    const std::string& mid,
+    RtpTransportInternal* rtp_transport) {
+  auto base_channel = GetChannel(mid);
+  if (base_channel) {
+    base_channel->SetRtpTransport(rtp_transport);
+  }
+}
 
-  transport_controller_->DestroyDtlsTransport(
-      transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-  if (need_to_delete_rtcp) {
-    transport_controller_->DestroyDtlsTransport(
-        transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
+void PeerConnection::OnDtlsTransportChanged(
+    const std::string& mid,
+    cricket::DtlsTransportInternal* dtls_transport) {
+  if (sctp_transport_) {
+    RTC_DCHECK(mid == sctp_mid_);
+    sctp_transport_->SetTransportChannel(dtls_transport);
   }
 }
 
diff --git a/pc/peerconnection.h b/pc/peerconnection.h
index d1ba212..fa46a4e 100644
--- a/pc/peerconnection.h
+++ b/pc/peerconnection.h
@@ -20,6 +20,7 @@
 #include "api/peerconnectioninterface.h"
 #include "api/turncustomizer.h"
 #include "pc/iceserverparsing.h"
+#include "pc/jseptransportcontroller.h"
 #include "pc/peerconnectionfactory.h"
 #include "pc/peerconnectioninternal.h"
 #include "pc/rtcstatscollector.h"
@@ -208,7 +209,7 @@
   std::string session_id() const override { return session_id_; }
 
   bool initial_offerer() const override {
-    return initial_offerer_ && *initial_offerer_;
+    return transport_controller_ && transport_controller_->initial_offerer();
   }
 
   std::vector<
@@ -234,12 +235,10 @@
   }
 
   rtc::Optional<std::string> sctp_content_name() const override {
-    return sctp_content_name_;
+    return sctp_mid_;
   }
 
-  rtc::Optional<std::string> sctp_transport_name() const override {
-    return sctp_transport_name_;
-  }
+  rtc::Optional<std::string> sctp_transport_name() const override;
 
   cricket::CandidateStatsList GetPooledCandidateStats() const override;
   std::map<std::string, std::string> GetTransportNamesByMid() const override;
@@ -709,7 +708,7 @@
       const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
   void OnDtlsSrtpSetupFailure(cricket::BaseChannel*, bool rtcp);
 
-  cricket::TransportController* transport_controller() const {
+  JsepTransportController* transport_controller() const {
     return transport_controller_.get();
   }
 
@@ -727,7 +726,9 @@
   // Updates the error state, signaling if necessary.
   void SetSessionError(SessionError error, const std::string& error_desc);
 
-  RTCError UpdateSessionState(SdpType type, cricket::ContentSource source);
+  RTCError UpdateSessionState(SdpType type,
+                              cricket::ContentSource source,
+                              const cricket::SessionDescription* description);
   // Push the media parts of the local or remote session description
   // down to all of the channels.
   RTCError PushdownMediaDescription(SdpType type,
@@ -744,18 +745,6 @@
       const std::string& content_name,
       cricket::TransportDescription* info);
 
-  // Returns the transport name for the given media section identified by |mid|.
-  // If BUNDLE is enabled and the media section is part of the bundle group,
-  // the transport name will be the first mid in the bundle group. Otherwise,
-  // the transport name will be the mid of the media section.
-  std::string GetTransportNameForMediaSection(
-      const std::string& mid,
-      const cricket::ContentGroup* bundle_group) const;
-
-  // Cause all the BaseChannels in the bundle group to have the same
-  // transport channel.
-  bool EnableBundle(const cricket::ContentGroup& bundle);
-
   // Enables media channels to allow sending of media.
   // This enables media to flow on all configured audio/video channels and the
   // RtpDataChannel.
@@ -792,17 +781,12 @@
       const cricket::SessionDescription& desc) const;
 
   // Helper methods to create media channels.
-  cricket::VoiceChannel* CreateVoiceChannel(const std::string& mid,
-                                            const std::string& transport_name);
-  cricket::VideoChannel* CreateVideoChannel(const std::string& mid,
-                                            const std::string& transport_name);
-  bool CreateDataChannel(const std::string& mid,
-                         const std::string& transport_name);
+  cricket::VoiceChannel* CreateVoiceChannel(const std::string& mid);
+  cricket::VideoChannel* CreateVideoChannel(const std::string& mid);
+  bool CreateDataChannel(const std::string& mid);
 
-  bool CreateSctpTransport_n(const std::string& content_name,
-                             const std::string& transport_name);
+  bool CreateSctpTransport_n(const std::string& mid);
   // For bundling.
-  void ChangeSctpTransport_n(const std::string& transport_name);
   void DestroySctpTransport_n();
   // SctpTransport signal handlers. Needed to marshal signals from the network
   // to signaling thread.
@@ -846,7 +830,7 @@
   // this session.
   bool SrtpRequired() const;
 
-  // TransportController signal handlers.
+  // JsepTransportController signal handlers.
   void OnTransportControllerConnectionState(cricket::IceConnectionState state);
   void OnTransportControllerGatheringState(cricket::IceGatheringState state);
   void OnTransportControllerCandidatesGathered(
@@ -880,8 +864,6 @@
 
   const std::string GetTransportName(const std::string& content_name);
 
-  void DestroyRtcpTransport_n(const std::string& transport_name);
-
   // Destroys and clears the BaseChannel associated with the given transceiver,
   // if such channel is set.
   void DestroyTransceiverChannel(
@@ -895,6 +877,12 @@
   // method is called.
   void DestroyBaseChannel(cricket::BaseChannel* channel);
 
+  void OnRtpTransportChanged(const std::string& mid,
+                             RtpTransportInternal* rtp_transport);
+
+  void OnDtlsTransportChanged(const std::string& mid,
+                              cricket::DtlsTransportInternal* dtls_transport);
+
   sigslot::signal1<DataChannel*> SignalDataChannelCreated_;
 
   // Storing the factory as a scoped reference pointer ensures that the memory
@@ -957,20 +945,16 @@
   std::string session_error_desc_;
 
   std::string session_id_;
-  rtc::Optional<bool> initial_offerer_;
 
-  std::unique_ptr<cricket::TransportController> transport_controller_;
+  std::unique_ptr<JsepTransportController> transport_controller_;
   std::unique_ptr<cricket::SctpTransportInternalFactory> sctp_factory_;
   // |rtp_data_channel_| is used if in RTP data channel mode, |sctp_transport_|
   // when using SCTP.
   cricket::RtpDataChannel* rtp_data_channel_ = nullptr;
 
   std::unique_ptr<cricket::SctpTransportInternal> sctp_transport_;
-  // |sctp_transport_name_| keeps track of what DTLS transport the SCTP
-  // transport is using (which can change due to bundling).
-  rtc::Optional<std::string> sctp_transport_name_;
-  // |sctp_content_name_| is the content name (MID) in SDP.
-  rtc::Optional<std::string> sctp_content_name_;
+  // |sctp_mid_| is the content name (MID) in SDP.
+  rtc::Optional<std::string> sctp_mid_;
   // Value cached on signaling thread. Only updated when SctpReadyToSendData
   // fires on the signaling thread.
   bool sctp_ready_to_send_data_ = false;
diff --git a/pc/peerconnection_bundle_unittest.cc b/pc/peerconnection_bundle_unittest.cc
index 16bd000..9819115 100644
--- a/pc/peerconnection_bundle_unittest.cc
+++ b/pc/peerconnection_bundle_unittest.cc
@@ -67,12 +67,14 @@
     return false;
   }
 
-  rtc::PacketTransportInternal* voice_rtp_transport_channel() {
-    return (voice_channel() ? voice_channel()->rtp_dtls_transport() : nullptr);
+  rtc::PacketTransportInternal* voice_rtp_transport() {
+    return (voice_channel() ? voice_channel()->rtp_packet_transport()
+                            : nullptr);
   }
 
-  rtc::PacketTransportInternal* voice_rtcp_transport_channel() {
-    return (voice_channel() ? voice_channel()->rtcp_dtls_transport() : nullptr);
+  rtc::PacketTransportInternal* voice_rtcp_transport() {
+    return (voice_channel() ? voice_channel()->rtcp_packet_transport()
+                            : nullptr);
   }
 
   cricket::VoiceChannel* voice_channel() {
@@ -86,12 +88,14 @@
     return nullptr;
   }
 
-  rtc::PacketTransportInternal* video_rtp_transport_channel() {
-    return (video_channel() ? video_channel()->rtp_dtls_transport() : nullptr);
+  rtc::PacketTransportInternal* video_rtp_transport() {
+    return (video_channel() ? video_channel()->rtp_packet_transport()
+                            : nullptr);
   }
 
-  rtc::PacketTransportInternal* video_rtcp_transport_channel() {
-    return (video_channel() ? video_channel()->rtcp_dtls_transport() : nullptr);
+  rtc::PacketTransportInternal* video_rtcp_transport() {
+    return (video_channel() ? video_channel()->rtcp_packet_transport()
+                            : nullptr);
   }
 
   cricket::VideoChannel* video_channel() {
@@ -348,6 +352,24 @@
   EXPECT_EQ(0u, caller->observer()->GetCandidatesByMline(1).size());
 }
 
+// It will fail if the offerer uses the mux-BUNDLE policy but the answerer
+// doesn't support BUNDLE.
+TEST_P(PeerConnectionBundleTest, MaxBundleNotSupportedInAnswer) {
+  RTCConfiguration config;
+  config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
+  auto caller = CreatePeerConnectionWithAudioVideo(config);
+  auto callee = CreatePeerConnectionWithAudioVideo();
+
+  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
+  bool equal_before =
+      (caller->voice_rtp_transport() == caller->video_rtp_transport());
+  EXPECT_EQ(true, equal_before);
+  RTCOfferAnswerOptions options;
+  options.use_rtp_mux = false;
+  EXPECT_FALSE(
+      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
+}
+
 // The following parameterized test verifies that an offer/answer with varying
 // bundle policies and either bundle in the answer or not will produce the
 // expected RTP transports for audio and video. In particular, for bundling we
@@ -393,16 +415,16 @@
   auto callee = CreatePeerConnectionWithAudioVideo();
 
   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  bool equal_before = (caller->voice_rtp_transport_channel() ==
-                       caller->video_rtp_transport_channel());
+  bool equal_before =
+      (caller->voice_rtp_transport() == caller->video_rtp_transport());
   EXPECT_EQ(expected_same_before_, equal_before);
 
   RTCOfferAnswerOptions options;
   options.use_rtp_mux = (bundle_included_ == BundleIncluded::kBundleInAnswer);
   ASSERT_TRUE(
       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
-  bool equal_after = (caller->voice_rtp_transport_channel() ==
-                      caller->video_rtp_transport_channel());
+  bool equal_after =
+      (caller->voice_rtp_transport() == caller->video_rtp_transport());
   EXPECT_EQ(expected_same_after_, equal_after);
 }
 
@@ -426,10 +448,6 @@
                                    BundleIncluded::kBundleInAnswer,
                                    true,
                                    true),
-                   std::make_tuple(BundlePolicy::kBundlePolicyMaxBundle,
-                                   BundleIncluded::kBundleNotInAnswer,
-                                   true,
-                                   true),
                    std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat,
                                    BundleIncluded::kBundleInAnswer,
                                    false,
@@ -454,13 +472,11 @@
   ASSERT_TRUE(callee->SetRemoteDescription(
       caller->CreateOfferAndSetAsLocal(options_with_bundle)));
 
-  EXPECT_EQ(callee->voice_rtp_transport_channel(),
-            callee->video_rtp_transport_channel());
+  EXPECT_EQ(callee->voice_rtp_transport(), callee->video_rtp_transport());
 
   ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
 
-  EXPECT_EQ(callee->voice_rtp_transport_channel(),
-            callee->video_rtp_transport_channel());
+  EXPECT_EQ(callee->voice_rtp_transport(), callee->video_rtp_transport());
 }
 
 TEST_P(PeerConnectionBundleTest,
@@ -496,8 +512,8 @@
   ASSERT_TRUE(
       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
 
-  EXPECT_FALSE(caller->voice_rtp_transport_channel());
-  EXPECT_TRUE(caller->video_rtp_transport_channel());
+  EXPECT_FALSE(caller->voice_rtp_transport());
+  EXPECT_TRUE(caller->video_rtp_transport());
 }
 
 // When requiring RTCP multiplexing, the PeerConnection never makes RTCP
@@ -510,19 +526,18 @@
 
   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
 
-  EXPECT_FALSE(caller->voice_rtcp_transport_channel());
-  EXPECT_FALSE(caller->video_rtcp_transport_channel());
+  EXPECT_FALSE(caller->voice_rtcp_transport());
+  EXPECT_FALSE(caller->video_rtcp_transport());
 
   ASSERT_TRUE(
       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
 
-  EXPECT_FALSE(caller->voice_rtcp_transport_channel());
-  EXPECT_FALSE(caller->video_rtcp_transport_channel());
+  EXPECT_FALSE(caller->voice_rtcp_transport());
+  EXPECT_FALSE(caller->video_rtcp_transport());
 }
 
-// When negotiating RTCP multiplexing, the PeerConnection makes RTCP transport
-// channels when the offer is sent, but will destroy them once the remote answer
-// is set.
+// When negotiating RTCP multiplexing, the PeerConnection makes RTCP transports
+// when the offer is sent, but will destroy them once the remote answer is set.
 TEST_P(PeerConnectionBundleTest,
        CreateRtcpTransportOnlyBeforeAnswerWithRtcpMuxNegotiate) {
   RTCConfiguration config;
@@ -532,14 +547,14 @@
 
   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
 
-  EXPECT_TRUE(caller->voice_rtcp_transport_channel());
-  EXPECT_TRUE(caller->video_rtcp_transport_channel());
+  EXPECT_TRUE(caller->voice_rtcp_transport());
+  EXPECT_TRUE(caller->video_rtcp_transport());
 
   ASSERT_TRUE(
       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
 
-  EXPECT_FALSE(caller->voice_rtcp_transport_channel());
-  EXPECT_FALSE(caller->video_rtcp_transport_channel());
+  EXPECT_FALSE(caller->voice_rtcp_transport());
+  EXPECT_FALSE(caller->video_rtcp_transport());
 }
 
 TEST_P(PeerConnectionBundleTest, FailToSetDescriptionWithBundleAndNoRtcpMux) {
@@ -588,7 +603,7 @@
 
   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
   ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
+      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
 
   // The way the *_WAIT checks work is they only wait if the condition fails,
   // which does not help in the case where state is not changing. This is
@@ -624,7 +639,7 @@
 
   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
 
-  auto* old_video_transport = caller->video_rtp_transport_channel();
+  auto* old_video_transport = caller->video_rtp_transport();
 
   auto answer = callee->CreateAnswer();
   auto* old_bundle_group =
@@ -640,9 +655,8 @@
 
   ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
 
-  EXPECT_EQ(old_video_transport, caller->video_rtp_transport_channel());
-  EXPECT_EQ(caller->voice_rtp_transport_channel(),
-            caller->video_rtp_transport_channel());
+  EXPECT_EQ(old_video_transport, caller->video_rtp_transport());
+  EXPECT_EQ(caller->voice_rtp_transport(), caller->video_rtp_transport());
 }
 
 INSTANTIATE_TEST_CASE_P(PeerConnectionBundleTest,
diff --git a/pc/peerconnection_ice_unittest.cc b/pc/peerconnection_ice_unittest.cc
index 9586236..edf2bf8 100644
--- a/pc/peerconnection_ice_unittest.cc
+++ b/pc/peerconnection_ice_unittest.cc
@@ -200,7 +200,9 @@
       if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
         cricket::BaseChannel* channel = transceiver->internal()->channel();
         if (channel) {
-          return channel->rtp_dtls_transport()->ice_transport()->GetIceRole();
+          auto dtls_transport = static_cast<cricket::DtlsTransportInternal*>(
+              channel->rtp_packet_transport());
+          return dtls_transport->ice_transport()->GetIceRole();
         }
       }
     }
diff --git a/pc/peerconnection_integrationtest.cc b/pc/peerconnection_integrationtest.cc
index 33bf267..6dbf320 100644
--- a/pc/peerconnection_integrationtest.cc
+++ b/pc/peerconnection_integrationtest.cc
@@ -2342,8 +2342,10 @@
 
   // Get the audio output level stats. Note that the level is not available
   // until an RTCP packet has been received.
-  EXPECT_TRUE_WAIT(callee()->OldGetStatsForTrack(remote_audio_track)->
-                   CaptureStartNtpTime() > 0, 2 * kMaxWaitForFramesMs);
+  EXPECT_TRUE_WAIT(
+      callee()->OldGetStatsForTrack(remote_audio_track)->CaptureStartNtpTime() >
+          0,
+      2 * kMaxWaitForFramesMs);
 }
 
 // Test that we can get stats (using the new stats implemnetation) for
diff --git a/pc/peerconnectionfactory.cc b/pc/peerconnectionfactory.cc
index 70e8d19..a7075ef 100644
--- a/pc/peerconnectionfactory.cc
+++ b/pc/peerconnectionfactory.cc
@@ -325,16 +325,6 @@
   return AudioTrackProxy::Create(signaling_thread_, track);
 }
 
-cricket::TransportController* PeerConnectionFactory::CreateTransportController(
-    cricket::PortAllocator* port_allocator,
-    bool redetermine_role_on_ice_restart,
-    RtcEventLog* event_log) {
-  RTC_DCHECK(signaling_thread_->IsCurrent());
-  return new cricket::TransportController(
-      signaling_thread_, network_thread_, port_allocator,
-      redetermine_role_on_ice_restart, options_.crypto_options, event_log);
-}
-
 std::unique_ptr<cricket::SctpTransportInternalFactory>
 PeerConnectionFactory::CreateSctpTransportInternalFactory() {
 #ifdef HAVE_SCTP
diff --git a/pc/peerconnectionfactory.h b/pc/peerconnectionfactory.h
index f0045f7..f58542f 100644
--- a/pc/peerconnectionfactory.h
+++ b/pc/peerconnectionfactory.h
@@ -88,11 +88,6 @@
   bool StartAecDump(rtc::PlatformFile file, int64_t max_size_bytes) override;
   void StopAecDump() override;
 
-  virtual cricket::TransportController* CreateTransportController(
-      cricket::PortAllocator* port_allocator,
-      bool redetermine_role_on_ice_restart,
-      RtcEventLog* event_log = nullptr);
-
   virtual std::unique_ptr<cricket::SctpTransportInternalFactory>
   CreateSctpTransportInternalFactory();
 
diff --git a/pc/peerconnectioninterface_unittest.cc b/pc/peerconnectioninterface_unittest.cc
index 62fd3bf..ad85d68 100644
--- a/pc/peerconnectioninterface_unittest.cc
+++ b/pc/peerconnectioninterface_unittest.cc
@@ -667,18 +667,7 @@
                                       std::move(call_factory),
                                       std::move(event_log_factory)) {}
 
-  cricket::TransportController* CreateTransportController(
-      cricket::PortAllocator* port_allocator,
-      bool redetermine_role_on_ice_restart,
-      webrtc::RtcEventLog* event_log = nullptr) override {
-    transport_controller = new cricket::TransportController(
-        rtc::Thread::Current(), rtc::Thread::Current(), port_allocator,
-        redetermine_role_on_ice_restart, rtc::CryptoOptions(), event_log);
-    return transport_controller;
-  }
-
   rtc::scoped_refptr<FakeAudioCaptureModule> fake_audio_capture_module_;
-  cricket::TransportController* transport_controller;
 };
 
 // TODO(steveanton): Convert to use the new PeerConnectionWrapper.
@@ -2318,8 +2307,7 @@
   content =
       cricket::GetFirstDataContent(pc_->local_description()->description());
   ASSERT_TRUE(content != NULL);
-  // Expected to fail since it's using an incompatible format.
-  EXPECT_TRUE(content->rejected);
+  EXPECT_FALSE(content->rejected);
 #endif
 }
 
@@ -2341,7 +2329,7 @@
   std::unique_ptr<SessionDescriptionInterface> desc(
       webrtc::CreateSessionDescription(SdpType::kOffer, kDtlsSdesFallbackSdp,
                                        nullptr));
-  EXPECT_FALSE(DoSetSessionDescription(std::move(desc), false));
+  EXPECT_FALSE(DoSetSessionDescription(std::move(desc), /*local=*/false));
 }
 
 // Test that we can create an audio only offer and receive an answer with a
diff --git a/pc/rtpsenderreceiver_unittest.cc b/pc/rtpsenderreceiver_unittest.cc
index 279aba2..69089a5 100644
--- a/pc/rtpsenderreceiver_unittest.cc
+++ b/pc/rtpsenderreceiver_unittest.cc
@@ -16,6 +16,7 @@
 #include "media/base/fakemediaengine.h"
 #include "media/base/rtpdataengine.h"
 #include "media/engine/fakewebrtccall.h"
+#include "p2p/base/fakedtlstransport.h"
 #include "pc/audiotrack.h"
 #include "pc/channelmanager.h"
 #include "pc/localaudiosource.h"
@@ -24,7 +25,6 @@
 #include "pc/rtpreceiver.h"
 #include "pc/rtpsender.h"
 #include "pc/streamcollection.h"
-#include "pc/test/faketransportcontroller.h"
 #include "pc/test/fakevideotracksource.h"
 #include "pc/videotrack.h"
 #include "pc/videotracksource.h"
@@ -69,17 +69,18 @@
     // Create channels to be used by the RtpSenders and RtpReceivers.
     channel_manager_.Init();
     bool srtp_required = true;
-    cricket::DtlsTransportInternal* rtp_transport =
-        fake_transport_controller_.CreateDtlsTransport(
-            cricket::CN_AUDIO, cricket::ICE_CANDIDATE_COMPONENT_RTP);
+    rtp_dtls_transport_ = rtc::MakeUnique<cricket::FakeDtlsTransport>(
+        "fake_dtls_transport", cricket::ICE_CANDIDATE_COMPONENT_RTP);
+    rtp_transport_ = CreateDtlsSrtpTransport();
+
     voice_channel_ = channel_manager_.CreateVoiceChannel(
-        &fake_call_, cricket::MediaConfig(),
-        rtp_transport, nullptr, rtc::Thread::Current(),
-        cricket::CN_AUDIO, srtp_required, cricket::AudioOptions());
+        &fake_call_, cricket::MediaConfig(), rtp_transport_.get(),
+        rtc::Thread::Current(), cricket::CN_AUDIO, srtp_required,
+        rtc::CryptoOptions(), cricket::AudioOptions());
     video_channel_ = channel_manager_.CreateVideoChannel(
-        &fake_call_, cricket::MediaConfig(),
-        rtp_transport, nullptr, rtc::Thread::Current(),
-        cricket::CN_VIDEO, srtp_required, cricket::VideoOptions());
+        &fake_call_, cricket::MediaConfig(), rtp_transport_.get(),
+        rtc::Thread::Current(), cricket::CN_VIDEO, srtp_required,
+        rtc::CryptoOptions(), cricket::VideoOptions());
     voice_channel_->Enable(true);
     video_channel_->Enable(true);
     voice_media_channel_ = media_engine_->GetVoiceChannel(0);
@@ -111,6 +112,18 @@
         cricket::StreamParams::CreateLegacy(kVideoSsrc2));
   }
 
+  std::unique_ptr<webrtc::RtpTransportInternal> CreateDtlsSrtpTransport() {
+    auto rtp_transport =
+        rtc::MakeUnique<webrtc::RtpTransport>(/*rtcp_mux_required=*/true);
+    auto srtp_transport =
+        rtc::MakeUnique<webrtc::SrtpTransport>(std::move(rtp_transport));
+    auto dtls_srtp_transport =
+        rtc::MakeUnique<webrtc::DtlsSrtpTransport>(std::move(srtp_transport));
+    dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport_.get(),
+                                           /*rtcp_dtls_transport=*/nullptr);
+    return dtls_srtp_transport;
+  }
+
   // Needed to use DTMF sender.
   void AddDtmfCodec() {
     cricket::AudioSendParameters params;
@@ -268,9 +281,12 @@
   rtc::Thread* const network_thread_;
   rtc::Thread* const worker_thread_;
   webrtc::RtcEventLogNullImpl event_log_;
+  // The |rtp_dtls_transport_| and |rtp_transport_| should be destroyed after
+  // the |channel_manager|.
+  std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport_;
+  std::unique_ptr<webrtc::RtpTransportInternal> rtp_transport_;
   // |media_engine_| is actually owned by |channel_manager_|.
   cricket::FakeMediaEngine* media_engine_;
-  cricket::FakeTransportController fake_transport_controller_;
   cricket::ChannelManager channel_manager_;
   cricket::FakeCall fake_call_;
   cricket::VoiceChannel* voice_channel_;
diff --git a/pc/rtptransport.cc b/pc/rtptransport.cc
index 26f7e3e..cab04e5 100644
--- a/pc/rtptransport.cc
+++ b/pc/rtptransport.cc
@@ -134,26 +134,6 @@
   return true;
 }
 
-bool RtpTransport::HandlesPacket(const uint8_t* data, size_t len) {
-  return bundle_filter_.DemuxPacket(data, len);
-}
-
-bool RtpTransport::HandlesPayloadType(int payload_type) const {
-  return bundle_filter_.FindPayloadType(payload_type);
-}
-
-void RtpTransport::AddHandledPayloadType(int payload_type) {
-  bundle_filter_.AddPayloadType(payload_type);
-}
-
-PacketTransportInterface* RtpTransport::GetRtpPacketTransport() const {
-  return rtp_packet_transport_;
-}
-
-PacketTransportInterface* RtpTransport::GetRtcpPacketTransport() const {
-  return rtcp_packet_transport_;
-}
-
 RTCError RtpTransport::SetParameters(const RtpTransportParameters& parameters) {
   if (parameters_.rtcp.mux && !parameters.rtcp.mux) {
     LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
@@ -272,12 +252,7 @@
                       << " packet: wrong size=" << packet->size();
     return false;
   }
-  if (rtcp) {
-    // Permit all (seemingly valid) RTCP packets.
-    return true;
-  }
-  // Check whether we handle this payload.
-  return HandlesPacket(packet->data(), packet->size());
+  return true;
 }
 
 }  // namespace webrtc
diff --git a/pc/rtptransport.h b/pc/rtptransport.h
index 637d447..f878980 100644
--- a/pc/rtptransport.h
+++ b/pc/rtptransport.h
@@ -13,7 +13,7 @@
 
 #include <string>
 
-#include "pc/bundlefilter.h"
+#include "api/ortc/rtptransportinterface.h"
 #include "pc/rtptransportinternal.h"
 #include "rtc_base/sigslot.h"
 
@@ -49,13 +49,19 @@
   }
   void SetRtcpPacketTransport(rtc::PacketTransportInternal* rtcp) override;
 
-  PacketTransportInterface* GetRtpPacketTransport() const override;
-  PacketTransportInterface* GetRtcpPacketTransport() const override;
+  PacketTransportInterface* GetRtpPacketTransport() const override {
+    return rtp_packet_transport_;
+  }
+  PacketTransportInterface* GetRtcpPacketTransport() const override {
+    return rtcp_packet_transport_;
+  }
 
   // TODO(zstein): Use these RtcpParameters for configuration elsewhere.
   RTCError SetParameters(const RtpTransportParameters& parameters) override;
   RtpTransportParameters GetParameters() const override;
 
+  bool IsReadyToSend() const override { return ready_to_send_; }
+
   bool IsWritable(bool rtcp) const override;
 
   bool SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
@@ -66,9 +72,7 @@
                       const rtc::PacketOptions& options,
                       int flags) override;
 
-  bool HandlesPayloadType(int payload_type) const override;
-
-  void AddHandledPayloadType(int payload_type) override;
+  bool IsSrtpActive() const override { return false; }
 
   void SetMetricsObserver(
       rtc::scoped_refptr<MetricsObserverInterface> metrics_observer) override {}
@@ -106,6 +110,15 @@
 
   bool WantsPacket(bool rtcp, const rtc::CopyOnWriteBuffer* packet);
 
+  RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override {
+    RTC_NOTREACHED();
+    return RTCError::OK();
+  }
+  RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) override {
+    RTC_NOTREACHED();
+    return RTCError::OK();
+  }
+
   bool rtcp_mux_enabled_;
 
   rtc::PacketTransportInternal* rtp_packet_transport_ = nullptr;
@@ -116,8 +129,6 @@
   bool rtcp_ready_to_send_ = false;
 
   RtpTransportParameters parameters_;
-
-  cricket::BundleFilter bundle_filter_;
 };
 
 }  // namespace webrtc
diff --git a/pc/rtptransport_unittest.cc b/pc/rtptransport_unittest.cc
index 3876aa3..0425942 100644
--- a/pc/rtptransport_unittest.cc
+++ b/pc/rtptransport_unittest.cc
@@ -60,9 +60,19 @@
 class SignalObserver : public sigslot::has_slots<> {
  public:
   explicit SignalObserver(RtpTransport* transport) {
+    transport_ = transport;
     transport->SignalReadyToSend.connect(this, &SignalObserver::OnReadyToSend);
     transport->SignalNetworkRouteChanged.connect(
         this, &SignalObserver::OnNetworkRouteChanged);
+    if (transport->rtp_packet_transport()) {
+      transport->rtp_packet_transport()->SignalSentPacket.connect(
+          this, &SignalObserver::OnSentPacket);
+    }
+
+    if (transport->rtcp_packet_transport()) {
+      transport->rtcp_packet_transport()->SignalSentPacket.connect(
+          this, &SignalObserver::OnSentPacket);
+    }
   }
 
   bool ready() const { return ready_; }
@@ -73,7 +83,24 @@
     network_route_ = std::move(network_route);
   }
 
+  void OnSentPacket(rtc::PacketTransportInternal* packet_transport,
+                    const rtc::SentPacket& sent_packet) {
+    if (packet_transport == transport_->rtp_packet_transport()) {
+      rtp_transport_sent_count_++;
+    } else {
+      ASSERT_EQ(transport_->rtcp_packet_transport(), packet_transport);
+      rtcp_transport_sent_count_++;
+    }
+  }
+
+  int rtp_transport_sent_count() { return rtp_transport_sent_count_; }
+
+  int rtcp_transport_sent_count() { return rtcp_transport_sent_count_; }
+
  private:
+  int rtp_transport_sent_count_ = 0;
+  int rtcp_transport_sent_count_ = 0;
+  RtpTransport* transport_ = nullptr;
   bool ready_ = false;
   rtc::Optional<rtc::NetworkRoute> network_route_;
 };
@@ -197,6 +224,32 @@
   EXPECT_FALSE(observer.network_route());
 }
 
+// Test that RTCP packets are sent over correct transport based on the RTCP-mux
+// status.
+TEST(RtpTransportTest, RtcpPacketSentOverCorrectTransport) {
+  // If the RTCP-mux is not enabled, RTCP packets are expected to be sent over
+  // the RtcpPacketTransport.
+  RtpTransport transport(kMuxDisabled);
+  rtc::FakePacketTransport fake_rtcp("fake_rtcp");
+  rtc::FakePacketTransport fake_rtp("fake_rtp");
+  transport.SetRtcpPacketTransport(&fake_rtcp);  // rtcp ready
+  transport.SetRtpPacketTransport(&fake_rtp);    // rtp ready
+  SignalObserver observer(&transport);
+
+  fake_rtp.SetDestination(&fake_rtp, true);
+  fake_rtcp.SetDestination(&fake_rtcp, true);
+
+  rtc::CopyOnWriteBuffer packet;
+  EXPECT_TRUE(transport.SendRtcpPacket(&packet, rtc::PacketOptions(), 0));
+  EXPECT_EQ(1, observer.rtcp_transport_sent_count());
+
+  // The RTCP packets are expected to be sent over RtpPacketTransport if
+  // RTCP-mux is enabled.
+  transport.SetRtcpMuxEnabled(true);
+  EXPECT_TRUE(transport.SendRtcpPacket(&packet, rtc::PacketOptions(), 0));
+  EXPECT_EQ(1, observer.rtp_transport_sent_count());
+}
+
 class SignalCounter : public sigslot::has_slots<> {
  public:
   explicit SignalCounter(RtpTransport* transport) {
@@ -263,7 +316,6 @@
   rtc::FakePacketTransport fake_rtp("fake_rtp");
   fake_rtp.SetDestination(&fake_rtp, true);
   transport.SetRtpPacketTransport(&fake_rtp);
-  transport.AddHandledPayloadType(0x11);
 
   // An rtp packet.
   const rtc::PacketOptions options;
@@ -274,21 +326,4 @@
   EXPECT_EQ(0, observer.rtcp_count());
 }
 
-// Test that SignalPacketReceived does not fire when a RTP packet with an
-// unhandled payload type is received.
-TEST(RtpTransportTest, DontSignalUnhandledRtpPayloadType) {
-  RtpTransport transport(kMuxDisabled);
-  SignalPacketReceivedCounter observer(&transport);
-  rtc::FakePacketTransport fake_rtp("fake_rtp");
-  fake_rtp.SetDestination(&fake_rtp, true);
-  transport.SetRtpPacketTransport(&fake_rtp);
-
-  const rtc::PacketOptions options;
-  const int flags = 0;
-  rtc::Buffer rtp_data(kRtpData, kRtpLen);
-  fake_rtp.SendPacket(rtp_data.data<char>(), kRtpLen, options, flags);
-  EXPECT_EQ(0, observer.rtp_count());
-  EXPECT_EQ(0, observer.rtcp_count());
-}
-
 }  // namespace webrtc
diff --git a/pc/rtptransportinternal.h b/pc/rtptransportinternal.h
index 0665fd7..a354936 100644
--- a/pc/rtptransportinternal.h
+++ b/pc/rtptransportinternal.h
@@ -13,11 +13,12 @@
 
 #include <string>
 
-#include "api/ortc/rtptransportinterface.h"
+#include "api/ortc/srtptransportinterface.h"
 #include "api/umametrics.h"
 #include "p2p/base/icetransportinternal.h"
 #include "rtc_base/networkroute.h"
 #include "rtc_base/sigslot.h"
+#include "rtc_base/sslstreamadapter.h"
 
 namespace rtc {
 class CopyOnWriteBuffer;
@@ -27,11 +28,11 @@
 
 namespace webrtc {
 
-// This represents the internal interface beneath RtpTransportInterface;
+// This represents the internal interface beneath SrtpTransportInterface;
 // it is not accessible to API consumers but is accessible to internal classes
 // in order to send and receive RTP and RTCP packets belonging to a single RTP
 // session. Additional convenience and configuration methods are also provided.
-class RtpTransportInternal : public RtpTransportInterface,
+class RtpTransportInternal : public SrtpTransportInterface,
                              public sigslot::has_slots<> {
  public:
   virtual void SetRtcpMuxEnabled(bool enable) = 0;
@@ -47,6 +48,8 @@
   virtual rtc::PacketTransportInternal* rtcp_packet_transport() const = 0;
   virtual void SetRtcpPacketTransport(rtc::PacketTransportInternal* rtcp) = 0;
 
+  virtual bool IsReadyToSend() const = 0;
+
   // Called whenever a transport's ready-to-send state changes. The argument
   // is true if all used transports are ready to send. This is more specific
   // than just "writable"; it means the last send didn't return ENOTCONN.
@@ -80,9 +83,7 @@
                               const rtc::PacketOptions& options,
                               int flags) = 0;
 
-  virtual bool HandlesPayloadType(int payload_type) const = 0;
-
-  virtual void AddHandledPayloadType(int payload_type) = 0;
+  virtual bool IsSrtpActive() const = 0;
 
   virtual void SetMetricsObserver(
       rtc::scoped_refptr<MetricsObserverInterface> metrics_observer) = 0;
diff --git a/pc/rtptransportinternaladapter.h b/pc/rtptransportinternaladapter.h
index 6a2d7e2..a1f4bfc 100644
--- a/pc/rtptransportinternaladapter.h
+++ b/pc/rtptransportinternaladapter.h
@@ -24,6 +24,8 @@
 // methods.
 class RtpTransportInternalAdapter : public RtpTransportInternal {
  public:
+  RtpTransportInternalAdapter() {}
+
   explicit RtpTransportInternalAdapter(RtpTransportInternal* transport)
       : transport_(transport) {
     RTC_DCHECK(transport_);
@@ -51,6 +53,8 @@
     transport_->SetRtcpPacketTransport(rtcp);
   }
 
+  bool IsReadyToSend() const override { return transport_->IsReadyToSend(); }
+
   bool IsWritable(bool rtcp) const override {
     return transport_->IsWritable(rtcp);
   }
@@ -67,14 +71,6 @@
     return transport_->SendRtcpPacket(packet, options, flags);
   }
 
-  bool HandlesPayloadType(int payload_type) const override {
-    return transport_->HandlesPayloadType(payload_type);
-  }
-
-  void AddHandledPayloadType(int payload_type) override {
-    return transport_->AddHandledPayloadType(payload_type);
-  }
-
   // RtpTransportInterface overrides.
   PacketTransportInterface* GetRtpPacketTransport() const override {
     return transport_->GetRtpPacketTransport();
@@ -92,6 +88,8 @@
     return transport_->GetParameters();
   }
 
+  RtpTransportAdapter* GetInternal() override { return nullptr; }
+
   void SetMetricsObserver(
       rtc::scoped_refptr<MetricsObserverInterface> metrics_observer) override {
     transport_->SetMetricsObserver(metrics_observer);
@@ -99,7 +97,7 @@
 
  protected:
   // Owned by the subclasses.
-  RtpTransportInternal* transport_;
+  RtpTransportInternal* transport_ = nullptr;
 };
 
 }  // namespace webrtc
diff --git a/pc/srtptransport.cc b/pc/srtptransport.cc
index 5eff3c9..3e7b154 100644
--- a/pc/srtptransport.cc
+++ b/pc/srtptransport.cc
@@ -21,19 +21,19 @@
 #include "rtc_base/copyonwritebuffer.h"
 #include "rtc_base/ptr_util.h"
 #include "rtc_base/trace_event.h"
+#include "rtc_base/zero_memory.h"
 
 namespace webrtc {
 
 SrtpTransport::SrtpTransport(bool rtcp_mux_enabled)
     : RtpTransportInternalAdapter(new RtpTransport(rtcp_mux_enabled)) {
   // Own the raw pointer |transport| from the base class.
-  rtp_transport_.reset(transport_);
+  rtp_transport_.reset(static_cast<RtpTransport*>(transport_));
   RTC_DCHECK(rtp_transport_);
   ConnectToRtpTransport();
 }
 
-SrtpTransport::SrtpTransport(
-    std::unique_ptr<RtpTransportInternal> rtp_transport)
+SrtpTransport::SrtpTransport(std::unique_ptr<RtpTransport> rtp_transport)
     : RtpTransportInternalAdapter(rtp_transport.get()),
       rtp_transport_(std::move(rtp_transport)) {
   RTC_DCHECK(rtp_transport_);
@@ -52,6 +52,86 @@
   rtp_transport_->SignalSentPacket.connect(this, &SrtpTransport::OnSentPacket);
 }
 
+RTCError SrtpTransport::SetSrtpSendKey(const cricket::CryptoParams& params) {
+  if (send_params_) {
+    LOG_AND_RETURN_ERROR(
+        webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+        "Setting the SRTP send key twice is currently unsupported.");
+  }
+  if (recv_params_ && recv_params_->cipher_suite != params.cipher_suite) {
+    LOG_AND_RETURN_ERROR(
+        webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+        "The send key and receive key must have the same cipher suite.");
+  }
+
+  send_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(params.cipher_suite);
+  if (*send_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) {
+    return RTCError(RTCErrorType::INVALID_PARAMETER,
+                    "Invalid SRTP crypto suite");
+  }
+
+  int send_key_len, send_salt_len;
+  if (!rtc::GetSrtpKeyAndSaltLengths(*send_cipher_suite_, &send_key_len,
+                                     &send_salt_len)) {
+    return RTCError(RTCErrorType::INVALID_PARAMETER,
+                    "Could not get lengths for crypto suite(s):"
+                    " send cipher_suite ");
+  }
+
+  send_key_ = rtc::ZeroOnFreeBuffer<uint8_t>(send_key_len + send_salt_len);
+  if (!ParseKeyParams(params.key_params, send_key_.data(), send_key_.size())) {
+    return RTCError(RTCErrorType::INVALID_PARAMETER,
+                    "Failed to parse the crypto key params");
+  }
+
+  if (!MaybeSetKeyParams()) {
+    return RTCError(RTCErrorType::INVALID_PARAMETER,
+                    "Failed to set the crypto key params");
+  }
+  send_params_ = params;
+  return RTCError::OK();
+}
+
+RTCError SrtpTransport::SetSrtpReceiveKey(const cricket::CryptoParams& params) {
+  if (recv_params_) {
+    LOG_AND_RETURN_ERROR(
+        webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+        "Setting the SRTP send key twice is currently unsupported.");
+  }
+  if (send_params_ && send_params_->cipher_suite != params.cipher_suite) {
+    LOG_AND_RETURN_ERROR(
+        webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+        "The send key and receive key must have the same cipher suite.");
+  }
+
+  recv_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(params.cipher_suite);
+  if (*recv_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) {
+    return RTCError(RTCErrorType::INVALID_PARAMETER,
+                    "Invalid SRTP crypto suite");
+  }
+
+  int recv_key_len, recv_salt_len;
+  if (!rtc::GetSrtpKeyAndSaltLengths(*recv_cipher_suite_, &recv_key_len,
+                                     &recv_salt_len)) {
+    return RTCError(RTCErrorType::INVALID_PARAMETER,
+                    "Could not get lengths for crypto suite(s):"
+                    " recv cipher_suite ");
+  }
+
+  recv_key_ = rtc::ZeroOnFreeBuffer<uint8_t>(recv_key_len + recv_salt_len);
+  if (!ParseKeyParams(params.key_params, recv_key_.data(), recv_key_.size())) {
+    return RTCError(RTCErrorType::INVALID_PARAMETER,
+                    "Failed to parse the crypto key params");
+  }
+
+  if (!MaybeSetKeyParams()) {
+    return RTCError(RTCErrorType::INVALID_PARAMETER,
+                    "Failed to set the crypto key params");
+  }
+  recv_params_ = params;
+  return RTCError::OK();
+}
+
 bool SrtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
                                   const rtc::PacketOptions& options,
                                   int flags) {
@@ -68,7 +148,7 @@
                                rtc::CopyOnWriteBuffer* packet,
                                const rtc::PacketOptions& options,
                                int flags) {
-  if (!IsActive()) {
+  if (!IsSrtpActive()) {
     RTC_LOG(LS_ERROR)
         << "Failed to send the packet because SRTP transport is inactive.";
     return false;
@@ -140,7 +220,7 @@
 void SrtpTransport::OnPacketReceived(bool rtcp,
                                      rtc::CopyOnWriteBuffer* packet,
                                      const rtc::PacketTime& packet_time) {
-  if (!IsActive()) {
+  if (!IsSrtpActive()) {
     RTC_LOG(LS_WARNING)
         << "Inactive SRTP transport received a packet. Drop it.";
     return;
@@ -181,7 +261,7 @@
   // Only append the SRTP overhead when there is a selected network route.
   if (network_route) {
     int srtp_overhead = 0;
-    if (IsActive()) {
+    if (IsSrtpActive()) {
       GetSrtpOverhead(&srtp_overhead);
     }
     network_route->packet_overhead += srtp_overhead;
@@ -271,7 +351,7 @@
   return true;
 }
 
-bool SrtpTransport::IsActive() const {
+bool SrtpTransport::IsSrtpActive() const {
   return send_session_ && recv_session_;
 }
 
@@ -297,7 +377,7 @@
 }
 
 bool SrtpTransport::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
-  if (!IsActive()) {
+  if (!IsSrtpActive()) {
     RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
     return false;
   }
@@ -310,7 +390,7 @@
                                int max_len,
                                int* out_len,
                                int64_t* index) {
-  if (!IsActive()) {
+  if (!IsSrtpActive()) {
     RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
     return false;
   }
@@ -322,7 +402,7 @@
                                 int in_len,
                                 int max_len,
                                 int* out_len) {
-  if (!IsActive()) {
+  if (!IsSrtpActive()) {
     RTC_LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
     return false;
   }
@@ -335,7 +415,7 @@
 }
 
 bool SrtpTransport::UnprotectRtp(void* p, int in_len, int* out_len) {
-  if (!IsActive()) {
+  if (!IsSrtpActive()) {
     RTC_LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active";
     return false;
   }
@@ -344,7 +424,7 @@
 }
 
 bool SrtpTransport::UnprotectRtcp(void* p, int in_len, int* out_len) {
-  if (!IsActive()) {
+  if (!IsSrtpActive()) {
     RTC_LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
     return false;
   }
@@ -359,7 +439,7 @@
 bool SrtpTransport::GetRtpAuthParams(uint8_t** key,
                                      int* key_len,
                                      int* tag_len) {
-  if (!IsActive()) {
+  if (!IsSrtpActive()) {
     RTC_LOG(LS_WARNING) << "Failed to GetRtpAuthParams: SRTP not active";
     return false;
   }
@@ -369,7 +449,7 @@
 }
 
 bool SrtpTransport::GetSrtpOverhead(int* srtp_overhead) const {
-  if (!IsActive()) {
+  if (!IsSrtpActive()) {
     RTC_LOG(LS_WARNING) << "Failed to GetSrtpOverhead: SRTP not active";
     return false;
   }
@@ -380,7 +460,7 @@
 }
 
 void SrtpTransport::EnableExternalAuth() {
-  RTC_DCHECK(!IsActive());
+  RTC_DCHECK(!IsSrtpActive());
   external_auth_enabled_ = true;
 }
 
@@ -389,7 +469,7 @@
 }
 
 bool SrtpTransport::IsExternalAuthActive() const {
-  if (!IsActive()) {
+  if (!IsSrtpActive()) {
     RTC_LOG(LS_WARNING)
         << "Failed to check IsExternalAuthActive: SRTP not active";
     return false;
@@ -399,6 +479,42 @@
   return send_session_->IsExternalAuthActive();
 }
 
+bool SrtpTransport::MaybeSetKeyParams() {
+  if (!send_cipher_suite_ || !recv_cipher_suite_) {
+    return true;
+  }
+
+  return SetRtpParams(*send_cipher_suite_, send_key_.data(),
+                      static_cast<int>(send_key_.size()), std::vector<int>(),
+                      *recv_cipher_suite_, recv_key_.data(),
+                      static_cast<int>(recv_key_.size()), std::vector<int>());
+}
+
+bool SrtpTransport::ParseKeyParams(const std::string& key_params,
+                                   uint8_t* key,
+                                   size_t len) {
+  // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2"
+
+  // Fail if key-method is wrong.
+  if (key_params.find("inline:") != 0) {
+    return false;
+  }
+
+  // Fail if base64 decode fails, or the key is the wrong size.
+  std::string key_b64(key_params.substr(7)), key_str;
+  if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, &key_str,
+                           nullptr) ||
+      key_str.size() != len) {
+    return false;
+  }
+
+  memcpy(key, key_str.c_str(), len);
+  // TODO(bugs.webrtc.org/8905): Switch to ZeroOnFreeBuffer for storing
+  // sensitive data.
+  rtc::ExplicitZeroMemory(&key_str[0], key_str.size());
+  return true;
+}
+
 void SrtpTransport::SetMetricsObserver(
     rtc::scoped_refptr<MetricsObserverInterface> metrics_observer) {
   metrics_observer_ = metrics_observer;
diff --git a/pc/srtptransport.h b/pc/srtptransport.h
index 818aabb..5bc9970 100644
--- a/pc/srtptransport.h
+++ b/pc/srtptransport.h
@@ -16,10 +16,13 @@
 #include <utility>
 #include <vector>
 
+#include "api/ortc/srtptransportinterface.h"
+#include "p2p/base/dtlstransportinternal.h"
 #include "p2p/base/icetransportinternal.h"
+#include "pc/rtptransport.h"
 #include "pc/rtptransportinternaladapter.h"
-#include "pc/srtpfilter.h"
 #include "pc/srtpsession.h"
+#include "rtc_base/buffer.h"
 #include "rtc_base/checks.h"
 
 namespace webrtc {
@@ -30,7 +33,29 @@
  public:
   explicit SrtpTransport(bool rtcp_mux_enabled);
 
-  explicit SrtpTransport(std::unique_ptr<RtpTransportInternal> rtp_transport);
+  explicit SrtpTransport(std::unique_ptr<RtpTransport> rtp_transport);
+
+  virtual ~SrtpTransport() {}
+
+  // SrtpTransportInterface overrides.
+  PacketTransportInterface* GetRtpPacketTransport() const override {
+    return rtp_transport_->GetRtpPacketTransport();
+  }
+  PacketTransportInterface* GetRtcpPacketTransport() const override {
+    return rtp_transport_->GetRtcpPacketTransport();
+  }
+
+  // TODO(zstein): Use these RtcpParameters for configuration elsewhere.
+  RTCError SetParameters(const RtpTransportParameters& parameters) override {
+    return rtp_transport_->SetParameters(parameters);
+  }
+  RtpTransportParameters GetParameters() const override {
+    return rtp_transport_->GetParameters();
+  }
+
+  // SrtpTransportInterface specific implementation.
+  RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override;
+  RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) override;
 
   bool SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
                      const rtc::PacketOptions& options,
@@ -42,10 +67,7 @@
 
   // The transport becomes active if the send_session_ and recv_session_ are
   // created.
-  bool IsActive() const;
-
-  // TODO(zstein): Remove this when we remove RtpTransportAdapter.
-  RtpTransportAdapter* GetInternal() override { return nullptr; }
+  bool IsSrtpActive() const override;
 
   // Create new send/recv sessions and set the negotiated crypto keys for RTP
   // packet encryption. The keys can either come from SDES negotiation or DTLS
@@ -138,14 +160,24 @@
 
   bool UnprotectRtcp(void* data, int in_len, int* out_len);
 
+  bool MaybeSetKeyParams();
+  bool ParseKeyParams(const std::string& key_params, uint8_t* key, size_t len);
+
   const std::string content_name_;
-  std::unique_ptr<RtpTransportInternal> rtp_transport_;
+  std::unique_ptr<RtpTransport> rtp_transport_;
 
   std::unique_ptr<cricket::SrtpSession> send_session_;
   std::unique_ptr<cricket::SrtpSession> recv_session_;
   std::unique_ptr<cricket::SrtpSession> send_rtcp_session_;
   std::unique_ptr<cricket::SrtpSession> recv_rtcp_session_;
 
+  rtc::Optional<cricket::CryptoParams> send_params_;
+  rtc::Optional<cricket::CryptoParams> recv_params_;
+  rtc::Optional<int> send_cipher_suite_;
+  rtc::Optional<int> recv_cipher_suite_;
+  rtc::ZeroOnFreeBuffer<uint8_t> send_key_;
+  rtc::ZeroOnFreeBuffer<uint8_t> recv_key_;
+
   bool external_auth_enabled_ = false;
 
   int rtp_abs_sendtime_extn_id_ = -1;
diff --git a/pc/srtptransport_unittest.cc b/pc/srtptransport_unittest.cc
index e0b2302..30e30f6 100644
--- a/pc/srtptransport_unittest.cc
+++ b/pc/srtptransport_unittest.cc
@@ -57,12 +57,6 @@
     rtp_transport1->SetRtpPacketTransport(rtp_packet_transport1_.get());
     rtp_transport2->SetRtpPacketTransport(rtp_packet_transport2_.get());
 
-    // Add payload type for RTP packet and RTCP packet.
-    rtp_transport1->AddHandledPayloadType(0x00);
-    rtp_transport2->AddHandledPayloadType(0x00);
-    rtp_transport1->AddHandledPayloadType(0xc9);
-    rtp_transport2->AddHandledPayloadType(0xc9);
-
     srtp_transport1_ =
         rtc::MakeUnique<SrtpTransport>(std::move(rtp_transport1));
     srtp_transport2_ =
@@ -229,8 +223,8 @@
         cs, key1, key1_len, extension_ids, cs, key2, key2_len, extension_ids));
     EXPECT_TRUE(srtp_transport2_->SetRtcpParams(
         cs, key2, key2_len, extension_ids, cs, key1, key1_len, extension_ids));
-    EXPECT_TRUE(srtp_transport1_->IsActive());
-    EXPECT_TRUE(srtp_transport2_->IsActive());
+    EXPECT_TRUE(srtp_transport1_->IsSrtpActive());
+    EXPECT_TRUE(srtp_transport2_->IsSrtpActive());
     if (rtc::IsGcmCryptoSuite(cs)) {
       EXPECT_FALSE(srtp_transport1_->IsExternalAuthActive());
       EXPECT_FALSE(srtp_transport2_->IsExternalAuthActive());
@@ -315,8 +309,8 @@
     EXPECT_TRUE(srtp_transport2_->SetRtpParams(cs, key2, key2_len,
                                                encrypted_headers, cs, key1,
                                                key1_len, encrypted_headers));
-    EXPECT_TRUE(srtp_transport1_->IsActive());
-    EXPECT_TRUE(srtp_transport2_->IsActive());
+    EXPECT_TRUE(srtp_transport1_->IsSrtpActive());
+    EXPECT_TRUE(srtp_transport2_->IsSrtpActive());
     EXPECT_FALSE(srtp_transport1_->IsExternalAuthActive());
     EXPECT_FALSE(srtp_transport2_->IsExternalAuthActive());
     TestSendRecvPacketWithEncryptedHeaderExtension(cs_name, encrypted_headers);
diff --git a/pc/test/fakepeerconnectionforstats.h b/pc/test/fakepeerconnectionforstats.h
index 1c2fb70..733291f 100644
--- a/pc/test/fakepeerconnectionforstats.h
+++ b/pc/test/fakepeerconnectionforstats.h
@@ -124,8 +124,8 @@
     auto* voice_media_channel_ptr = voice_media_channel.get();
     voice_channel_ = rtc::MakeUnique<cricket::VoiceChannel>(
         worker_thread_, network_thread_, signaling_thread_, nullptr,
-        std::move(voice_media_channel), mid, kDefaultRtcpMuxRequired,
-        kDefaultSrtpRequired);
+        std::move(voice_media_channel), mid, kDefaultSrtpRequired,
+        rtc::CryptoOptions());
     voice_channel_->set_transport_name_for_testing(transport_name);
     GetOrCreateFirstTransceiverOfType(cricket::MEDIA_TYPE_AUDIO)
         ->internal()
@@ -141,8 +141,8 @@
     auto video_media_channel_ptr = video_media_channel.get();
     video_channel_ = rtc::MakeUnique<cricket::VideoChannel>(
         worker_thread_, network_thread_, signaling_thread_,
-        std::move(video_media_channel), mid, kDefaultRtcpMuxRequired,
-        kDefaultSrtpRequired);
+        std::move(video_media_channel), mid, kDefaultSrtpRequired,
+        rtc::CryptoOptions());
     video_channel_->set_transport_name_for_testing(transport_name);
     GetOrCreateFirstTransceiverOfType(cricket::MEDIA_TYPE_VIDEO)
         ->internal()
diff --git a/pc/test/faketransportcontroller.h b/pc/test/faketransportcontroller.h
deleted file mode 100644
index 4a4cc96..0000000
--- a/pc/test/faketransportcontroller.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- *  Copyright 2009 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_TEST_FAKETRANSPORTCONTROLLER_H_
-#define PC_TEST_FAKETRANSPORTCONTROLLER_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "p2p/base/fakedtlstransport.h"
-#include "p2p/base/fakeicetransport.h"
-#include "pc/transportcontroller.h"
-#include "rtc_base/bind.h"
-#include "rtc_base/sslfingerprint.h"
-#include "rtc_base/thread.h"
-
-namespace cricket {
-
-// Fake TransportController class, which can be passed into a WebRtcSession
-// object for test purposes. Can be connected to other FakeTransportControllers
-// via Connect().
-//
-// This fake is unusual in that for the most part, it's implemented with the
-// real TransportController code, but with fake TransportChannels underneath.
-class FakeTransportController : public TransportController {
- public:
-  FakeTransportController()
-      : TransportController(rtc::Thread::Current(),
-                            rtc::Thread::Current(),
-                            nullptr,
-                            /*redetermine_role_on_ice_restart=*/true,
-                            rtc::CryptoOptions()) {}
-
-  explicit FakeTransportController(bool redetermine_role_on_ice_restart)
-      : TransportController(rtc::Thread::Current(),
-                            rtc::Thread::Current(),
-                            nullptr,
-                            redetermine_role_on_ice_restart,
-                            rtc::CryptoOptions()) {}
-
-  explicit FakeTransportController(IceRole role)
-      : TransportController(rtc::Thread::Current(),
-                            rtc::Thread::Current(),
-                            nullptr,
-                            /*redetermine_role_on_ice_restart=*/true,
-                            rtc::CryptoOptions()) {
-    SetIceRole(role);
-  }
-
-  explicit FakeTransportController(rtc::Thread* network_thread)
-      : TransportController(rtc::Thread::Current(),
-                            network_thread,
-                            nullptr,
-                            /*redetermine_role_on_ice_restart=*/true,
-                            rtc::CryptoOptions()) {}
-
-  FakeTransportController(rtc::Thread* network_thread, IceRole role)
-      : TransportController(rtc::Thread::Current(),
-                            network_thread,
-                            nullptr,
-                            /*redetermine_role_on_ice_restart=*/true,
-                            rtc::CryptoOptions()) {
-    SetIceRole(role);
-  }
-
-  FakeDtlsTransport* GetFakeDtlsTransport_n(const std::string& transport_name,
-                                            int component) {
-    return static_cast<FakeDtlsTransport*>(
-        get_channel_for_testing(transport_name, component));
-  }
-
-  // Simulate the exchange of transport descriptions, and the gathering and
-  // exchange of ICE candidates.
-  void Connect(FakeTransportController* dest) {
-    for (const std::string& transport_name : transport_names_for_testing()) {
-      std::unique_ptr<rtc::SSLFingerprint> local_fingerprint;
-      std::unique_ptr<rtc::SSLFingerprint> remote_fingerprint;
-      if (certificate_for_testing()) {
-        local_fingerprint.reset(rtc::SSLFingerprint::CreateFromCertificate(
-            certificate_for_testing()));
-      }
-      if (dest->certificate_for_testing()) {
-        remote_fingerprint.reset(rtc::SSLFingerprint::CreateFromCertificate(
-            dest->certificate_for_testing()));
-      }
-      TransportDescription local_desc(
-          std::vector<std::string>(),
-          rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH),
-          rtc::CreateRandomString(cricket::ICE_PWD_LENGTH),
-          cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_NONE,
-          local_fingerprint.get());
-      TransportDescription remote_desc(
-          std::vector<std::string>(),
-          rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH),
-          rtc::CreateRandomString(cricket::ICE_PWD_LENGTH),
-          cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_NONE,
-          remote_fingerprint.get());
-      std::string err;
-      SetLocalTransportDescription(transport_name, local_desc,
-                                   webrtc::SdpType::kOffer, &err);
-      dest->SetRemoteTransportDescription(transport_name, local_desc,
-                                          webrtc::SdpType::kOffer, &err);
-      dest->SetLocalTransportDescription(transport_name, remote_desc,
-                                         webrtc::SdpType::kAnswer, &err);
-      SetRemoteTransportDescription(transport_name, remote_desc,
-                                    webrtc::SdpType::kAnswer, &err);
-    }
-    MaybeStartGathering();
-    dest->MaybeStartGathering();
-    network_thread()->Invoke<void>(
-        RTC_FROM_HERE,
-        rtc::Bind(&FakeTransportController::SetChannelDestinations_n, this,
-                  dest));
-  }
-
-  void DestroyRtcpTransport(const std::string& transport_name) {
-    DestroyDtlsTransport_n(transport_name,
-                           cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-  }
-
- protected:
-  IceTransportInternal* CreateIceTransportChannel_n(
-      const std::string& transport_name,
-      int component) override {
-    return new FakeIceTransport(transport_name, component);
-  }
-
-  DtlsTransportInternal* CreateDtlsTransportChannel_n(
-      const std::string& transport_name,
-      int component,
-      IceTransportInternal* ice) override {
-    return new FakeDtlsTransport(static_cast<FakeIceTransport*>(ice));
-  }
-
- private:
-  void SetChannelDestinations_n(FakeTransportController* dest) {
-    for (DtlsTransportInternal* tc : channels_for_testing()) {
-      FakeDtlsTransport* local = static_cast<FakeDtlsTransport*>(tc);
-      FakeDtlsTransport* remote = dest->GetFakeDtlsTransport_n(
-          local->transport_name(), local->component());
-      if (remote) {
-        bool asymmetric = false;
-        local->SetDestination(remote, asymmetric);
-      }
-    }
-  }
-};
-
-}  // namespace cricket
-
-#endif  // PC_TEST_FAKETRANSPORTCONTROLLER_H_
diff --git a/pc/test/testsdpstrings.h b/pc/test/testsdpstrings.h
index 0d751aa..ea9935c 100644
--- a/pc/test/testsdpstrings.h
+++ b/pc/test/testsdpstrings.h
@@ -61,7 +61,7 @@
     "a=candidate:5 2 UDP 1694302206 74.95.2.170 33611 typ srflx raddr"
     " 10.0.254.2 rport 58890\r\n"
 #ifdef HAVE_SCTP
-    "m=application 45536 SCTP/DTLS 5000\r\n"
+    "m=application 45536 DTLS/SCTP 5000\r\n"
     "c=IN IP4 74.95.2.170\r\n"
     "a=fmtp:5000 protocol=webrtc-datachannel;streams=16\r\n"
     "a=sendrecv\r\n"
diff --git a/pc/transportcontroller.cc b/pc/transportcontroller.cc
deleted file mode 100644
index 4e20981..0000000
--- a/pc/transportcontroller.cc
+++ /dev/null
@@ -1,1101 +0,0 @@
-/*
- *  Copyright 2015 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.
- */
-
-#include "pc/transportcontroller.h"
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-
-#include "p2p/base/port.h"
-#include "rtc_base/bind.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/ptr_util.h"
-#include "rtc_base/thread.h"
-
-using webrtc::SdpType;
-
-namespace {
-
-enum {
-  MSG_ICECONNECTIONSTATE,
-  MSG_RECEIVING,
-  MSG_ICEGATHERINGSTATE,
-  MSG_CANDIDATESGATHERED,
-};
-
-struct CandidatesData : public rtc::MessageData {
-  CandidatesData(const std::string& transport_name,
-                 const cricket::Candidates& candidates)
-      : transport_name(transport_name), candidates(candidates) {}
-
-  std::string transport_name;
-  cricket::Candidates candidates;
-};
-
-bool VerifyCandidate(const cricket::Candidate& cand, std::string* error) {
-  // No address zero.
-  if (cand.address().IsNil() || cand.address().IsAnyIP()) {
-    *error = "candidate has address of zero";
-    return false;
-  }
-
-  // Disallow all ports below 1024, except for 80 and 443 on public addresses.
-  int port = cand.address().port();
-  if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
-      (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
-    // Expected for active-only candidates per
-    // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
-    // Libjingle clients emit port 0, in "active" mode.
-    return true;
-  }
-  if (port < 1024) {
-    if ((port != 80) && (port != 443)) {
-      *error = "candidate has port below 1024, but not 80 or 443";
-      return false;
-    }
-
-    if (cand.address().IsPrivateIP()) {
-      *error = "candidate has port of 80 or 443 with private IP address";
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool VerifyCandidates(const cricket::Candidates& candidates,
-                      std::string* error) {
-  for (const cricket::Candidate& candidate : candidates) {
-    if (!VerifyCandidate(candidate, error)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-}  // namespace
-
-namespace cricket {
-
-// This class groups the DTLS and ICE channels, and helps keep track of
-// how many external objects (BaseChannels) reference each channel.
-class TransportController::ChannelPair {
- public:
-  // TODO(deadbeef): Change the types of |dtls| and |ice| to
-  // DtlsTransport and P2PTransportChannelWrapper, once TransportChannelImpl is
-  // removed.
-  ChannelPair(DtlsTransportInternal* dtls, IceTransportInternal* ice)
-      : ice_(ice), dtls_(dtls) {}
-
-  // Currently, all ICE-related calls still go through this DTLS channel. But
-  // that will change once we get rid of TransportChannelImpl, and the DTLS
-  // channel interface no longer includes ICE-specific methods.
-  const DtlsTransportInternal* dtls() const { return dtls_.get(); }
-  DtlsTransportInternal* dtls() { return dtls_.get(); }
-  const IceTransportInternal* ice() const { return ice_.get(); }
-  IceTransportInternal* ice() { return ice_.get(); }
-
- private:
-  std::unique_ptr<IceTransportInternal> ice_;
-  std::unique_ptr<DtlsTransportInternal> dtls_;
-
-  RTC_DISALLOW_COPY_AND_ASSIGN(ChannelPair);
-};
-
-TransportController::TransportController(
-    rtc::Thread* signaling_thread,
-    rtc::Thread* network_thread,
-    PortAllocator* port_allocator,
-    bool redetermine_role_on_ice_restart,
-    const rtc::CryptoOptions& crypto_options,
-    webrtc::RtcEventLog* event_log)
-    : signaling_thread_(signaling_thread),
-      network_thread_(network_thread),
-      port_allocator_(port_allocator),
-      redetermine_role_on_ice_restart_(redetermine_role_on_ice_restart),
-      crypto_options_(crypto_options),
-      event_log_(event_log) {}
-
-TransportController::~TransportController() {
-  // Channel destructors may try to send packets, so this needs to happen on
-  // the network thread.
-  network_thread_->Invoke<void>(
-      RTC_FROM_HERE,
-      rtc::Bind(&TransportController::DestroyAllChannels_n, this));
-}
-
-bool TransportController::SetSslMaxProtocolVersion(
-    rtc::SSLProtocolVersion version) {
-  return network_thread_->Invoke<bool>(
-      RTC_FROM_HERE, rtc::Bind(&TransportController::SetSslMaxProtocolVersion_n,
-                               this, version));
-}
-
-void TransportController::SetIceConfig(const IceConfig& config) {
-  network_thread_->Invoke<void>(
-      RTC_FROM_HERE,
-      rtc::Bind(&TransportController::SetIceConfig_n, this, config));
-}
-
-void TransportController::SetIceRole(IceRole ice_role) {
-  network_thread_->Invoke<void>(
-      RTC_FROM_HERE,
-      rtc::Bind(&TransportController::SetIceRole_n, this, ice_role));
-}
-
-void TransportController::SetNeedsIceRestartFlag() {
-  for (auto& kv : transports_) {
-    kv.second->SetNeedsIceRestartFlag();
-  }
-}
-
-bool TransportController::NeedsIceRestart(
-    const std::string& transport_name) const {
-  const JsepTransport* transport = GetJsepTransport(transport_name);
-  if (!transport) {
-    return false;
-  }
-  return transport->NeedsIceRestart();
-}
-
-bool TransportController::GetSslRole(const std::string& transport_name,
-                                     rtc::SSLRole* role) const {
-  return network_thread_->Invoke<bool>(
-      RTC_FROM_HERE, rtc::Bind(&TransportController::GetSslRole_n, this,
-                               transport_name, role));
-}
-
-bool TransportController::SetLocalCertificate(
-    const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
-  return network_thread_->Invoke<bool>(
-      RTC_FROM_HERE, rtc::Bind(&TransportController::SetLocalCertificate_n,
-                               this, certificate));
-}
-
-bool TransportController::GetLocalCertificate(
-    const std::string& transport_name,
-    rtc::scoped_refptr<rtc::RTCCertificate>* certificate) const {
-  if (network_thread_->IsCurrent()) {
-    return GetLocalCertificate_n(transport_name, certificate);
-  }
-  return network_thread_->Invoke<bool>(
-      RTC_FROM_HERE, rtc::Bind(&TransportController::GetLocalCertificate_n,
-                               this, transport_name, certificate));
-}
-
-std::unique_ptr<rtc::SSLCertChain> TransportController::GetRemoteSSLCertChain(
-    const std::string& transport_name) const {
-  if (!network_thread_->IsCurrent()) {
-    return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
-        RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
-  }
-
-  // Get the certificate from the RTP channel's DTLS handshake. Should be
-  // identical to the RTCP channel's, since they were given the same remote
-  // fingerprint.
-  const RefCountedChannel* ch =
-      GetChannel_n(transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-  if (!ch) {
-    return nullptr;
-  }
-  return ch->dtls()->GetRemoteSSLCertChain();
-}
-
-bool TransportController::SetLocalTransportDescription(
-    const std::string& transport_name,
-    const TransportDescription& tdesc,
-    SdpType type,
-    std::string* err) {
-  return network_thread_->Invoke<bool>(
-      RTC_FROM_HERE,
-      rtc::Bind(&TransportController::SetLocalTransportDescription_n, this,
-                transport_name, tdesc, type, err));
-}
-
-bool TransportController::SetRemoteTransportDescription(
-    const std::string& transport_name,
-    const TransportDescription& tdesc,
-    SdpType type,
-    std::string* err) {
-  return network_thread_->Invoke<bool>(
-      RTC_FROM_HERE,
-      rtc::Bind(&TransportController::SetRemoteTransportDescription_n, this,
-                transport_name, tdesc, type, err));
-}
-
-void TransportController::MaybeStartGathering() {
-  network_thread_->Invoke<void>(
-      RTC_FROM_HERE,
-      rtc::Bind(&TransportController::MaybeStartGathering_n, this));
-}
-
-bool TransportController::AddRemoteCandidates(const std::string& transport_name,
-                                              const Candidates& candidates,
-                                              std::string* err) {
-  return network_thread_->Invoke<bool>(
-      RTC_FROM_HERE, rtc::Bind(&TransportController::AddRemoteCandidates_n,
-                               this, transport_name, candidates, err));
-}
-
-bool TransportController::RemoveRemoteCandidates(const Candidates& candidates,
-                                                 std::string* err) {
-  return network_thread_->Invoke<bool>(
-      RTC_FROM_HERE, rtc::Bind(&TransportController::RemoveRemoteCandidates_n,
-                               this, candidates, err));
-}
-
-bool TransportController::ReadyForRemoteCandidates(
-    const std::string& transport_name) const {
-  return network_thread_->Invoke<bool>(
-      RTC_FROM_HERE, rtc::Bind(&TransportController::ReadyForRemoteCandidates_n,
-                               this, transport_name));
-}
-
-bool TransportController::GetStats(const std::string& transport_name,
-                                   TransportStats* stats) {
-  if (network_thread_->IsCurrent()) {
-    return GetStats_n(transport_name, stats);
-  }
-  return network_thread_->Invoke<bool>(
-      RTC_FROM_HERE,
-      rtc::Bind(&TransportController::GetStats_n, this, transport_name, stats));
-}
-
-void TransportController::SetMetricsObserver(
-    webrtc::MetricsObserverInterface* metrics_observer) {
-  return network_thread_->Invoke<void>(
-      RTC_FROM_HERE, rtc::Bind(&TransportController::SetMetricsObserver_n, this,
-                               metrics_observer));
-}
-
-DtlsTransportInternal* TransportController::CreateDtlsTransport(
-    const std::string& transport_name,
-    int component) {
-  return network_thread_->Invoke<DtlsTransportInternal*>(
-      RTC_FROM_HERE, rtc::Bind(&TransportController::CreateDtlsTransport_n,
-                               this, transport_name, component));
-}
-
-DtlsTransportInternal* TransportController::CreateDtlsTransport_n(
-    const std::string& transport_name,
-    int component) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  RefCountedChannel* existing_channel = GetChannel_n(transport_name, component);
-  if (existing_channel) {
-    // Channel already exists; increment reference count and return.
-    existing_channel->AddRef();
-    return existing_channel->dtls();
-  }
-
-  // Need to create a new channel.
-  JsepTransport* transport = GetOrCreateJsepTransport(transport_name);
-
-  // Create DTLS channel wrapping ICE channel, and configure it.
-  IceTransportInternal* ice =
-      CreateIceTransportChannel_n(transport_name, component);
-  DtlsTransportInternal* dtls =
-      CreateDtlsTransportChannel_n(transport_name, component, ice);
-  dtls->ice_transport()->SetMetricsObserver(metrics_observer_);
-  dtls->ice_transport()->SetIceRole(ice_role_);
-  dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
-  dtls->ice_transport()->SetIceConfig(ice_config_);
-  if (certificate_) {
-    bool set_cert_success = dtls->SetLocalCertificate(certificate_);
-    RTC_DCHECK(set_cert_success);
-  }
-
-  // Connect to signals offered by the channels. Currently, the DTLS channel
-  // forwards signals from the ICE channel, so we only need to connect to the
-  // DTLS channel. In the future this won't be the case.
-  dtls->SignalWritableState.connect(
-      this, &TransportController::OnChannelWritableState_n);
-  dtls->SignalReceivingState.connect(
-      this, &TransportController::OnChannelReceivingState_n);
-  dtls->SignalDtlsHandshakeError.connect(
-      this, &TransportController::OnDtlsHandshakeError);
-  dtls->ice_transport()->SignalGatheringState.connect(
-      this, &TransportController::OnChannelGatheringState_n);
-  dtls->ice_transport()->SignalCandidateGathered.connect(
-      this, &TransportController::OnChannelCandidateGathered_n);
-  dtls->ice_transport()->SignalCandidatesRemoved.connect(
-      this, &TransportController::OnChannelCandidatesRemoved_n);
-  dtls->ice_transport()->SignalRoleConflict.connect(
-      this, &TransportController::OnChannelRoleConflict_n);
-  dtls->ice_transport()->SignalStateChanged.connect(
-      this, &TransportController::OnChannelStateChanged_n);
-  RefCountedChannel* new_pair = new RefCountedChannel(dtls, ice);
-  new_pair->AddRef();
-  channels_.insert(channels_.end(), new_pair);
-  bool channel_added = transport->AddChannel(dtls, component);
-  RTC_DCHECK(channel_added);
-  // Adding a channel could cause aggregate state to change.
-  UpdateAggregateStates_n();
-  return dtls;
-}
-
-void TransportController::DestroyDtlsTransport(
-    const std::string& transport_name,
-    int component) {
-  network_thread_->Invoke<void>(
-      RTC_FROM_HERE, rtc::Bind(&TransportController::DestroyDtlsTransport_n,
-                               this, transport_name, component));
-}
-
-void TransportController::DestroyDtlsTransport_n(
-    const std::string& transport_name,
-    int component) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  auto it = GetChannelIterator_n(transport_name, component);
-  if (it == channels_.end()) {
-    RTC_LOG(LS_WARNING) << "Attempting to delete " << transport_name
-                        << " TransportChannel " << component
-                        << ", which doesn't exist.";
-    return;
-  }
-  // Release one reference to the RefCountedChannel, and do additional cleanup
-  // only if it was the last one. Matches the AddRef logic in
-  // CreateDtlsTransport_n.
-  if ((*it)->Release() == rtc::RefCountReleaseStatus::kOtherRefsRemained) {
-    return;
-  }
-  channels_.erase(it);
-
-  JsepTransport* t = GetJsepTransport(transport_name);
-  bool channel_removed = t->RemoveChannel(component);
-  RTC_DCHECK(channel_removed);
-  // Just as we create a Transport when its first channel is created,
-  // we delete it when its last channel is deleted.
-  if (!t->HasChannels()) {
-    transports_.erase(transport_name);
-  }
-  // Removing a channel could cause aggregate state to change.
-  UpdateAggregateStates_n();
-}
-
-webrtc::SrtpTransport* TransportController::CreateSdesTransport(
-    const std::string& transport_name,
-    bool rtcp_mux_enabled) {
-  if (!network_thread_->IsCurrent()) {
-    return network_thread_->Invoke<webrtc::SrtpTransport*>(RTC_FROM_HERE, [&] {
-      return CreateSdesTransport(transport_name, rtcp_mux_enabled);
-    });
-  }
-
-  auto existing_rtp_transport = FindRtpTransport(transport_name);
-
-  if (existing_rtp_transport) {
-    // For SRTP transport wrapper, the |srtp_transport| is expected to be
-    // non-null and |dtls_srtp_transport| is expected to be a nullptr.
-    if (!existing_rtp_transport->srtp_transport ||
-        existing_rtp_transport->dtls_srtp_transport) {
-      RTC_LOG(LS_ERROR)
-          << "Failed to create an RTP transport for SDES using name: "
-          << transport_name << " because the type doesn't match.";
-      return nullptr;
-    }
-    existing_rtp_transport->AddRef();
-    return existing_rtp_transport->srtp_transport;
-  }
-
-  auto new_srtp_transport =
-      rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_mux_enabled);
-
-  // The SDES should use an IceTransport rather than a DtlsTransport. We call
-  // |CreateDtlsTransport_n| here because the DtlsTransport will downgrade to an
-  // wrapper over IceTransport if we don't set the certificates and it will just
-  // forward the packets and signals without using DTLS. The support of SDES
-  // will be removed once all the downstream application stop using it.
-  new_srtp_transport->SetRtpPacketTransport(CreateDtlsTransport_n(
-      transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP));
-  if (!rtcp_mux_enabled) {
-    new_srtp_transport->SetRtcpPacketTransport(CreateDtlsTransport_n(
-        transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP));
-  }
-
-#if defined(ENABLE_EXTERNAL_AUTH)
-  new_srtp_transport->EnableExternalAuth();
-#endif
-
-  auto new_rtp_transport_wrapper = new RefCountedRtpTransport();
-  new_rtp_transport_wrapper->srtp_transport = new_srtp_transport.get();
-  new_rtp_transport_wrapper->rtp_transport = std::move(new_srtp_transport);
-  new_rtp_transport_wrapper->AddRef();
-  rtp_transports_[transport_name] = new_rtp_transport_wrapper;
-  return rtp_transports_[transport_name]->srtp_transport;
-}
-
-webrtc::DtlsSrtpTransport* TransportController::CreateDtlsSrtpTransport(
-    const std::string& transport_name,
-    bool rtcp_mux_enabled) {
-  if (!network_thread_->IsCurrent()) {
-    return network_thread_->Invoke<webrtc::DtlsSrtpTransport*>(
-        RTC_FROM_HERE, [&] {
-          return CreateDtlsSrtpTransport(transport_name, rtcp_mux_enabled);
-        });
-  }
-  auto existing_rtp_transport = FindRtpTransport(transport_name);
-
-  if (existing_rtp_transport) {
-    // For DTLS-SRTP transport wrapper, the |dtls_srtp_transport| is expected to
-    // be non-null and |srtp_transport| is expected to be a nullptr.
-    if (existing_rtp_transport->srtp_transport ||
-        !existing_rtp_transport->dtls_srtp_transport) {
-      RTC_LOG(LS_ERROR)
-          << "Failed to create an RTP transport for DTLS-SRTP using name: "
-          << transport_name << " because the type doesn't match.";
-      return nullptr;
-    }
-    existing_rtp_transport->AddRef();
-    return existing_rtp_transport->dtls_srtp_transport;
-  }
-
-  auto new_srtp_transport =
-      rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_mux_enabled);
-
-#if defined(ENABLE_EXTERNAL_AUTH)
-  new_srtp_transport->EnableExternalAuth();
-#endif
-
-  auto new_dtls_srtp_transport =
-      rtc::MakeUnique<webrtc::DtlsSrtpTransport>(std::move(new_srtp_transport));
-
-  auto rtp_dtls_transport = CreateDtlsTransport_n(
-      transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
-  auto rtcp_dtls_transport =
-      rtcp_mux_enabled
-          ? nullptr
-          : CreateDtlsTransport_n(transport_name,
-                                  cricket::ICE_CANDIDATE_COMPONENT_RTCP);
-
-  new_dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
-                                             rtcp_dtls_transport);
-
-  auto new_rtp_transport_wrapper = new RefCountedRtpTransport();
-  new_rtp_transport_wrapper->dtls_srtp_transport =
-      new_dtls_srtp_transport.get();
-  new_rtp_transport_wrapper->rtp_transport = std::move(new_dtls_srtp_transport);
-  new_rtp_transport_wrapper->AddRef();
-  rtp_transports_[transport_name] = new_rtp_transport_wrapper;
-  return rtp_transports_[transport_name]->dtls_srtp_transport;
-}
-
-void TransportController::DestroyTransport(const std::string& transport_name) {
-  if (!network_thread_->IsCurrent()) {
-    network_thread_->Invoke<void>(RTC_FROM_HERE,
-                                  [&] { DestroyTransport(transport_name); });
-    return;
-  }
-
-  auto existing_rtp_transport = FindRtpTransport(transport_name);
-  if (!existing_rtp_transport) {
-    RTC_LOG(LS_WARNING) << "Attempting to delete " << transport_name
-                        << " transport , which doesn't exist.";
-    return;
-  }
-  if (existing_rtp_transport->Release() ==
-      rtc::RefCountReleaseStatus::kDroppedLastRef) {
-    rtp_transports_.erase(transport_name);
-  }
-  return;
-}
-
-std::vector<std::string> TransportController::transport_names_for_testing() {
-  std::vector<std::string> ret;
-  for (const auto& kv : transports_) {
-    ret.push_back(kv.first);
-  }
-  return ret;
-}
-
-std::vector<DtlsTransportInternal*>
-TransportController::channels_for_testing() {
-  std::vector<DtlsTransportInternal*> ret;
-  for (RefCountedChannel* channel : channels_) {
-    ret.push_back(channel->dtls());
-  }
-  return ret;
-}
-
-DtlsTransportInternal* TransportController::get_channel_for_testing(
-    const std::string& transport_name,
-    int component) {
-  RefCountedChannel* ch = GetChannel_n(transport_name, component);
-  return ch ? ch->dtls() : nullptr;
-}
-
-IceTransportInternal* TransportController::CreateIceTransportChannel_n(
-    const std::string& transport_name,
-    int component) {
-  return new P2PTransportChannel(transport_name, component, port_allocator_,
-                                 event_log_);
-}
-
-DtlsTransportInternal* TransportController::CreateDtlsTransportChannel_n(
-    const std::string&,
-    int,
-    IceTransportInternal* ice) {
-  DtlsTransport* dtls = new DtlsTransport(ice, crypto_options_);
-  dtls->SetSslMaxProtocolVersion(ssl_max_version_);
-  return dtls;
-}
-
-void TransportController::OnMessage(rtc::Message* pmsg) {
-  RTC_DCHECK(signaling_thread_->IsCurrent());
-
-  switch (pmsg->message_id) {
-    case MSG_ICECONNECTIONSTATE: {
-      rtc::TypedMessageData<IceConnectionState>* data =
-          static_cast<rtc::TypedMessageData<IceConnectionState>*>(pmsg->pdata);
-      SignalConnectionState(data->data());
-      delete data;
-      break;
-    }
-    case MSG_RECEIVING: {
-      rtc::TypedMessageData<bool>* data =
-          static_cast<rtc::TypedMessageData<bool>*>(pmsg->pdata);
-      SignalReceiving(data->data());
-      delete data;
-      break;
-    }
-    case MSG_ICEGATHERINGSTATE: {
-      rtc::TypedMessageData<IceGatheringState>* data =
-          static_cast<rtc::TypedMessageData<IceGatheringState>*>(pmsg->pdata);
-      SignalGatheringState(data->data());
-      delete data;
-      break;
-    }
-    case MSG_CANDIDATESGATHERED: {
-      CandidatesData* data = static_cast<CandidatesData*>(pmsg->pdata);
-      SignalCandidatesGathered(data->transport_name, data->candidates);
-      delete data;
-      break;
-    }
-    default:
-      RTC_NOTREACHED();
-  }
-}
-
-const TransportController::RefCountedRtpTransport*
-TransportController::FindRtpTransport(const std::string& transport_name) {
-  auto it = rtp_transports_.find(transport_name);
-  return it == rtp_transports_.end() ? nullptr : it->second;
-}
-
-std::vector<TransportController::RefCountedChannel*>::iterator
-TransportController::GetChannelIterator_n(const std::string& transport_name,
-                                          int component) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  return std::find_if(channels_.begin(), channels_.end(),
-                      [transport_name, component](RefCountedChannel* channel) {
-                        return channel->dtls()->transport_name() ==
-                                   transport_name &&
-                               channel->dtls()->component() == component;
-                      });
-}
-
-std::vector<TransportController::RefCountedChannel*>::const_iterator
-TransportController::GetChannelIterator_n(const std::string& transport_name,
-                                          int component) const {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  return std::find_if(
-      channels_.begin(), channels_.end(),
-      [transport_name, component](const RefCountedChannel* channel) {
-        return channel->dtls()->transport_name() == transport_name &&
-               channel->dtls()->component() == component;
-      });
-}
-
-const JsepTransport* TransportController::GetJsepTransport(
-    const std::string& transport_name) const {
-  auto it = transports_.find(transport_name);
-  return (it == transports_.end()) ? nullptr : it->second.get();
-}
-
-JsepTransport* TransportController::GetJsepTransport(
-    const std::string& transport_name) {
-  auto it = transports_.find(transport_name);
-  return (it == transports_.end()) ? nullptr : it->second.get();
-}
-
-const TransportController::RefCountedChannel* TransportController::GetChannel_n(
-    const std::string& transport_name,
-    int component) const {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  auto it = GetChannelIterator_n(transport_name, component);
-  return (it == channels_.end()) ? nullptr : *it;
-}
-
-TransportController::RefCountedChannel* TransportController::GetChannel_n(
-    const std::string& transport_name,
-    int component) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  auto it = GetChannelIterator_n(transport_name, component);
-  return (it == channels_.end()) ? nullptr : *it;
-}
-
-JsepTransport* TransportController::GetOrCreateJsepTransport(
-    const std::string& transport_name) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  JsepTransport* transport = GetJsepTransport(transport_name);
-  if (transport) {
-    return transport;
-  }
-
-  transport = new JsepTransport(transport_name, certificate_);
-  transports_[transport_name] = std::unique_ptr<JsepTransport>(transport);
-  return transport;
-}
-
-void TransportController::DestroyAllChannels_n() {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  transports_.clear();
-  // TODO(nisse): If |channels_| were a vector of scoped_refptr, we
-  // wouldn't need this strange hack.
-  for (RefCountedChannel* channel : channels_) {
-    // Even though these objects are normally ref-counted, if
-    // TransportController is deleted while they still have references, just
-    // remove all references.
-    while (channel->Release() ==
-           rtc::RefCountReleaseStatus::kOtherRefsRemained) {
-    }
-  }
-  channels_.clear();
-}
-
-bool TransportController::SetSslMaxProtocolVersion_n(
-    rtc::SSLProtocolVersion version) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  // Max SSL version can only be set before transports are created.
-  if (!transports_.empty()) {
-    return false;
-  }
-
-  ssl_max_version_ = version;
-  return true;
-}
-
-void TransportController::SetIceConfig_n(const IceConfig& config) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  ice_config_ = config;
-  for (auto& channel : channels_) {
-    channel->dtls()->ice_transport()->SetIceConfig(ice_config_);
-  }
-}
-
-void TransportController::SetIceRole_n(IceRole ice_role) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  ice_role_ = ice_role;
-  for (auto& channel : channels_) {
-    channel->dtls()->ice_transport()->SetIceRole(ice_role_);
-  }
-}
-
-bool TransportController::GetSslRole_n(const std::string& transport_name,
-                                       rtc::SSLRole* role) const {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  const JsepTransport* t = GetJsepTransport(transport_name);
-  if (!t) {
-    return false;
-  }
-  rtc::Optional<rtc::SSLRole> current_role = t->GetSslRole();
-  if (!current_role) {
-    return false;
-  }
-  *role = *current_role;
-  return true;
-}
-
-bool TransportController::SetLocalCertificate_n(
-    const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  // Can't change a certificate, or set a null certificate.
-  if (certificate_ || !certificate) {
-    return false;
-  }
-  certificate_ = certificate;
-
-  // Set certificate for JsepTransport, which verifies it matches the
-  // fingerprint in SDP, and DTLS transport.
-  // Fallback from DTLS to SDES is not supported.
-  for (auto& kv : transports_) {
-    kv.second->SetLocalCertificate(certificate_);
-  }
-  for (auto& channel : channels_) {
-    bool set_cert_success = channel->dtls()->SetLocalCertificate(certificate_);
-    RTC_DCHECK(set_cert_success);
-  }
-  return true;
-}
-
-bool TransportController::GetLocalCertificate_n(
-    const std::string& transport_name,
-    rtc::scoped_refptr<rtc::RTCCertificate>* certificate) const {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  const JsepTransport* t = GetJsepTransport(transport_name);
-  if (!t) {
-    return false;
-  }
-  return t->GetLocalCertificate(certificate);
-}
-
-bool TransportController::SetLocalTransportDescription_n(
-    const std::string& transport_name,
-    const TransportDescription& tdesc,
-    SdpType type,
-    std::string* err) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  JsepTransport* transport = GetJsepTransport(transport_name);
-  if (!transport) {
-    // If we didn't find a transport, that's not an error;
-    // it could have been deleted as a result of bundling.
-    // TODO(deadbeef): Make callers smarter so they won't attempt to set a
-    // description on a deleted transport.
-    return true;
-  }
-
-  // The initial offer side may use ICE Lite, in which case, per RFC5245 Section
-  // 5.1.1, the answer side should take the controlling role if it is in the
-  // full ICE mode.
-  //
-  // When both sides use ICE Lite, the initial offer side must take the
-  // controlling role, and this is the default logic implemented in
-  // SetLocalDescription in PeerConnection.
-  if (transport->remote_description() &&
-      transport->remote_description()->ice_mode == ICEMODE_LITE &&
-      ice_role_ == ICEROLE_CONTROLLED && tdesc.ice_mode == ICEMODE_FULL) {
-    SetIceRole_n(ICEROLE_CONTROLLING);
-  }
-
-  // Older versions of Chrome expect the ICE role to be re-determined when an
-  // ICE restart occurs, and also don't perform conflict resolution correctly,
-  // so for now we can't safely stop doing this, unless the application opts in
-  // by setting |redetermine_role_on_ice_restart_| to false.
-  // See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
-  // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
-  // enough population.
-  if (redetermine_role_on_ice_restart_ && transport->local_description() &&
-      IceCredentialsChanged(transport->local_description()->ice_ufrag,
-                            transport->local_description()->ice_pwd,
-                            tdesc.ice_ufrag, tdesc.ice_pwd) &&
-      // Don't change the ICE role if the remote endpoint is ICE lite; we
-      // should always be controlling in that case.
-      (!transport->remote_description() ||
-       transport->remote_description()->ice_mode != ICEMODE_LITE)) {
-    IceRole new_ice_role =
-        (type == SdpType::kOffer) ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED;
-    SetIceRole(new_ice_role);
-  }
-
-  RTC_LOG(LS_INFO) << "Set local transport description on " << transport_name;
-  return transport->SetLocalTransportDescription(tdesc, type, err);
-}
-
-bool TransportController::SetRemoteTransportDescription_n(
-    const std::string& transport_name,
-    const TransportDescription& tdesc,
-    SdpType type,
-    std::string* err) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  // If our role is ICEROLE_CONTROLLED and the remote endpoint supports only
-  // ice_lite, this local endpoint should take the CONTROLLING role.
-  // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
-  // be in a TransportDescription in the first place...
-  if (ice_role_ == ICEROLE_CONTROLLED && tdesc.ice_mode == ICEMODE_LITE) {
-    SetIceRole_n(ICEROLE_CONTROLLING);
-  }
-
-  JsepTransport* transport = GetJsepTransport(transport_name);
-  if (!transport) {
-    // If we didn't find a transport, that's not an error;
-    // it could have been deleted as a result of bundling.
-    // TODO(deadbeef): Make callers smarter so they won't attempt to set a
-    // description on a deleted transport.
-    return true;
-  }
-
-  // If we use ICE Lite and the remote endpoint uses the full implementation of
-  // ICE, the local endpoint must take the controlled role, and the other side
-  // must be the controlling role.
-  if (transport->local_description() &&
-      transport->local_description()->ice_mode == ICEMODE_LITE &&
-      ice_role_ == ICEROLE_CONTROLLING && tdesc.ice_mode == ICEMODE_FULL) {
-    SetIceRole_n(ICEROLE_CONTROLLED);
-  }
-
-  RTC_LOG(LS_INFO) << "Set remote transport description on " << transport_name;
-  return transport->SetRemoteTransportDescription(tdesc, type, err);
-}
-
-void TransportController::MaybeStartGathering_n() {
-  for (auto& channel : channels_) {
-    channel->dtls()->ice_transport()->MaybeStartGathering();
-  }
-}
-
-bool TransportController::AddRemoteCandidates_n(
-    const std::string& transport_name,
-    const Candidates& candidates,
-    std::string* err) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  // Verify each candidate before passing down to the transport layer.
-  if (!VerifyCandidates(candidates, err)) {
-    return false;
-  }
-
-  JsepTransport* transport = GetJsepTransport(transport_name);
-  if (!transport) {
-    // If we didn't find a transport, that's not an error;
-    // it could have been deleted as a result of bundling.
-    return true;
-  }
-
-  for (const Candidate& candidate : candidates) {
-    RefCountedChannel* channel =
-        GetChannel_n(transport_name, candidate.component());
-    if (!channel) {
-      *err = "Candidate has an unknown component: " + candidate.ToString() +
-             " for content: " + transport_name;
-      return false;
-    }
-    channel->dtls()->ice_transport()->AddRemoteCandidate(candidate);
-  }
-  return true;
-}
-
-bool TransportController::RemoveRemoteCandidates_n(const Candidates& candidates,
-                                                   std::string* err) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  // Verify each candidate before passing down to the transport layer.
-  if (!VerifyCandidates(candidates, err)) {
-    return false;
-  }
-
-  std::map<std::string, Candidates> candidates_by_transport_name;
-  for (const Candidate& cand : candidates) {
-    if (!cand.transport_name().empty()) {
-      candidates_by_transport_name[cand.transport_name()].push_back(cand);
-    } else {
-      RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
-                           "transport name set: "
-                        << cand.ToString();
-    }
-  }
-
-  bool result = true;
-  for (const auto& kv : candidates_by_transport_name) {
-    const std::string& transport_name = kv.first;
-    const Candidates& candidates = kv.second;
-    JsepTransport* transport = GetJsepTransport(transport_name);
-    if (!transport) {
-      // If we didn't find a transport, that's not an error;
-      // it could have been deleted as a result of bundling.
-      continue;
-    }
-    for (const Candidate& candidate : candidates) {
-      RefCountedChannel* channel =
-          GetChannel_n(transport_name, candidate.component());
-      if (channel) {
-        channel->dtls()->ice_transport()->RemoveRemoteCandidate(candidate);
-      }
-    }
-  }
-  return result;
-}
-
-bool TransportController::ReadyForRemoteCandidates_n(
-    const std::string& transport_name) const {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  const JsepTransport* transport = GetJsepTransport(transport_name);
-  if (!transport) {
-    return false;
-  }
-  return transport->ready_for_remote_candidates();
-}
-
-bool TransportController::GetStats_n(const std::string& transport_name,
-                                     TransportStats* stats) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  JsepTransport* transport = GetJsepTransport(transport_name);
-  if (!transport) {
-    return false;
-  }
-  return transport->GetStats(stats);
-}
-
-void TransportController::SetMetricsObserver_n(
-    webrtc::MetricsObserverInterface* metrics_observer) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  metrics_observer_ = metrics_observer;
-  for (auto& channel : channels_) {
-    channel->dtls()->ice_transport()->SetMetricsObserver(metrics_observer);
-  }
-}
-
-void TransportController::OnChannelWritableState_n(
-    rtc::PacketTransportInternal* transport) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
-                   << " writability changed to " << transport->writable()
-                   << ".";
-  UpdateAggregateStates_n();
-}
-
-void TransportController::OnChannelReceivingState_n(
-    rtc::PacketTransportInternal* transport) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  UpdateAggregateStates_n();
-}
-
-void TransportController::OnChannelGatheringState_n(
-    IceTransportInternal* channel) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  UpdateAggregateStates_n();
-}
-
-void TransportController::OnChannelCandidateGathered_n(
-    IceTransportInternal* channel,
-    const Candidate& candidate) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  // We should never signal peer-reflexive candidates.
-  if (candidate.type() == PRFLX_PORT_TYPE) {
-    RTC_NOTREACHED();
-    return;
-  }
-  std::vector<Candidate> candidates;
-  candidates.push_back(candidate);
-  CandidatesData* data =
-      new CandidatesData(channel->transport_name(), candidates);
-  signaling_thread_->Post(RTC_FROM_HERE, this, MSG_CANDIDATESGATHERED, data);
-}
-
-void TransportController::OnChannelCandidatesRemoved_n(
-    IceTransportInternal* channel,
-    const Candidates& candidates) {
-  invoker_.AsyncInvoke<void>(
-      RTC_FROM_HERE, signaling_thread_,
-      rtc::Bind(&TransportController::OnChannelCandidatesRemoved, this,
-                candidates));
-}
-
-void TransportController::OnChannelCandidatesRemoved(
-    const Candidates& candidates) {
-  RTC_DCHECK(signaling_thread_->IsCurrent());
-  SignalCandidatesRemoved(candidates);
-}
-
-void TransportController::OnChannelRoleConflict_n(
-    IceTransportInternal* channel) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  // Note: since the role conflict is handled entirely on the network thread,
-  // we don't need to worry about role conflicts occurring on two ports at once.
-  // The first one encountered should immediately reverse the role.
-  IceRole reversed_role = (ice_role_ == ICEROLE_CONTROLLING)
-                              ? ICEROLE_CONTROLLED
-                              : ICEROLE_CONTROLLING;
-  RTC_LOG(LS_INFO) << "Got role conflict; switching to "
-                   << (reversed_role == ICEROLE_CONTROLLING ? "controlling"
-                                                            : "controlled")
-                   << " role.";
-  SetIceRole_n(reversed_role);
-}
-
-void TransportController::OnChannelStateChanged_n(
-    IceTransportInternal* channel) {
-  RTC_DCHECK(network_thread_->IsCurrent());
-  RTC_LOG(LS_INFO) << channel->transport_name() << " TransportChannel "
-                   << channel->component()
-                   << " state changed. Check if state is complete.";
-  UpdateAggregateStates_n();
-}
-
-void TransportController::UpdateAggregateStates_n() {
-  RTC_DCHECK(network_thread_->IsCurrent());
-
-  IceConnectionState new_connection_state = kIceConnectionConnecting;
-  IceGatheringState new_gathering_state = kIceGatheringNew;
-  bool any_receiving = false;
-  bool any_failed = false;
-  bool all_connected = !channels_.empty();
-  bool all_completed = !channels_.empty();
-  bool any_gathering = false;
-  bool all_done_gathering = !channels_.empty();
-  for (const auto& channel : channels_) {
-    any_receiving = any_receiving || channel->dtls()->receiving();
-    any_failed = any_failed || channel->dtls()->ice_transport()->GetState() ==
-                                   IceTransportState::STATE_FAILED;
-    all_connected = all_connected && channel->dtls()->writable();
-    all_completed =
-        all_completed && channel->dtls()->writable() &&
-        channel->dtls()->ice_transport()->GetState() ==
-            IceTransportState::STATE_COMPLETED &&
-        channel->dtls()->ice_transport()->GetIceRole() == ICEROLE_CONTROLLING &&
-        channel->dtls()->ice_transport()->gathering_state() ==
-            kIceGatheringComplete;
-    any_gathering =
-        any_gathering ||
-        channel->dtls()->ice_transport()->gathering_state() != kIceGatheringNew;
-    all_done_gathering = all_done_gathering &&
-                         channel->dtls()->ice_transport()->gathering_state() ==
-                             kIceGatheringComplete;
-  }
-  if (any_failed) {
-    new_connection_state = kIceConnectionFailed;
-  } else if (all_completed) {
-    new_connection_state = kIceConnectionCompleted;
-  } else if (all_connected) {
-    new_connection_state = kIceConnectionConnected;
-  }
-  if (connection_state_ != new_connection_state) {
-    connection_state_ = new_connection_state;
-    signaling_thread_->Post(
-        RTC_FROM_HERE, this, MSG_ICECONNECTIONSTATE,
-        new rtc::TypedMessageData<IceConnectionState>(new_connection_state));
-  }
-
-  if (receiving_ != any_receiving) {
-    receiving_ = any_receiving;
-    signaling_thread_->Post(RTC_FROM_HERE, this, MSG_RECEIVING,
-                            new rtc::TypedMessageData<bool>(any_receiving));
-  }
-
-  if (all_done_gathering) {
-    new_gathering_state = kIceGatheringComplete;
-  } else if (any_gathering) {
-    new_gathering_state = kIceGatheringGathering;
-  }
-  if (gathering_state_ != new_gathering_state) {
-    gathering_state_ = new_gathering_state;
-    signaling_thread_->Post(
-        RTC_FROM_HERE, this, MSG_ICEGATHERINGSTATE,
-        new rtc::TypedMessageData<IceGatheringState>(new_gathering_state));
-  }
-}
-
-void TransportController::OnDtlsHandshakeError(rtc::SSLHandshakeError error) {
-  SignalDtlsHandshakeError(error);
-}
-
-}  // namespace cricket
diff --git a/pc/transportcontroller.h b/pc/transportcontroller.h
deleted file mode 100644
index ea07dfe..0000000
--- a/pc/transportcontroller.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- *  Copyright 2015 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_TRANSPORTCONTROLLER_H_
-#define PC_TRANSPORTCONTROLLER_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "api/candidate.h"
-#include "p2p/base/dtlstransport.h"
-#include "p2p/base/p2ptransportchannel.h"
-#include "pc/dtlssrtptransport.h"
-#include "pc/jseptransport.h"
-#include "pc/rtptransport.h"
-#include "pc/srtptransport.h"
-#include "rtc_base/asyncinvoker.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/sigslot.h"
-#include "rtc_base/sslstreamadapter.h"
-
-namespace rtc {
-class Thread;
-class PacketTransportInternal;
-}  // namespace rtc
-
-namespace webrtc {
-class MetricsObserverInterface;
-class RtcEventLog;
-}  // namespace webrtc
-
-namespace cricket {
-
-class TransportController : public sigslot::has_slots<>,
-                            public rtc::MessageHandler {
- public:
-  // If |redetermine_role_on_ice_restart| is true, ICE role is redetermined
-  // upon setting a local transport description that indicates an ICE restart.
-  // For the constructor that doesn't take this parameter, it defaults to true.
-  //
-  // |crypto_options| is used to determine if created DTLS transports negotiate
-  // GCM crypto suites or not.
-  TransportController(rtc::Thread* signaling_thread,
-                      rtc::Thread* network_thread,
-                      PortAllocator* port_allocator,
-                      bool redetermine_role_on_ice_restart,
-                      const rtc::CryptoOptions& crypto_options,
-                      webrtc::RtcEventLog* event_log = nullptr);
-
-  virtual ~TransportController();
-
-  rtc::Thread* signaling_thread() const { return signaling_thread_; }
-  rtc::Thread* network_thread() const { return network_thread_; }
-
-  PortAllocator* port_allocator() const { return port_allocator_; }
-
-  // Can only be set before transports are created.
-  // TODO(deadbeef): Make this an argument to the constructor once BaseSession
-  // and WebRtcSession are combined
-  bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version);
-
-  void SetIceConfig(const IceConfig& config);
-  void SetIceRole(IceRole ice_role);
-
-  // Set the "needs-ice-restart" flag as described in JSEP. After the flag is
-  // set, offers should generate new ufrags/passwords until an ICE restart
-  // occurs.
-  void SetNeedsIceRestartFlag();
-  // Returns true if the ICE restart flag above was set, and no ICE restart has
-  // occurred yet for this transport (by applying a local description with
-  // changed ufrag/password). If the transport has been deleted as a result of
-  // bundling, returns false.
-  bool NeedsIceRestart(const std::string& transport_name) const;
-
-  bool GetSslRole(const std::string& transport_name, rtc::SSLRole* role) const;
-
-  // Specifies the identity to use in this session.
-  // Can only be called once.
-  bool SetLocalCertificate(
-      const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
-  bool GetLocalCertificate(
-      const std::string& transport_name,
-      rtc::scoped_refptr<rtc::RTCCertificate>* certificate) const;
-  // Caller owns returned certificate chain. This method mainly exists for
-  // stats reporting.
-  std::unique_ptr<rtc::SSLCertChain> GetRemoteSSLCertChain(
-      const std::string& transport_name) const;
-
-  bool SetLocalTransportDescription(const std::string& transport_name,
-                                    const TransportDescription& tdesc,
-                                    webrtc::SdpType type,
-                                    std::string* err);
-  bool SetRemoteTransportDescription(const std::string& transport_name,
-                                     const TransportDescription& tdesc,
-                                     webrtc::SdpType type,
-                                     std::string* err);
-  // Start gathering candidates for any new transports, or transports doing an
-  // ICE restart.
-  void MaybeStartGathering();
-  bool AddRemoteCandidates(const std::string& transport_name,
-                           const Candidates& candidates,
-                           std::string* err);
-  bool RemoveRemoteCandidates(const Candidates& candidates, std::string* err);
-  bool ReadyForRemoteCandidates(const std::string& transport_name) const;
-  // TODO(deadbeef): GetStats isn't const because all the way down to
-  // OpenSSLStreamAdapter,
-  // GetSslCipherSuite and GetDtlsSrtpCryptoSuite are not const. Fix this.
-  bool GetStats(const std::string& transport_name, TransportStats* stats);
-  void SetMetricsObserver(webrtc::MetricsObserverInterface* metrics_observer);
-
-  // Creates a channel if it doesn't exist. Otherwise, increments a reference
-  // count and returns an existing channel.
-  DtlsTransportInternal* CreateDtlsTransport(const std::string& transport_name,
-                                             int component);
-  virtual DtlsTransportInternal* CreateDtlsTransport_n(
-      const std::string& transport_name,
-      int component);
-
-  // Decrements a channel's reference count, and destroys the channel if
-  // nothing is referencing it.
-  virtual void DestroyDtlsTransport(const std::string& transport_name,
-                                    int component);
-  virtual void DestroyDtlsTransport_n(const std::string& transport_name,
-                                      int component);
-
-  // Create an SrtpTransport/DtlsSrtpTransport if it doesn't exist.
-  // Otherwise, increments a reference count and returns the existing one.
-  // These methods are not currently used but the plan is to transition
-  // PeerConnection and BaseChannel to use them instead of CreateDtlsTransport.
-  webrtc::SrtpTransport* CreateSdesTransport(const std::string& transport_name,
-                                             bool rtcp_mux_enabled);
-  webrtc::DtlsSrtpTransport* CreateDtlsSrtpTransport(
-      const std::string& transport_name,
-      bool rtcp_mux_enabled);
-
-  // Destroy an RTP level transport which can be an RtpTransport, an
-  // SrtpTransport or a DtlsSrtpTransport.
-  void DestroyTransport(const std::string& transport_name);
-
-  // TODO(deadbeef): Remove all for_testing methods!
-  const rtc::scoped_refptr<rtc::RTCCertificate>& certificate_for_testing()
-      const {
-    return certificate_;
-  }
-  std::vector<std::string> transport_names_for_testing();
-  std::vector<DtlsTransportInternal*> channels_for_testing();
-  DtlsTransportInternal* get_channel_for_testing(
-      const std::string& transport_name,
-      int component);
-
-  // All of these signals are fired on the signalling thread.
-
-  // If any transport failed => failed,
-  // Else if all completed => completed,
-  // Else if all connected => connected,
-  // Else => connecting
-  sigslot::signal1<IceConnectionState> SignalConnectionState;
-
-  // Receiving if any transport is receiving
-  sigslot::signal1<bool> SignalReceiving;
-
-  // If all transports done gathering => complete,
-  // Else if any are gathering => gathering,
-  // Else => new
-  sigslot::signal1<IceGatheringState> SignalGatheringState;
-
-  // (transport_name, candidates)
-  sigslot::signal2<const std::string&, const Candidates&>
-      SignalCandidatesGathered;
-
-  sigslot::signal1<const Candidates&> SignalCandidatesRemoved;
-
-  sigslot::signal1<rtc::SSLHandshakeError> SignalDtlsHandshakeError;
-
- protected:
-  // TODO(deadbeef): Get rid of these virtual methods. Used by
-  // FakeTransportController currently, but FakeTransportController shouldn't
-  // even be functioning by subclassing TransportController.
-  virtual IceTransportInternal* CreateIceTransportChannel_n(
-      const std::string& transport_name,
-      int component);
-  virtual DtlsTransportInternal* CreateDtlsTransportChannel_n(
-      const std::string& transport_name,
-      int component,
-      IceTransportInternal* ice);
-
- private:
-  void OnMessage(rtc::Message* pmsg) override;
-
-  class ChannelPair;
-  typedef rtc::RefCountedObject<ChannelPair> RefCountedChannel;
-
-  // Wrapper for RtpTransport that keeps a reference count.
-  // When using SDES, |srtp_transport| is non-null, |dtls_srtp_transport| is
-  // null and |rtp_transport.get()| == |srtp_transport|,
-  // When using DTLS-SRTP, |dtls_srtp_transport| is non-null, |srtp_transport|
-  // is null and |rtp_transport.get()| == |dtls_srtp_transport|,
-  // When using unencrypted RTP, only |rtp_transport| is non-null.
-  struct RtpTransportWrapper {
-    // |rtp_transport| is always non-null.
-    std::unique_ptr<webrtc::RtpTransportInternal> rtp_transport;
-    webrtc::SrtpTransport* srtp_transport = nullptr;
-    webrtc::DtlsSrtpTransport* dtls_srtp_transport = nullptr;
-  };
-
-  typedef rtc::RefCountedObject<RtpTransportWrapper> RefCountedRtpTransport;
-
-  const RefCountedRtpTransport* FindRtpTransport(
-      const std::string& transport_name);
-
-  // Helper functions to get a channel or transport, or iterator to it (in case
-  // it needs to be erased).
-  std::vector<RefCountedChannel*>::iterator GetChannelIterator_n(
-      const std::string& transport_name,
-      int component);
-  std::vector<RefCountedChannel*>::const_iterator GetChannelIterator_n(
-      const std::string& transport_name,
-      int component) const;
-  const JsepTransport* GetJsepTransport(
-      const std::string& transport_name) const;
-  JsepTransport* GetJsepTransport(const std::string& transport_name);
-  const RefCountedChannel* GetChannel_n(const std::string& transport_name,
-                                        int component) const;
-  RefCountedChannel* GetChannel_n(const std::string& transport_name,
-                                  int component);
-
-  JsepTransport* GetOrCreateJsepTransport(const std::string& transport_name);
-  void DestroyAllChannels_n();
-
-  bool SetSslMaxProtocolVersion_n(rtc::SSLProtocolVersion version);
-  void SetIceConfig_n(const IceConfig& config);
-  void SetIceRole_n(IceRole ice_role);
-  bool GetSslRole_n(const std::string& transport_name,
-                    rtc::SSLRole* role) const;
-  bool SetLocalCertificate_n(
-      const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
-  bool GetLocalCertificate_n(
-      const std::string& transport_name,
-      rtc::scoped_refptr<rtc::RTCCertificate>* certificate) const;
-  bool SetLocalTransportDescription_n(const std::string& transport_name,
-                                      const TransportDescription& tdesc,
-                                      webrtc::SdpType type,
-                                      std::string* err);
-  bool SetRemoteTransportDescription_n(const std::string& transport_name,
-                                       const TransportDescription& tdesc,
-                                       webrtc::SdpType type,
-                                       std::string* err);
-  void MaybeStartGathering_n();
-  bool AddRemoteCandidates_n(const std::string& transport_name,
-                             const Candidates& candidates,
-                             std::string* err);
-  bool RemoveRemoteCandidates_n(const Candidates& candidates, std::string* err);
-  bool ReadyForRemoteCandidates_n(const std::string& transport_name) const;
-  bool GetStats_n(const std::string& transport_name, TransportStats* stats);
-  void SetMetricsObserver_n(webrtc::MetricsObserverInterface* metrics_observer);
-
-  // Handlers for signals from Transport.
-  void OnChannelWritableState_n(rtc::PacketTransportInternal* transport);
-  void OnChannelReceivingState_n(rtc::PacketTransportInternal* transport);
-  void OnChannelGatheringState_n(IceTransportInternal* channel);
-  void OnChannelCandidateGathered_n(IceTransportInternal* channel,
-                                    const Candidate& candidate);
-  void OnChannelCandidatesRemoved(const Candidates& candidates);
-  void OnChannelCandidatesRemoved_n(IceTransportInternal* channel,
-                                    const Candidates& candidates);
-  void OnChannelRoleConflict_n(IceTransportInternal* channel);
-  void OnChannelStateChanged_n(IceTransportInternal* channel);
-
-  void UpdateAggregateStates_n();
-
-  void OnDtlsHandshakeError(rtc::SSLHandshakeError error);
-
-  rtc::Thread* const signaling_thread_ = nullptr;
-  rtc::Thread* const network_thread_ = nullptr;
-  PortAllocator* const port_allocator_ = nullptr;
-
-  std::map<std::string, std::unique_ptr<JsepTransport>> transports_;
-  std::vector<RefCountedChannel*> channels_;
-
-  std::map<std::string, RefCountedRtpTransport*> rtp_transports_;
-
-  // Aggregate state for TransportChannelImpls.
-  IceConnectionState connection_state_ = kIceConnectionConnecting;
-  bool receiving_ = false;
-  IceGatheringState gathering_state_ = kIceGatheringNew;
-
-  IceConfig ice_config_;
-  IceRole ice_role_ = ICEROLE_CONTROLLING;
-  bool redetermine_role_on_ice_restart_;
-  uint64_t ice_tiebreaker_ = rtc::CreateRandomId64();
-  rtc::CryptoOptions crypto_options_;
-  rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12;
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
-  rtc::AsyncInvoker invoker_;
-
-  webrtc::MetricsObserverInterface* metrics_observer_ = nullptr;
-
-  webrtc::RtcEventLog* event_log_;
-
-  RTC_DISALLOW_COPY_AND_ASSIGN(TransportController);
-};
-
-}  // namespace cricket
-
-#endif  // PC_TRANSPORTCONTROLLER_H_
diff --git a/pc/transportcontroller_unittest.cc b/pc/transportcontroller_unittest.cc
deleted file mode 100644
index 4f38c66..0000000
--- a/pc/transportcontroller_unittest.cc
+++ /dev/null
@@ -1,1019 +0,0 @@
-/*
- *  Copyright 2015 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.
- */
-
-#include <map>
-#include <memory>
-
-#include "p2p/base/dtlstransport.h"
-#include "p2p/base/fakeportallocator.h"
-#include "p2p/base/p2ptransportchannel.h"
-#include "p2p/base/portallocator.h"
-#include "pc/test/faketransportcontroller.h"
-#include "pc/transportcontroller.h"
-#include "rtc_base/fakesslidentity.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/helpers.h"
-#include "rtc_base/sslidentity.h"
-#include "rtc_base/thread.h"
-#include "test/gtest.h"
-
-using webrtc::SdpType;
-
-static const int kTimeout = 100;
-static const char kIceUfrag1[] = "TESTICEUFRAG0001";
-static const char kIcePwd1[] = "TESTICEPWD00000000000001";
-static const char kIceUfrag2[] = "TESTICEUFRAG0002";
-static const char kIcePwd2[] = "TESTICEPWD00000000000002";
-static const char kIceUfrag3[] = "TESTICEUFRAG0003";
-static const char kIcePwd3[] = "TESTICEPWD00000000000003";
-static const bool kRtcpMuxEnabled = true;
-
-namespace cricket {
-
-// Only subclassing from FakeTransportController because currently that's the
-// only way to have a TransportController with fake ICE/DTLS transports.
-//
-// TODO(deadbeef): Pass a "TransportFactory" or something similar into
-// TransportController, instead of using inheritance in this way for testing.
-typedef FakeTransportController TransportControllerForTest;
-
-class TransportControllerTest : public testing::Test,
-                                public sigslot::has_slots<> {
- public:
-  TransportControllerTest()
-      : transport_controller_(new TransportControllerForTest()),
-        signaling_thread_(rtc::Thread::Current()) {
-    ConnectTransportControllerSignals();
-  }
-
-  void CreateTransportControllerWithNetworkThread() {
-    if (!network_thread_) {
-      network_thread_ = rtc::Thread::CreateWithSocketServer();
-      network_thread_->Start();
-    }
-    transport_controller_.reset(
-        new TransportControllerForTest(network_thread_.get()));
-    ConnectTransportControllerSignals();
-  }
-
-  void ConnectTransportControllerSignals() {
-    transport_controller_->SignalConnectionState.connect(
-        this, &TransportControllerTest::OnConnectionState);
-    transport_controller_->SignalReceiving.connect(
-        this, &TransportControllerTest::OnReceiving);
-    transport_controller_->SignalGatheringState.connect(
-        this, &TransportControllerTest::OnGatheringState);
-    transport_controller_->SignalCandidatesGathered.connect(
-        this, &TransportControllerTest::OnCandidatesGathered);
-  }
-
-  FakeDtlsTransport* CreateFakeDtlsTransport(const std::string& content,
-                                             int component) {
-    DtlsTransportInternal* transport =
-        transport_controller_->CreateDtlsTransport_n(content, component);
-    return static_cast<FakeDtlsTransport*>(transport);
-  }
-
-  void DestroyFakeDtlsTransport(const std::string& content, int component) {
-    transport_controller_->DestroyDtlsTransport_n(content, component);
-  }
-
-  Candidate CreateCandidate(int component) {
-    Candidate c;
-    c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
-    c.set_component(1);
-    c.set_protocol(UDP_PROTOCOL_NAME);
-    c.set_priority(1);
-    return c;
-  }
-
-  // Used for thread hopping test.
-  void CreateFakeDtlsTransportsAndCompleteConnectionOnNetworkThread() {
-    network_thread_->Invoke<void>(
-        RTC_FROM_HERE,
-        rtc::Bind(&TransportControllerTest::
-                      CreateFakeDtlsTransportsAndCompleteConnection_w,
-                  this));
-  }
-
-  void CreateFakeDtlsTransportsAndCompleteConnection_w() {
-    transport_controller_->SetIceRole(ICEROLE_CONTROLLING);
-    FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-    ASSERT_NE(nullptr, transport1);
-    FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-    ASSERT_NE(nullptr, transport2);
-
-    TransportDescription local_desc(std::vector<std::string>(), kIceUfrag1,
-                                    kIcePwd1, ICEMODE_FULL,
-                                    CONNECTIONROLE_ACTPASS, nullptr);
-    std::string err;
-    transport_controller_->SetLocalTransportDescription("audio", local_desc,
-                                                        SdpType::kOffer, &err);
-    transport_controller_->SetLocalTransportDescription("video", local_desc,
-                                                        SdpType::kOffer, &err);
-    transport_controller_->MaybeStartGathering();
-    transport1->fake_ice_transport()->SignalCandidateGathered(
-        transport1->fake_ice_transport(), CreateCandidate(1));
-    transport2->fake_ice_transport()->SignalCandidateGathered(
-        transport2->fake_ice_transport(), CreateCandidate(1));
-    transport1->fake_ice_transport()->SetCandidatesGatheringComplete();
-    transport2->fake_ice_transport()->SetCandidatesGatheringComplete();
-    transport1->fake_ice_transport()->SetConnectionCount(2);
-    transport2->fake_ice_transport()->SetConnectionCount(2);
-    transport1->SetReceiving(true);
-    transport2->SetReceiving(true);
-    transport1->SetWritable(true);
-    transport2->SetWritable(true);
-    transport1->fake_ice_transport()->SetConnectionCount(1);
-    transport2->fake_ice_transport()->SetConnectionCount(1);
-  }
-
-  IceConfig CreateIceConfig(
-      int receiving_timeout,
-      ContinualGatheringPolicy continual_gathering_policy) {
-    IceConfig config;
-    config.receiving_timeout = receiving_timeout;
-    config.continual_gathering_policy = continual_gathering_policy;
-    return config;
-  }
-
- protected:
-  void OnConnectionState(IceConnectionState state) {
-    if (!signaling_thread_->IsCurrent()) {
-      signaled_on_non_signaling_thread_ = true;
-    }
-    connection_state_ = state;
-    ++connection_state_signal_count_;
-  }
-
-  void OnReceiving(bool receiving) {
-    if (!signaling_thread_->IsCurrent()) {
-      signaled_on_non_signaling_thread_ = true;
-    }
-    receiving_ = receiving;
-    ++receiving_signal_count_;
-  }
-
-  void OnGatheringState(IceGatheringState state) {
-    if (!signaling_thread_->IsCurrent()) {
-      signaled_on_non_signaling_thread_ = true;
-    }
-    gathering_state_ = state;
-    ++gathering_state_signal_count_;
-  }
-
-  void OnCandidatesGathered(const std::string& transport_name,
-                            const Candidates& candidates) {
-    if (!signaling_thread_->IsCurrent()) {
-      signaled_on_non_signaling_thread_ = true;
-    }
-    candidates_[transport_name].insert(candidates_[transport_name].end(),
-                                       candidates.begin(), candidates.end());
-    ++candidates_signal_count_;
-  }
-
-  std::unique_ptr<rtc::Thread> network_thread_;  // Not used for most tests.
-  std::unique_ptr<TransportControllerForTest> transport_controller_;
-
-  // Information received from signals from transport controller.
-  IceConnectionState connection_state_ = kIceConnectionConnecting;
-  bool receiving_ = false;
-  IceGatheringState gathering_state_ = kIceGatheringNew;
-  // transport_name => candidates
-  std::map<std::string, Candidates> candidates_;
-  // Counts of each signal emitted.
-  int connection_state_signal_count_ = 0;
-  int receiving_signal_count_ = 0;
-  int gathering_state_signal_count_ = 0;
-  int candidates_signal_count_ = 0;
-
-  // Used to make sure signals only come on signaling thread.
-  rtc::Thread* const signaling_thread_ = nullptr;
-  bool signaled_on_non_signaling_thread_ = false;
-};
-
-TEST_F(TransportControllerTest, TestSetIceConfig) {
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-
-  transport_controller_->SetIceConfig(
-      CreateIceConfig(1000, GATHER_CONTINUALLY));
-  EXPECT_EQ(1000, transport1->fake_ice_transport()->receiving_timeout());
-  EXPECT_TRUE(transport1->fake_ice_transport()->gather_continually());
-
-  transport_controller_->SetIceConfig(
-      CreateIceConfig(1000, GATHER_CONTINUALLY_AND_RECOVER));
-  // Test that value stored in controller is applied to new transports.
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport2);
-  EXPECT_EQ(1000, transport2->fake_ice_transport()->receiving_timeout());
-  EXPECT_TRUE(transport2->fake_ice_transport()->gather_continually());
-}
-
-TEST_F(TransportControllerTest, TestSetSslMaxProtocolVersion) {
-  EXPECT_TRUE(transport_controller_->SetSslMaxProtocolVersion(
-      rtc::SSL_PROTOCOL_DTLS_12));
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-
-  ASSERT_NE(nullptr, transport);
-  EXPECT_EQ(rtc::SSL_PROTOCOL_DTLS_12, transport->ssl_max_protocol_version());
-
-  // Setting max version after transport is created should fail.
-  EXPECT_FALSE(transport_controller_->SetSslMaxProtocolVersion(
-      rtc::SSL_PROTOCOL_DTLS_10));
-}
-
-TEST_F(TransportControllerTest, TestSetIceRole) {
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-
-  transport_controller_->SetIceRole(ICEROLE_CONTROLLING);
-  EXPECT_EQ(ICEROLE_CONTROLLING,
-            transport1->fake_ice_transport()->GetIceRole());
-  transport_controller_->SetIceRole(ICEROLE_CONTROLLED);
-  EXPECT_EQ(ICEROLE_CONTROLLED, transport1->fake_ice_transport()->GetIceRole());
-
-  // Test that value stored in controller is applied to new transports.
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport2);
-  EXPECT_EQ(ICEROLE_CONTROLLED, transport2->fake_ice_transport()->GetIceRole());
-}
-
-// Test that when one transport encounters a role conflict, the ICE role is
-// swapped on every transport.
-TEST_F(TransportControllerTest, TestIceRoleConflict) {
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport2);
-
-  transport_controller_->SetIceRole(ICEROLE_CONTROLLING);
-  EXPECT_EQ(ICEROLE_CONTROLLING,
-            transport1->fake_ice_transport()->GetIceRole());
-  EXPECT_EQ(ICEROLE_CONTROLLING,
-            transport2->fake_ice_transport()->GetIceRole());
-
-  transport1->fake_ice_transport()->SignalRoleConflict(
-      transport1->fake_ice_transport());
-  EXPECT_EQ(ICEROLE_CONTROLLED, transport1->fake_ice_transport()->GetIceRole());
-  EXPECT_EQ(ICEROLE_CONTROLLED, transport2->fake_ice_transport()->GetIceRole());
-
-  // Should be able to handle a second role conflict. The remote endpoint can
-  // change its role/tie-breaker when it does an ICE restart.
-  transport2->fake_ice_transport()->SignalRoleConflict(
-      transport2->fake_ice_transport());
-  EXPECT_EQ(ICEROLE_CONTROLLING,
-            transport1->fake_ice_transport()->GetIceRole());
-  EXPECT_EQ(ICEROLE_CONTROLLING,
-            transport2->fake_ice_transport()->GetIceRole());
-}
-
-TEST_F(TransportControllerTest, TestGetSslRole) {
-  rtc::SSLRole role;
-  CreateFakeDtlsTransport("audio", 1);
-
-  // Should return false before role has been negotiated.
-  EXPECT_FALSE(transport_controller_->GetSslRole("audio", &role));
-
-  // To negotiate an SSL role, need to set a local certificate, and
-  // local/remote transport descriptions with DTLS info.
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA)));
-  std::unique_ptr<rtc::SSLFingerprint> fingerprint(
-      rtc::SSLFingerprint::CreateFromCertificate(certificate));
-  transport_controller_->SetLocalCertificate(certificate);
-
-  // Set the same fingerprint on both sides since the remote fingerprint
-  // doesn't really matter for this test.
-  TransportDescription local_desc(std::vector<std::string>(), kIceUfrag1,
-                                  kIcePwd1, ICEMODE_FULL,
-                                  CONNECTIONROLE_ACTPASS, fingerprint.get());
-  TransportDescription remote_desc(std::vector<std::string>(), kIceUfrag2,
-                                   kIcePwd2, ICEMODE_FULL,
-                                   CONNECTIONROLE_ACTIVE, fingerprint.get());
-  std::string err;
-  EXPECT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", local_desc, SdpType::kOffer, &err));
-  EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription(
-      "audio", remote_desc, SdpType::kAnswer, &err));
-
-  // Finally we can get the role. Should be "server" since the remote
-  // endpoint's role was "active".
-  EXPECT_TRUE(transport_controller_->GetSslRole("audio", &role));
-  EXPECT_EQ(rtc::SSL_SERVER, role);
-
-  // Lastly, test that GetSslRole returns false for a nonexistent transport.
-  EXPECT_FALSE(transport_controller_->GetSslRole("video", &role));
-}
-
-TEST_F(TransportControllerTest, TestSetAndGetLocalCertificate) {
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
-      rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
-          rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
-  rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
-
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-
-  EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
-  EXPECT_TRUE(transport_controller_->GetLocalCertificate(
-      "audio", &returned_certificate));
-  EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
-            returned_certificate->identity()->certificate().ToPEMString());
-
-  // Should fail if called for a nonexistant transport.
-  EXPECT_FALSE(transport_controller_->GetLocalCertificate(
-      "video", &returned_certificate));
-
-  // Test that identity stored in controller is applied to new transports.
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport2);
-  EXPECT_TRUE(transport_controller_->GetLocalCertificate(
-      "video", &returned_certificate));
-  EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
-            returned_certificate->identity()->certificate().ToPEMString());
-
-  // Shouldn't be able to change the identity once set.
-  EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
-}
-
-TEST_F(TransportControllerTest, TestGetRemoteSSLCertChain) {
-  rtc::FakeSSLCertificate fake_certificate("fake_data");
-
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-
-  transport->SetRemoteSSLCertificate(&fake_certificate);
-  std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
-      transport_controller_->GetRemoteSSLCertChain("audio");
-  EXPECT_TRUE(returned_cert_chain);
-  EXPECT_EQ(fake_certificate.ToPEMString(),
-            returned_cert_chain->Get(0).ToPEMString());
-
-  // Should fail if called for a nonexistant transport.
-  EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain("video"));
-}
-
-TEST_F(TransportControllerTest, TestSetLocalTransportDescription) {
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-  TransportDescription local_desc(std::vector<std::string>(), kIceUfrag1,
-                                  kIcePwd1, ICEMODE_FULL,
-                                  CONNECTIONROLE_ACTPASS, nullptr);
-  std::string err;
-  EXPECT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", local_desc, SdpType::kOffer, &err));
-  // Check that ICE ufrag and pwd were propagated to transport.
-  EXPECT_EQ(kIceUfrag1, transport->fake_ice_transport()->ice_ufrag());
-  EXPECT_EQ(kIcePwd1, transport->fake_ice_transport()->ice_pwd());
-  // After setting local description, we should be able to start gathering
-  // candidates.
-  transport_controller_->MaybeStartGathering();
-  EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout);
-  EXPECT_EQ(1, gathering_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSetRemoteTransportDescription) {
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-  TransportDescription remote_desc(std::vector<std::string>(), kIceUfrag1,
-                                   kIcePwd1, ICEMODE_FULL,
-                                   CONNECTIONROLE_ACTPASS, nullptr);
-  std::string err;
-  EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription(
-      "audio", remote_desc, SdpType::kOffer, &err));
-  // Check that ICE ufrag and pwd were propagated to transport.
-  EXPECT_EQ(kIceUfrag1, transport->fake_ice_transport()->remote_ice_ufrag());
-  EXPECT_EQ(kIcePwd1, transport->fake_ice_transport()->remote_ice_pwd());
-}
-
-TEST_F(TransportControllerTest, TestAddRemoteCandidates) {
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-  Candidates candidates;
-  candidates.push_back(CreateCandidate(1));
-  std::string err;
-  EXPECT_TRUE(
-      transport_controller_->AddRemoteCandidates("audio", candidates, &err));
-  EXPECT_EQ(1U, transport->fake_ice_transport()->remote_candidates().size());
-}
-
-TEST_F(TransportControllerTest, TestReadyForRemoteCandidates) {
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-  // We expect to be ready for remote candidates only after local and remote
-  // descriptions are set.
-  EXPECT_FALSE(transport_controller_->ReadyForRemoteCandidates("audio"));
-
-  std::string err;
-  TransportDescription remote_desc(std::vector<std::string>(), kIceUfrag1,
-                                   kIcePwd1, ICEMODE_FULL,
-                                   CONNECTIONROLE_ACTPASS, nullptr);
-  EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription(
-      "audio", remote_desc, SdpType::kOffer, &err));
-  EXPECT_FALSE(transport_controller_->ReadyForRemoteCandidates("audio"));
-
-  TransportDescription local_desc(std::vector<std::string>(), kIceUfrag2,
-                                  kIcePwd2, ICEMODE_FULL,
-                                  CONNECTIONROLE_ACTPASS, nullptr);
-  EXPECT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", local_desc, SdpType::kAnswer, &err));
-  EXPECT_TRUE(transport_controller_->ReadyForRemoteCandidates("audio"));
-}
-
-TEST_F(TransportControllerTest, TestGetStats) {
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("audio", 2);
-  ASSERT_NE(nullptr, transport2);
-  FakeDtlsTransport* transport3 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport3);
-
-  TransportStats stats;
-  EXPECT_TRUE(transport_controller_->GetStats("audio", &stats));
-  EXPECT_EQ("audio", stats.transport_name);
-  EXPECT_EQ(2U, stats.channel_stats.size());
-}
-
-// Test that a "transport" from a stats perspective (combination of RTP/RTCP
-// transports) goes away when all references to its transports are gone.
-TEST_F(TransportControllerTest, TestCreateAndDestroyFakeDtlsTransport) {
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport2);
-  ASSERT_EQ(transport1, transport2);
-  FakeDtlsTransport* transport3 = CreateFakeDtlsTransport("audio", 2);
-  ASSERT_NE(nullptr, transport3);
-
-  // Using GetStats to check if transport is destroyed from an outside class's
-  // perspective.
-  TransportStats stats;
-  EXPECT_TRUE(transport_controller_->GetStats("audio", &stats));
-  DestroyFakeDtlsTransport("audio", 2);
-  DestroyFakeDtlsTransport("audio", 1);
-  EXPECT_TRUE(transport_controller_->GetStats("audio", &stats));
-  DestroyFakeDtlsTransport("audio", 1);
-  EXPECT_FALSE(transport_controller_->GetStats("audio", &stats));
-}
-
-TEST_F(TransportControllerTest, TestSignalConnectionStateFailed) {
-  // Need controlling ICE role to get in failed state.
-  transport_controller_->SetIceRole(ICEROLE_CONTROLLING);
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport2);
-
-  // Should signal "failed" if any transport failed; transport is considered
-  // failed
-  // if it previously had a connection but now has none, and gathering is
-  // complete.
-  transport1->fake_ice_transport()->SetCandidatesGatheringComplete();
-  transport1->fake_ice_transport()->SetConnectionCount(1);
-  transport1->fake_ice_transport()->SetConnectionCount(0);
-  EXPECT_EQ_WAIT(kIceConnectionFailed, connection_state_, kTimeout);
-  EXPECT_EQ(1, connection_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalConnectionStateConnected) {
-  transport_controller_->SetIceRole(ICEROLE_CONTROLLING);
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport2);
-  FakeDtlsTransport* transport3 = CreateFakeDtlsTransport("video", 2);
-  ASSERT_NE(nullptr, transport3);
-
-  // First, have one transport connect, and another fail, to ensure that
-  // the first transport connecting didn't trigger a "connected" state signal.
-  // We should only get a signal when all are connected.
-  transport1->fake_ice_transport()->SetConnectionCount(2);
-  transport1->SetWritable(true);
-  transport3->fake_ice_transport()->SetCandidatesGatheringComplete();
-  transport3->fake_ice_transport()->SetConnectionCount(1);
-  transport3->fake_ice_transport()->SetConnectionCount(0);
-  EXPECT_EQ_WAIT(kIceConnectionFailed, connection_state_, kTimeout);
-  // Signal count of 1 means that the only signal emitted was "failed".
-  EXPECT_EQ(1, connection_state_signal_count_);
-
-  // Destroy the failed transport to return to "connecting" state.
-  DestroyFakeDtlsTransport("video", 2);
-  EXPECT_EQ_WAIT(kIceConnectionConnecting, connection_state_, kTimeout);
-  EXPECT_EQ(2, connection_state_signal_count_);
-
-  // Make the remaining transport reach a connected state.
-  transport2->fake_ice_transport()->SetConnectionCount(2);
-  transport2->SetWritable(true);
-  EXPECT_EQ_WAIT(kIceConnectionConnected, connection_state_, kTimeout);
-  EXPECT_EQ(3, connection_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalConnectionStateComplete) {
-  transport_controller_->SetIceRole(ICEROLE_CONTROLLING);
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport2);
-  FakeDtlsTransport* transport3 = CreateFakeDtlsTransport("video", 2);
-  ASSERT_NE(nullptr, transport3);
-
-  // Similar to above test, but we're now reaching the completed state, which
-  // means only one connection per FakeDtlsTransport.
-  transport1->fake_ice_transport()->SetCandidatesGatheringComplete();
-  transport1->fake_ice_transport()->SetConnectionCount(1);
-  transport1->SetWritable(true);
-  transport3->fake_ice_transport()->SetCandidatesGatheringComplete();
-  transport3->fake_ice_transport()->SetConnectionCount(1);
-  transport3->fake_ice_transport()->SetConnectionCount(0);
-  EXPECT_EQ_WAIT(kIceConnectionFailed, connection_state_, kTimeout);
-  // Signal count of 1 means that the only signal emitted was "failed".
-  EXPECT_EQ(1, connection_state_signal_count_);
-
-  // Destroy the failed transport to return to "connecting" state.
-  DestroyFakeDtlsTransport("video", 2);
-  EXPECT_EQ_WAIT(kIceConnectionConnecting, connection_state_, kTimeout);
-  EXPECT_EQ(2, connection_state_signal_count_);
-
-  // Make the remaining transport reach a connected state.
-  transport2->fake_ice_transport()->SetCandidatesGatheringComplete();
-  transport2->fake_ice_transport()->SetConnectionCount(2);
-  transport2->SetWritable(true);
-  EXPECT_EQ_WAIT(kIceConnectionConnected, connection_state_, kTimeout);
-  EXPECT_EQ(3, connection_state_signal_count_);
-
-  // Finally, transition to completed state.
-  transport2->fake_ice_transport()->SetConnectionCount(1);
-  EXPECT_EQ_WAIT(kIceConnectionCompleted, connection_state_, kTimeout);
-  EXPECT_EQ(4, connection_state_signal_count_);
-}
-
-// Make sure that if we're "connected" and remove a transport, we stay in the
-// "connected" state.
-TEST_F(TransportControllerTest, TestDestroyTransportAndStayConnected) {
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport2);
-
-  transport1->fake_ice_transport()->SetCandidatesGatheringComplete();
-  transport1->fake_ice_transport()->SetConnectionCount(2);
-  transport1->SetWritable(true);
-  transport2->fake_ice_transport()->SetCandidatesGatheringComplete();
-  transport2->fake_ice_transport()->SetConnectionCount(2);
-  transport2->SetWritable(true);
-  EXPECT_EQ_WAIT(kIceConnectionConnected, connection_state_, kTimeout);
-  EXPECT_EQ(1, connection_state_signal_count_);
-
-  // Destroy one transport, then "complete" the other one, so we reach
-  // a known state.
-  DestroyFakeDtlsTransport("video", 1);
-  transport1->fake_ice_transport()->SetConnectionCount(1);
-  EXPECT_EQ_WAIT(kIceConnectionCompleted, connection_state_, kTimeout);
-  // Signal count of 2 means the deletion didn't cause any unexpected signals
-  EXPECT_EQ(2, connection_state_signal_count_);
-}
-
-// If we destroy the last/only transport, we should simply transition to
-// "connecting".
-TEST_F(TransportControllerTest, TestDestroyLastTransportWhileConnected) {
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-
-  transport->fake_ice_transport()->SetCandidatesGatheringComplete();
-  transport->fake_ice_transport()->SetConnectionCount(2);
-  transport->SetWritable(true);
-  EXPECT_EQ_WAIT(kIceConnectionConnected, connection_state_, kTimeout);
-  EXPECT_EQ(1, connection_state_signal_count_);
-
-  DestroyFakeDtlsTransport("audio", 1);
-  EXPECT_EQ_WAIT(kIceConnectionConnecting, connection_state_, kTimeout);
-  // Signal count of 2 means the deletion didn't cause any unexpected signals
-  EXPECT_EQ(2, connection_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalReceiving) {
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport2);
-
-  // Should signal receiving as soon as any transport is receiving.
-  transport1->SetReceiving(true);
-  EXPECT_TRUE_WAIT(receiving_, kTimeout);
-  EXPECT_EQ(1, receiving_signal_count_);
-
-  transport2->SetReceiving(true);
-  transport1->SetReceiving(false);
-  transport2->SetReceiving(false);
-  EXPECT_TRUE_WAIT(!receiving_, kTimeout);
-  EXPECT_EQ(2, receiving_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalGatheringStateGathering) {
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-  transport->fake_ice_transport()->MaybeStartGathering();
-  // Should be in the gathering state as soon as any transport starts gathering.
-  EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout);
-  EXPECT_EQ(1, gathering_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalGatheringStateComplete) {
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport2);
-  FakeDtlsTransport* transport3 = CreateFakeDtlsTransport("data", 1);
-  ASSERT_NE(nullptr, transport3);
-
-  transport3->fake_ice_transport()->MaybeStartGathering();
-  EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout);
-  EXPECT_EQ(1, gathering_state_signal_count_);
-
-  // Have one transport finish gathering, then destroy it, to make sure
-  // gathering
-  // completion wasn't signalled if only one transport finished gathering.
-  transport3->fake_ice_transport()->SetCandidatesGatheringComplete();
-  DestroyFakeDtlsTransport("data", 1);
-  EXPECT_EQ_WAIT(kIceGatheringNew, gathering_state_, kTimeout);
-  EXPECT_EQ(2, gathering_state_signal_count_);
-
-  // Make remaining transports start and then finish gathering.
-  transport1->fake_ice_transport()->MaybeStartGathering();
-  transport2->fake_ice_transport()->MaybeStartGathering();
-  EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout);
-  EXPECT_EQ(3, gathering_state_signal_count_);
-
-  transport1->fake_ice_transport()->SetCandidatesGatheringComplete();
-  transport2->fake_ice_transport()->SetCandidatesGatheringComplete();
-  EXPECT_EQ_WAIT(kIceGatheringComplete, gathering_state_, kTimeout);
-  EXPECT_EQ(4, gathering_state_signal_count_);
-}
-
-// Test that when the last transport that hasn't finished connecting and/or
-// gathering is destroyed, the aggregate state jumps to "completed". This can
-// happen if, for example, we have an audio and video transport, the audio
-// transport completes, then we start bundling video on the audio transport.
-TEST_F(TransportControllerTest,
-       TestSignalingWhenLastIncompleteTransportDestroyed) {
-  transport_controller_->SetIceRole(ICEROLE_CONTROLLING);
-  FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport1);
-  FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1);
-  ASSERT_NE(nullptr, transport2);
-
-  transport1->fake_ice_transport()->SetCandidatesGatheringComplete();
-  EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout);
-  EXPECT_EQ(1, gathering_state_signal_count_);
-
-  transport1->fake_ice_transport()->SetConnectionCount(1);
-  transport1->SetWritable(true);
-  DestroyFakeDtlsTransport("video", 1);
-  EXPECT_EQ_WAIT(kIceConnectionCompleted, connection_state_, kTimeout);
-  EXPECT_EQ(1, connection_state_signal_count_);
-  EXPECT_EQ_WAIT(kIceGatheringComplete, gathering_state_, kTimeout);
-  EXPECT_EQ(2, gathering_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalCandidatesGathered) {
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-
-  // Transport won't signal candidates until it has a local description.
-  TransportDescription local_desc(std::vector<std::string>(), kIceUfrag1,
-                                  kIcePwd1, ICEMODE_FULL,
-                                  CONNECTIONROLE_ACTPASS, nullptr);
-  std::string err;
-  EXPECT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", local_desc, SdpType::kOffer, &err));
-  transport_controller_->MaybeStartGathering();
-
-  transport->fake_ice_transport()->SignalCandidateGathered(
-      transport->fake_ice_transport(), CreateCandidate(1));
-  EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
-  EXPECT_EQ(1U, candidates_["audio"].size());
-}
-
-TEST_F(TransportControllerTest, TestSignalingOccursOnSignalingThread) {
-  CreateTransportControllerWithNetworkThread();
-  CreateFakeDtlsTransportsAndCompleteConnectionOnNetworkThread();
-
-  // connecting --> connected --> completed
-  EXPECT_EQ_WAIT(kIceConnectionCompleted, connection_state_, kTimeout);
-  EXPECT_EQ(2, connection_state_signal_count_);
-
-  EXPECT_TRUE_WAIT(receiving_, kTimeout);
-  EXPECT_EQ(1, receiving_signal_count_);
-
-  // new --> gathering --> complete
-  EXPECT_EQ_WAIT(kIceGatheringComplete, gathering_state_, kTimeout);
-  EXPECT_EQ(2, gathering_state_signal_count_);
-
-  EXPECT_EQ_WAIT(1U, candidates_["audio"].size(), kTimeout);
-  EXPECT_EQ_WAIT(1U, candidates_["video"].size(), kTimeout);
-  EXPECT_EQ(2, candidates_signal_count_);
-
-  EXPECT_TRUE(!signaled_on_non_signaling_thread_);
-}
-
-// Older versions of Chrome expect the ICE role to be re-determined when an
-// ICE restart occurs, and also don't perform conflict resolution correctly,
-// so for now we can't safely stop doing this.
-// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
-// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
-// enough population.
-TEST_F(TransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-  std::string err;
-  // Do an initial offer answer, so that the next offer is an ICE restart.
-  transport_controller_->SetIceRole(ICEROLE_CONTROLLED);
-  TransportDescription remote_desc(std::vector<std::string>(), kIceUfrag1,
-                                   kIcePwd1, ICEMODE_FULL,
-                                   CONNECTIONROLE_ACTPASS, nullptr);
-  EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription(
-      "audio", remote_desc, SdpType::kOffer, &err));
-  TransportDescription local_desc(std::vector<std::string>(), kIceUfrag2,
-                                  kIcePwd2, ICEMODE_FULL,
-                                  CONNECTIONROLE_ACTPASS, nullptr);
-  EXPECT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", local_desc, SdpType::kAnswer, &err));
-  EXPECT_EQ(ICEROLE_CONTROLLED, transport->fake_ice_transport()->GetIceRole());
-
-  // The endpoint that initiated an ICE restart should take the controlling
-  // role.
-  TransportDescription ice_restart_desc(std::vector<std::string>(), kIceUfrag3,
-                                        kIcePwd3, ICEMODE_FULL,
-                                        CONNECTIONROLE_ACTPASS, nullptr);
-  EXPECT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", ice_restart_desc, SdpType::kOffer, &err));
-  EXPECT_EQ(ICEROLE_CONTROLLING, transport->fake_ice_transport()->GetIceRole());
-}
-
-// Test that if the TransportController was created with the
-// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
-// redetermined on an ICE restart.
-TEST_F(TransportControllerTest, IceRoleNotRedetermined) {
-  bool redetermine_role = false;
-  transport_controller_.reset(new TransportControllerForTest(redetermine_role));
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-  std::string err;
-  // Do an initial offer answer, so that the next offer is an ICE restart.
-  transport_controller_->SetIceRole(ICEROLE_CONTROLLED);
-  TransportDescription remote_desc(std::vector<std::string>(), kIceUfrag1,
-                                   kIcePwd1, ICEMODE_FULL,
-                                   CONNECTIONROLE_ACTPASS, nullptr);
-  EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription(
-      "audio", remote_desc, SdpType::kOffer, &err));
-  TransportDescription local_desc(std::vector<std::string>(), kIceUfrag2,
-                                  kIcePwd2, ICEMODE_FULL,
-                                  CONNECTIONROLE_ACTPASS, nullptr);
-  EXPECT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", local_desc, SdpType::kAnswer, &err));
-  EXPECT_EQ(ICEROLE_CONTROLLED, transport->fake_ice_transport()->GetIceRole());
-
-  // The endpoint that initiated an ICE restart should keep the existing role.
-  TransportDescription ice_restart_desc(std::vector<std::string>(), kIceUfrag3,
-                                        kIcePwd3, ICEMODE_FULL,
-                                        CONNECTIONROLE_ACTPASS, nullptr);
-  EXPECT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", ice_restart_desc, SdpType::kOffer, &err));
-  EXPECT_EQ(ICEROLE_CONTROLLED, transport->fake_ice_transport()->GetIceRole());
-}
-
-// Tests ICE role is reversed after receiving ice-lite from remote.
-TEST_F(TransportControllerTest, TestSetRemoteIceLiteInOffer) {
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-  std::string err;
-
-  transport_controller_->SetIceRole(ICEROLE_CONTROLLED);
-  TransportDescription remote_desc(std::vector<std::string>(), kIceUfrag1,
-                                   kIcePwd1, ICEMODE_LITE,
-                                   CONNECTIONROLE_ACTPASS, nullptr);
-  EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription(
-      "audio", remote_desc, SdpType::kOffer, &err));
-  TransportDescription local_desc(kIceUfrag1, kIcePwd1);
-  ASSERT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", local_desc, SdpType::kAnswer, nullptr));
-
-  EXPECT_EQ(ICEROLE_CONTROLLING, transport->fake_ice_transport()->GetIceRole());
-  EXPECT_EQ(ICEMODE_LITE, transport->fake_ice_transport()->remote_ice_mode());
-}
-
-// Tests ice-lite in remote answer.
-TEST_F(TransportControllerTest, TestSetRemoteIceLiteInAnswer) {
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-  std::string err;
-
-  transport_controller_->SetIceRole(ICEROLE_CONTROLLING);
-  TransportDescription local_desc(kIceUfrag1, kIcePwd1);
-  ASSERT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", local_desc, SdpType::kOffer, nullptr));
-  EXPECT_EQ(ICEROLE_CONTROLLING, transport->fake_ice_transport()->GetIceRole());
-  // Transports will be created in ICEFULL_MODE.
-  EXPECT_EQ(ICEMODE_FULL, transport->fake_ice_transport()->remote_ice_mode());
-  TransportDescription remote_desc(std::vector<std::string>(), kIceUfrag1,
-                                   kIcePwd1, ICEMODE_LITE, CONNECTIONROLE_NONE,
-                                   nullptr);
-  ASSERT_TRUE(transport_controller_->SetRemoteTransportDescription(
-      "audio", remote_desc, SdpType::kAnswer, nullptr));
-  EXPECT_EQ(ICEROLE_CONTROLLING, transport->fake_ice_transport()->GetIceRole());
-  // After receiving remote description with ICEMODE_LITE, transport should
-  // have mode set to ICEMODE_LITE.
-  EXPECT_EQ(ICEMODE_LITE, transport->fake_ice_transport()->remote_ice_mode());
-}
-
-// Tests that the ICE role remains "controlling" if a subsequent offer that
-// does an ICE restart is received from an ICE lite endpoint. Regression test
-// for: https://crbug.com/710760
-TEST_F(TransportControllerTest,
-       IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
-  FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1);
-  ASSERT_NE(nullptr, transport);
-  std::string err;
-
-  // Initial offer/answer.
-  TransportDescription remote_desc(std::vector<std::string>(), kIceUfrag1,
-                                   kIcePwd1, ICEMODE_LITE,
-                                   CONNECTIONROLE_ACTPASS, nullptr);
-  TransportDescription local_desc(kIceUfrag1, kIcePwd1);
-  ASSERT_TRUE(transport_controller_->SetRemoteTransportDescription(
-      "audio", remote_desc, SdpType::kOffer, &err));
-  ASSERT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", local_desc, SdpType::kAnswer, nullptr));
-  // Subsequent ICE restart offer/answer.
-  remote_desc.ice_ufrag = kIceUfrag2;
-  remote_desc.ice_pwd = kIcePwd2;
-  local_desc.ice_ufrag = kIceUfrag2;
-  local_desc.ice_pwd = kIcePwd2;
-  ASSERT_TRUE(transport_controller_->SetRemoteTransportDescription(
-      "audio", remote_desc, SdpType::kOffer, &err));
-  ASSERT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", local_desc, SdpType::kAnswer, nullptr));
-
-  EXPECT_EQ(ICEROLE_CONTROLLING, transport->fake_ice_transport()->GetIceRole());
-}
-
-// Tests SetNeedsIceRestartFlag and NeedsIceRestart, setting the flag and then
-// initiating an ICE restart for one of the transports.
-TEST_F(TransportControllerTest, NeedsIceRestart) {
-  CreateFakeDtlsTransport("audio", 1);
-  CreateFakeDtlsTransport("video", 1);
-
-  // Do initial offer/answer so there's something to restart.
-  TransportDescription local_desc(kIceUfrag1, kIcePwd1);
-  TransportDescription remote_desc(kIceUfrag1, kIcePwd1);
-  ASSERT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", local_desc, SdpType::kOffer, nullptr));
-  ASSERT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "video", local_desc, SdpType::kOffer, nullptr));
-  ASSERT_TRUE(transport_controller_->SetRemoteTransportDescription(
-      "audio", remote_desc, SdpType::kAnswer, nullptr));
-  ASSERT_TRUE(transport_controller_->SetRemoteTransportDescription(
-      "video", remote_desc, SdpType::kAnswer, nullptr));
-
-  // Initially NeedsIceRestart should return false.
-  EXPECT_FALSE(transport_controller_->NeedsIceRestart("audio"));
-  EXPECT_FALSE(transport_controller_->NeedsIceRestart("video"));
-
-  // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
-  // true.
-  transport_controller_->SetNeedsIceRestartFlag();
-  EXPECT_TRUE(transport_controller_->NeedsIceRestart("audio"));
-  EXPECT_TRUE(transport_controller_->NeedsIceRestart("video"));
-  // For a nonexistent transport, false should be returned.
-  EXPECT_FALSE(transport_controller_->NeedsIceRestart("deadbeef"));
-
-  // Do ICE restart but only for audio.
-  TransportDescription ice_restart_local_desc(kIceUfrag2, kIcePwd2);
-  ASSERT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "audio", ice_restart_local_desc, SdpType::kOffer, nullptr));
-  ASSERT_TRUE(transport_controller_->SetLocalTransportDescription(
-      "video", local_desc, SdpType::kOffer, nullptr));
-  // NeedsIceRestart should still be true for video.
-  EXPECT_FALSE(transport_controller_->NeedsIceRestart("audio"));
-  EXPECT_TRUE(transport_controller_->NeedsIceRestart("video"));
-}
-
-enum class RTPTransportType { kSdes, kDtlsSrtp };
-std::ostream& operator<<(std::ostream& out, RTPTransportType value) {
-  switch (value) {
-    case RTPTransportType::kSdes:
-      return out << "SDES";
-    case RTPTransportType::kDtlsSrtp:
-      return out << "DTLS-SRTP";
-  }
-  return out;
-}
-
-// Tests the TransportController can correctly create and destroy the RTP
-// transports.
-class TransportControllerRTPTransportTest
-    : public TransportControllerTest,
-      public ::testing::WithParamInterface<RTPTransportType> {
- protected:
-  // Helper function used to create an RTP layer transport.
-  webrtc::RtpTransportInternal* CreateRtpTransport(
-      const std::string& transport_name) {
-    RTPTransportType type = GetParam();
-    switch (type) {
-      case RTPTransportType::kSdes:
-        return transport_controller_->CreateSdesTransport(transport_name,
-                                                          kRtcpMuxEnabled);
-      case RTPTransportType::kDtlsSrtp:
-        return transport_controller_->CreateDtlsSrtpTransport(transport_name,
-                                                              kRtcpMuxEnabled);
-    }
-    return nullptr;
-  }
-};
-
-// Tests that creating transports with the same name will cause the
-// second call to re-use the transport created in the first call.
-TEST_P(TransportControllerRTPTransportTest, CreateTransportsWithReference) {
-  const std::string transport_name = "transport";
-  webrtc::RtpTransportInternal* transport1 = CreateRtpTransport(transport_name);
-  webrtc::RtpTransportInternal* transport2 = CreateRtpTransport(transport_name);
-  EXPECT_NE(nullptr, transport1);
-  EXPECT_NE(nullptr, transport2);
-  // The TransportController is expected to return the existing one when using
-  // the same transport name.
-  EXPECT_EQ(transport1, transport2);
-  transport_controller_->DestroyTransport(transport_name);
-  transport_controller_->DestroyTransport(transport_name);
-}
-
-// Tests that creating different type of RTP transports with same name is not
-// allowed.
-TEST_P(TransportControllerRTPTransportTest,
-       CreateDifferentTypeOfTransportsWithSameName) {
-  const std::string transport_name = "transport";
-  webrtc::RtpTransportInternal* transport1 = CreateRtpTransport(transport_name);
-  EXPECT_NE(nullptr, transport1);
-  RTPTransportType type = GetParam();
-  switch (type) {
-    case RTPTransportType::kSdes:
-      EXPECT_EQ(nullptr, transport_controller_->CreateDtlsSrtpTransport(
-                             transport_name, kRtcpMuxEnabled));
-      break;
-    case RTPTransportType::kDtlsSrtp:
-      EXPECT_EQ(nullptr, transport_controller_->CreateSdesTransport(
-                             transport_name, kRtcpMuxEnabled));
-      break;
-    default:
-      ASSERT_TRUE(false);
-  }
-  transport_controller_->DestroyTransport(transport_name);
-}
-
-// Tests the RTP transport is not actually destroyed if references still exist.
-TEST_P(TransportControllerRTPTransportTest, DestroyTransportWithReference) {
-  const std::string transport_name = "transport";
-  webrtc::RtpTransportInternal* transport1 = CreateRtpTransport(transport_name);
-  webrtc::RtpTransportInternal* transport2 = CreateRtpTransport(transport_name);
-  EXPECT_NE(nullptr, transport1);
-  EXPECT_NE(nullptr, transport2);
-  transport_controller_->DestroyTransport(transport_name);
-  EXPECT_NE(nullptr, transport1->rtp_packet_transport());
-  EXPECT_EQ(nullptr, transport1->rtcp_packet_transport());
-  transport_controller_->DestroyTransport(transport_name);
-}
-
-// Tests the RTP is actually destroyed if there is no reference to it.
-// Disabled because of sometimes not working on Windows.
-// https://bugs.webrtc.org/34942
-TEST_P(TransportControllerRTPTransportTest,
-       DISABLED_DestroyTransportWithNoReference) {
-  const std::string transport_name = "transport";
-  webrtc::RtpTransportInternal* transport1 = CreateRtpTransport(transport_name);
-  webrtc::RtpTransportInternal* transport2 = CreateRtpTransport(transport_name);
-  EXPECT_NE(nullptr, transport1);
-  EXPECT_NE(nullptr, transport2);
-  transport_controller_->DestroyTransport(transport_name);
-  transport_controller_->DestroyTransport(transport_name);
-#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
-  EXPECT_DEATH(transport1->IsWritable(false), /*error_message=*/"");
-#endif
-}
-
-INSTANTIATE_TEST_CASE_P(TransportControllerTest,
-                        TransportControllerRTPTransportTest,
-                        ::testing::Values(RTPTransportType::kSdes,
-                                          RTPTransportType::kDtlsSrtp));
-
-}  // namespace cricket