Replace BundleFilter with RtpDemuxer in RtpTransport.

BundleFilter is replaced by RtpDemuxer in RtpTransport for payload
type-based demuxing. RtpTransport will support MID-based demuxing later.

Each BaseChannel has its own RTP demuxing criteria and when connecting
to the RtpTransport, BaseChannel will register itself as a demuxer sink.

The inheritance model is changed. New inheritance chain:
DtlsSrtpTransport->SrtpTransport->RtpTranpsort

The JsepTransport2 is renamed to JsepTransport.

NOTE:
When RTCP packets are received, Call::DeliverRtcp will be called for
multiple times (webrtc:9035) which is an existing issue. With this CL,
it will become more of a problem and should be fixed.

Bug: webrtc:8587
Change-Id: Ibd880e7b744bd912336a691309950bc18e42cf62
Reviewed-on: https://webrtc-review.googlesource.com/65786
Commit-Queue: Zhi Huang <zhihuang@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Reviewed-by: Benjamin Wright <benwright@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22867}
diff --git a/media/base/rtputils.cc b/media/base/rtputils.cc
index d0ba1cf..e8fd10d 100644
--- a/media/base/rtputils.cc
+++ b/media/base/rtputils.cc
@@ -275,6 +275,16 @@
   return (static_cast<const uint8_t*>(data)[0] >> 6) == kRtpVersion;
 }
 
+// Check the RTP payload type. If 63 < payload type < 96, it's RTCP.
+// For additional details, see http://tools.ietf.org/html/rfc5761.
+bool IsRtcpPacket(const char* data, size_t len) {
+  if (len < 2) {
+    return false;
+  }
+  char pt = data[1] & 0x7F;
+  return (63 < pt) && (pt < 96);
+}
+
 bool IsValidRtpPayloadType(int payload_type) {
   return payload_type >= 0 && payload_type <= 127;
 }
diff --git a/media/base/rtputils.h b/media/base/rtputils.h
index 0b7205c..5258c0b 100644
--- a/media/base/rtputils.h
+++ b/media/base/rtputils.h
@@ -55,6 +55,7 @@
 
 bool IsRtpPacket(const void* data, size_t len);
 
+bool IsRtcpPacket(const char* data, size_t len);
 // True if |payload type| is 0-127.
 bool IsValidRtpPayloadType(int payload_type);
 
diff --git a/ortc/rtptransportadapter.cc b/ortc/rtptransportadapter.cc
index acd71db..7705e17 100644
--- a/ortc/rtptransportadapter.cc
+++ b/ortc/rtptransportadapter.cc
@@ -171,8 +171,8 @@
 
   transport_->SignalReadyToSend.connect(this,
                                         &RtpTransportAdapter::OnReadyToSend);
-  transport_->SignalPacketReceived.connect(
-      this, &RtpTransportAdapter::OnPacketReceived);
+  transport_->SignalRtcpPacketReceived.connect(
+      this, &RtpTransportAdapter::OnRtcpPacketReceived);
   transport_->SignalWritableState.connect(
       this, &RtpTransportAdapter::OnWritableState);
 }
diff --git a/ortc/rtptransportadapter.h b/ortc/rtptransportadapter.h
index 72bd3f6..c1b8efa 100644
--- a/ortc/rtptransportadapter.h
+++ b/ortc/rtptransportadapter.h
@@ -14,13 +14,11 @@
 #include <memory>
 #include <vector>
 
-#include "api/ortc/srtptransportinterface.h"
 #include "api/rtcerror.h"
 #include "media/base/streamparams.h"
 #include "ortc/rtptransportcontrolleradapter.h"
 #include "pc/channel.h"
-#include "pc/rtptransport.h"
-#include "pc/rtptransportinternal.h"
+#include "pc/rtptransportinternaladapter.h"
 #include "pc/srtptransport.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/sigslot.h"
@@ -82,8 +80,6 @@
 
   bool IsSrtpActive() const override { return transport_->IsSrtpActive(); }
 
-  bool IsSrtpTransport() const { return srtp_transport_ != nullptr; }
-
  protected:
   RtpTransportAdapter* GetInternal() override { return this; }
 
@@ -96,10 +92,9 @@
 
   void OnReadyToSend(bool ready) { SignalReadyToSend(ready); }
 
-  void OnPacketReceived(bool rtcp,
-                        rtc::CopyOnWriteBuffer* packet,
-                        const rtc::PacketTime& time) {
-    SignalPacketReceived(rtcp, packet, time);
+  void OnRtcpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                            const rtc::PacketTime& time) {
+    SignalRtcpPacketReceived(packet, time);
   }
 
   void OnWritableState(bool writable) { SignalWritableState(writable); }
diff --git a/ortc/rtptransportcontrolleradapter.cc b/ortc/rtptransportcontrolleradapter.cc
index b772ffa..f69edd5 100644
--- a/ortc/rtptransportcontrolleradapter.cc
+++ b/ortc/rtptransportcontrolleradapter.cc
@@ -869,8 +869,6 @@
       cricket::AudioOptions());
   RTC_DCHECK(voice_channel_);
   voice_channel_->Enable(true);
-  voice_channel_->DisableEncryption(
-      !inner_audio_transport_->GetInternal()->IsSrtpTransport());
 }
 
 void RtpTransportControllerAdapter::CreateVideoChannel() {
@@ -880,8 +878,6 @@
       cricket::VideoOptions());
   RTC_DCHECK(video_channel_);
   video_channel_->Enable(true);
-  video_channel_->DisableEncryption(
-      !inner_video_transport_->GetInternal()->IsSrtpTransport());
 }
 
 void RtpTransportControllerAdapter::DestroyVoiceChannel() {
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index b59de48..b9b2f84 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -30,8 +30,6 @@
   defines = []
   sources = [
     "audiomonitor.h",
-    "bundlefilter.cc",
-    "bundlefilter.h",
     "channel.cc",
     "channel.h",
     "channelmanager.cc",
@@ -42,8 +40,8 @@
     "dtlssrtptransport.h",
     "externalhmac.cc",
     "externalhmac.h",
-    "jseptransport2.cc",
-    "jseptransport2.h",
+    "jseptransport.cc",
+    "jseptransport.h",
     "jseptransportcontroller.cc",
     "jseptransportcontroller.h",
     "mediasession.cc",
@@ -76,10 +74,13 @@
     "../api:optional",
     "../api:ortc_api",
     "../api:video_frame_api",
+    "../call:rtp_interfaces",
+    "../call:rtp_receiver",
     "../common_video:common_video",
     "../media:rtc_data",
     "../media:rtc_h264_profile_id",
     "../media:rtc_media_base",
+    "../modules/rtp_rtcp:rtp_rtcp_format",
     "../p2p:rtc_p2p",
     "../rtc_base:checks",
     "../rtc_base:rtc_base",
@@ -270,12 +271,11 @@
     testonly = true
 
     sources = [
-      "bundlefilter_unittest.cc",
       "channel_unittest.cc",
       "channelmanager_unittest.cc",
       "currentspeakermonitor_unittest.cc",
       "dtlssrtptransport_unittest.cc",
-      "jseptransport2_unittest.cc",
+      "jseptransport_unittest.cc",
       "jseptransportcontroller_unittest.cc",
       "mediasession_unittest.cc",
       "rtcpmuxfilter_unittest.cc",
@@ -308,9 +308,11 @@
       "../api:array_view",
       "../api:fakemetricsobserver",
       "../api:libjingle_peerconnection_api",
+      "../call:rtp_interfaces",
       "../logging:rtc_event_log_api",
       "../media:rtc_media_base",
       "../media:rtc_media_tests_utils",
+      "../modules/rtp_rtcp:rtp_rtcp_format",
       "../p2p:p2p_test_utils",
       "../p2p:rtc_p2p",
       "../rtc_base:checks",
diff --git a/pc/channel.cc b/pc/channel.cc
index a1869c4..0414125 100644
--- a/pc/channel.cc
+++ b/pc/channel.cc
@@ -17,6 +17,7 @@
 #include "api/call/audio_sink.h"
 #include "media/base/mediaconstants.h"
 #include "media/base/rtputils.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
 #include "rtc_base/bind.h"
 #include "rtc_base/byteorder.h"
 #include "rtc_base/checks.h"
@@ -108,13 +109,13 @@
       crypto_options_(crypto_options),
       media_channel_(std::move(media_channel)) {
   RTC_DCHECK_RUN_ON(worker_thread_);
+  demuxer_criteria_.mid = content_name;
   RTC_LOG(LS_INFO) << "Created channel for " << content_name;
 }
 
 BaseChannel::~BaseChannel() {
   TRACE_EVENT0("webrtc", "BaseChannel::~BaseChannel");
   RTC_DCHECK_RUN_ON(worker_thread_);
-  Deinit();
   // Eats any outstanding messages or packets.
   worker_thread_->Clear(&invoker_);
   worker_thread_->Clear(this);
@@ -125,15 +126,15 @@
   RTC_LOG(LS_INFO) << "Destroyed channel: " << content_name_;
 }
 
-void BaseChannel::ConnectToRtpTransport() {
+bool BaseChannel::ConnectToRtpTransport() {
   RTC_DCHECK(rtp_transport_);
+  if (!RegisterRtpDemuxerSink()) {
+    return false;
+  }
   rtp_transport_->SignalReadyToSend.connect(
       this, &BaseChannel::OnTransportReadyToSend);
-  // TODO(zstein):  RtpTransport::SignalPacketReceived will probably be replaced
-  // with a callback interface later so that the demuxer can select which
-  // channel to signal.
-  rtp_transport_->SignalPacketReceived.connect(this,
-                                               &BaseChannel::OnPacketReceived);
+  rtp_transport_->SignalRtcpPacketReceived.connect(
+      this, &BaseChannel::OnRtcpPacketReceived);
   rtp_transport_->SignalNetworkRouteChanged.connect(
       this, &BaseChannel::OnNetworkRouteChanged);
   rtp_transport_->SignalWritableState.connect(this,
@@ -146,12 +147,14 @@
   if (metrics_observer_) {
     rtp_transport_->SetMetricsObserver(metrics_observer_);
   }
+  return true;
 }
 
 void BaseChannel::DisconnectFromRtpTransport() {
   RTC_DCHECK(rtp_transport_);
+  rtp_transport_->UnregisterRtpDemuxerSink(this);
   rtp_transport_->SignalReadyToSend.disconnect(this);
-  rtp_transport_->SignalPacketReceived.disconnect(this);
+  rtp_transport_->SignalRtcpPacketReceived.disconnect(this);
   rtp_transport_->SignalNetworkRouteChanged.disconnect(this);
   rtp_transport_->SignalWritableState.disconnect(this);
   rtp_transport_->SignalSentPacket.disconnect(this);
@@ -160,9 +163,8 @@
 
 void BaseChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport) {
   RTC_DCHECK_RUN_ON(worker_thread_);
-  network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
-    SetRtpTransport(rtp_transport);
-  });
+  network_thread_->Invoke<void>(
+      RTC_FROM_HERE, [this, rtp_transport] { SetRtpTransport(rtp_transport); });
 
   // Both RTP and RTCP channels should be set, we can call SetInterface on
   // the media channel and it can set network options.
@@ -187,12 +189,15 @@
   });
 }
 
-void BaseChannel::SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport) {
+bool BaseChannel::SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport) {
+  if (rtp_transport == rtp_transport_) {
+    return true;
+  }
+
   if (!network_thread_->IsCurrent()) {
-    network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
-      SetRtpTransport(rtp_transport);
+    return network_thread_->Invoke<bool>(RTC_FROM_HERE, [this, rtp_transport] {
+      return SetRtpTransport(rtp_transport);
     });
-    return;
   }
 
   if (rtp_transport_) {
@@ -204,7 +209,10 @@
     RTC_DCHECK(rtp_transport_->rtp_packet_transport());
     transport_name_ = rtp_transport_->rtp_packet_transport()->transport_name();
 
-    ConnectToRtpTransport();
+    if (!ConnectToRtpTransport()) {
+      RTC_LOG(LS_ERROR) << "Failed to connect to the new RtpTransport.";
+      return false;
+    }
     OnTransportReadyToSend(rtp_transport_->IsReadyToSend());
     UpdateWritableState_n();
 
@@ -220,6 +228,7 @@
       }
     }
   }
+  return true;
 }
 
 void BaseChannel::SetMetricsObserver(
@@ -239,11 +248,19 @@
 }
 
 bool BaseChannel::AddRecvStream(const StreamParams& sp) {
+  demuxer_criteria_.ssrcs.insert(sp.first_ssrc());
+  if (!RegisterRtpDemuxerSink()) {
+    return false;
+  }
   return InvokeOnWorker<bool>(RTC_FROM_HERE,
                               Bind(&BaseChannel::AddRecvStream_w, this, sp));
 }
 
 bool BaseChannel::RemoveRecvStream(uint32_t ssrc) {
+  demuxer_criteria_.ssrcs.erase(ssrc);
+  if (!RegisterRtpDemuxerSink()) {
+    return false;
+  }
   return InvokeOnWorker<bool>(
       RTC_FROM_HERE, Bind(&BaseChannel::RemoveRecvStream_w, this, ssrc));
 }
@@ -295,7 +312,7 @@
   return enabled() &&
          webrtc::RtpTransceiverDirectionHasRecv(remote_content_direction_) &&
          webrtc::RtpTransceiverDirectionHasSend(local_content_direction_) &&
-         was_ever_writable() && (srtp_active() || encryption_disabled_);
+         was_ever_writable();
 }
 
 bool BaseChannel::SendPacket(rtc::CopyOnWriteBuffer* packet,
@@ -430,23 +447,56 @@
               : rtp_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS);
 }
 
-bool BaseChannel::HandlesPayloadType(int packet_type) const {
-  return bundle_filter_.FindPayloadType(packet_type);
+void BaseChannel::OnRtpPacket(const webrtc::RtpPacketReceived& parsed_packet) {
+  // Reconstruct the PacketTime from the |parsed_packet|.
+  // RtpPacketReceived.arrival_time_ms = (PacketTime + 500) / 1000;
+  // Note: The |not_before| field is always 0 here. This field is not currently
+  // used, so it should be fine.
+  int64_t timestamp = -1;
+  if (parsed_packet.arrival_time_ms() > 0) {
+    timestamp = parsed_packet.arrival_time_ms() * 1000;
+  }
+  rtc::PacketTime packet_time(timestamp, /*not_before=*/0);
+
+  OnPacketReceived(/*rtcp=*/false, parsed_packet.Buffer(), packet_time);
+}
+
+void BaseChannel::UpdateRtpHeaderExtensionMap(
+    const RtpHeaderExtensions& header_extensions) {
+  RTC_DCHECK(rtp_transport_);
+  // Update the header extension map on network thread in case there is data
+  // race.
+  // TODO(zhihuang): Add an rtc::ThreadChecker make sure to RtpTransport won't
+  // be accessed from different threads.
+  //
+  // NOTE: This doesn't take the BUNDLE case in account meaning the RTP header
+  // extension maps are not merged when BUNDLE is enabled. This is fine because
+  // the ID for MID should be consistent among all the RTP transports.
+  network_thread_->Invoke<void>(RTC_FROM_HERE, [this, &header_extensions] {
+    rtp_transport_->UpdateRtpHeaderExtensionMap(header_extensions);
+  });
+}
+
+bool BaseChannel::RegisterRtpDemuxerSink() {
+  RTC_DCHECK(rtp_transport_);
+  return network_thread_->Invoke<bool>(RTC_FROM_HERE, [this] {
+    return rtp_transport_->RegisterRtpDemuxerSink(demuxer_criteria_, this);
+  });
+}
+
+void BaseChannel::OnRtcpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                                       const rtc::PacketTime& packet_time) {
+  OnPacketReceived(/*rtcp=*/true, *packet, packet_time);
 }
 
 void BaseChannel::OnPacketReceived(bool rtcp,
-                                   rtc::CopyOnWriteBuffer* packet,
+                                   const rtc::CopyOnWriteBuffer& packet,
                                    const rtc::PacketTime& packet_time) {
   if (!has_received_packet_ && !rtcp) {
     has_received_packet_ = true;
     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
@@ -467,7 +517,7 @@
 
   invoker_.AsyncInvoke<void>(
       RTC_FROM_HERE, worker_thread_,
-      Bind(&BaseChannel::ProcessPacket, this, rtcp, *packet, packet_time));
+      Bind(&BaseChannel::ProcessPacket, this, rtcp, packet, packet_time));
 }
 
 void BaseChannel::ProcessPacket(bool rtcp,
@@ -595,7 +645,9 @@
     // the unsignaled stream params that are cached.
     if ((!it->has_ssrcs() && !HasStreamWithNoSsrcs(streams)) ||
         !GetStreamBySsrc(streams, it->first_ssrc())) {
-      if (!RemoveRecvStream_w(it->first_ssrc())) {
+      if (RemoveRecvStream_w(it->first_ssrc())) {
+        RTC_LOG(LS_INFO) << "Remove remote ssrc: " << it->first_ssrc();
+      } else {
         std::ostringstream desc;
         desc << "Failed to remove remote stream with ssrc "
              << it->first_ssrc() << ".";
@@ -604,6 +656,7 @@
       }
     }
   }
+  demuxer_criteria_.ssrcs.clear();
   // Check for new streams.
   for (StreamParamsVec::const_iterator it = streams.begin();
       it != streams.end(); ++it) {
@@ -621,7 +674,11 @@
         ret = false;
       }
     }
+    // Update the receiving SSRCs.
+    demuxer_criteria_.ssrcs.insert(it->ssrcs.begin(), it->ssrcs.end());
   }
+  // Re-register the sink to update the receiving ssrcs.
+  RegisterRtpDemuxerSink();
   remote_streams_ = streams;
   return ret;
 }
@@ -663,7 +720,7 @@
 }
 
 void BaseChannel::AddHandledPayloadType(int payload_type) {
-  bundle_filter_.AddPayloadType(payload_type);
+  demuxer_criteria_.payload_types.insert(static_cast<uint8_t>(payload_type));
 }
 
 void BaseChannel::FlushRtcpMessages_n() {
@@ -752,6 +809,7 @@
 
   RtpHeaderExtensions rtp_header_extensions =
       GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions());
+  UpdateRtpHeaderExtensionMap(rtp_header_extensions);
 
   AudioRecvParameters recv_params = last_recv_params_;
   RtpParametersFromMediaDescription(audio, rtp_header_extensions, &recv_params);
@@ -763,6 +821,12 @@
   for (const AudioCodec& codec : audio->codecs()) {
     AddHandledPayloadType(codec.id);
   }
+  // Need to re-register the sink to update the handled payload.
+  if (!RegisterRtpDemuxerSink()) {
+    RTC_LOG(LS_ERROR) << "Failed to set up audio demuxing.";
+    return false;
+  }
+
   last_recv_params_ = recv_params;
 
   // TODO(pthatcher): Move local streams into AudioSendParameters, and
@@ -880,6 +944,7 @@
 
   RtpHeaderExtensions rtp_header_extensions =
       GetFilteredRtpHeaderExtensions(video->rtp_header_extensions());
+  UpdateRtpHeaderExtensionMap(rtp_header_extensions);
 
   VideoRecvParameters recv_params = last_recv_params_;
   RtpParametersFromMediaDescription(video, rtp_header_extensions, &recv_params);
@@ -891,6 +956,12 @@
   for (const VideoCodec& codec : video->codecs()) {
     AddHandledPayloadType(codec.id);
   }
+  // Need to re-register the sink to update the handled payload.
+  if (!RegisterRtpDemuxerSink()) {
+    RTC_LOG(LS_ERROR) << "Failed to set up video demuxing.";
+    return false;
+  }
+
   last_recv_params_ = recv_params;
 
   // TODO(pthatcher): Move local streams into VideoSendParameters, and
@@ -1039,6 +1110,12 @@
   for (const DataCodec& codec : data->codecs()) {
     AddHandledPayloadType(codec.id);
   }
+  // Need to re-register the sink to update the handled payload.
+  if (!RegisterRtpDemuxerSink()) {
+    RTC_LOG(LS_ERROR) << "Failed to set up data demuxing.";
+    return false;
+  }
+
   last_recv_params_ = recv_params;
 
   // TODO(pthatcher): Move local streams into DataSendParameters, and
diff --git a/pc/channel.h b/pc/channel.h
index cf04b5c..50356fa 100644
--- a/pc/channel.h
+++ b/pc/channel.h
@@ -23,13 +23,13 @@
 #include "api/rtpreceiverinterface.h"
 #include "api/videosinkinterface.h"
 #include "api/videosourceinterface.h"
+#include "call/rtp_packet_sink_interface.h"
 #include "media/base/mediachannel.h"
 #include "media/base/mediaengine.h"
 #include "media/base/streamparams.h"
 #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/rtptransport.h"
@@ -68,9 +68,10 @@
 // vtable, and the media channel's thread using BaseChannel as the
 // NetworkInterface.
 
-class BaseChannel
-    : public rtc::MessageHandler, public sigslot::has_slots<>,
-      public MediaChannel::NetworkInterface {
+class BaseChannel : public rtc::MessageHandler,
+                    public sigslot::has_slots<>,
+                    public MediaChannel::NetworkInterface,
+                    public webrtc::RtpPacketSinkInterface {
  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).
@@ -108,7 +109,7 @@
   // encryption, an SrtpTransport for SDES or a DtlsSrtpTransport for DTLS-SRTP.
   // This can be called from any thread and it hops to the network thread
   // internally. It would replace the |SetTransports| and its variants.
-  void SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport);
+  bool SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport);
 
   // Channel control
   bool SetLocalContent(const MediaContentDescription* content,
@@ -120,7 +121,7 @@
 
   bool Enable(bool enable);
 
-  // Multiplexing
+  // TODO(zhihuang): These methods are used for testing and can be removed.
   bool AddRecvStream(const StreamParams& sp);
   bool RemoveRecvStream(uint32_t ssrc);
   bool AddSendStream(const StreamParams& sp);
@@ -172,10 +173,8 @@
 
   virtual cricket::MediaType media_type() = 0;
 
-  // Public for testing.
-  // TODO(zstein): Remove this once channels register themselves with
-  // an RtpTransport in a more explicit way.
-  bool HandlesPayloadType(int payload_type) const;
+  // RtpPacketSinkInterface overrides.
+  void OnRtpPacket(const webrtc::RtpPacketReceived& packet) override;
 
   // Used by the RTCStatsCollector tests to set the transport name without
   // creating RtpTransports.
@@ -186,8 +185,6 @@
   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(); }
 
@@ -232,12 +229,11 @@
                   rtc::CopyOnWriteBuffer* packet,
                   const rtc::PacketOptions& options);
 
-  bool WantsPacket(bool rtcp, const rtc::CopyOnWriteBuffer* packet);
-  void HandlePacket(bool rtcp, rtc::CopyOnWriteBuffer* packet,
-                    const rtc::PacketTime& packet_time);
-  // TODO(zstein): packet can be const once the RtpTransport handles protection.
+  void OnRtcpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                            const rtc::PacketTime& packet_time);
+
   void OnPacketReceived(bool rtcp,
-                        rtc::CopyOnWriteBuffer* packet,
+                        const rtc::CopyOnWriteBuffer& packet,
                         const rtc::PacketTime& packet_time);
   void ProcessPacket(bool rtcp,
                      const rtc::CopyOnWriteBuffer& packet,
@@ -282,11 +278,6 @@
   RtpHeaderExtensions GetFilteredRtpHeaderExtensions(
       const RtpHeaderExtensions& extensions);
 
-  // Helper method to get RTP Absoulute SendTime extension header id if
-  // present in remote supported extensions list.
-  void MaybeCacheRtpAbsSendTimeHeaderExtension_w(
-      const std::vector<webrtc::RtpExtension>& extensions);
-
   // From MessageHandler
   void OnMessage(rtc::Message* pmsg) override;
 
@@ -298,8 +289,13 @@
 
   void AddHandledPayloadType(int payload_type);
 
+  void UpdateRtpHeaderExtensionMap(
+      const RtpHeaderExtensions& header_extensions);
+
+  bool RegisterRtpDemuxerSink();
+
  private:
-  void ConnectToRtpTransport();
+  bool ConnectToRtpTransport();
   void DisconnectFromRtpTransport();
   void SignalSentPacket_n(const rtc::SentPacket& sent_packet);
   void SignalSentPacket_w(const rtc::SentPacket& sent_packet);
@@ -317,11 +313,6 @@
   rtc::scoped_refptr<webrtc::MetricsObserverInterface> metrics_observer_;
 
   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.
-  std::unique_ptr<webrtc::SrtpTransport> sdes_transport_;
-  std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport_;
-  std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport_;
 
   std::vector<std::pair<rtc::Socket::Option, int> > socket_options_;
   std::vector<std::pair<rtc::Socket::Option, int> > rtcp_socket_options_;
@@ -345,14 +336,7 @@
   webrtc::RtpTransceiverDirection remote_content_direction_ =
       webrtc::RtpTransceiverDirection::kInactive;
 
-  // 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;
+  webrtc::RtpDemuxerCriteria demuxer_criteria_;
 };
 
 // VoiceChannel is a specialization that adds support for early media, DTMF,
diff --git a/pc/channel_unittest.cc b/pc/channel_unittest.cc
index c398f07..0d8fdc3 100644
--- a/pc/channel_unittest.cc
+++ b/pc/channel_unittest.cc
@@ -42,6 +42,8 @@
 const cricket::DataCodec kGoogleDataCodec(101, "google-data");
 const uint32_t kSsrc1 = 0x1111;
 const uint32_t kSsrc2 = 0x2222;
+const uint32_t kSsrc3 = 0x3333;
+const uint32_t kSsrc4 = 0x4444;
 const int kAudioPts[] = {0, 8};
 const int kVideoPts[] = {97, 99};
 enum class NetworkIsWorker { Yes, No };
@@ -239,13 +241,6 @@
     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,
@@ -289,9 +284,8 @@
   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);
+        rtc::MakeUnique<webrtc::RtpTransport>(rtcp_packet_transport == nullptr);
 
     rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
     if (rtcp_packet_transport) {
@@ -303,11 +297,8 @@
   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));
+    auto dtls_srtp_transport = rtc::MakeUnique<webrtc::DtlsSrtpTransport>(
+        rtcp_dtls_transport == nullptr);
 
     dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
                                            rtcp_dtls_transport);
@@ -1177,10 +1168,6 @@
     CreateChannels(flags, flags);
     EXPECT_TRUE(SendInitiate());
     EXPECT_TRUE(SendAccept());
-    EXPECT_TRUE(channel1_->HandlesPayloadType(pl_type1));
-    EXPECT_TRUE(channel2_->HandlesPayloadType(pl_type1));
-    EXPECT_FALSE(channel1_->HandlesPayloadType(pl_type2));
-    EXPECT_FALSE(channel2_->HandlesPayloadType(pl_type2));
 
     // Both channels can receive pl_type1 only.
     SendCustomRtp1(kSsrc1, ++sequence_number1_1, pl_type1);
@@ -1191,11 +1178,11 @@
     EXPECT_TRUE(CheckNoRtp1());
     EXPECT_TRUE(CheckNoRtp2());
 
-    SendCustomRtp1(kSsrc1, ++sequence_number1_1, pl_type2);
-    SendCustomRtp2(kSsrc2, ++sequence_number2_2, pl_type2);
+    SendCustomRtp1(kSsrc3, ++sequence_number1_1, pl_type2);
+    SendCustomRtp2(kSsrc4, ++sequence_number2_2, pl_type2);
     WaitForThreads();
-    EXPECT_FALSE(CheckCustomRtp2(kSsrc1, sequence_number1_1, pl_type2));
-    EXPECT_FALSE(CheckCustomRtp1(kSsrc2, sequence_number2_2, pl_type2));
+    EXPECT_FALSE(CheckCustomRtp2(kSsrc3, sequence_number1_1, pl_type2));
+    EXPECT_FALSE(CheckCustomRtp1(kSsrc4, sequence_number2_2, pl_type2));
 
     // RTCP test
     SendCustomRtcp1(kSsrc1);
diff --git a/pc/channelmanager_unittest.cc b/pc/channelmanager_unittest.cc
index 38da139..b65b18b 100644
--- a/pc/channelmanager_unittest.cc
+++ b/pc/channelmanager_unittest.cc
@@ -55,12 +55,8 @@
   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));
+        rtc::MakeUnique<webrtc::DtlsSrtpTransport>(/*rtcp_mux_required=*/true);
     dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport_.get(),
                                            /*rtcp_dtls_transport=*/nullptr);
     return dtls_srtp_transport;
diff --git a/pc/dtlssrtptransport.cc b/pc/dtlssrtptransport.cc
index f40c96f..4ccec73 100644
--- a/pc/dtlssrtptransport.cc
+++ b/pc/dtlssrtptransport.cc
@@ -24,22 +24,8 @@
 
 namespace webrtc {
 
-DtlsSrtpTransport::DtlsSrtpTransport(
-    std::unique_ptr<webrtc::SrtpTransport> srtp_transport)
-    : RtpTransportInternalAdapter(srtp_transport.get()) {
-  srtp_transport_ = std::move(srtp_transport);
-  RTC_DCHECK(srtp_transport_);
-  srtp_transport_->SignalPacketReceived.connect(
-      this, &DtlsSrtpTransport::OnPacketReceived);
-  srtp_transport_->SignalReadyToSend.connect(this,
-                                             &DtlsSrtpTransport::OnReadyToSend);
-  srtp_transport_->SignalNetworkRouteChanged.connect(
-      this, &DtlsSrtpTransport::OnNetworkRouteChanged);
-  srtp_transport_->SignalWritableState.connect(
-      this, &DtlsSrtpTransport::OnWritableState);
-  srtp_transport_->SignalSentPacket.connect(this,
-                                            &DtlsSrtpTransport::OnSentPacket);
-}
+DtlsSrtpTransport::DtlsSrtpTransport(bool rtcp_mux_enabled)
+    : SrtpTransport(rtcp_mux_enabled) {}
 
 void DtlsSrtpTransport::SetDtlsTransports(
     cricket::DtlsTransportInternal* rtp_dtls_transport,
@@ -54,7 +40,7 @@
   // DtlsTransport changes and wait until the DTLS handshake is complete to set
   // the newly negotiated parameters.
   if (IsSrtpActive()) {
-    srtp_transport_->ResetParams();
+    ResetParams();
   }
 
   const std::string transport_name =
@@ -76,13 +62,13 @@
   SetRtpDtlsTransport(rtp_dtls_transport);
   SetRtpPacketTransport(rtp_dtls_transport);
 
-  UpdateWritableStateAndMaybeSetupDtlsSrtp();
+  MaybeSetupDtlsSrtp();
 }
 
 void DtlsSrtpTransport::SetRtcpMuxEnabled(bool enable) {
-  srtp_transport_->SetRtcpMuxEnabled(enable);
+  SrtpTransport::SetRtcpMuxEnabled(enable);
   if (enable) {
-    UpdateWritableStateAndMaybeSetupDtlsSrtp();
+    MaybeSetupDtlsSrtp();
   }
 }
 
@@ -128,10 +114,9 @@
 }
 
 bool DtlsSrtpTransport::IsDtlsWritable() {
-  auto rtp_packet_transport = srtp_transport_->rtp_packet_transport();
   auto rtcp_packet_transport =
-      rtcp_mux_enabled() ? nullptr : srtp_transport_->rtcp_packet_transport();
-  return rtp_packet_transport && rtp_packet_transport->writable() &&
+      rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
+  return rtp_dtls_transport_ && rtp_dtls_transport_->writable() &&
          (!rtcp_packet_transport || rtcp_packet_transport->writable());
 }
 
@@ -140,7 +125,7 @@
 }
 
 void DtlsSrtpTransport::MaybeSetupDtlsSrtp() {
-  if (IsSrtpActive() || !DtlsHandshakeCompleted()) {
+  if (IsSrtpActive() || !IsDtlsWritable()) {
     return;
   }
 
@@ -170,11 +155,10 @@
 
   if (!ExtractParams(rtp_dtls_transport_, &selected_crypto_suite, &send_key,
                      &recv_key) ||
-      !srtp_transport_->SetRtpParams(
-          selected_crypto_suite, &send_key[0],
-          static_cast<int>(send_key.size()), send_extension_ids,
-          selected_crypto_suite, &recv_key[0],
-          static_cast<int>(recv_key.size()), recv_extension_ids)) {
+      !SetRtpParams(selected_crypto_suite, &send_key[0],
+                    static_cast<int>(send_key.size()), send_extension_ids,
+                    selected_crypto_suite, &recv_key[0],
+                    static_cast<int>(recv_key.size()), recv_extension_ids)) {
     SignalDtlsSrtpSetupFailure(this, /*rtcp=*/false);
     RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTP failed";
   }
@@ -202,11 +186,11 @@
   rtc::ZeroOnFreeBuffer<unsigned char> rtcp_recv_key;
   if (!ExtractParams(rtcp_dtls_transport_, &selected_crypto_suite,
                      &rtcp_send_key, &rtcp_recv_key) ||
-      !srtp_transport_->SetRtcpParams(
-          selected_crypto_suite, &rtcp_send_key[0],
-          static_cast<int>(rtcp_send_key.size()), send_extension_ids,
-          selected_crypto_suite, &rtcp_recv_key[0],
-          static_cast<int>(rtcp_recv_key.size()), recv_extension_ids)) {
+      !SetRtcpParams(selected_crypto_suite, &rtcp_send_key[0],
+                     static_cast<int>(rtcp_send_key.size()), send_extension_ids,
+                     selected_crypto_suite, &rtcp_recv_key[0],
+                     static_cast<int>(rtcp_recv_key.size()),
+                     recv_extension_ids)) {
     SignalDtlsSrtpSetupFailure(this, /*rtcp=*/true);
     RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTCP failed";
   }
@@ -307,59 +291,22 @@
   SetDtlsTransport(rtcp_dtls_transport, &rtcp_dtls_transport_);
 }
 
-void DtlsSrtpTransport::UpdateWritableStateAndMaybeSetupDtlsSrtp() {
-  bool writable = IsDtlsWritable();
-  SetWritable(writable);
-  if (writable) {
-    MaybeSetupDtlsSrtp();
-  }
-}
-
-void DtlsSrtpTransport::SetWritable(bool writable) {
-  // Only fire the signal if the writable state changes.
-  if (writable_ != writable) {
-    writable_ = writable;
-    SignalWritableState(writable_);
-  }
-}
-
 void DtlsSrtpTransport::OnDtlsState(cricket::DtlsTransportInternal* transport,
                                     cricket::DtlsTransportState state) {
   RTC_DCHECK(transport == rtp_dtls_transport_ ||
              transport == rtcp_dtls_transport_);
 
   if (state != cricket::DTLS_TRANSPORT_CONNECTED) {
-    srtp_transport_->ResetParams();
+    ResetParams();
     return;
   }
 
   MaybeSetupDtlsSrtp();
 }
 
-void DtlsSrtpTransport::OnWritableState(bool writable) {
-  SetWritable(writable);
-  if (writable) {
-    MaybeSetupDtlsSrtp();
-  }
-}
-
-void DtlsSrtpTransport::OnSentPacket(const rtc::SentPacket& sent_packet) {
-  SignalSentPacket(sent_packet);
-}
-
-void DtlsSrtpTransport::OnPacketReceived(bool rtcp,
-                                         rtc::CopyOnWriteBuffer* packet,
-                                         const rtc::PacketTime& packet_time) {
-  SignalPacketReceived(rtcp, packet, packet_time);
-}
-
-void DtlsSrtpTransport::OnReadyToSend(bool ready) {
-  SignalReadyToSend(ready);
-}
-
-void DtlsSrtpTransport::OnNetworkRouteChanged(
-    rtc::Optional<rtc::NetworkRoute> network_route) {
-  SignalNetworkRouteChanged(network_route);
+void DtlsSrtpTransport::OnWritableState(
+    rtc::PacketTransportInternal* packet_transport) {
+  MaybeSetupDtlsSrtp();
 }
 
 }  // namespace webrtc
diff --git a/pc/dtlssrtptransport.h b/pc/dtlssrtptransport.h
index 889bd22..c24034a 100644
--- a/pc/dtlssrtptransport.h
+++ b/pc/dtlssrtptransport.h
@@ -16,20 +16,17 @@
 #include <vector>
 
 #include "p2p/base/dtlstransportinternal.h"
-#include "pc/rtptransportinternaladapter.h"
 #include "pc/srtptransport.h"
 #include "rtc_base/buffer.h"
 
 namespace webrtc {
 
-// This class is intended to be used as an RtpTransport and it wraps both an
-// SrtpTransport and DtlsTransports(RTP/RTCP). When the DTLS handshake is
-// finished, it extracts the keying materials from DtlsTransport and sets them
-// to SrtpTransport.
-class DtlsSrtpTransport : public RtpTransportInternalAdapter {
+// The subclass of SrtpTransport is used for DTLS-SRTP. When the DTLS handshake
+// is finished, it extracts the keying materials from DtlsTransport and
+// configures the SrtpSessions in the base class.
+class DtlsSrtpTransport : public SrtpTransport {
  public:
-  explicit DtlsSrtpTransport(
-      std::unique_ptr<webrtc::SrtpTransport> srtp_transport);
+  explicit DtlsSrtpTransport(bool rtcp_mux_enabled);
 
   // Set P2P layer RTP/RTCP DtlsTransports. When using RTCP-muxing,
   // |rtcp_dtls_transport| is null.
@@ -45,15 +42,6 @@
   void UpdateRecvEncryptedHeaderExtensionIds(
       const std::vector<int>& recv_extension_ids);
 
-  bool IsSrtpActive() const override { return srtp_transport_->IsSrtpActive(); }
-
-  // Cache RTP Absoulute SendTime extension header ID. This is only used when
-  // external authentication is enabled.
-  void CacheRtpAbsSendTimeHeaderExtension(int rtp_abs_sendtime_extn_id) {
-    srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(
-        rtp_abs_sendtime_extn_id);
-  }
-
   sigslot::signal2<DtlsSrtpTransport*, bool> SignalDtlsSrtpSetupFailure;
 
   RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override {
@@ -82,23 +70,13 @@
   void SetRtpDtlsTransport(cricket::DtlsTransportInternal* rtp_dtls_transport);
   void SetRtcpDtlsTransport(
       cricket::DtlsTransportInternal* rtcp_dtls_transport);
-  void UpdateWritableStateAndMaybeSetupDtlsSrtp();
-  // Set the writability and fire the SignalWritableState if the writability
-  // changes.
-  void SetWritable(bool writable);
 
   void OnDtlsState(cricket::DtlsTransportInternal* dtls_transport,
                    cricket::DtlsTransportState state);
-  void OnWritableState(bool writable);
-  void OnSentPacket(const rtc::SentPacket& sent_packet);
-  void OnPacketReceived(bool rtcp,
-                        rtc::CopyOnWriteBuffer* packet,
-                        const rtc::PacketTime& packet_time);
-  void OnReadyToSend(bool ready);
-  void OnNetworkRouteChanged(rtc::Optional<rtc::NetworkRoute> network_route);
 
-  bool writable_ = false;
-  std::unique_ptr<SrtpTransport> srtp_transport_;
+  // Override the SrtpTransport::OnWritableState.
+  void OnWritableState(rtc::PacketTransportInternal* packet_transport) override;
+
   // Owned by the TransportController.
   cricket::DtlsTransportInternal* rtp_dtls_transport_ = nullptr;
   cricket::DtlsTransportInternal* rtcp_dtls_transport_ = nullptr;
diff --git a/pc/dtlssrtptransport_unittest.cc b/pc/dtlssrtptransport_unittest.cc
index f0e4f28..37d517b 100644
--- a/pc/dtlssrtptransport_unittest.cc
+++ b/pc/dtlssrtptransport_unittest.cc
@@ -33,47 +33,26 @@
 
 const int kRtpAuthTagLen = 10;
 
-class TransportObserver : public sigslot::has_slots<> {
- public:
-  void OnPacketReceived(bool rtcp,
-                        rtc::CopyOnWriteBuffer* packet,
-                        const rtc::PacketTime& packet_time) {
-    rtcp ? last_recv_rtcp_packet_ = *packet : last_recv_rtp_packet_ = *packet;
-  }
-
-  void OnReadyToSend(bool ready) { ready_to_send_ = ready; }
-
-  rtc::CopyOnWriteBuffer last_recv_rtp_packet() {
-    return last_recv_rtp_packet_;
-  }
-
-  rtc::CopyOnWriteBuffer last_recv_rtcp_packet() {
-    return last_recv_rtcp_packet_;
-  }
-
-  bool ready_to_send() { return ready_to_send_; }
-
- private:
-  rtc::CopyOnWriteBuffer last_recv_rtp_packet_;
-  rtc::CopyOnWriteBuffer last_recv_rtcp_packet_;
-  bool ready_to_send_ = false;
-};
-
 class DtlsSrtpTransportTest : public testing::Test,
                               public sigslot::has_slots<> {
  protected:
   DtlsSrtpTransportTest() {}
 
+  ~DtlsSrtpTransportTest() {
+    if (dtls_srtp_transport1_) {
+      dtls_srtp_transport1_->UnregisterRtpDemuxerSink(&transport_observer1_);
+    }
+    if (dtls_srtp_transport2_) {
+      dtls_srtp_transport2_->UnregisterRtpDemuxerSink(&transport_observer2_);
+    }
+  }
+
   std::unique_ptr<DtlsSrtpTransport> MakeDtlsSrtpTransport(
       FakeDtlsTransport* rtp_dtls,
       FakeDtlsTransport* rtcp_dtls,
       bool rtcp_mux_enabled) {
-    auto rtp_transport = rtc::MakeUnique<RtpTransport>(rtcp_mux_enabled);
-
-    auto srtp_transport =
-        rtc::MakeUnique<SrtpTransport>(std::move(rtp_transport));
     auto dtls_srtp_transport =
-        rtc::MakeUnique<DtlsSrtpTransport>(std::move(srtp_transport));
+        rtc::MakeUnique<DtlsSrtpTransport>(rtcp_mux_enabled);
 
     dtls_srtp_transport->SetDtlsTransports(rtp_dtls, rtcp_dtls);
 
@@ -90,15 +69,24 @@
     dtls_srtp_transport2_ =
         MakeDtlsSrtpTransport(rtp_dtls2, rtcp_dtls2, rtcp_mux_enabled);
 
-    dtls_srtp_transport1_->SignalPacketReceived.connect(
-        &transport_observer1_, &TransportObserver::OnPacketReceived);
+    dtls_srtp_transport1_->SignalRtcpPacketReceived.connect(
+        &transport_observer1_,
+        &webrtc::TransportObserver::OnRtcpPacketReceived);
     dtls_srtp_transport1_->SignalReadyToSend.connect(
-        &transport_observer1_, &TransportObserver::OnReadyToSend);
+        &transport_observer1_, &webrtc::TransportObserver::OnReadyToSend);
 
-    dtls_srtp_transport2_->SignalPacketReceived.connect(
-        &transport_observer2_, &TransportObserver::OnPacketReceived);
+    dtls_srtp_transport2_->SignalRtcpPacketReceived.connect(
+        &transport_observer2_,
+        &webrtc::TransportObserver::OnRtcpPacketReceived);
     dtls_srtp_transport2_->SignalReadyToSend.connect(
-        &transport_observer2_, &TransportObserver::OnReadyToSend);
+        &transport_observer2_, &webrtc::TransportObserver::OnReadyToSend);
+    webrtc::RtpDemuxerCriteria demuxer_criteria;
+    // 0x00 is the payload type used in kPcmuFrame.
+    demuxer_criteria.payload_types = {0x00};
+    dtls_srtp_transport1_->RegisterRtpDemuxerSink(demuxer_criteria,
+                                                  &transport_observer1_);
+    dtls_srtp_transport2_->RegisterRtpDemuxerSink(demuxer_criteria,
+                                                  &transport_observer2_);
   }
 
   void CompleteDtlsHandshake(FakeDtlsTransport* fake_dtls1,
@@ -248,8 +236,8 @@
 
   std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport1_;
   std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport2_;
-  TransportObserver transport_observer1_;
-  TransportObserver transport_observer2_;
+  webrtc::TransportObserver transport_observer1_;
+  webrtc::TransportObserver transport_observer2_;
 
   int sequence_number_ = 0;
 };
diff --git a/pc/jseptransport2.cc b/pc/jseptransport.cc
similarity index 93%
rename from pc/jseptransport2.cc
rename to pc/jseptransport.cc
index a4a0348..ab785af 100644
--- a/pc/jseptransport2.cc
+++ b/pc/jseptransport.cc
@@ -8,7 +8,7 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "pc/jseptransport2.h"
+#include "pc/jseptransport.h"
 
 #include <memory>
 #include <utility>  // for std::pair
@@ -21,6 +21,7 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/ptr_util.h"
+#include "rtc_base/strings/string_builder.h"
 
 using webrtc::SdpType;
 
@@ -86,7 +87,7 @@
   return *this;
 }
 
-JsepTransport2::JsepTransport2(
+JsepTransport::JsepTransport(
     const std::string& mid,
     const rtc::scoped_refptr<rtc::RTCCertificate>& local_certificate,
     std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport,
@@ -115,9 +116,9 @@
   }
 }
 
-JsepTransport2::~JsepTransport2() {}
+JsepTransport::~JsepTransport() {}
 
-webrtc::RTCError JsepTransport2::SetLocalJsepTransportDescription(
+webrtc::RTCError JsepTransport::SetLocalJsepTransportDescription(
     const JsepTransportDescription& jsep_description,
     SdpType type) {
   webrtc::RTCError error;
@@ -195,7 +196,7 @@
   return webrtc::RTCError::OK();
 }
 
-webrtc::RTCError JsepTransport2::SetRemoteJsepTransportDescription(
+webrtc::RTCError JsepTransport::SetRemoteJsepTransportDescription(
     const JsepTransportDescription& jsep_description,
     webrtc::SdpType type) {
   webrtc::RTCError error;
@@ -251,7 +252,7 @@
   return webrtc::RTCError::OK();
 }
 
-webrtc::RTCError JsepTransport2::AddRemoteCandidates(
+webrtc::RTCError JsepTransport::AddRemoteCandidates(
     const Candidates& candidates) {
   if (!local_description_ || !remote_description_) {
     return webrtc::RTCError(webrtc::RTCErrorType::INVALID_STATE,
@@ -276,14 +277,14 @@
   return webrtc::RTCError::OK();
 }
 
-void JsepTransport2::SetNeedsIceRestartFlag() {
+void JsepTransport::SetNeedsIceRestartFlag() {
   if (!needs_ice_restart_) {
     needs_ice_restart_ = true;
     RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag set for transport " << mid();
   }
 }
 
-rtc::Optional<rtc::SSLRole> JsepTransport2::GetDtlsRole() const {
+rtc::Optional<rtc::SSLRole> JsepTransport::GetDtlsRole() const {
   RTC_DCHECK(rtp_dtls_transport_);
   rtc::SSLRole dtls_role;
   if (!rtp_dtls_transport_->GetDtlsRole(&dtls_role)) {
@@ -293,7 +294,7 @@
   return rtc::Optional<rtc::SSLRole>(dtls_role);
 }
 
-bool JsepTransport2::GetStats(TransportStats* stats) {
+bool JsepTransport::GetStats(TransportStats* stats) {
   stats->transport_name = mid();
   stats->channel_stats.clear();
   bool ret = GetTransportStats(rtp_dtls_transport_.get(), stats);
@@ -303,7 +304,7 @@
   return ret;
 }
 
-webrtc::RTCError JsepTransport2::VerifyCertificateFingerprint(
+webrtc::RTCError JsepTransport::VerifyCertificateFingerprint(
     const rtc::RTCCertificate* certificate,
     const rtc::SSLFingerprint* fingerprint) const {
   if (!fingerprint) {
@@ -320,22 +321,23 @@
   if (*fp_tmp == *fingerprint) {
     return webrtc::RTCError::OK();
   }
-  std::ostringstream desc;
+  char ss_buf[1024];
+  rtc::SimpleStringBuilder desc(ss_buf);
   desc << "Local fingerprint does not match identity. Expected: ";
   desc << fp_tmp->ToString();
   desc << " Got: " << fingerprint->ToString();
-  return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER, desc.str());
+  return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
+                          std::string(desc.str()));
 }
 
-void JsepTransport2::SetLocalIceParameters(
-    IceTransportInternal* ice_transport) {
+void JsepTransport::SetLocalIceParameters(IceTransportInternal* ice_transport) {
   RTC_DCHECK(ice_transport);
   RTC_DCHECK(local_description_);
   ice_transport->SetIceParameters(
       local_description_->transport_desc.GetIceParameters());
 }
 
-void JsepTransport2::SetRemoteIceParameters(
+void JsepTransport::SetRemoteIceParameters(
     IceTransportInternal* ice_transport) {
   RTC_DCHECK(ice_transport);
   RTC_DCHECK(remote_description_);
@@ -344,7 +346,7 @@
   ice_transport->SetRemoteIceMode(remote_description_->transport_desc.ice_mode);
 }
 
-webrtc::RTCError JsepTransport2::SetNegotiatedDtlsParameters(
+webrtc::RTCError JsepTransport::SetNegotiatedDtlsParameters(
     DtlsTransportInternal* dtls_transport,
     rtc::Optional<rtc::SSLRole> dtls_role,
     rtc::SSLFingerprint* remote_fingerprint) {
@@ -367,9 +369,9 @@
   return webrtc::RTCError::OK();
 }
 
-bool JsepTransport2::SetRtcpMux(bool enable,
-                                webrtc::SdpType type,
-                                ContentSource source) {
+bool JsepTransport::SetRtcpMux(bool enable,
+                               webrtc::SdpType type,
+                               ContentSource source) {
   bool ret = false;
   switch (type) {
     case SdpType::kOffer:
@@ -399,7 +401,7 @@
   return ret;
 }
 
-void JsepTransport2::ActivateRtcpMux() {
+void JsepTransport::ActivateRtcpMux() {
   if (unencrypted_rtp_transport_) {
     RTC_DCHECK(!sdes_transport_);
     RTC_DCHECK(!dtls_srtp_transport_);
@@ -420,10 +422,10 @@
   SignalRtcpMuxActive();
 }
 
-bool JsepTransport2::SetSdes(const std::vector<CryptoParams>& cryptos,
-                             const std::vector<int>& encrypted_extension_ids,
-                             webrtc::SdpType type,
-                             ContentSource source) {
+bool JsepTransport::SetSdes(const std::vector<CryptoParams>& cryptos,
+                            const std::vector<int>& encrypted_extension_ids,
+                            webrtc::SdpType type,
+                            ContentSource source) {
   bool ret = false;
   ret = sdes_negotiator_.Process(cryptos, type, source);
   if (!ret) {
@@ -464,7 +466,7 @@
   return ret;
 }
 
-webrtc::RTCError JsepTransport2::NegotiateAndSetDtlsParameters(
+webrtc::RTCError JsepTransport::NegotiateAndSetDtlsParameters(
     SdpType local_description_type) {
   if (!local_description_ || !remote_description_) {
     return webrtc::RTCError(webrtc::RTCErrorType::INVALID_STATE,
@@ -516,7 +518,7 @@
   return error;
 }
 
-webrtc::RTCError JsepTransport2::NegotiateDtlsRole(
+webrtc::RTCError JsepTransport::NegotiateDtlsRole(
     SdpType local_description_type,
     ConnectionRole local_connection_role,
     ConnectionRole remote_connection_role,
@@ -604,8 +606,8 @@
   return webrtc::RTCError::OK();
 }
 
-bool JsepTransport2::GetTransportStats(DtlsTransportInternal* dtls_transport,
-                                       TransportStats* stats) {
+bool JsepTransport::GetTransportStats(DtlsTransportInternal* dtls_transport,
+                                      TransportStats* stats) {
   RTC_DCHECK(dtls_transport);
   TransportChannelStats substats;
   substats.component = dtls_transport == rtcp_dtls_transport_.get()
diff --git a/pc/jseptransport2.h b/pc/jseptransport.h
similarity index 96%
rename from pc/jseptransport2.h
rename to pc/jseptransport.h
index 8656cf5..290ac4a 100644
--- a/pc/jseptransport2.h
+++ b/pc/jseptransport.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef PC_JSEPTRANSPORT2_H_
-#define PC_JSEPTRANSPORT2_H_
+#ifndef PC_JSEPTRANSPORT_H_
+#define PC_JSEPTRANSPORT_H_
 
 #include <map>
 #include <memory>
@@ -68,14 +68,14 @@
 // JSEP. Each transport consists of DTLS and ICE transport channels for RTP
 // (and possibly RTCP, if rtcp-mux isn't used).
 //
-// On Threading:  JsepTransport performs work solely on the network thread, and
+// On Threading: JsepTransport performs work solely on the network thread, and
 // so its methods should only be called on the network thread.
-class JsepTransport2 : public sigslot::has_slots<> {
+class JsepTransport : public sigslot::has_slots<> {
  public:
   // |mid| is just used for log statements in order to identify the Transport.
   // Note that |local_certificate| is allowed to be null since a remote
   // description may be set before a local certificate is generated.
-  JsepTransport2(
+  JsepTransport(
       const std::string& mid,
       const rtc::scoped_refptr<rtc::RTCCertificate>& local_certificate,
       std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport,
@@ -84,7 +84,7 @@
       std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport,
       std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport);
 
-  ~JsepTransport2() override;
+  ~JsepTransport() override;
 
   // Returns the MID of this transport. This is only used for logging.
   const std::string& mid() const { return mid_; }
@@ -239,9 +239,9 @@
   rtc::Optional<std::vector<int>> send_extension_ids_;
   rtc::Optional<std::vector<int>> recv_extension_ids_;
 
-  RTC_DISALLOW_COPY_AND_ASSIGN(JsepTransport2);
+  RTC_DISALLOW_COPY_AND_ASSIGN(JsepTransport);
 };
 
 }  // namespace cricket
 
-#endif  // PC_JSEPTRANSPORT2_H_
+#endif  // PC_JSEPTRANSPORT_H_
diff --git a/pc/jseptransport2_unittest.cc b/pc/jseptransport_unittest.cc
similarity index 97%
rename from pc/jseptransport2_unittest.cc
rename to pc/jseptransport_unittest.cc
index 2f015cdc..f6f3e1e 100644
--- a/pc/jseptransport2_unittest.cc
+++ b/pc/jseptransport_unittest.cc
@@ -15,7 +15,7 @@
 #include "media/base/fakertp.h"
 #include "p2p/base/fakedtlstransport.h"
 #include "p2p/base/fakeicetransport.h"
-#include "pc/jseptransport2.h"
+#include "pc/jseptransport.h"
 #include "rtc_base/gunit.h"
 
 namespace cricket {
@@ -44,9 +44,8 @@
   std::unique_ptr<webrtc::SrtpTransport> CreateSdesTransport(
       rtc::PacketTransportInternal* rtp_packet_transport,
       rtc::PacketTransportInternal* rtcp_packet_transport) {
-    bool rtcp_mux_enabled = (rtcp_packet_transport == nullptr);
-    auto srtp_transport =
-        rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_mux_enabled);
+    auto srtp_transport = rtc::MakeUnique<webrtc::SrtpTransport>(
+        rtcp_packet_transport == nullptr);
 
     srtp_transport->SetRtpPacketTransport(rtp_packet_transport);
     if (rtcp_packet_transport) {
@@ -58,21 +57,17 @@
   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));
-
+    auto dtls_srtp_transport = rtc::MakeUnique<webrtc::DtlsSrtpTransport>(
+        rtcp_dtls_transport == nullptr);
     dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
                                            rtcp_dtls_transport);
     return dtls_srtp_transport;
   }
 
-  // Create a new JsepTransport2 with a FakeDtlsTransport and a
+  // Create a new JsepTransport with a FakeDtlsTransport and a
   // FakeIceTransport.
-  std::unique_ptr<JsepTransport2> CreateJsepTransport2(bool rtcp_mux_enabled,
-                                                       SrtpMode srtp_mode) {
+  std::unique_ptr<JsepTransport> CreateJsepTransport2(bool rtcp_mux_enabled,
+                                                      SrtpMode srtp_mode) {
     auto ice = rtc::MakeUnique<FakeIceTransport>(kTransportName,
                                                  ICE_CANDIDATE_COMPONENT_RTP);
     auto rtp_dtls_transport =
@@ -102,7 +97,7 @@
         RTC_NOTREACHED();
     }
 
-    auto jsep_transport = rtc::MakeUnique<JsepTransport2>(
+    auto jsep_transport = rtc::MakeUnique<JsepTransport>(
         kTransportName, /*local_certificate=*/nullptr,
         std::move(unencrypted_rtp_transport), std::move(sdes_transport),
         std::move(dtls_srtp_transport), std::move(rtp_dtls_transport),
@@ -144,7 +139,7 @@
 
   void OnRtcpMuxActive() { signal_rtcp_mux_active_received_ = true; }
 
-  std::unique_ptr<JsepTransport2> jsep_transport_;
+  std::unique_ptr<JsepTransport> jsep_transport_;
   bool signal_rtcp_mux_active_received_ = false;
   // The SrtpTransport is owned by |jsep_transport_|. Keep a raw pointer here
   // for testing.
@@ -1096,7 +1091,7 @@
   }
 
   void TestOneWaySendRecvPacketWithEncryptedHeaderExtension(
-      JsepTransport2* sender_transport) {
+      JsepTransport* sender_transport) {
     size_t rtp_len = sizeof(kPcmuFrameWithExtensions);
     size_t packet_size = rtp_len + GetRtpAuthLen();
     rtc::Buffer rtp_packet_buffer(packet_size);
@@ -1119,8 +1114,8 @@
 
   int sequence_number_ = 0;
   int received_packet_count_ = 0;
-  std::unique_ptr<JsepTransport2> jsep_transport1_;
-  std::unique_ptr<JsepTransport2> jsep_transport2_;
+  std::unique_ptr<JsepTransport> jsep_transport1_;
+  std::unique_ptr<JsepTransport> jsep_transport2_;
   std::vector<int> recv_encrypted_headers1_;
   std::vector<int> recv_encrypted_headers2_;
 };
diff --git a/pc/jseptransportcontroller.cc b/pc/jseptransportcontroller.cc
index b5ce5fe..b8234fa 100644
--- a/pc/jseptransportcontroller.cc
+++ b/pc/jseptransportcontroller.cc
@@ -94,7 +94,10 @@
     : signaling_thread_(signaling_thread),
       network_thread_(network_thread),
       port_allocator_(port_allocator),
-      config_(config) {}
+      config_(config) {
+  // The |transport_observer| is assumed to be non-null.
+  RTC_DCHECK(config_.transport_observer);
+}
 
 JsepTransportController::~JsepTransportController() {
   // Channel destructors may try to send packets, so this needs to happen on
@@ -181,7 +184,7 @@
 
 bool JsepTransportController::NeedsIceRestart(
     const std::string& transport_name) const {
-  const cricket::JsepTransport2* transport =
+  const cricket::JsepTransport* transport =
       GetJsepTransportByName(transport_name);
   if (!transport) {
     return false;
@@ -196,7 +199,7 @@
         RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
   }
 
-  const cricket::JsepTransport2* t = GetJsepTransportForMid(mid);
+  const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
   if (!t) {
     return rtc::Optional<rtc::SSLRole>();
   }
@@ -237,7 +240,7 @@
         RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
   }
 
-  const cricket::JsepTransport2* t = GetJsepTransportByName(transport_name);
+  const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
   if (!t) {
     return nullptr;
   }
@@ -329,7 +332,7 @@
   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 =
+    cricket::JsepTransport* jsep_transport =
         GetJsepTransportByName(transport_name);
     if (!jsep_transport) {
       RTC_LOG(LS_WARNING)
@@ -355,7 +358,7 @@
         RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
   }
 
-  cricket::JsepTransport2* transport = GetJsepTransportByName(transport_name);
+  cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
   if (!transport) {
     return false;
   }
@@ -467,15 +470,12 @@
     cricket::DtlsTransportInternal* rtp_dtls_transport,
     cricket::DtlsTransportInternal* rtcp_dtls_transport) {
   RTC_DCHECK(network_thread_->IsCurrent());
-  auto srtp_transport =
-      rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
+  auto dtls_srtp_transport = rtc::MakeUnique<webrtc::DtlsSrtpTransport>(
+      rtcp_dtls_transport == nullptr);
   if (config_.enable_external_auth) {
-    srtp_transport->EnableExternalAuth();
+    dtls_srtp_transport->EnableExternalAuth();
   }
 
-  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;
@@ -574,12 +574,18 @@
     const cricket::TransportInfo& transport_info =
         description->transport_infos()[i];
     if (content_info.rejected) {
-      HandleRejectedContent(content_info, description);
+      if (!HandleRejectedContent(content_info, description)) {
+        return RTCError(RTCErrorType::INVALID_PARAMETER,
+                        "Failed to process the rejected m= section.");
+      }
       continue;
     }
 
     if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
-      HandleBundledContent(content_info);
+      if (!HandleBundledContent(content_info)) {
+        return RTCError(RTCErrorType::INVALID_PARAMETER,
+                        "Failed to process the bundled m= section.");
+      }
       continue;
     }
 
@@ -598,7 +604,7 @@
     int rtp_abs_sendtime_extn_id =
         GetRtpAbsSendTimeHeaderExtensionId(content_info);
 
-    cricket::JsepTransport2* transport =
+    cricket::JsepTransport* transport =
         GetJsepTransportForMid(content_info.name);
     RTC_DCHECK(transport);
 
@@ -736,21 +742,20 @@
   return RTCError::OK();
 }
 
-void JsepTransportController::HandleRejectedContent(
+bool JsepTransportController::HandleRejectedContent(
     const cricket::ContentInfo& content_info,
     const cricket::SessionDescription* description) {
+  bool ret = true;
   // If the content is rejected, let the
   // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
-  // then destroy the cricket::JsepTransport2.
-  RemoveTransportForMid(content_info.name, content_info.type);
-  // If the answerer rejects the first content, which other contents are bundled
-  // on, all the other contents in the bundle group will be rejected.
+  // then destroy the cricket::JsepTransport.
+  ret = RemoveTransportForMid(content_info.name, content_info.type);
   if (content_info.name == bundled_mid()) {
     for (auto content_name : bundle_group_->content_names()) {
       const cricket::ContentInfo* content_in_group =
           description->GetContentByName(content_name);
       RTC_DCHECK(content_in_group);
-      RemoveTransportForMid(content_name, content_in_group->type);
+      ret = ret && RemoveTransportForMid(content_name, content_in_group->type);
     }
     bundle_group_.reset();
   } else if (IsBundled(content_info.name)) {
@@ -761,45 +766,60 @@
       bundle_group_.reset();
     }
   }
-  MaybeDestroyJsepTransport(content_info.name);
+  if (ret) {
+    MaybeDestroyJsepTransport(content_info.name);
+  }
+  return ret;
 }
 
-void JsepTransportController::HandleBundledContent(
+bool JsepTransportController::HandleBundledContent(
     const cricket::ContentInfo& content_info) {
   auto jsep_transport = GetJsepTransportByName(*bundled_mid());
   RTC_DCHECK(jsep_transport);
   // If the content is bundled, let the
   // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
-  // then destroy the cricket::JsepTransport2.
-  SetTransportForMid(content_info.name, jsep_transport, content_info.type);
-  MaybeDestroyJsepTransport(content_info.name);
+  // then destroy the cricket::JsepTransport.
+  if (SetTransportForMid(content_info.name, jsep_transport,
+                         content_info.type)) {
+    MaybeDestroyJsepTransport(content_info.name);
+    return true;
+  }
+  return false;
 }
 
-void JsepTransportController::SetTransportForMid(
+bool JsepTransportController::SetTransportForMid(
     const std::string& mid,
-    cricket::JsepTransport2* jsep_transport,
+    cricket::JsepTransport* jsep_transport,
     cricket::MediaProtocolType protocol_type) {
+  RTC_DCHECK(jsep_transport);
   if (mid_to_transport_[mid] == jsep_transport) {
-    return;
+    return true;
   }
 
+  bool ret = true;
   mid_to_transport_[mid] = jsep_transport;
   if (protocol_type == cricket::MediaProtocolType::kRtp) {
-    SignalRtpTransportChanged(mid, jsep_transport->rtp_transport());
+    ret = config_.transport_observer->OnRtpTransportChanged(
+        mid, jsep_transport->rtp_transport());
   } else {
-    SignalDtlsTransportChanged(mid, jsep_transport->rtp_dtls_transport());
+    config_.transport_observer->OnDtlsTransportChanged(
+        mid, jsep_transport->rtp_dtls_transport());
   }
+  return ret;
 }
 
-void JsepTransportController::RemoveTransportForMid(
+bool JsepTransportController::RemoveTransportForMid(
     const std::string& mid,
     cricket::MediaProtocolType protocol_type) {
+  bool ret = true;
   if (protocol_type == cricket::MediaProtocolType::kRtp) {
-    SignalRtpTransportChanged(mid, nullptr);
+    ret = config_.transport_observer->OnRtpTransportChanged(mid, nullptr);
+    RTC_DCHECK(ret);
   } else {
-    SignalDtlsTransportChanged(mid, nullptr);
+    config_.transport_observer->OnDtlsTransportChanged(mid, nullptr);
   }
   mid_to_transport_.erase(mid);
+  return ret;
 }
 
 cricket::JsepTransportDescription
@@ -905,25 +925,25 @@
   return send_time_extension ? send_time_extension->id : -1;
 }
 
-const cricket::JsepTransport2* JsepTransportController::GetJsepTransportForMid(
+const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
     const std::string& mid) const {
   auto it = mid_to_transport_.find(mid);
   return it == mid_to_transport_.end() ? nullptr : it->second;
 }
 
-cricket::JsepTransport2* JsepTransportController::GetJsepTransportForMid(
+cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
     const std::string& mid) {
   auto it = mid_to_transport_.find(mid);
   return it == mid_to_transport_.end() ? nullptr : it->second;
 }
 
-const cricket::JsepTransport2* JsepTransportController::GetJsepTransportByName(
+const cricket::JsepTransport* 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(
+cricket::JsepTransport* 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();
@@ -932,8 +952,7 @@
 RTCError JsepTransportController::MaybeCreateJsepTransport(
     const cricket::ContentInfo& content_info) {
   RTC_DCHECK(network_thread_->IsCurrent());
-  cricket::JsepTransport2* transport =
-      GetJsepTransportByName(content_info.name);
+  cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
   if (transport) {
     return RTCError::OK();
   }
@@ -970,8 +989,8 @@
         content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
   }
 
-  std::unique_ptr<cricket::JsepTransport2> jsep_transport =
-      rtc::MakeUnique<cricket::JsepTransport2>(
+  std::unique_ptr<cricket::JsepTransport> jsep_transport =
+      rtc::MakeUnique<cricket::JsepTransport>(
           content_info.name, certificate_, std::move(unencrypted_rtp_transport),
           std::move(sdes_transport), std::move(dtls_srtp_transport),
           std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport));
@@ -1018,7 +1037,7 @@
 }
 
 cricket::IceRole JsepTransportController::DetermineIceRole(
-    cricket::JsepTransport2* jsep_transport,
+    cricket::JsepTransport* jsep_transport,
     const cricket::TransportInfo& transport_info,
     SdpType type,
     bool local) {
diff --git a/pc/jseptransportcontroller.h b/pc/jseptransportcontroller.h
index 6e44534..c3c7919 100644
--- a/pc/jseptransportcontroller.h
+++ b/pc/jseptransportcontroller.h
@@ -25,7 +25,7 @@
 #include "p2p/base/transportfactoryinterface.h"
 #include "pc/channel.h"
 #include "pc/dtlssrtptransport.h"
-#include "pc/jseptransport2.h"
+#include "pc/jseptransport.h"
 #include "pc/rtptransport.h"
 #include "pc/srtptransport.h"
 #include "rtc_base/asyncinvoker.h"
@@ -44,6 +44,23 @@
 class JsepTransportController : public sigslot::has_slots<>,
                                 public rtc::MessageHandler {
  public:
+  // Used when the RtpTransport/DtlsTransport of the m= section is changed
+  // because the section is rejected or BUNDLE is enabled.
+  class Observer {
+   public:
+    virtual ~Observer() {}
+
+    // Returns true if media associated with |mid| was successfully set up to be
+    // demultiplexed on |rtp_transport|. Could return false if two bundled m=
+    // sections use the same SSRC, for example.
+    virtual bool OnRtpTransportChanged(const std::string& mid,
+                                       RtpTransportInternal* rtp_transport) = 0;
+
+    virtual void OnDtlsTransportChanged(
+        const std::string& mid,
+        cricket::DtlsTransportInternal* dtls_transport) = 0;
+  };
+
   struct Config {
     // If |redetermine_role_on_ice_restart| is true, ICE role is redetermined
     // upon setting a local transport description that indicates an ICE
@@ -61,6 +78,7 @@
     bool enable_external_auth = false;
     // Used to inject the ICE/DTLS transports created externally.
     cricket::TransportFactoryInterface* external_transport_factory = nullptr;
+    Observer* transport_observer = nullptr;
   };
 
   // The ICE related events are signaled on the |signaling_thread|.
@@ -136,6 +154,7 @@
   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,
@@ -158,19 +177,6 @@
 
   sigslot::signal1<rtc::SSLHandshakeError> SignalDtlsHandshakeError;
 
-  // This will be fired when BUNDLE is enabled, the PeerConnection will handle
-  // the signal and set the RtpTransport for the BaseChannel.
-  // The first argument is the MID and the second is the new RtpTransport.
-  // Before firing this signal, the previous RtpTransport must no longer be
-  // referenced.
-  sigslot::signal2<const std::string&, RtpTransportInternal*>
-      SignalRtpTransportChanged;
-
-  // SCTP version of the signal above. PeerConnection will set a new
-  // DtlsTransport for the SctpTransport.
-  sigslot::signal2<const std::string&, cricket::DtlsTransportInternal*>
-      SignalDtlsTransportChanged;
-
  private:
   void OnMessage(rtc::Message* pmsg) override;
 
@@ -183,14 +189,14 @@
       const cricket::SessionDescription* description);
   RTCError ValidateContent(const cricket::ContentInfo& content_info);
 
-  void HandleRejectedContent(const cricket::ContentInfo& content_info,
+  bool HandleRejectedContent(const cricket::ContentInfo& content_info,
                              const cricket::SessionDescription* description);
-  void HandleBundledContent(const cricket::ContentInfo& content_info);
+  bool HandleBundledContent(const cricket::ContentInfo& content_info);
 
-  void SetTransportForMid(const std::string& mid,
-                          cricket::JsepTransport2* jsep_transport,
+  bool SetTransportForMid(const std::string& mid,
+                          cricket::JsepTransport* jsep_transport,
                           cricket::MediaProtocolType protocol_type);
-  void RemoveTransportForMid(const std::string& mid,
+  bool RemoveTransportForMid(const std::string& mid,
                              cricket::MediaProtocolType protocol_type);
 
   cricket::JsepTransportDescription CreateJsepTransportDescription(
@@ -226,15 +232,15 @@
   // 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 cricket::JsepTransport* GetJsepTransportForMid(
       const std::string& mid) const;
-  cricket::JsepTransport2* GetJsepTransportForMid(const std::string& mid);
+  cricket::JsepTransport* 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 cricket::JsepTransport* GetJsepTransportByName(
       const std::string& transport_name) const;
-  cricket::JsepTransport2* GetJsepTransportByName(
+  cricket::JsepTransport* GetJsepTransportByName(
       const std::string& transport_name);
 
   RTCError MaybeCreateJsepTransport(const cricket::ContentInfo& content_info);
@@ -244,7 +250,7 @@
   void SetIceRole_n(cricket::IceRole ice_role);
 
   cricket::IceRole DetermineIceRole(
-      cricket::JsepTransport2* jsep_transport,
+      cricket::JsepTransport* jsep_transport,
       const cricket::TransportInfo& transport_info,
       SdpType type,
       bool local);
@@ -291,11 +297,11 @@
   rtc::Thread* const network_thread_ = nullptr;
   cricket::PortAllocator* const port_allocator_ = nullptr;
 
-  std::map<std::string, std::unique_ptr<cricket::JsepTransport2>>
+  std::map<std::string, std::unique_ptr<cricket::JsepTransport>>
       jsep_transports_by_name_;
   // This keeps track of the mapping between media section
-  // (BaseChannel/SctpTransport) and the JsepTransport2 underneath.
-  std::map<std::string, cricket::JsepTransport2*> mid_to_transport_;
+  // (BaseChannel/SctpTransport) and the JsepTransport underneath.
+  std::map<std::string, cricket::JsepTransport*> mid_to_transport_;
 
   // Aggregate state for Transports.
   cricket::IceConnectionState ice_connection_state_ =
diff --git a/pc/jseptransportcontroller_unittest.cc b/pc/jseptransportcontroller_unittest.cc
index 16a829f..b8ec316 100644
--- a/pc/jseptransportcontroller_unittest.cc
+++ b/pc/jseptransportcontroller_unittest.cc
@@ -59,7 +59,8 @@
   }
 };
 
-class JsepTransportControllerTest : public testing::Test,
+class JsepTransportControllerTest : public JsepTransportController::Observer,
+                                    public testing::Test,
                                     public sigslot::has_slots<> {
  public:
   JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
@@ -71,6 +72,7 @@
       rtc::Thread* signaling_thread = rtc::Thread::Current(),
       rtc::Thread* network_thread = rtc::Thread::Current(),
       cricket::PortAllocator* port_allocator = nullptr) {
+    config.transport_observer = this;
     // The tests only works with |fake_transport_factory|;
     config.external_transport_factory = fake_transport_factory_.get();
     transport_controller_ = rtc::MakeUnique<JsepTransportController>(
@@ -85,10 +87,6 @@
         this, &JsepTransportControllerTest::OnGatheringState);
     transport_controller_->SignalIceCandidatesGathered.connect(
         this, &JsepTransportControllerTest::OnCandidatesGathered);
-    transport_controller_->SignalRtpTransportChanged.connect(
-        this, &JsepTransportControllerTest::OnRtpTransportChanged);
-    transport_controller_->SignalDtlsTransportChanged.connect(
-        this, &JsepTransportControllerTest::OnDtlsTransportChanged);
   }
 
   std::unique_ptr<cricket::SessionDescription>
@@ -262,13 +260,16 @@
     ++candidates_signal_count_;
   }
 
-  void OnRtpTransportChanged(const std::string& mid,
-                             RtpTransportInternal* rtp_transport) {
+  // JsepTransportController::Observer overrides.
+  bool OnRtpTransportChanged(const std::string& mid,
+                             RtpTransportInternal* rtp_transport) override {
     changed_rtp_transport_by_mid_[mid] = rtp_transport;
+    return true;
   }
 
-  void OnDtlsTransportChanged(const std::string& mid,
-                              cricket::DtlsTransportInternal* dtls_transport) {
+  void OnDtlsTransportChanged(
+      const std::string& mid,
+      cricket::DtlsTransportInternal* dtls_transport) override {
     changed_dtls_transport_by_mid_[mid] = dtls_transport;
   }
 
diff --git a/pc/mediasession.h b/pc/mediasession.h
index 5b94539..997a469 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/jseptransport2.h"
+#include "pc/jseptransport.h"
 #include "pc/sessiondescription.h"
 
 namespace cricket {
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 2721063..c7dc73b 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -932,6 +932,7 @@
   config.bundle_policy = configuration.bundle_policy;
   config.rtcp_mux_policy = configuration.rtcp_mux_policy;
   config.crypto_options = options.crypto_options;
+  config.transport_observer = this;
 #if defined(ENABLE_EXTERNAL_AUTH)
   config.enable_external_auth = true;
 #endif
@@ -947,10 +948,6 @@
       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();
 
@@ -5430,9 +5427,6 @@
   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_);
   }
@@ -5458,9 +5452,6 @@
   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_);
   }
@@ -5500,9 +5491,6 @@
     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_);
     }
@@ -6100,7 +6088,6 @@
 
 void PeerConnection::DestroyBaseChannel(cricket::BaseChannel* channel) {
   RTC_DCHECK(channel);
-
   switch (channel->media_type()) {
     case cricket::MEDIA_TYPE_AUDIO:
       channel_manager()->DestroyVoiceChannel(
@@ -6120,13 +6107,14 @@
   }
 }
 
-void PeerConnection::OnRtpTransportChanged(
+bool PeerConnection::OnRtpTransportChanged(
     const std::string& mid,
     RtpTransportInternal* rtp_transport) {
   auto base_channel = GetChannel(mid);
   if (base_channel) {
-    base_channel->SetRtpTransport(rtp_transport);
+    return base_channel->SetRtpTransport(rtp_transport);
   }
+  return true;
 }
 
 void PeerConnection::OnDtlsTransportChanged(
diff --git a/pc/peerconnection.h b/pc/peerconnection.h
index fa46a4e..c019ef9 100644
--- a/pc/peerconnection.h
+++ b/pc/peerconnection.h
@@ -51,6 +51,7 @@
 // - Generating stats.
 class PeerConnection : public PeerConnectionInternal,
                        public DataChannelProviderInterface,
+                       public JsepTransportController::Observer,
                        public rtc::MessageHandler,
                        public sigslot::has_slots<> {
  public:
@@ -877,11 +878,13 @@
   // method is called.
   void DestroyBaseChannel(cricket::BaseChannel* channel);
 
-  void OnRtpTransportChanged(const std::string& mid,
-                             RtpTransportInternal* rtp_transport);
+  // JsepTransportController::Observer override.
+  bool OnRtpTransportChanged(const std::string& mid,
+                             RtpTransportInternal* rtp_transport) override;
 
-  void OnDtlsTransportChanged(const std::string& mid,
-                              cricket::DtlsTransportInternal* dtls_transport);
+  void OnDtlsTransportChanged(
+      const std::string& mid,
+      cricket::DtlsTransportInternal* dtls_transport) override;
 
   sigslot::signal1<DataChannel*> SignalDataChannelCreated_;
 
diff --git a/pc/peerconnection_bundle_unittest.cc b/pc/peerconnection_bundle_unittest.cc
index a1b69d8..dfd47cd 100644
--- a/pc/peerconnection_bundle_unittest.cc
+++ b/pc/peerconnection_bundle_unittest.cc
@@ -666,6 +666,42 @@
   EXPECT_EQ(caller->voice_rtp_transport(), caller->video_rtp_transport());
 }
 
+// This tests that applying description with conflicted RTP demuxing criteria
+// will fail.
+TEST_P(PeerConnectionBundleTest,
+       ApplyDescriptionWithConflictedDemuxCriteriaFail) {
+  auto caller = CreatePeerConnectionWithAudioVideo();
+  auto callee = CreatePeerConnectionWithAudioVideo();
+
+  RTCOfferAnswerOptions options;
+  options.use_rtp_mux = false;
+  auto offer = caller->CreateOffer(options);
+  // Modified the SDP to make two m= sections have the same SSRC.
+  ASSERT_GE(offer->description()->contents().size(), 2U);
+  offer->description()
+      ->contents()[0]
+      .description->mutable_streams()[0]
+      .ssrcs[0] = 1111222;
+  offer->description()
+      ->contents()[1]
+      .description->mutable_streams()[0]
+      .ssrcs[0] = 1111222;
+  EXPECT_TRUE(
+      caller->SetLocalDescription(CloneSessionDescription(offer.get())));
+  EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer)));
+  EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal(options));
+
+  // Enable BUNDLE in subsequent offer/answer exchange and two m= sections are
+  // expectd to use one RtpTransport underneath.
+  options.use_rtp_mux = true;
+  EXPECT_TRUE(
+      callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
+  auto answer = callee->CreateAnswer(options);
+  // When BUNDLE is enabled, applying the description is expected to fail
+  // because the demuxing criteria is conflicted.
+  EXPECT_FALSE(callee->SetLocalDescription(std::move(answer)));
+}
+
 // This tests that changing the pre-negotiated BUNDLE tag is not supported.
 TEST_P(PeerConnectionBundleTest, RejectDescriptionChangingBundleTag) {
   RTCConfiguration config;
diff --git a/pc/peerconnection_integrationtest.cc b/pc/peerconnection_integrationtest.cc
index 7379c71..583765d 100644
--- a/pc/peerconnection_integrationtest.cc
+++ b/pc/peerconnection_integrationtest.cc
@@ -2273,6 +2273,8 @@
 
 // Test that if two video tracks are sent (from caller to callee, in this test),
 // they're transmitted correctly end-to-end.
+// TODO(zhihuang): Enable this test in Unified Plan mode once the MID-based
+// demuxing is ready.
 TEST_P(PeerConnectionIntegrationTest, EndToEndCallWithTwoVideoTracks) {
   ASSERT_TRUE(CreatePeerConnectionWrappers());
   ConnectFakeSignaling();
@@ -2395,7 +2397,6 @@
 TEST_P(PeerConnectionIntegrationTest, GetBytesSentStatsWithOldStatsApi) {
   ASSERT_TRUE(CreatePeerConnectionWrappers());
   ConnectFakeSignaling();
-  caller()->AddAudioVideoTracks();
   auto audio_track = caller()->CreateLocalAudioTrack();
   auto video_track = caller()->CreateLocalVideoTrack();
   caller()->AddTrack(audio_track);
diff --git a/pc/peerconnection_media_unittest.cc b/pc/peerconnection_media_unittest.cc
index 228243c..f59d6aa 100644
--- a/pc/peerconnection_media_unittest.cc
+++ b/pc/peerconnection_media_unittest.cc
@@ -967,8 +967,8 @@
 
 // Tests that an answer responds with the same MIDs as the offer.
 TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
-  const std::string kAudioMid = "not default1";
-  const std::string kVideoMid = "not default2";
+  const std::string kAudioMid = "notdefault1";
+  const std::string kVideoMid = "notdefault2";
 
   auto caller = CreatePeerConnectionWithAudioVideo();
   auto callee = CreatePeerConnectionWithAudioVideo();
@@ -988,8 +988,8 @@
 // Test that if the callee creates a re-offer, the MIDs are the same as the
 // original offer.
 TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
-  const std::string kAudioMid = "not default1";
-  const std::string kVideoMid = "not default2";
+  const std::string kAudioMid = "notdefault1";
+  const std::string kVideoMid = "notdefault2";
 
   auto caller = CreatePeerConnectionWithAudioVideo();
   auto callee = CreatePeerConnectionWithAudioVideo();
diff --git a/pc/rtpsenderreceiver_unittest.cc b/pc/rtpsenderreceiver_unittest.cc
index 69089a5..d9b543b 100644
--- a/pc/rtpsenderreceiver_unittest.cc
+++ b/pc/rtpsenderreceiver_unittest.cc
@@ -113,12 +113,8 @@
   }
 
   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));
+        rtc::MakeUnique<webrtc::DtlsSrtpTransport>(/*rtcp_mux_required=*/true);
     dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport_.get(),
                                            /*rtcp_dtls_transport=*/nullptr);
     return dtls_srtp_transport;
diff --git a/pc/rtptransport.cc b/pc/rtptransport.cc
index ce6996c..366d6e2 100644
--- a/pc/rtptransport.cc
+++ b/pc/rtptransport.cc
@@ -10,7 +10,10 @@
 
 #include "pc/rtptransport.h"
 
+#include <utility>
+
 #include "media/base/rtputils.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
 #include "p2p/base/p2pconstants.h"
 #include "p2p/base/packettransportinterface.h"
 #include "rtc_base/checks.h"
@@ -44,7 +47,7 @@
     new_packet_transport->SignalReadPacket.connect(this,
                                                    &RtpTransport::OnReadPacket);
     new_packet_transport->SignalNetworkRouteChanged.connect(
-        this, &RtpTransport::OnNetworkRouteChange);
+        this, &RtpTransport::OnNetworkRouteChanged);
     new_packet_transport->SignalWritableState.connect(
         this, &RtpTransport::OnWritableState);
     new_packet_transport->SignalSentPacket.connect(this,
@@ -80,7 +83,7 @@
     new_packet_transport->SignalReadPacket.connect(this,
                                                    &RtpTransport::OnReadPacket);
     new_packet_transport->SignalNetworkRouteChanged.connect(
-        this, &RtpTransport::OnNetworkRouteChange);
+        this, &RtpTransport::OnNetworkRouteChanged);
     new_packet_transport->SignalWritableState.connect(
         this, &RtpTransport::OnWritableState);
     new_packet_transport->SignalSentPacket.connect(this,
@@ -134,6 +137,29 @@
   return true;
 }
 
+void RtpTransport::UpdateRtpHeaderExtensionMap(
+    const cricket::RtpHeaderExtensions& header_extensions) {
+  header_extension_map_ = RtpHeaderExtensionMap(header_extensions);
+}
+
+bool RtpTransport::RegisterRtpDemuxerSink(const RtpDemuxerCriteria& criteria,
+                                          RtpPacketSinkInterface* sink) {
+  rtp_demuxer_.RemoveSink(sink);
+  if (!rtp_demuxer_.AddSink(criteria, sink)) {
+    RTC_LOG(LS_ERROR) << "Failed to register the sink for RTP demuxer.";
+    return false;
+  }
+  return true;
+}
+
+bool RtpTransport::UnregisterRtpDemuxerSink(RtpPacketSinkInterface* sink) {
+  if (!rtp_demuxer_.RemoveSink(sink)) {
+    RTC_LOG(LS_ERROR) << "Failed to unregister the sink for RTP demuxer.";
+    return false;
+  }
+  return true;
+}
+
 RTCError RtpTransport::SetParameters(const RtpTransportParameters& parameters) {
   if (parameters_.rtcp.mux && !parameters.rtcp.mux) {
     LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
@@ -160,11 +186,26 @@
   return parameters_;
 }
 
+void RtpTransport::DemuxPacket(rtc::CopyOnWriteBuffer* packet,
+                               const rtc::PacketTime& time) {
+  webrtc::RtpPacketReceived parsed_packet(&header_extension_map_);
+  if (!parsed_packet.Parse(std::move(*packet))) {
+    RTC_LOG(LS_ERROR)
+        << "Failed to parse the incoming RTP packet before demuxing. Drop it.";
+    return;
+  }
+
+  if (time.timestamp != -1) {
+    parsed_packet.set_arrival_time_ms((time.timestamp + 500) / 1000);
+  }
+  rtp_demuxer_.OnRtpPacket(parsed_packet);
+}
+
 RtpTransportAdapter* RtpTransport::GetInternal() {
   return nullptr;
 }
 
-bool RtpTransport::IsRtpTransportWritable() {
+bool RtpTransport::IsTransportWritable() {
   auto rtcp_packet_transport =
       rtcp_mux_enabled_ ? nullptr : rtcp_packet_transport_;
   return rtp_packet_transport_ && rtp_packet_transport_->writable() &&
@@ -175,7 +216,7 @@
   SetReadyToSend(transport == rtcp_packet_transport_, true);
 }
 
-void RtpTransport::OnNetworkRouteChange(
+void RtpTransport::OnNetworkRouteChanged(
     rtc::Optional<rtc::NetworkRoute> network_route) {
   SignalNetworkRouteChanged(network_route);
 }
@@ -184,7 +225,7 @@
     rtc::PacketTransportInternal* packet_transport) {
   RTC_DCHECK(packet_transport == rtp_packet_transport_ ||
              packet_transport == rtcp_packet_transport_);
-  SignalWritableState(IsRtpTransportWritable());
+  SignalWritableState(IsTransportWritable());
 }
 
 void RtpTransport::OnSentPacket(rtc::PacketTransportInternal* packet_transport,
@@ -194,6 +235,49 @@
   SignalSentPacket(sent_packet);
 }
 
+void RtpTransport::OnRtpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                                       const rtc::PacketTime& packet_time) {
+  DemuxPacket(packet, packet_time);
+}
+
+void RtpTransport::OnRtcpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                                        const rtc::PacketTime& packet_time) {
+  SignalRtcpPacketReceived(packet, packet_time);
+}
+
+void RtpTransport::OnReadPacket(rtc::PacketTransportInternal* transport,
+                                const char* data,
+                                size_t len,
+                                const rtc::PacketTime& packet_time,
+                                int flags) {
+  TRACE_EVENT0("webrtc", "RtpTransport::OnReadPacket");
+
+  // When using RTCP multiplexing we might get RTCP packets on the RTP
+  // transport. We check the RTP payload type to determine if it is RTCP.
+  bool rtcp =
+      transport == rtcp_packet_transport() || cricket::IsRtcpPacket(data, len);
+
+  // Filter out the packet that is neither RTP nor RTCP.
+  if (!rtcp && !cricket::IsRtpPacket(data, len)) {
+    return;
+  }
+
+  rtc::CopyOnWriteBuffer packet(data, len);
+  // Protect ourselves against crazy data.
+  if (!cricket::IsValidRtpRtcpPacketSize(rtcp, packet.size())) {
+    RTC_LOG(LS_ERROR) << "Dropping incoming "
+                      << cricket::RtpRtcpStringLiteral(rtcp)
+                      << " packet: wrong size=" << packet.size();
+    return;
+  }
+
+  if (rtcp) {
+    OnRtcpPacketReceived(&packet, packet_time);
+  } else {
+    OnRtpPacketReceived(&packet, packet_time);
+  }
+}
+
 void RtpTransport::SetReadyToSend(bool rtcp, bool ready) {
   if (rtcp) {
     rtcp_ready_to_send_ = ready;
@@ -213,52 +297,4 @@
   }
 }
 
-// Check the RTP payload type.  If 63 < payload type < 96, it's RTCP.
-// For additional details, see http://tools.ietf.org/html/rfc5761.
-bool IsRtcp(const char* data, int len) {
-  if (len < 2) {
-    return false;
-  }
-  char pt = data[1] & 0x7F;
-  return (63 < pt) && (pt < 96);
-}
-
-void RtpTransport::OnReadPacket(rtc::PacketTransportInternal* transport,
-                                const char* data,
-                                size_t len,
-                                const rtc::PacketTime& packet_time,
-                                int flags) {
-  TRACE_EVENT0("webrtc", "RtpTransport::OnReadPacket");
-
-  if (!cricket::IsRtpPacket(data, len) &&
-      !IsRtcp(data, static_cast<int>(len))) {
-    return;
-  }
-
-  // When using RTCP multiplexing we might get RTCP packets on the RTP
-  // transport. We check the RTP payload type to determine if it is RTCP.
-  bool rtcp = transport == rtcp_packet_transport() ||
-              IsRtcp(data, static_cast<int>(len));
-  rtc::CopyOnWriteBuffer packet(data, len);
-
-  if (!WantsPacket(rtcp, &packet)) {
-    return;
-  }
-
-  // This mutates |packet| if it is protected.
-  SignalPacketReceived(rtcp, &packet, packet_time);
-}
-
-bool RtpTransport::WantsPacket(bool rtcp,
-                               const rtc::CopyOnWriteBuffer* packet) {
-  // Protect ourselves against crazy data.
-  if (!packet || !cricket::IsValidRtpRtcpPacketSize(rtcp, packet->size())) {
-    RTC_LOG(LS_ERROR) << "Dropping incoming "
-                      << cricket::RtpRtcpStringLiteral(rtcp)
-                      << " packet: wrong size=" << packet->size();
-    return false;
-  }
-  return true;
-}
-
 }  // namespace webrtc
diff --git a/pc/rtptransport.h b/pc/rtptransport.h
index f878980..6620095 100644
--- a/pc/rtptransport.h
+++ b/pc/rtptransport.h
@@ -13,7 +13,8 @@
 
 #include <string>
 
-#include "api/ortc/rtptransportinterface.h"
+#include "call/rtp_demuxer.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
 #include "pc/rtptransportinternal.h"
 #include "rtc_base/sigslot.h"
 
@@ -74,6 +75,14 @@
 
   bool IsSrtpActive() const override { return false; }
 
+  void UpdateRtpHeaderExtensionMap(
+      const cricket::RtpHeaderExtensions& header_extensions) override;
+
+  bool RegisterRtpDemuxerSink(const RtpDemuxerCriteria& criteria,
+                              RtpPacketSinkInterface* sink) override;
+
+  bool UnregisterRtpDemuxerSink(RtpPacketSinkInterface* sink) override;
+
   void SetMetricsObserver(
       rtc::scoped_refptr<MetricsObserverInterface> metrics_observer) override {}
 
@@ -81,15 +90,33 @@
   // TODO(zstein): Remove this when we remove RtpTransportAdapter.
   RtpTransportAdapter* GetInternal() override;
 
- private:
-  bool IsRtpTransportWritable();
-  bool HandlesPacket(const uint8_t* data, size_t len);
+  // These methods will be used in the subclasses.
+  void DemuxPacket(rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& time);
 
+  bool SendPacket(bool rtcp,
+                  rtc::CopyOnWriteBuffer* packet,
+                  const rtc::PacketOptions& options,
+                  int flags);
+
+  // Overridden by SrtpTransport.
+  virtual void OnNetworkRouteChanged(
+      rtc::Optional<rtc::NetworkRoute> network_route);
+  virtual void OnRtpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                                   const rtc::PacketTime& packet_time);
+  virtual void OnRtcpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                                    const rtc::PacketTime& packet_time);
+  // Overridden by SrtpTransport and DtlsSrtpTransport.
+  virtual void OnWritableState(rtc::PacketTransportInternal* packet_transport);
+
+ private:
   void OnReadyToSend(rtc::PacketTransportInternal* transport);
-  void OnNetworkRouteChange(rtc::Optional<rtc::NetworkRoute> network_route);
-  void OnWritableState(rtc::PacketTransportInternal* packet_transport);
   void OnSentPacket(rtc::PacketTransportInternal* packet_transport,
                     const rtc::SentPacket& sent_packet);
+  void OnReadPacket(rtc::PacketTransportInternal* transport,
+                    const char* data,
+                    size_t len,
+                    const rtc::PacketTime& packet_time,
+                    int flags);
 
   // Updates "ready to send" for an individual channel and fires
   // SignalReadyToSend.
@@ -97,19 +124,11 @@
 
   void MaybeSignalReadyToSend();
 
-  bool SendPacket(bool rtcp,
-                  rtc::CopyOnWriteBuffer* packet,
-                  const rtc::PacketOptions& options,
-                  int flags);
+  bool IsTransportWritable();
 
-  void OnReadPacket(rtc::PacketTransportInternal* transport,
-                    const char* data,
-                    size_t len,
-                    const rtc::PacketTime& packet_time,
-                    int flags);
-
-  bool WantsPacket(bool rtcp, const rtc::CopyOnWriteBuffer* packet);
-
+  // SRTP specific methods.
+  // TODO(zhihuang): Improve the inheritance model so that the RtpTransport
+  // doesn't need to implement SRTP specfic methods.
   RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override {
     RTC_NOTREACHED();
     return RTCError::OK();
@@ -129,6 +148,10 @@
   bool rtcp_ready_to_send_ = false;
 
   RtpTransportParameters parameters_;
+  RtpDemuxer rtp_demuxer_;
+
+  // Used for identifying the MID for RtpDemuxer.
+  RtpHeaderExtensionMap header_extension_map_;
 };
 
 }  // namespace webrtc
diff --git a/pc/rtptransport_unittest.cc b/pc/rtptransport_unittest.cc
index 0425942..97ea2e4 100644
--- a/pc/rtptransport_unittest.cc
+++ b/pc/rtptransport_unittest.cc
@@ -250,49 +250,37 @@
   EXPECT_EQ(1, observer.rtp_transport_sent_count());
 }
 
-class SignalCounter : public sigslot::has_slots<> {
- public:
-  explicit SignalCounter(RtpTransport* transport) {
-    transport->SignalReadyToSend.connect(this, &SignalCounter::OnReadyToSend);
-  }
-  int count() const { return count_; }
-  void OnReadyToSend(bool ready) { ++count_; }
-
- private:
-  int count_ = 0;
-};
-
 TEST(RtpTransportTest, ChangingReadyToSendStateOnlySignalsWhenChanged) {
   RtpTransport transport(kMuxEnabled);
-  SignalCounter observer(&transport);
+  TransportObserver observer(&transport);
   rtc::FakePacketTransport fake_rtp("fake_rtp");
   fake_rtp.SetWritable(true);
 
   // State changes, so we should signal.
   transport.SetRtpPacketTransport(&fake_rtp);
-  EXPECT_EQ(observer.count(), 1);
+  EXPECT_EQ(observer.ready_to_send_signal_count(), 1);
 
   // State does not change, so we should not signal.
   transport.SetRtpPacketTransport(&fake_rtp);
-  EXPECT_EQ(observer.count(), 1);
+  EXPECT_EQ(observer.ready_to_send_signal_count(), 1);
 
   // State does not change, so we should not signal.
   transport.SetRtcpMuxEnabled(true);
-  EXPECT_EQ(observer.count(), 1);
+  EXPECT_EQ(observer.ready_to_send_signal_count(), 1);
 
   // State changes, so we should signal.
   transport.SetRtcpMuxEnabled(false);
-  EXPECT_EQ(observer.count(), 2);
+  EXPECT_EQ(observer.ready_to_send_signal_count(), 2);
 }
 
 // Test that SignalPacketReceived fires with rtcp=true when a RTCP packet is
 // received.
 TEST(RtpTransportTest, SignalDemuxedRtcp) {
   RtpTransport transport(kMuxDisabled);
-  SignalPacketReceivedCounter observer(&transport);
   rtc::FakePacketTransport fake_rtp("fake_rtp");
   fake_rtp.SetDestination(&fake_rtp, true);
   transport.SetRtpPacketTransport(&fake_rtp);
+  TransportObserver observer(&transport);
 
   // An rtcp packet.
   const char data[] = {0, 73, 0, 0};
@@ -312,10 +300,14 @@
 // handled payload type is received.
 TEST(RtpTransportTest, SignalHandledRtpPayloadType) {
   RtpTransport transport(kMuxDisabled);
-  SignalPacketReceivedCounter observer(&transport);
   rtc::FakePacketTransport fake_rtp("fake_rtp");
   fake_rtp.SetDestination(&fake_rtp, true);
   transport.SetRtpPacketTransport(&fake_rtp);
+  TransportObserver observer(&transport);
+  RtpDemuxerCriteria demuxer_criteria;
+  // Add a handled payload type.
+  demuxer_criteria.payload_types = {0x11};
+  transport.RegisterRtpDemuxerSink(demuxer_criteria, &observer);
 
   // An rtp packet.
   const rtc::PacketOptions options;
@@ -324,6 +316,31 @@
   fake_rtp.SendPacket(rtp_data.data<char>(), kRtpLen, options, flags);
   EXPECT_EQ(1, observer.rtp_count());
   EXPECT_EQ(0, observer.rtcp_count());
+  // Remove the sink before destroying the transport.
+  transport.UnregisterRtpDemuxerSink(&observer);
+}
+
+// Test that SignalPacketReceived does not fire when a RTP packet with an
+// unhandled payload type is received.
+TEST(RtpTransportTest, DontSignalUnhandledRtpPayloadType) {
+  RtpTransport transport(kMuxDisabled);
+  rtc::FakePacketTransport fake_rtp("fake_rtp");
+  fake_rtp.SetDestination(&fake_rtp, true);
+  transport.SetRtpPacketTransport(&fake_rtp);
+  TransportObserver observer(&transport);
+  RtpDemuxerCriteria demuxer_criteria;
+  // Add an unhandled payload type.
+  demuxer_criteria.payload_types = {0x12};
+  transport.RegisterRtpDemuxerSink(demuxer_criteria, &observer);
+
+  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());
+  // Remove the sink before destroying the transport.
+  transport.UnregisterRtpDemuxerSink(&observer);
 }
 
 }  // namespace webrtc
diff --git a/pc/rtptransportinternal.h b/pc/rtptransportinternal.h
index a354936..7845d42 100644
--- a/pc/rtptransportinternal.h
+++ b/pc/rtptransportinternal.h
@@ -15,7 +15,9 @@
 
 #include "api/ortc/srtptransportinterface.h"
 #include "api/umametrics.h"
+#include "call/rtp_demuxer.h"
 #include "p2p/base/icetransportinternal.h"
+#include "pc/sessiondescription.h"
 #include "rtc_base/networkroute.h"
 #include "rtc_base/sigslot.h"
 #include "rtc_base/sslstreamadapter.h"
@@ -55,11 +57,11 @@
   // than just "writable"; it means the last send didn't return ENOTCONN.
   sigslot::signal1<bool> SignalReadyToSend;
 
-  // TODO(zstein): Consider having two signals - RtpPacketReceived and
-  // RtcpPacketReceived.
-  // The first argument is true for RTCP packets and false for RTP packets.
-  sigslot::signal3<bool, rtc::CopyOnWriteBuffer*, const rtc::PacketTime&>
-      SignalPacketReceived;
+  // Called whenever an RTCP packet is received. There is no equivalent signal
+  // for RTP packets because they would be forwarded to the BaseChannel through
+  // the RtpDemuxer callback.
+  sigslot::signal2<rtc::CopyOnWriteBuffer*, const rtc::PacketTime&>
+      SignalRtcpPacketReceived;
 
   // Called whenever the network route of the P2P layer transport changes.
   // The argument is an optional network route.
@@ -83,10 +85,28 @@
                               const rtc::PacketOptions& options,
                               int flags) = 0;
 
+  // This method updates the RTP header extension map so that the RTP transport
+  // can parse the received packets and identify the MID. This is called by the
+  // BaseChannel when setting the content description.
+  //
+  // TODO(zhihuang): Merging and replacing following methods handling header
+  // extensions with SetParameters:
+  //   UpdateRtpHeaderExtensionMap,
+  //   UpdateSendEncryptedHeaderExtensionIds,
+  //   UpdateRecvEncryptedHeaderExtensionIds,
+  //   CacheRtpAbsSendTimeHeaderExtension,
+  virtual void UpdateRtpHeaderExtensionMap(
+      const cricket::RtpHeaderExtensions& header_extensions) = 0;
+
   virtual bool IsSrtpActive() const = 0;
 
   virtual void SetMetricsObserver(
       rtc::scoped_refptr<MetricsObserverInterface> metrics_observer) = 0;
+
+  virtual bool RegisterRtpDemuxerSink(const RtpDemuxerCriteria& criteria,
+                                      RtpPacketSinkInterface* sink) = 0;
+
+  virtual bool UnregisterRtpDemuxerSink(RtpPacketSinkInterface* sink) = 0;
 };
 
 }  // namespace webrtc
diff --git a/pc/rtptransportinternaladapter.h b/pc/rtptransportinternaladapter.h
index a1f4bfc..ed7258d 100644
--- a/pc/rtptransportinternaladapter.h
+++ b/pc/rtptransportinternaladapter.h
@@ -71,6 +71,20 @@
     return transport_->SendRtcpPacket(packet, options, flags);
   }
 
+  void UpdateRtpHeaderExtensionMap(
+      const cricket::RtpHeaderExtensions& header_extensions) override {
+    transport_->UpdateRtpHeaderExtensionMap(header_extensions);
+  }
+
+  bool RegisterRtpDemuxerSink(const RtpDemuxerCriteria& criteria,
+                              RtpPacketSinkInterface* sink) override {
+    return transport_->RegisterRtpDemuxerSink(criteria, sink);
+  }
+
+  bool UnregisterRtpDemuxerSink(RtpPacketSinkInterface* sink) override {
+    return transport_->UnregisterRtpDemuxerSink(sink);
+  }
+
   // RtpTransportInterface overrides.
   PacketTransportInterface* GetRtpPacketTransport() const override {
     return transport_->GetRtpPacketTransport();
diff --git a/pc/rtptransporttestutil.h b/pc/rtptransporttestutil.h
index c2bdaad..2707e1c 100644
--- a/pc/rtptransporttestutil.h
+++ b/pc/rtptransporttestutil.h
@@ -11,32 +11,66 @@
 #ifndef PC_RTPTRANSPORTTESTUTIL_H_
 #define PC_RTPTRANSPORTTESTUTIL_H_
 
+#include "call/rtp_packet_sink_interface.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
 #include "pc/rtptransportinternal.h"
 #include "rtc_base/sigslot.h"
 
 namespace webrtc {
 
-class SignalPacketReceivedCounter : public sigslot::has_slots<> {
+// Used to handle the signals when the RtpTransport receives an RTP/RTCP packet.
+// Used in Rtp/Srtp/DtlsTransport unit tests.
+class TransportObserver : public RtpPacketSinkInterface,
+                          public sigslot::has_slots<> {
  public:
-  explicit SignalPacketReceivedCounter(RtpTransportInternal* transport) {
-    transport->SignalPacketReceived.connect(
-        this, &SignalPacketReceivedCounter::OnPacketReceived);
+  TransportObserver() {}
+
+  explicit TransportObserver(RtpTransportInternal* rtp_transport) {
+    rtp_transport->SignalRtcpPacketReceived.connect(
+        this, &TransportObserver::OnRtcpPacketReceived);
+    rtp_transport->SignalReadyToSend.connect(this,
+                                             &TransportObserver::OnReadyToSend);
   }
-  int rtcp_count() const { return rtcp_count_; }
+
+  // RtpPacketInterface override.
+  void OnRtpPacket(const RtpPacketReceived& packet) override {
+    rtp_count_++;
+    last_recv_rtp_packet_ = packet.Buffer();
+  }
+
+  void OnRtcpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                            const rtc::PacketTime& packet_time) {
+    rtcp_count_++;
+    last_recv_rtcp_packet_ = *packet;
+  }
+
   int rtp_count() const { return rtp_count_; }
+  int rtcp_count() const { return rtcp_count_; }
+
+  rtc::CopyOnWriteBuffer last_recv_rtp_packet() {
+    return last_recv_rtp_packet_;
+  }
+
+  rtc::CopyOnWriteBuffer last_recv_rtcp_packet() {
+    return last_recv_rtcp_packet_;
+  }
+
+  void OnReadyToSend(bool ready) {
+    ready_to_send_signal_count_++;
+    ready_to_send_ = ready;
+  }
+
+  bool ready_to_send() { return ready_to_send_; }
+
+  int ready_to_send_signal_count() { return ready_to_send_signal_count_; }
 
  private:
-  void OnPacketReceived(bool rtcp,
-                        rtc::CopyOnWriteBuffer*,
-                        const rtc::PacketTime&) {
-    if (rtcp) {
-      ++rtcp_count_;
-    } else {
-      ++rtp_count_;
-    }
-  }
-  int rtcp_count_ = 0;
+  bool ready_to_send_ = false;
   int rtp_count_ = 0;
+  int rtcp_count_ = 0;
+  int ready_to_send_signal_count_ = 0;
+  rtc::CopyOnWriteBuffer last_recv_rtp_packet_;
+  rtc::CopyOnWriteBuffer last_recv_rtcp_packet_;
 };
 
 }  // namespace webrtc
diff --git a/pc/srtptransport.cc b/pc/srtptransport.cc
index 3e7b154..1fe0cc8 100644
--- a/pc/srtptransport.cc
+++ b/pc/srtptransport.cc
@@ -19,6 +19,7 @@
 #include "rtc_base/asyncpacketsocket.h"
 #include "rtc_base/base64.h"
 #include "rtc_base/copyonwritebuffer.h"
+#include "rtc_base/numerics/safe_conversions.h"
 #include "rtc_base/ptr_util.h"
 #include "rtc_base/trace_event.h"
 #include "rtc_base/zero_memory.h"
@@ -26,31 +27,7 @@
 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(static_cast<RtpTransport*>(transport_));
-  RTC_DCHECK(rtp_transport_);
-  ConnectToRtpTransport();
-}
-
-SrtpTransport::SrtpTransport(std::unique_ptr<RtpTransport> rtp_transport)
-    : RtpTransportInternalAdapter(rtp_transport.get()),
-      rtp_transport_(std::move(rtp_transport)) {
-  RTC_DCHECK(rtp_transport_);
-  ConnectToRtpTransport();
-}
-
-void SrtpTransport::ConnectToRtpTransport() {
-  rtp_transport_->SignalPacketReceived.connect(
-      this, &SrtpTransport::OnPacketReceived);
-  rtp_transport_->SignalReadyToSend.connect(this,
-                                            &SrtpTransport::OnReadyToSend);
-  rtp_transport_->SignalNetworkRouteChanged.connect(
-      this, &SrtpTransport::OnNetworkRouteChanged);
-  rtp_transport_->SignalWritableState.connect(this,
-                                              &SrtpTransport::OnWritableState);
-  rtp_transport_->SignalSentPacket.connect(this, &SrtpTransport::OnSentPacket);
-}
+    : RtpTransport(rtcp_mux_enabled) {}
 
 RTCError SrtpTransport::SetSrtpSendKey(const cricket::CryptoParams& params) {
   if (send_params_) {
@@ -135,125 +112,128 @@
 bool SrtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
                                   const rtc::PacketOptions& options,
                                   int flags) {
-  return SendPacket(false, packet, options, flags);
-}
-
-bool SrtpTransport::SendRtcpPacket(rtc::CopyOnWriteBuffer* packet,
-                                   const rtc::PacketOptions& options,
-                                   int flags) {
-  return SendPacket(true, packet, options, flags);
-}
-
-bool SrtpTransport::SendPacket(bool rtcp,
-                               rtc::CopyOnWriteBuffer* packet,
-                               const rtc::PacketOptions& options,
-                               int flags) {
   if (!IsSrtpActive()) {
     RTC_LOG(LS_ERROR)
         << "Failed to send the packet because SRTP transport is inactive.";
     return false;
   }
-
   rtc::PacketOptions updated_options = options;
-  rtc::CopyOnWriteBuffer cp = *packet;
   TRACE_EVENT0("webrtc", "SRTP Encode");
   bool res;
   uint8_t* data = packet->data();
-  int len = static_cast<int>(packet->size());
-  if (!rtcp) {
+  int len = rtc::checked_cast<int>(packet->size());
 // If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done
 // inside libsrtp for a RTP packet. A external HMAC module will be writing
 // a fake HMAC value. This is ONLY done for a RTP packet.
 // Socket layer will update rtp sendtime extension header if present in
 // packet with current time before updating the HMAC.
 #if !defined(ENABLE_EXTERNAL_AUTH)
-    res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
+  res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
 #else
-    if (!IsExternalAuthActive()) {
-      res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
-    } else {
-      updated_options.packet_time_params.rtp_sendtime_extension_id =
-          rtp_abs_sendtime_extn_id_;
-      res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len,
-                       &updated_options.packet_time_params.srtp_packet_index);
-      // If protection succeeds, let's get auth params from srtp.
+  if (!IsExternalAuthActive()) {
+    res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
+  } else {
+    updated_options.packet_time_params.rtp_sendtime_extension_id =
+        rtp_abs_sendtime_extn_id_;
+    res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len,
+                     &updated_options.packet_time_params.srtp_packet_index);
+    // If protection succeeds, let's get auth params from srtp.
+    if (res) {
+      uint8_t* auth_key = nullptr;
+      int key_len = 0;
+      res = GetRtpAuthParams(
+          &auth_key, &key_len,
+          &updated_options.packet_time_params.srtp_auth_tag_len);
       if (res) {
-        uint8_t* auth_key = NULL;
-        int key_len;
-        res = GetRtpAuthParams(
-            &auth_key, &key_len,
-            &updated_options.packet_time_params.srtp_auth_tag_len);
-        if (res) {
-          updated_options.packet_time_params.srtp_auth_key.resize(key_len);
-          updated_options.packet_time_params.srtp_auth_key.assign(
-              auth_key, auth_key + key_len);
-        }
+        updated_options.packet_time_params.srtp_auth_key.resize(key_len);
+        updated_options.packet_time_params.srtp_auth_key.assign(
+            auth_key, auth_key + key_len);
       }
     }
+  }
 #endif
-    if (!res) {
-      int seq_num = -1;
-      uint32_t ssrc = 0;
-      cricket::GetRtpSeqNum(data, len, &seq_num);
-      cricket::GetRtpSsrc(data, len, &ssrc);
-      RTC_LOG(LS_ERROR) << "Failed to protect RTP packet: size=" << len
-                        << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
-      return false;
-    }
-  } else {
-    res = ProtectRtcp(data, len, static_cast<int>(packet->capacity()), &len);
-    if (!res) {
-      int type = -1;
-      cricket::GetRtcpType(data, len, &type);
-      RTC_LOG(LS_ERROR) << "Failed to protect RTCP packet: size=" << len
-                        << ", type=" << type;
-      return false;
-    }
+  if (!res) {
+    int seq_num = -1;
+    uint32_t ssrc = 0;
+    cricket::GetRtpSeqNum(data, len, &seq_num);
+    cricket::GetRtpSsrc(data, len, &ssrc);
+    RTC_LOG(LS_ERROR) << "Failed to protect RTP packet: size=" << len
+                      << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
+    return false;
   }
 
   // Update the length of the packet now that we've added the auth tag.
   packet->SetSize(len);
-  return rtcp ? rtp_transport_->SendRtcpPacket(packet, updated_options, flags)
-              : rtp_transport_->SendRtpPacket(packet, updated_options, flags);
+  return SendPacket(/*rtcp=*/false, packet, updated_options, flags);
 }
 
-void SrtpTransport::OnPacketReceived(bool rtcp,
-                                     rtc::CopyOnWriteBuffer* packet,
-                                     const rtc::PacketTime& packet_time) {
+bool SrtpTransport::SendRtcpPacket(rtc::CopyOnWriteBuffer* packet,
+                                   const rtc::PacketOptions& options,
+                                   int flags) {
+  if (!IsSrtpActive()) {
+    RTC_LOG(LS_ERROR)
+        << "Failed to send the packet because SRTP transport is inactive.";
+    return false;
+  }
+
+  TRACE_EVENT0("webrtc", "SRTP Encode");
+  uint8_t* data = packet->data();
+  int len = rtc::checked_cast<int>(packet->size());
+  if (!ProtectRtcp(data, len, static_cast<int>(packet->capacity()), &len)) {
+    int type = -1;
+    cricket::GetRtcpType(data, len, &type);
+    RTC_LOG(LS_ERROR) << "Failed to protect RTCP packet: size=" << len
+                      << ", type=" << type;
+    return false;
+  }
+  // Update the length of the packet now that we've added the auth tag.
+  packet->SetSize(len);
+
+  return SendPacket(/*rtcp=*/true, packet, options, flags);
+}
+
+void SrtpTransport::OnRtpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                                        const rtc::PacketTime& packet_time) {
   if (!IsSrtpActive()) {
     RTC_LOG(LS_WARNING)
-        << "Inactive SRTP transport received a packet. Drop it.";
+        << "Inactive SRTP transport received an RTP packet. Drop it.";
     return;
   }
-
   TRACE_EVENT0("webrtc", "SRTP Decode");
   char* data = packet->data<char>();
-  int len = static_cast<int>(packet->size());
-  bool res;
-  if (!rtcp) {
-    res = UnprotectRtp(data, len, &len);
-    if (!res) {
-      int seq_num = -1;
-      uint32_t ssrc = 0;
-      cricket::GetRtpSeqNum(data, len, &seq_num);
-      cricket::GetRtpSsrc(data, len, &ssrc);
-      RTC_LOG(LS_ERROR) << "Failed to unprotect RTP packet: size=" << len
-                        << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
-      return;
-    }
-  } else {
-    res = UnprotectRtcp(data, len, &len);
-    if (!res) {
-      int type = -1;
-      cricket::GetRtcpType(data, len, &type);
-      RTC_LOG(LS_ERROR) << "Failed to unprotect RTCP packet: size=" << len
-                        << ", type=" << type;
-      return;
-    }
+  int len = rtc::checked_cast<int>(packet->size());
+  if (!UnprotectRtp(data, len, &len)) {
+    int seq_num = -1;
+    uint32_t ssrc = 0;
+    cricket::GetRtpSeqNum(data, len, &seq_num);
+    cricket::GetRtpSsrc(data, len, &ssrc);
+    RTC_LOG(LS_ERROR) << "Failed to unprotect RTP packet: size=" << len
+                      << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
+    return;
   }
-
   packet->SetSize(len);
-  SignalPacketReceived(rtcp, packet, packet_time);
+  DemuxPacket(packet, packet_time);
+}
+
+void SrtpTransport::OnRtcpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                                         const rtc::PacketTime& packet_time) {
+  if (!IsSrtpActive()) {
+    RTC_LOG(LS_WARNING)
+        << "Inactive SRTP transport received an RTCP packet. Drop it.";
+    return;
+  }
+  TRACE_EVENT0("webrtc", "SRTP Decode");
+  char* data = packet->data<char>();
+  int len = rtc::checked_cast<int>(packet->size());
+  if (!UnprotectRtcp(data, len, &len)) {
+    int type = -1;
+    cricket::GetRtcpType(data, len, &type);
+    RTC_LOG(LS_ERROR) << "Failed to unprotect RTCP packet: size=" << len
+                      << ", type=" << type;
+    return;
+  }
+  packet->SetSize(len);
+  SignalRtcpPacketReceived(packet, packet_time);
 }
 
 void SrtpTransport::OnNetworkRouteChanged(
@@ -269,6 +249,11 @@
   SignalNetworkRouteChanged(network_route);
 }
 
+void SrtpTransport::OnWritableState(
+    rtc::PacketTransportInternal* packet_transport) {
+  SignalWritableState(IsWritable(/*rtcp=*/true) && IsWritable(/*rtcp=*/true));
+}
+
 bool SrtpTransport::SetRtpParams(int send_cs,
                                  const uint8_t* send_key,
                                  int send_key_len,
@@ -309,6 +294,7 @@
   RTC_LOG(LS_INFO) << "SRTP " << (new_sessions ? "activated" : "updated")
                    << " with negotiated parameters: send cipher_suite "
                    << send_cs << " recv cipher_suite " << recv_cs;
+  MaybeUpdateWritableState();
   return true;
 }
 
@@ -347,7 +333,7 @@
   RTC_LOG(LS_INFO) << "SRTCP activated with negotiated parameters:"
                       " send cipher_suite "
                    << send_cs << " recv cipher_suite " << recv_cs;
-
+  MaybeUpdateWritableState();
   return true;
 }
 
@@ -355,11 +341,16 @@
   return send_session_ && recv_session_;
 }
 
+bool SrtpTransport::IsWritable(bool rtcp) const {
+  return IsSrtpActive() && RtpTransport::IsWritable(rtcp);
+}
+
 void SrtpTransport::ResetParams() {
   send_session_ = nullptr;
   recv_session_ = nullptr;
   send_rtcp_session_ = nullptr;
   recv_rtcp_session_ = nullptr;
+  MaybeUpdateWritableState();
   RTC_LOG(LS_INFO) << "The params in SRTP transport are reset.";
 }
 
@@ -530,7 +521,15 @@
   if (recv_rtcp_session_) {
     recv_rtcp_session_->SetMetricsObserver(metrics_observer_);
   }
-  rtp_transport_->SetMetricsObserver(metrics_observer);
+}
+
+void SrtpTransport::MaybeUpdateWritableState() {
+  bool writable = IsWritable(/*rtcp=*/true) && IsWritable(/*rtcp=*/false);
+  // Only fire the signal if the writable state changes.
+  if (writable_ != writable) {
+    writable_ = writable;
+    SignalWritableState(writable_);
+  }
 }
 
 }  // namespace webrtc
diff --git a/pc/srtptransport.h b/pc/srtptransport.h
index 5bc9970..3266e54 100644
--- a/pc/srtptransport.h
+++ b/pc/srtptransport.h
@@ -20,38 +20,20 @@
 #include "p2p/base/dtlstransportinternal.h"
 #include "p2p/base/icetransportinternal.h"
 #include "pc/rtptransport.h"
-#include "pc/rtptransportinternaladapter.h"
 #include "pc/srtpsession.h"
 #include "rtc_base/buffer.h"
 #include "rtc_base/checks.h"
 
 namespace webrtc {
 
-// This class will eventually be a wrapper around RtpTransportInternal
-// that protects and unprotects sent and received RTP packets.
-class SrtpTransport : public RtpTransportInternalAdapter {
+// This subclass of the RtpTransport is used for SRTP which is reponsible for
+// protecting/unprotecting the packets. It provides interfaces to set the crypto
+// parameters for the SrtpSession underneath.
+class SrtpTransport : public RtpTransport {
  public:
   explicit SrtpTransport(bool rtcp_mux_enabled);
 
-  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();
-  }
+  virtual ~SrtpTransport() = default;
 
   // SrtpTransportInterface specific implementation.
   RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override;
@@ -69,6 +51,8 @@
   // created.
   bool IsSrtpActive() const override;
 
+  bool IsWritable(bool rtcp) 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
   // handshake.
@@ -120,29 +104,23 @@
     rtp_abs_sendtime_extn_id_ = rtp_abs_sendtime_extn_id;
   }
 
-  void SetMetricsObserver(
-      rtc::scoped_refptr<MetricsObserverInterface> metrics_observer) override;
+ protected:
+  // If the writable state changed, fire the SignalWritableState.
+  void MaybeUpdateWritableState();
 
  private:
   void ConnectToRtpTransport();
   void CreateSrtpSessions();
 
-  bool SendPacket(bool rtcp,
-                  rtc::CopyOnWriteBuffer* packet,
-                  const rtc::PacketOptions& options,
-                  int flags);
+  void OnRtpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                           const rtc::PacketTime& packet_time) override;
+  void OnRtcpPacketReceived(rtc::CopyOnWriteBuffer* packet,
+                            const rtc::PacketTime& packet_time) override;
+  void OnNetworkRouteChanged(
+      rtc::Optional<rtc::NetworkRoute> network_route) override;
 
-  void OnPacketReceived(bool rtcp,
-                        rtc::CopyOnWriteBuffer* packet,
-                        const rtc::PacketTime& packet_time);
-  void OnReadyToSend(bool ready) { SignalReadyToSend(ready); }
-  void OnNetworkRouteChanged(rtc::Optional<rtc::NetworkRoute> network_route);
-
-  void OnWritableState(bool writable) { SignalWritableState(writable); }
-
-  void OnSentPacket(const rtc::SentPacket& sent_packet) {
-    SignalSentPacket(sent_packet);
-  }
+  // Override the RtpTransport::OnWritableState.
+  void OnWritableState(rtc::PacketTransportInternal* packet_transport) override;
 
   bool ProtectRtp(void* data, int in_len, int max_len, int* out_len);
 
@@ -163,8 +141,10 @@
   bool MaybeSetKeyParams();
   bool ParseKeyParams(const std::string& key_params, uint8_t* key, size_t len);
 
+  void SetMetricsObserver(
+      rtc::scoped_refptr<MetricsObserverInterface> metrics_observer) override;
+
   const std::string content_name_;
-  std::unique_ptr<RtpTransport> rtp_transport_;
 
   std::unique_ptr<cricket::SrtpSession> send_session_;
   std::unique_ptr<cricket::SrtpSession> recv_session_;
@@ -178,6 +158,8 @@
   rtc::ZeroOnFreeBuffer<uint8_t> send_key_;
   rtc::ZeroOnFreeBuffer<uint8_t> recv_key_;
 
+  bool writable_ = false;
+
   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 30e30f6..5af45c8 100644
--- a/pc/srtptransport_unittest.cc
+++ b/pc/srtptransport_unittest.cc
@@ -42,8 +42,6 @@
  protected:
   SrtpTransportTest() {
     bool rtcp_mux_enabled = true;
-    auto rtp_transport1 = rtc::MakeUnique<RtpTransport>(rtcp_mux_enabled);
-    auto rtp_transport2 = rtc::MakeUnique<RtpTransport>(rtcp_mux_enabled);
 
     rtp_packet_transport1_ =
         rtc::MakeUnique<rtc::FakePacketTransport>("fake_packet_transport1");
@@ -54,32 +52,32 @@
     rtp_packet_transport1_->SetDestination(rtp_packet_transport2_.get(),
                                            asymmetric);
 
-    rtp_transport1->SetRtpPacketTransport(rtp_packet_transport1_.get());
-    rtp_transport2->SetRtpPacketTransport(rtp_packet_transport2_.get());
+    srtp_transport1_ = rtc::MakeUnique<SrtpTransport>(rtcp_mux_enabled);
+    srtp_transport2_ = rtc::MakeUnique<SrtpTransport>(rtcp_mux_enabled);
 
-    srtp_transport1_ =
-        rtc::MakeUnique<SrtpTransport>(std::move(rtp_transport1));
-    srtp_transport2_ =
-        rtc::MakeUnique<SrtpTransport>(std::move(rtp_transport2));
+    srtp_transport1_->SetRtpPacketTransport(rtp_packet_transport1_.get());
+    srtp_transport2_->SetRtpPacketTransport(rtp_packet_transport2_.get());
 
-    srtp_transport1_->SignalPacketReceived.connect(
-        this, &SrtpTransportTest::OnPacketReceived1);
-    srtp_transport2_->SignalPacketReceived.connect(
-        this, &SrtpTransportTest::OnPacketReceived2);
+    srtp_transport1_->SignalRtcpPacketReceived.connect(
+        &rtp_sink1_, &TransportObserver::OnRtcpPacketReceived);
+    srtp_transport2_->SignalRtcpPacketReceived.connect(
+        &rtp_sink2_, &TransportObserver::OnRtcpPacketReceived);
+
+    RtpDemuxerCriteria demuxer_criteria;
+    // 0x00 is the payload type used in kPcmuFrame.
+    demuxer_criteria.payload_types = {0x00};
+
+    srtp_transport1_->RegisterRtpDemuxerSink(demuxer_criteria, &rtp_sink1_);
+    srtp_transport2_->RegisterRtpDemuxerSink(demuxer_criteria, &rtp_sink2_);
   }
 
-  void OnPacketReceived1(bool rtcp,
-                         rtc::CopyOnWriteBuffer* packet,
-                         const rtc::PacketTime& packet_time) {
-    RTC_LOG(LS_INFO) << "SrtpTransport1 Received a packet.";
-    last_recv_packet1_ = *packet;
-  }
-
-  void OnPacketReceived2(bool rtcp,
-                         rtc::CopyOnWriteBuffer* packet,
-                         const rtc::PacketTime& packet_time) {
-    RTC_LOG(LS_INFO) << "SrtpTransport2 Received a packet.";
-    last_recv_packet2_ = *packet;
+  ~SrtpTransportTest() {
+    if (srtp_transport1_) {
+      srtp_transport1_->UnregisterRtpDemuxerSink(&rtp_sink1_);
+    }
+    if (srtp_transport2_) {
+      srtp_transport2_->UnregisterRtpDemuxerSink(&rtp_sink2_);
+    }
   }
 
   // With external auth enabled, SRTP doesn't write the auth tag and
@@ -136,9 +134,9 @@
     if (srtp_transport1_->IsExternalAuthActive()) {
       TestRtpAuthParams(srtp_transport1_.get(), cipher_suite_name);
     } else {
-      ASSERT_TRUE(last_recv_packet2_.data());
-      EXPECT_EQ(0,
-                memcmp(last_recv_packet2_.data(), original_rtp_data, rtp_len));
+      ASSERT_TRUE(rtp_sink2_.last_recv_rtp_packet().data());
+      EXPECT_EQ(0, memcmp(rtp_sink2_.last_recv_rtp_packet().data(),
+                          original_rtp_data, rtp_len));
       // Get the encrypted packet from underneath packet transport and verify
       // the data is actually encrypted.
       auto fake_rtp_packet_transport = static_cast<rtc::FakePacketTransport*>(
@@ -153,9 +151,9 @@
     if (srtp_transport2_->IsExternalAuthActive()) {
       TestRtpAuthParams(srtp_transport2_.get(), cipher_suite_name);
     } else {
-      ASSERT_TRUE(last_recv_packet1_.data());
-      EXPECT_EQ(0,
-                memcmp(last_recv_packet1_.data(), original_rtp_data, rtp_len));
+      ASSERT_TRUE(rtp_sink1_.last_recv_rtp_packet().data());
+      EXPECT_EQ(0, memcmp(rtp_sink1_.last_recv_rtp_packet().data(),
+                          original_rtp_data, rtp_len));
       auto fake_rtp_packet_transport = static_cast<rtc::FakePacketTransport*>(
           srtp_transport2_->rtp_packet_transport());
       EXPECT_NE(0, memcmp(fake_rtp_packet_transport->last_sent_packet()->data(),
@@ -164,12 +162,12 @@
   }
 
   void TestSendRecvRtcpPacket(const std::string& cipher_suite_name) {
-    size_t rtcp_len = sizeof(kRtcpReport);
+    size_t rtcp_len = sizeof(::kRtcpReport);
     size_t packet_size =
         rtcp_len + 4 + rtc::rtcp_auth_tag_len(cipher_suite_name);
     rtc::Buffer rtcp_packet_buffer(packet_size);
     char* rtcp_packet_data = rtcp_packet_buffer.data<char>();
-    memcpy(rtcp_packet_data, kRtcpReport, rtcp_len);
+    memcpy(rtcp_packet_data, ::kRtcpReport, rtcp_len);
 
     rtc::CopyOnWriteBuffer rtcp_packet1to2(rtcp_packet_data, rtcp_len,
                                            packet_size);
@@ -181,8 +179,9 @@
     // that the packet can be successfully received and decrypted.
     ASSERT_TRUE(srtp_transport1_->SendRtcpPacket(&rtcp_packet1to2, options,
                                                  cricket::PF_SRTP_BYPASS));
-    ASSERT_TRUE(last_recv_packet2_.data());
-    EXPECT_EQ(0, memcmp(last_recv_packet2_.data(), rtcp_packet_data, rtcp_len));
+    ASSERT_TRUE(rtp_sink2_.last_recv_rtcp_packet().data());
+    EXPECT_EQ(0, memcmp(rtp_sink2_.last_recv_rtcp_packet().data(),
+                        rtcp_packet_data, rtcp_len));
     // Get the encrypted packet from underneath packet transport and verify the
     // data is actually encrypted.
     auto fake_rtp_packet_transport = static_cast<rtc::FakePacketTransport*>(
@@ -193,8 +192,9 @@
     // Do the same thing in the opposite direction;
     ASSERT_TRUE(srtp_transport2_->SendRtcpPacket(&rtcp_packet2to1, options,
                                                  cricket::PF_SRTP_BYPASS));
-    ASSERT_TRUE(last_recv_packet1_.data());
-    EXPECT_EQ(0, memcmp(last_recv_packet1_.data(), rtcp_packet_data, rtcp_len));
+    ASSERT_TRUE(rtp_sink1_.last_recv_rtcp_packet().data());
+    EXPECT_EQ(0, memcmp(rtp_sink1_.last_recv_rtcp_packet().data(),
+                        rtcp_packet_data, rtcp_len));
     fake_rtp_packet_transport = static_cast<rtc::FakePacketTransport*>(
         srtp_transport2_->rtp_packet_transport());
     EXPECT_NE(0, memcmp(fake_rtp_packet_transport->last_sent_packet()->data(),
@@ -261,8 +261,9 @@
     // that the packet can be successfully received and decrypted.
     ASSERT_TRUE(srtp_transport1_->SendRtpPacket(&rtp_packet1to2, options,
                                                 cricket::PF_SRTP_BYPASS));
-    ASSERT_TRUE(last_recv_packet2_.data());
-    EXPECT_EQ(0, memcmp(last_recv_packet2_.data(), original_rtp_data, rtp_len));
+    ASSERT_TRUE(rtp_sink2_.last_recv_rtp_packet().data());
+    EXPECT_EQ(0, memcmp(rtp_sink2_.last_recv_rtp_packet().data(),
+                        original_rtp_data, rtp_len));
     // Get the encrypted packet from underneath packet transport and verify the
     // data and header extension are actually encrypted.
     auto fake_rtp_packet_transport = static_cast<rtc::FakePacketTransport*>(
@@ -278,8 +279,9 @@
     // Do the same thing in the opposite direction;
     ASSERT_TRUE(srtp_transport2_->SendRtpPacket(&rtp_packet2to1, options,
                                                 cricket::PF_SRTP_BYPASS));
-    ASSERT_TRUE(last_recv_packet1_.data());
-    EXPECT_EQ(0, memcmp(last_recv_packet1_.data(), original_rtp_data, rtp_len));
+    ASSERT_TRUE(rtp_sink1_.last_recv_rtp_packet().data());
+    EXPECT_EQ(0, memcmp(rtp_sink1_.last_recv_rtp_packet().data(),
+                        original_rtp_data, rtp_len));
     fake_rtp_packet_transport = static_cast<rtc::FakePacketTransport*>(
         srtp_transport2_->rtp_packet_transport());
     EXPECT_NE(0, memcmp(fake_rtp_packet_transport->last_sent_packet()->data(),
@@ -322,8 +324,9 @@
   std::unique_ptr<rtc::FakePacketTransport> rtp_packet_transport1_;
   std::unique_ptr<rtc::FakePacketTransport> rtp_packet_transport2_;
 
-  rtc::CopyOnWriteBuffer last_recv_packet1_;
-  rtc::CopyOnWriteBuffer last_recv_packet2_;
+  TransportObserver rtp_sink1_;
+  TransportObserver rtp_sink2_;
+
   int sequence_number_ = 0;
 };