Replace DatagramDtlsAdaptor with DatagramRtpTransport.

DatagramDtlsAdaptor wraps a DatagramTransport in a DtlsTransport.  This
is only used by wrapping it again, in an RtpTransport.  It is simpler to
just wrap DatagramTransport directly into an RtpTransport.

DatagramTransport is never used as a DtlsTransport, and doesn't support
most of the functionality exposed by the DtlsTransport interface.

However, it supports *all* the functionality of the RtpTransport, making
this a much cleaner fit.

Bug: webrtc:9719
Change-Id: I699e8124ee4cb6c8c187162f9b444ff0431a4902
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/149400
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28921}
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index f5c6254..33b6fa2 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -36,8 +36,8 @@
     "channel_manager.h",
     "composite_rtp_transport.cc",
     "composite_rtp_transport.h",
-    "datagram_dtls_adaptor.cc",
-    "datagram_dtls_adaptor.h",
+    "datagram_rtp_transport.cc",
+    "datagram_rtp_transport.h",
     "dtls_srtp_transport.cc",
     "dtls_srtp_transport.h",
     "dtls_transport.cc",
diff --git a/pc/datagram_dtls_adaptor.cc b/pc/datagram_dtls_adaptor.cc
deleted file mode 100644
index 190a2d3..0000000
--- a/pc/datagram_dtls_adaptor.cc
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "pc/datagram_dtls_adaptor.h"
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-
-#include "absl/memory/memory.h"
-#include "absl/strings/string_view.h"
-#include "absl/types/optional.h"
-#include "api/rtc_error.h"
-#include "api/rtc_event_log/rtc_event_log.h"
-#include "logging/rtc_event_log/events/rtc_event_dtls_transport_state.h"
-#include "logging/rtc_event_log/events/rtc_event_dtls_writable_state.h"
-#include "modules/rtp_rtcp/include/rtp_header_parser.h"
-#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
-#include "modules/rtp_rtcp/source/rtp_packet.h"
-#include "p2p/base/dtls_transport_internal.h"
-#include "p2p/base/packet_transport_internal.h"
-#include "rtc_base/buffer.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/dscp.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/message_queue.h"
-#include "rtc_base/rtc_certificate.h"
-#include "rtc_base/ssl_stream_adapter.h"
-#include "rtc_base/stream.h"
-#include "rtc_base/thread.h"
-#include "system_wrappers/include/field_trial.h"
-
-#ifdef BYPASS_DATAGRAM_DTLS_TEST_ONLY
-// Send unencrypted packets directly to ICE, bypassing datagtram
-// transport. Use in tests only.
-constexpr bool kBypassDatagramDtlsTestOnly = true;
-#else
-constexpr bool kBypassDatagramDtlsTestOnly = false;
-#endif
-
-namespace cricket {
-
-namespace {
-
-// Field trials.
-// Disable datagram to RTCP feedback translation and enable RTCP feedback loop
-// on top of datagram feedback loop. Note that two
-// feedback loops add unneccesary overhead, so it's preferable to use feedback
-// loop provided by datagram transport and convert datagram ACKs to RTCP ACKs,
-// but enabling RTCP feedback loop may be useful in tests and experiments.
-const char kDisableDatagramToRtcpFeebackTranslationFieldTrial[] =
-    "WebRTC-kDisableDatagramToRtcpFeebackTranslation";
-
-}  // namespace
-
-// Maximum packet size of RTCP feedback packet for allocation. We re-create RTCP
-// feedback packets when we get ACK notifications from datagram transport. Our
-// rtcp feedback packets contain only 1 ACK, so they are much smaller than 1250.
-constexpr size_t kMaxRtcpFeedbackPacketSize = 1250;
-
-DatagramDtlsAdaptor::DatagramDtlsAdaptor(
-    const std::vector<webrtc::RtpExtension>& rtp_header_extensions,
-    IceTransportInternal* ice_transport,
-    webrtc::DatagramTransportInterface* datagram_transport,
-    const webrtc::CryptoOptions& crypto_options,
-    webrtc::RtcEventLog* event_log)
-    : crypto_options_(crypto_options),
-      ice_transport_(ice_transport),
-      datagram_transport_(datagram_transport),
-      event_log_(event_log),
-      disable_datagram_to_rtcp_feeback_translation_(
-          webrtc::field_trial::IsEnabled(
-              kDisableDatagramToRtcpFeebackTranslationFieldTrial)) {
-  // Save extension map for parsing RTP packets (we only need transport
-  // sequence numbers).
-  const webrtc::RtpExtension* transport_sequence_number_extension =
-      webrtc::RtpExtension::FindHeaderExtensionByUri(
-          rtp_header_extensions, webrtc::TransportSequenceNumber::kUri);
-
-  if (transport_sequence_number_extension != nullptr) {
-    rtp_header_extension_map_.Register<webrtc::TransportSequenceNumber>(
-        transport_sequence_number_extension->id);
-  } else {
-    RTC_LOG(LS_ERROR) << "Transport sequence numbers are not supported in "
-                         "datagram transport connection";
-  }
-
-  // TODO(sukhanov): Add CHECK to make sure that field trial
-  // WebRTC-ExcludeTransportSequenceNumberFromFecFieldTrial is enabled.
-  // If feedback loop is translation is enabled, FEC packets must exclude
-  // transport sequence numbers, otherwise recovered packets will be corrupt.
-
-  RTC_DCHECK(ice_transport_);
-  RTC_DCHECK(datagram_transport_);
-  ConnectToIceTransport();
-}
-
-void DatagramDtlsAdaptor::ConnectToIceTransport() {
-  ice_transport_->SignalWritableState.connect(
-      this, &DatagramDtlsAdaptor::OnWritableState);
-  ice_transport_->SignalReadyToSend.connect(
-      this, &DatagramDtlsAdaptor::OnReadyToSend);
-  ice_transport_->SignalReceivingState.connect(
-      this, &DatagramDtlsAdaptor::OnReceivingState);
-  // Datagram transport does not propagate network route change.
-  ice_transport_->SignalNetworkRouteChanged.connect(
-      this, &DatagramDtlsAdaptor::OnNetworkRouteChanged);
-  if (kBypassDatagramDtlsTestOnly) {
-    // In bypass mode we have to subscribe to ICE read and sent events.
-    // Test only case to use ICE directly instead of data transport.
-    ice_transport_->SignalReadPacket.connect(
-        this, &DatagramDtlsAdaptor::OnReadPacket);
-    ice_transport_->SignalSentPacket.connect(
-        this, &DatagramDtlsAdaptor::OnSentPacket);
-  } else {
-    // Subscribe to Data Transport read packets.
-    datagram_transport_->SetDatagramSink(this);
-    datagram_transport_->SetTransportStateCallback(this);
-  }
-}
-
-DatagramDtlsAdaptor::~DatagramDtlsAdaptor() {
-  // Unsubscribe from Datagram Transport dinks.
-  datagram_transport_->SetDatagramSink(nullptr);
-  datagram_transport_->SetTransportStateCallback(nullptr);
-}
-
-const webrtc::CryptoOptions& DatagramDtlsAdaptor::crypto_options() const {
-  return crypto_options_;
-}
-
-int DatagramDtlsAdaptor::SendPacket(const char* data,
-                                    size_t len,
-                                    const rtc::PacketOptions& options,
-                                    int flags) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-
-  // TODO(sukhanov): Handle options and flags.
-  if (kBypassDatagramDtlsTestOnly) {
-    // In bypass mode sent directly to ICE.
-    return ice_transport_->SendPacket(data, len, options);
-  }
-
-  // Assign and increment datagram_id.
-  const webrtc::DatagramId datagram_id = current_datagram_id_++;
-
-  rtc::ArrayView<const uint8_t> original_data(
-      reinterpret_cast<const uint8_t*>(data), len);
-
-  // Send as is (without extracting transport sequence number) for
-  //    - All RTCP packets, because they do not have transport sequence number.
-  //    - RTP packets if we are not doing datagram => RTCP feedback translation.
-  if (disable_datagram_to_rtcp_feeback_translation_ ||
-      webrtc::RtpHeaderParser::IsRtcp(original_data.data(),
-                                      original_data.size())) {
-    // Even if we are not extracting transport sequence number we need to
-    // propagate "Sent" notification for both RTP and RTCP packets. For this
-    // reason we need save options.packet_id in packet map.
-    sent_rtp_packet_map_[datagram_id] = SentPacketInfo(options.packet_id);
-
-    return SendDatagram(original_data, datagram_id);
-  }
-
-  // Parse RTP packet.
-  webrtc::RtpPacket rtp_packet(&rtp_header_extension_map_);
-  if (!rtp_packet.Parse(original_data)) {
-    RTC_NOTREACHED() << "Failed to parse outgoing RtpPacket, len=" << len
-                     << ", options.packet_id=" << options.packet_id;
-    return -1;
-  }
-
-  // Try to get transport sequence number.
-  uint16_t transport_senquence_number;
-  if (!rtp_packet.GetExtension<webrtc::TransportSequenceNumber>(
-          &transport_senquence_number)) {
-    // Save packet info without transport sequence number.
-    sent_rtp_packet_map_[datagram_id] = SentPacketInfo(options.packet_id);
-
-    RTC_LOG(LS_VERBOSE)
-        << "Sending rtp packet without transport sequence number, packet="
-        << rtp_packet.ToString();
-
-    return SendDatagram(original_data, datagram_id);
-  }
-
-  // Save packet info with sequence number and ssrc so we could reconstruct
-  // RTCP feedback packet when we receive datagram ACK.
-  sent_rtp_packet_map_[datagram_id] = SentPacketInfo(
-      options.packet_id, rtp_packet.Ssrc(), transport_senquence_number);
-
-  // Since datagram transport provides feedback and timestamps, we do not need
-  // to send transport sequence number, so we remove it from RTP packet. Later
-  // when we get Ack for sent datagram, we will re-create RTCP feedback packet.
-  if (!rtp_packet.RemoveExtension(webrtc::TransportSequenceNumber::kId)) {
-    RTC_NOTREACHED() << "Failed to remove transport sequence number, packet="
-                     << rtp_packet.ToString();
-    return -1;
-  }
-
-  RTC_LOG(LS_VERBOSE) << "Removed transport_senquence_number="
-                      << transport_senquence_number
-                      << " from packet=" << rtp_packet.ToString()
-                      << ", saved bytes=" << len - rtp_packet.size();
-
-  return SendDatagram(
-      rtc::ArrayView<const uint8_t>(rtp_packet.data(), rtp_packet.size()),
-      datagram_id);
-}
-
-int DatagramDtlsAdaptor::SendDatagram(rtc::ArrayView<const uint8_t> data,
-                                      webrtc::DatagramId datagram_id) {
-  webrtc::RTCError error = datagram_transport_->SendDatagram(data, datagram_id);
-  return (error.ok() ? data.size() : -1);
-}
-
-void DatagramDtlsAdaptor::OnReadPacket(rtc::PacketTransportInternal* transport,
-                                       const char* data,
-                                       size_t size,
-                                       const int64_t& packet_time_us,
-                                       int flags) {
-  // Only used in bypass mode.
-  RTC_DCHECK(kBypassDatagramDtlsTestOnly);
-
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-  RTC_DCHECK_EQ(transport, ice_transport_);
-  RTC_DCHECK(flags == 0);
-
-  PropagateReadPacket(
-      rtc::MakeArrayView(reinterpret_cast<const uint8_t*>(data), size),
-      packet_time_us);
-}
-
-void DatagramDtlsAdaptor::OnDatagramReceived(
-    rtc::ArrayView<const uint8_t> data) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-  RTC_DCHECK(!kBypassDatagramDtlsTestOnly);
-
-  // TODO(sukhanov): I am not filling out time, but on my video quality
-  // test in WebRTC the time was not set either and higher layers of the stack
-  // overwrite -1 with current current rtc time. Leaveing comment for now to
-  // make sure it works as expected.
-  int64_t packet_time_us = -1;
-
-  PropagateReadPacket(data, packet_time_us);
-}
-
-void DatagramDtlsAdaptor::OnDatagramSent(webrtc::DatagramId datagram_id) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-
-  // Find packet_id and propagate OnPacketSent notification.
-  const auto& it = sent_rtp_packet_map_.find(datagram_id);
-  if (it == sent_rtp_packet_map_.end()) {
-    RTC_NOTREACHED() << "Did not find sent packet info for sent datagram_id="
-                     << datagram_id;
-    return;
-  }
-
-  // Also see how DatagramDtlsAdaptor::OnSentPacket handles OnSentPacket
-  // notification from ICE in bypass mode.
-  rtc::SentPacket sent_packet(/*packet_id=*/it->second.packet_id,
-                              rtc::TimeMillis());
-
-  PropagateOnSentNotification(sent_packet);
-}
-
-bool DatagramDtlsAdaptor::GetAndRemoveSentPacketInfo(
-    webrtc::DatagramId datagram_id,
-    SentPacketInfo* sent_packet_info) {
-  RTC_CHECK(sent_packet_info != nullptr);
-
-  const auto& it = sent_rtp_packet_map_.find(datagram_id);
-  if (it == sent_rtp_packet_map_.end()) {
-    return false;
-  }
-
-  *sent_packet_info = it->second;
-  sent_rtp_packet_map_.erase(it);
-  return true;
-}
-
-void DatagramDtlsAdaptor::OnDatagramAcked(const webrtc::DatagramAck& ack) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-
-  SentPacketInfo sent_packet_info;
-  if (!GetAndRemoveSentPacketInfo(ack.datagram_id, &sent_packet_info)) {
-    // TODO(sukhanov): If OnDatagramAck() can come after OnDatagramLost(),
-    // datagram_id is already deleted and we may need to relax the CHECK below.
-    // It's probably OK to ignore such datagrams, because it's been a few RTTs
-    // anyway since they were sent.
-    RTC_NOTREACHED() << "Did not find sent packet info for datagram_id="
-                     << ack.datagram_id;
-    return;
-  }
-
-  RTC_LOG(LS_VERBOSE) << "Datagram acked, ack.datagram_id=" << ack.datagram_id
-                      << ", sent_packet_info.packet_id="
-                      << sent_packet_info.packet_id
-                      << ", sent_packet_info.transport_sequence_number="
-                      << sent_packet_info.transport_sequence_number.value_or(-1)
-                      << ", sent_packet_info.ssrc="
-                      << sent_packet_info.ssrc.value_or(-1)
-                      << ", receive_timestamp_ms="
-                      << ack.receive_timestamp.ms();
-
-  // If transport sequence number was not present in RTP packet, we do not need
-  // to propagate RTCP feedback.
-  if (!sent_packet_info.transport_sequence_number) {
-    return;
-  }
-
-  // TODO(sukhanov): We noticed that datagram transport implementations can
-  // return zero timestamps in the middle of the call. This is workaround to
-  // avoid propagating zero timestamps, but we need to understand why we have
-  // them in the first place.
-  int64_t receive_timestamp_us = ack.receive_timestamp.us();
-
-  if (receive_timestamp_us == 0) {
-    receive_timestamp_us = previous_nonzero_timestamp_us_;
-  } else {
-    previous_nonzero_timestamp_us_ = receive_timestamp_us;
-  }
-
-  // Ssrc must be provided in packet info if transport sequence number is set,
-  // which is guaranteed by SentPacketInfo constructor.
-  RTC_CHECK(sent_packet_info.ssrc);
-
-  // Recreate RTCP feedback packet.
-  webrtc::rtcp::TransportFeedback feedback_packet;
-  feedback_packet.SetMediaSsrc(*sent_packet_info.ssrc);
-
-  const uint16_t transport_sequence_number =
-      sent_packet_info.transport_sequence_number.value();
-
-  feedback_packet.SetBase(transport_sequence_number, receive_timestamp_us);
-  feedback_packet.AddReceivedPacket(transport_sequence_number,
-                                    receive_timestamp_us);
-
-  rtc::Buffer buffer(kMaxRtcpFeedbackPacketSize);
-  size_t index = 0;
-  if (!feedback_packet.Create(buffer.data(), &index, buffer.capacity(),
-                              nullptr)) {
-    RTC_NOTREACHED() << "Failed to create RTCP feedback packet";
-    return;
-  }
-
-  RTC_CHECK_GT(index, 0);
-  RTC_CHECK_LE(index, kMaxRtcpFeedbackPacketSize);
-
-  // Propagage created RTCP packet as normal incoming packet.
-  buffer.SetSize(index);
-  PropagateReadPacket(buffer, /*packet_time_us=*/-1);
-}
-
-void DatagramDtlsAdaptor::OnDatagramLost(webrtc::DatagramId datagram_id) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-
-  RTC_LOG(LS_INFO) << "Datagram lost, datagram_id=" << datagram_id;
-
-  SentPacketInfo sent_packet_info;
-  if (!GetAndRemoveSentPacketInfo(datagram_id, &sent_packet_info)) {
-    RTC_NOTREACHED() << "Did not find sent packet info for lost datagram_id="
-                     << datagram_id;
-  }
-}
-
-void DatagramDtlsAdaptor::OnSentPacket(rtc::PacketTransportInternal* transport,
-                                       const rtc::SentPacket& sent_packet) {
-  // Only used in bypass mode.
-  RTC_DCHECK(kBypassDatagramDtlsTestOnly);
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-
-  PropagateOnSentNotification(sent_packet);
-}
-
-void DatagramDtlsAdaptor::PropagateOnSentNotification(
-    const rtc::SentPacket& sent_packet) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-  SignalSentPacket(this, sent_packet);
-}
-
-void DatagramDtlsAdaptor::PropagateReadPacket(
-    rtc::ArrayView<const uint8_t> data,
-    const int64_t& packet_time_us) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-  SignalReadPacket(this, reinterpret_cast<const char*>(data.data()),
-                   data.size(), packet_time_us, /*flags=*/0);
-}
-
-int DatagramDtlsAdaptor::component() const {
-  return kDatagramDtlsAdaptorComponent;
-}
-bool DatagramDtlsAdaptor::IsDtlsActive() const {
-  return false;
-}
-bool DatagramDtlsAdaptor::GetDtlsRole(rtc::SSLRole* role) const {
-  return false;
-}
-bool DatagramDtlsAdaptor::SetDtlsRole(rtc::SSLRole role) {
-  return false;
-}
-bool DatagramDtlsAdaptor::GetSrtpCryptoSuite(int* cipher) {
-  return false;
-}
-bool DatagramDtlsAdaptor::GetSslCipherSuite(int* cipher) {
-  return false;
-}
-
-rtc::scoped_refptr<rtc::RTCCertificate>
-DatagramDtlsAdaptor::GetLocalCertificate() const {
-  return nullptr;
-}
-
-bool DatagramDtlsAdaptor::SetLocalCertificate(
-    const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
-  return false;
-}
-
-std::unique_ptr<rtc::SSLCertChain> DatagramDtlsAdaptor::GetRemoteSSLCertChain()
-    const {
-  return nullptr;
-}
-
-bool DatagramDtlsAdaptor::ExportKeyingMaterial(const std::string& label,
-                                               const uint8_t* context,
-                                               size_t context_len,
-                                               bool use_context,
-                                               uint8_t* result,
-                                               size_t result_len) {
-  return false;
-}
-
-bool DatagramDtlsAdaptor::SetRemoteFingerprint(const std::string& digest_alg,
-                                               const uint8_t* digest,
-                                               size_t digest_len) {
-  // TODO(sukhanov): We probably should not called with fingerptints in
-  // datagram scenario, but we may need to change code up the stack before
-  // we can return false or DCHECK.
-  return true;
-}
-
-bool DatagramDtlsAdaptor::SetSslMaxProtocolVersion(
-    rtc::SSLProtocolVersion version) {
-  // TODO(sukhanov): We may be able to return false and/or DCHECK that we
-  // are not called if datagram transport is used, but we need to change
-  // integration before we can do it.
-  return true;
-}
-
-IceTransportInternal* DatagramDtlsAdaptor::ice_transport() {
-  return ice_transport_;
-}
-
-// Similar implementaton as in p2p/base/dtls_transport.cc.
-void DatagramDtlsAdaptor::OnReadyToSend(
-    rtc::PacketTransportInternal* transport) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-  if (writable()) {
-    SignalReadyToSend(this);
-  }
-}
-
-void DatagramDtlsAdaptor::OnWritableState(
-    rtc::PacketTransportInternal* transport) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-  RTC_DCHECK(transport == ice_transport_);
-  RTC_LOG(LS_VERBOSE) << "ice_transport writable state changed to "
-                      << ice_transport_->writable();
-
-  if (kBypassDatagramDtlsTestOnly) {
-    // Note: SignalWritableState fired by set_writable.
-    set_writable(ice_transport_->writable());
-    return;
-  }
-
-  switch (dtls_state()) {
-    case DTLS_TRANSPORT_NEW:
-      break;
-    case DTLS_TRANSPORT_CONNECTED:
-      // Note: SignalWritableState fired by set_writable.
-      // Do we also need set_receiving(ice_transport_->receiving()) here now, in
-      // case we lose that signal before "DTLS" connects?
-      // DtlsTransport::OnWritableState does not set_receiving in a similar
-      // case, so leaving it out for the time being, but it would be good to
-      // understand why.
-      set_writable(ice_transport_->writable());
-      break;
-    case DTLS_TRANSPORT_CONNECTING:
-      // Do nothing.
-      break;
-    case DTLS_TRANSPORT_FAILED:
-    case DTLS_TRANSPORT_CLOSED:
-      // Should not happen. Do nothing.
-      break;
-  }
-}
-
-void DatagramDtlsAdaptor::OnStateChanged(webrtc::MediaTransportState state) {
-  // Convert MediaTransportState to DTLS state.
-  switch (state) {
-    case webrtc::MediaTransportState::kPending:
-      set_dtls_state(DTLS_TRANSPORT_CONNECTING);
-      break;
-
-    case webrtc::MediaTransportState::kWritable:
-      // Since we do not set writable state until datagram transport is
-      // connected, we need to call set_writable first.
-      set_writable(ice_transport_->writable());
-      set_dtls_state(DTLS_TRANSPORT_CONNECTED);
-      break;
-
-    case webrtc::MediaTransportState::kClosed:
-      set_dtls_state(DTLS_TRANSPORT_CLOSED);
-      break;
-  }
-}
-
-DtlsTransportState DatagramDtlsAdaptor::dtls_state() const {
-  return dtls_state_;
-}
-
-const std::string& DatagramDtlsAdaptor::transport_name() const {
-  return ice_transport_->transport_name();
-}
-
-bool DatagramDtlsAdaptor::writable() const {
-  // NOTE that even if ice is writable, writable_ maybe false, because we
-  // propagte writable only after DTLS is connect (this is consistent with
-  // implementation in dtls_transport.cc).
-  return writable_;
-}
-
-bool DatagramDtlsAdaptor::receiving() const {
-  return receiving_;
-}
-
-int DatagramDtlsAdaptor::SetOption(rtc::Socket::Option opt, int value) {
-  return ice_transport_->SetOption(opt, value);
-}
-
-int DatagramDtlsAdaptor::GetError() {
-  return ice_transport_->GetError();
-}
-
-void DatagramDtlsAdaptor::OnNetworkRouteChanged(
-    absl::optional<rtc::NetworkRoute> network_route) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-  SignalNetworkRouteChanged(network_route);
-}
-
-void DatagramDtlsAdaptor::OnReceivingState(
-    rtc::PacketTransportInternal* transport) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-  RTC_DCHECK(transport == ice_transport_);
-  RTC_LOG(LS_VERBOSE) << "ice_transport receiving state changed to "
-                      << ice_transport_->receiving();
-
-  if (kBypassDatagramDtlsTestOnly || dtls_state() == DTLS_TRANSPORT_CONNECTED) {
-    // Note: SignalReceivingState fired by set_receiving.
-    set_receiving(ice_transport_->receiving());
-  }
-}
-
-void DatagramDtlsAdaptor::set_receiving(bool receiving) {
-  if (receiving_ == receiving) {
-    return;
-  }
-  receiving_ = receiving;
-  SignalReceivingState(this);
-}
-
-// Similar implementaton as in p2p/base/dtls_transport.cc.
-void DatagramDtlsAdaptor::set_writable(bool writable) {
-  if (writable_ == writable) {
-    return;
-  }
-  if (event_log_) {
-    event_log_->Log(
-        absl::make_unique<webrtc::RtcEventDtlsWritableState>(writable));
-  }
-  RTC_LOG(LS_VERBOSE) << "set_writable to: " << writable;
-  writable_ = writable;
-  if (writable_) {
-    SignalReadyToSend(this);
-  }
-  SignalWritableState(this);
-}
-
-// Similar implementaton as in p2p/base/dtls_transport.cc.
-void DatagramDtlsAdaptor::set_dtls_state(DtlsTransportState state) {
-  if (dtls_state_ == state) {
-    return;
-  }
-  if (event_log_) {
-    event_log_->Log(absl::make_unique<webrtc::RtcEventDtlsTransportState>(
-        ConvertDtlsTransportState(state)));
-  }
-  RTC_LOG(LS_VERBOSE) << "set_dtls_state from:" << dtls_state_ << " to "
-                      << state;
-  dtls_state_ = state;
-  SignalDtlsState(this, state);
-}
-
-}  // namespace cricket
diff --git a/pc/datagram_dtls_adaptor.h b/pc/datagram_dtls_adaptor.h
deleted file mode 100644
index 7ebd15b..0000000
--- a/pc/datagram_dtls_adaptor.h
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- *  Copyright 2019 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef PC_DATAGRAM_DTLS_ADAPTOR_H_
-#define PC_DATAGRAM_DTLS_ADAPTOR_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "api/crypto/crypto_options.h"
-#include "api/datagram_transport_interface.h"
-#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
-#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
-#include "p2p/base/dtls_transport_internal.h"
-#include "p2p/base/ice_transport_internal.h"
-#include "p2p/base/packet_transport_internal.h"
-#include "rtc_base/buffer.h"
-#include "rtc_base/buffer_queue.h"
-#include "rtc_base/constructor_magic.h"
-#include "rtc_base/ssl_stream_adapter.h"
-#include "rtc_base/stream.h"
-#include "rtc_base/strings/string_builder.h"
-#include "rtc_base/thread_checker.h"
-
-namespace cricket {
-
-constexpr int kDatagramDtlsAdaptorComponent = -1;
-
-// DTLS wrapper around DatagramTransportInterface.
-// Does not encrypt.
-// Owns Datagram and Ice transports.
-class DatagramDtlsAdaptor : public DtlsTransportInternal,
-                            public webrtc::DatagramSinkInterface,
-                            public webrtc::MediaTransportStateCallback {
- public:
-  // TODO(sukhanov): Taking crypto options, because DtlsTransportInternal
-  // has a virtual getter crypto_options(). Consider removing getter and
-  // removing crypto_options from DatagramDtlsAdaptor.
-  DatagramDtlsAdaptor(
-      const std::vector<webrtc::RtpExtension>& rtp_header_extensions,
-      IceTransportInternal* ice_transport,
-      webrtc::DatagramTransportInterface* datagram_transport,
-      const webrtc::CryptoOptions& crypto_options,
-      webrtc::RtcEventLog* event_log);
-
-  ~DatagramDtlsAdaptor() override;
-
-  // Connects to ICE transport callbacks.
-  void ConnectToIceTransport();
-
-  // =====================================================
-  // Overrides for webrtc::DatagramTransportSinkInterface
-  // and MediaTransportStateCallback
-  // =====================================================
-  void OnDatagramReceived(rtc::ArrayView<const uint8_t> data) override;
-
-  void OnDatagramSent(webrtc::DatagramId datagram_id) override;
-
-  void OnDatagramAcked(const webrtc::DatagramAck& ack) override;
-
-  void OnDatagramLost(webrtc::DatagramId datagram_id) override;
-
-  void OnStateChanged(webrtc::MediaTransportState state) override;
-
-  // =====================================================
-  // DtlsTransportInternal overrides
-  // =====================================================
-  const webrtc::CryptoOptions& crypto_options() const override;
-  DtlsTransportState dtls_state() const override;
-  int component() const override;
-  bool IsDtlsActive() const override;
-  bool GetDtlsRole(rtc::SSLRole* role) const override;
-  bool SetDtlsRole(rtc::SSLRole role) override;
-  bool GetSrtpCryptoSuite(int* cipher) override;
-  bool GetSslCipherSuite(int* cipher) override;
-  rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const override;
-  bool SetLocalCertificate(
-      const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override;
-  std::unique_ptr<rtc::SSLCertChain> GetRemoteSSLCertChain() const override;
-  bool ExportKeyingMaterial(const std::string& label,
-                            const uint8_t* context,
-                            size_t context_len,
-                            bool use_context,
-                            uint8_t* result,
-                            size_t result_len) override;
-  bool SetRemoteFingerprint(const std::string& digest_alg,
-                            const uint8_t* digest,
-                            size_t digest_len) override;
-  bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override;
-  IceTransportInternal* ice_transport() override;
-
-  const std::string& transport_name() const override;
-  bool writable() const override;
-  bool receiving() const override;
-
- private:
-  // RTP/RTCP packet info stored for each sent packet.
-  struct SentPacketInfo {
-    // RTP packet info with ssrc and transport sequence number.
-    SentPacketInfo(int64_t packet_id,
-                   uint32_t ssrc,
-                   uint16_t transport_sequence_number)
-        : ssrc(ssrc),
-          transport_sequence_number(transport_sequence_number),
-          packet_id(packet_id) {}
-
-    // Packet info without SSRC and transport sequence number used for RTCP
-    // packets, RTP packets when transport sequence number is not provided or
-    // when feedback translation is disabled.
-    explicit SentPacketInfo(int64_t packet_id) : packet_id(packet_id) {}
-
-    SentPacketInfo() = default;
-
-    absl::optional<uint32_t> ssrc;
-
-    // Transport sequence number (if it was provided in outgoing RTP packet).
-    // It is used to re-create RTCP feedback packets from datagram ACKs.
-    absl::optional<uint16_t> transport_sequence_number;
-
-    // Packet id from rtc::PacketOptions. It is required to propagage sent
-    // notification up the stack (SignalSentPacket).
-    int64_t packet_id = 0;
-  };
-
-  // Finds SentPacketInfo for given |datagram_id| and removes map entry.
-  // Returns false if entry was not found.
-  bool GetAndRemoveSentPacketInfo(webrtc::DatagramId datagram_id,
-                                  SentPacketInfo* sent_packet_info);
-
-  // Sends datagram to datagram_transport.
-  int SendDatagram(rtc::ArrayView<const uint8_t> data,
-                   webrtc::DatagramId datagram_id);
-
-  void set_receiving(bool receiving);
-  void set_writable(bool writable);
-  void set_dtls_state(DtlsTransportState state);
-
-  // Forwards incoming packet up the stack.
-  void PropagateReadPacket(rtc::ArrayView<const uint8_t> data,
-                           const int64_t& packet_time_us);
-
-  // Signals SentPacket notification.
-  void PropagateOnSentNotification(const rtc::SentPacket& sent_packet);
-
-  // Listens to read packet notifications from ICE (only used in bypass mode).
-  void OnReadPacket(rtc::PacketTransportInternal* transport,
-                    const char* data,
-                    size_t size,
-                    const int64_t& packet_time_us,
-                    int flags);
-
-  void OnReadyToSend(rtc::PacketTransportInternal* transport);
-  void OnWritableState(rtc::PacketTransportInternal* transport);
-  void OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route);
-  void OnReceivingState(rtc::PacketTransportInternal* transport);
-
-  int SendPacket(const char* data,
-                 size_t len,
-                 const rtc::PacketOptions& options,
-                 int flags) override;
-  int SetOption(rtc::Socket::Option opt, int value) override;
-  int GetError() override;
-  void OnSentPacket(rtc::PacketTransportInternal* transport,
-                    const rtc::SentPacket& sent_packet);
-
-  rtc::ThreadChecker thread_checker_;
-  webrtc::CryptoOptions crypto_options_;
-  IceTransportInternal* ice_transport_;
-
-  webrtc::DatagramTransportInterface* datagram_transport_;
-
-  // Current ICE writable state. Must be modified by calling set_ice_writable(),
-  // which propagates change notifications.
-  bool writable_ = false;
-
-  // Current receiving state. Must be modified by calling set_receiving(), which
-  // propagates change notifications.
-  bool receiving_ = false;
-
-  // Current DTLS state. Must be modified by calling set_dtls_state(), which
-  // propagates change notifications.
-  DtlsTransportState dtls_state_ = DTLS_TRANSPORT_NEW;
-
-  webrtc::RtcEventLog* const event_log_;
-
-  // Extension map for parsing transport sequence numbers.
-  webrtc::RtpHeaderExtensionMap rtp_header_extension_map_;
-
-  // Keeps information about sent RTP packet until they are Acked or Lost.
-  std::map<webrtc::DatagramId, SentPacketInfo> sent_rtp_packet_map_;
-
-  // Current datagram_id, incremented after each sent RTP packets.
-  // Datagram id is passed to datagram transport when we send datagram and we
-  // get it back in notifications about Sent, Acked and Lost datagrams.
-  int64_t current_datagram_id_ = 0;
-
-  // TODO(sukhanov): Previous nonzero timestamp is required for workaround for
-  // zero timestamps received, which sometimes are received from datagram
-  // transport. Investigate if we can eliminate zero timestamps.
-  int64_t previous_nonzero_timestamp_us_ = 0;
-
-  // Disable datagram to RTCP feedback translation and enable RTCP feedback
-  // loop (note that having both RTCP and datagram feedback loops is
-  // inefficient, but can be useful in tests and experiments).
-  const bool disable_datagram_to_rtcp_feeback_translation_;
-};
-
-}  // namespace cricket
-
-#endif  // PC_DATAGRAM_DTLS_ADAPTOR_H_
diff --git a/pc/datagram_rtp_transport.cc b/pc/datagram_rtp_transport.cc
new file mode 100644
index 0000000..ebf82a7
--- /dev/null
+++ b/pc/datagram_rtp_transport.cc
@@ -0,0 +1,387 @@
+/*
+ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "pc/datagram_rtp_transport.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/rtc_error.h"
+#include "media/base/rtp_utils.h"
+#include "modules/rtp_rtcp/include/rtp_header_parser.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "modules/rtp_rtcp/source/rtp_packet.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "p2p/base/dtls_transport_internal.h"
+#include "p2p/base/packet_transport_internal.h"
+#include "rtc_base/buffer.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/dscp.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/message_queue.h"
+#include "rtc_base/rtc_certificate.h"
+#include "rtc_base/ssl_stream_adapter.h"
+#include "rtc_base/stream.h"
+#include "rtc_base/thread.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+
+namespace {
+
+// Field trials.
+// Disable datagram to RTCP feedback translation and enable RTCP feedback loop
+// on top of datagram feedback loop. Note that two
+// feedback loops add unneccesary overhead, so it's preferable to use feedback
+// loop provided by datagram transport and convert datagram ACKs to RTCP ACKs,
+// but enabling RTCP feedback loop may be useful in tests and experiments.
+const char kDisableDatagramToRtcpFeebackTranslationFieldTrial[] =
+    "WebRTC-kDisableDatagramToRtcpFeebackTranslation";
+
+}  // namespace
+
+// Maximum packet size of RTCP feedback packet for allocation. We re-create RTCP
+// feedback packets when we get ACK notifications from datagram transport. Our
+// rtcp feedback packets contain only 1 ACK, so they are much smaller than 1250.
+constexpr size_t kMaxRtcpFeedbackPacketSize = 1250;
+
+DatagramRtpTransport::DatagramRtpTransport(
+    const std::vector<RtpExtension>& rtp_header_extensions,
+    cricket::IceTransportInternal* ice_transport,
+    DatagramTransportInterface* datagram_transport)
+    : ice_transport_(ice_transport),
+      datagram_transport_(datagram_transport),
+      disable_datagram_to_rtcp_feeback_translation_(field_trial::IsEnabled(
+          kDisableDatagramToRtcpFeebackTranslationFieldTrial)) {
+  // Save extension map for parsing RTP packets (we only need transport
+  // sequence numbers).
+  const RtpExtension* transport_sequence_number_extension =
+      RtpExtension::FindHeaderExtensionByUri(rtp_header_extensions,
+                                             TransportSequenceNumber::kUri);
+
+  if (transport_sequence_number_extension != nullptr) {
+    rtp_header_extension_map_.Register<TransportSequenceNumber>(
+        transport_sequence_number_extension->id);
+  } else {
+    RTC_LOG(LS_ERROR) << "Transport sequence numbers are not supported in "
+                         "datagram transport connection";
+  }
+
+  // TODO(sukhanov): Add CHECK to make sure that field trial
+  // WebRTC-ExcludeTransportSequenceNumberFromFecFieldTrial is enabled.
+  // If feedback loop is translation is enabled, FEC packets must exclude
+  // transport sequence numbers, otherwise recovered packets will be corrupt.
+
+  RTC_DCHECK(ice_transport_);
+  RTC_DCHECK(datagram_transport_);
+
+  ice_transport_->SignalNetworkRouteChanged.connect(
+      this, &DatagramRtpTransport::OnNetworkRouteChanged);
+  // Subscribe to DatagramTransport to read incoming packets.
+  datagram_transport_->SetDatagramSink(this);
+  datagram_transport_->SetTransportStateCallback(this);
+}
+
+DatagramRtpTransport::~DatagramRtpTransport() {
+  // Unsubscribe from DatagramTransport sinks.
+  datagram_transport_->SetDatagramSink(nullptr);
+  datagram_transport_->SetTransportStateCallback(nullptr);
+}
+
+bool DatagramRtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
+                                         const rtc::PacketOptions& options,
+                                         int flags) {
+  RTC_DCHECK_RUN_ON(&thread_checker_);
+
+  // Assign and increment datagram_id.
+  const DatagramId datagram_id = current_datagram_id_++;
+
+  // Send as is (without extracting transport sequence number) for
+  // RTP packets if we are not doing datagram => RTCP feedback translation.
+  if (disable_datagram_to_rtcp_feeback_translation_) {
+    // Even if we are not extracting transport sequence number we need to
+    // propagate "Sent" notification for both RTP and RTCP packets. For this
+    // reason we need save options.packet_id in packet map.
+    sent_rtp_packet_map_[datagram_id] = SentPacketInfo(options.packet_id);
+
+    return SendDatagram(*packet, datagram_id);
+  }
+
+  // Parse RTP packet.
+  RtpPacket rtp_packet(&rtp_header_extension_map_);
+  // TODO(mellem): Verify that this doesn't mangle something (it shouldn't).
+  if (!rtp_packet.Parse(*packet)) {
+    RTC_NOTREACHED() << "Failed to parse outgoing RtpPacket, len="
+                     << packet->size()
+                     << ", options.packet_id=" << options.packet_id;
+    return -1;
+  }
+
+  // Try to get transport sequence number.
+  uint16_t transport_senquence_number;
+  if (!rtp_packet.GetExtension<TransportSequenceNumber>(
+          &transport_senquence_number)) {
+    // Save packet info without transport sequence number.
+    sent_rtp_packet_map_[datagram_id] = SentPacketInfo(options.packet_id);
+
+    RTC_LOG(LS_VERBOSE)
+        << "Sending rtp packet without transport sequence number, packet="
+        << rtp_packet.ToString();
+
+    return SendDatagram(*packet, datagram_id);
+  }
+
+  // Save packet info with sequence number and ssrc so we could reconstruct
+  // RTCP feedback packet when we receive datagram ACK.
+  sent_rtp_packet_map_[datagram_id] = SentPacketInfo(
+      options.packet_id, rtp_packet.Ssrc(), transport_senquence_number);
+
+  // Since datagram transport provides feedback and timestamps, we do not need
+  // to send transport sequence number, so we remove it from RTP packet. Later
+  // when we get Ack for sent datagram, we will re-create RTCP feedback packet.
+  if (!rtp_packet.RemoveExtension(TransportSequenceNumber::kId)) {
+    RTC_NOTREACHED() << "Failed to remove transport sequence number, packet="
+                     << rtp_packet.ToString();
+    return -1;
+  }
+
+  RTC_LOG(LS_VERBOSE) << "Removed transport_senquence_number="
+                      << transport_senquence_number
+                      << " from packet=" << rtp_packet.ToString()
+                      << ", saved bytes=" << packet->size() - rtp_packet.size();
+
+  return SendDatagram(
+      rtc::ArrayView<const uint8_t>(rtp_packet.data(), rtp_packet.size()),
+      datagram_id);
+}
+
+bool DatagramRtpTransport::SendRtcpPacket(rtc::CopyOnWriteBuffer* packet,
+                                          const rtc::PacketOptions& options,
+                                          int flags) {
+  RTC_DCHECK_RUN_ON(&thread_checker_);
+
+  // Assign and increment datagram_id.
+  const DatagramId datagram_id = current_datagram_id_++;
+
+  // Even if we are not extracting transport sequence number we need to
+  // propagate "Sent" notification for both RTP and RTCP packets. For this
+  // reason we need save options.packet_id in packet map.
+  sent_rtp_packet_map_[datagram_id] = SentPacketInfo(options.packet_id);
+  return SendDatagram(*packet, datagram_id);
+}
+
+bool DatagramRtpTransport::SendDatagram(rtc::ArrayView<const uint8_t> data,
+                                        DatagramId datagram_id) {
+  return datagram_transport_->SendDatagram(data, datagram_id).ok();
+}
+
+void DatagramRtpTransport::OnDatagramReceived(
+    rtc::ArrayView<const uint8_t> data) {
+  RTC_DCHECK_RUN_ON(&thread_checker_);
+
+  rtc::ArrayView<const char> cdata(reinterpret_cast<const char*>(data.data()),
+                                   data.size());
+  if (cricket::InferRtpPacketType(cdata) == cricket::RtpPacketType::kRtcp) {
+    rtc::CopyOnWriteBuffer buffer(data.data(), data.size());
+    SignalRtcpPacketReceived(&buffer, /*packet_time_us=*/-1);
+    return;
+  }
+
+  // TODO(sukhanov): I am not filling out time, but on my video quality
+  // test in WebRTC the time was not set either and higher layers of the stack
+  // overwrite -1 with current current rtc time. Leaveing comment for now to
+  // make sure it works as expected.
+  RtpPacketReceived parsed_packet(&rtp_header_extension_map_);
+  if (!parsed_packet.Parse(data)) {
+    RTC_LOG(LS_ERROR) << "Failed to parse incoming RTP packet";
+    return;
+  }
+  if (!rtp_demuxer_.OnRtpPacket(parsed_packet)) {
+    RTC_LOG(LS_WARNING) << "Failed to demux RTP packet: "
+                        << RtpDemuxer::DescribePacket(parsed_packet);
+  }
+}
+
+void DatagramRtpTransport::OnDatagramSent(DatagramId datagram_id) {
+  RTC_DCHECK_RUN_ON(&thread_checker_);
+
+  // Find packet_id and propagate OnPacketSent notification.
+  const auto& it = sent_rtp_packet_map_.find(datagram_id);
+  if (it == sent_rtp_packet_map_.end()) {
+    RTC_NOTREACHED() << "Did not find sent packet info for sent datagram_id="
+                     << datagram_id;
+    return;
+  }
+
+  // Also see how DatagramRtpTransport::OnSentPacket handles OnSentPacket
+  // notification from ICE in bypass mode.
+  rtc::SentPacket sent_packet(/*packet_id=*/it->second.packet_id,
+                              rtc::TimeMillis());
+
+  SignalSentPacket(sent_packet);
+}
+
+bool DatagramRtpTransport::GetAndRemoveSentPacketInfo(
+    DatagramId datagram_id,
+    SentPacketInfo* sent_packet_info) {
+  RTC_CHECK(sent_packet_info != nullptr);
+
+  const auto& it = sent_rtp_packet_map_.find(datagram_id);
+  if (it == sent_rtp_packet_map_.end()) {
+    return false;
+  }
+
+  *sent_packet_info = it->second;
+  sent_rtp_packet_map_.erase(it);
+  return true;
+}
+
+void DatagramRtpTransport::OnDatagramAcked(const DatagramAck& ack) {
+  RTC_DCHECK_RUN_ON(&thread_checker_);
+
+  SentPacketInfo sent_packet_info;
+  if (!GetAndRemoveSentPacketInfo(ack.datagram_id, &sent_packet_info)) {
+    // TODO(sukhanov): If OnDatagramAck() can come after OnDatagramLost(),
+    // datagram_id is already deleted and we may need to relax the CHECK below.
+    // It's probably OK to ignore such datagrams, because it's been a few RTTs
+    // anyway since they were sent.
+    RTC_NOTREACHED() << "Did not find sent packet info for datagram_id="
+                     << ack.datagram_id;
+    return;
+  }
+
+  RTC_LOG(LS_VERBOSE) << "Datagram acked, ack.datagram_id=" << ack.datagram_id
+                      << ", sent_packet_info.packet_id="
+                      << sent_packet_info.packet_id
+                      << ", sent_packet_info.transport_sequence_number="
+                      << sent_packet_info.transport_sequence_number.value_or(-1)
+                      << ", sent_packet_info.ssrc="
+                      << sent_packet_info.ssrc.value_or(-1)
+                      << ", receive_timestamp_ms="
+                      << ack.receive_timestamp.ms();
+
+  // If transport sequence number was not present in RTP packet, we do not need
+  // to propagate RTCP feedback.
+  if (!sent_packet_info.transport_sequence_number) {
+    return;
+  }
+
+  // TODO(sukhanov): We noticed that datagram transport implementations can
+  // return zero timestamps in the middle of the call. This is workaround to
+  // avoid propagating zero timestamps, but we need to understand why we have
+  // them in the first place.
+  int64_t receive_timestamp_us = ack.receive_timestamp.us();
+
+  if (receive_timestamp_us == 0) {
+    receive_timestamp_us = previous_nonzero_timestamp_us_;
+  } else {
+    previous_nonzero_timestamp_us_ = receive_timestamp_us;
+  }
+
+  // Ssrc must be provided in packet info if transport sequence number is set,
+  // which is guaranteed by SentPacketInfo constructor.
+  RTC_CHECK(sent_packet_info.ssrc);
+
+  // Recreate RTCP feedback packet.
+  rtcp::TransportFeedback feedback_packet;
+  feedback_packet.SetMediaSsrc(*sent_packet_info.ssrc);
+
+  const uint16_t transport_sequence_number =
+      sent_packet_info.transport_sequence_number.value();
+
+  feedback_packet.SetBase(transport_sequence_number, receive_timestamp_us);
+  feedback_packet.AddReceivedPacket(transport_sequence_number,
+                                    receive_timestamp_us);
+
+  rtc::CopyOnWriteBuffer buffer(kMaxRtcpFeedbackPacketSize);
+  size_t index = 0;
+  if (!feedback_packet.Create(buffer.data(), &index, buffer.capacity(),
+                              nullptr)) {
+    RTC_NOTREACHED() << "Failed to create RTCP feedback packet";
+    return;
+  }
+
+  RTC_CHECK_GT(index, 0);
+  RTC_CHECK_LE(index, kMaxRtcpFeedbackPacketSize);
+
+  // Propagage created RTCP packet as normal incoming packet.
+  buffer.SetSize(index);
+  SignalRtcpPacketReceived(&buffer, /*packet_time_us=*/-1);
+}
+
+void DatagramRtpTransport::OnDatagramLost(DatagramId datagram_id) {
+  RTC_DCHECK_RUN_ON(&thread_checker_);
+
+  RTC_LOG(LS_INFO) << "Datagram lost, datagram_id=" << datagram_id;
+
+  SentPacketInfo sent_packet_info;
+  if (!GetAndRemoveSentPacketInfo(datagram_id, &sent_packet_info)) {
+    RTC_NOTREACHED() << "Did not find sent packet info for lost datagram_id="
+                     << datagram_id;
+  }
+}
+
+void DatagramRtpTransport::OnStateChanged(MediaTransportState state) {
+  state_ = state;
+  SignalWritableState(state_ == MediaTransportState::kWritable);
+  if (state_ == MediaTransportState::kWritable) {
+    SignalReadyToSend(true);
+  }
+}
+
+const std::string& DatagramRtpTransport::transport_name() const {
+  return ice_transport_->transport_name();
+}
+
+int DatagramRtpTransport::SetRtpOption(rtc::Socket::Option opt, int value) {
+  return ice_transport_->SetOption(opt, value);
+}
+
+int DatagramRtpTransport::SetRtcpOption(rtc::Socket::Option opt, int value) {
+  return -1;
+}
+
+bool DatagramRtpTransport::IsReadyToSend() const {
+  return state_ == MediaTransportState::kWritable;
+}
+
+bool DatagramRtpTransport::IsWritable(bool /*rtcp*/) const {
+  return state_ == MediaTransportState::kWritable;
+}
+
+void DatagramRtpTransport::UpdateRtpHeaderExtensionMap(
+    const cricket::RtpHeaderExtensions& header_extensions) {
+  rtp_header_extension_map_ = RtpHeaderExtensionMap(header_extensions);
+}
+
+bool DatagramRtpTransport::RegisterRtpDemuxerSink(
+    const RtpDemuxerCriteria& criteria,
+    RtpPacketSinkInterface* sink) {
+  rtp_demuxer_.RemoveSink(sink);
+  return rtp_demuxer_.AddSink(criteria, sink);
+}
+
+bool DatagramRtpTransport::UnregisterRtpDemuxerSink(
+    RtpPacketSinkInterface* sink) {
+  return rtp_demuxer_.RemoveSink(sink);
+}
+
+void DatagramRtpTransport::OnNetworkRouteChanged(
+    absl::optional<rtc::NetworkRoute> network_route) {
+  RTC_DCHECK_RUN_ON(&thread_checker_);
+  SignalNetworkRouteChanged(network_route);
+}
+
+}  // namespace webrtc
diff --git a/pc/datagram_rtp_transport.h b/pc/datagram_rtp_transport.h
new file mode 100644
index 0000000..1dfa37b
--- /dev/null
+++ b/pc/datagram_rtp_transport.h
@@ -0,0 +1,172 @@
+/*
+ *  Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef PC_DATAGRAM_RTP_TRANSPORT_H_
+#define PC_DATAGRAM_RTP_TRANSPORT_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "api/crypto/crypto_options.h"
+#include "api/datagram_transport_interface.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "p2p/base/ice_transport_internal.h"
+#include "p2p/base/packet_transport_internal.h"
+#include "pc/rtp_transport_internal.h"
+#include "rtc_base/buffer.h"
+#include "rtc_base/buffer_queue.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/ssl_stream_adapter.h"
+#include "rtc_base/stream.h"
+#include "rtc_base/strings/string_builder.h"
+#include "rtc_base/thread_checker.h"
+
+namespace webrtc {
+
+constexpr int kDatagramDtlsAdaptorComponent = -1;
+
+// RTP transport which uses the DatagramTransportInterface to send and receive
+// packets.
+class DatagramRtpTransport : public RtpTransportInternal,
+                             public webrtc::DatagramSinkInterface,
+                             public webrtc::MediaTransportStateCallback {
+ public:
+  DatagramRtpTransport(
+      const std::vector<webrtc::RtpExtension>& rtp_header_extensions,
+      cricket::IceTransportInternal* ice_transport,
+      DatagramTransportInterface* datagram_transport);
+
+  ~DatagramRtpTransport() override;
+
+  // =====================================================
+  // Overrides for webrtc::DatagramTransportSinkInterface
+  // and MediaTransportStateCallback
+  // =====================================================
+  void OnDatagramReceived(rtc::ArrayView<const uint8_t> data) override;
+
+  void OnDatagramSent(webrtc::DatagramId datagram_id) override;
+
+  void OnDatagramAcked(const webrtc::DatagramAck& ack) override;
+
+  void OnDatagramLost(webrtc::DatagramId datagram_id) override;
+
+  void OnStateChanged(webrtc::MediaTransportState state) override;
+
+  // =====================================================
+  // RtpTransportInternal overrides
+  // =====================================================
+  bool SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
+                     const rtc::PacketOptions& options,
+                     int flags) override;
+
+  bool SendRtcpPacket(rtc::CopyOnWriteBuffer* packet,
+                      const rtc::PacketOptions& options,
+                      int flags) override;
+
+  const std::string& transport_name() const override;
+
+  // Datagram transport always muxes RTCP.
+  bool rtcp_mux_enabled() const override { return true; }
+  void SetRtcpMuxEnabled(bool enable) override {}
+
+  int SetRtpOption(rtc::Socket::Option opt, int value) override;
+  int SetRtcpOption(rtc::Socket::Option opt, int value) override;
+
+  bool IsReadyToSend() const override;
+
+  bool IsWritable(bool rtcp) const override;
+
+  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;
+
+ private:
+  // RTP/RTCP packet info stored for each sent packet.
+  struct SentPacketInfo {
+    // RTP packet info with ssrc and transport sequence number.
+    SentPacketInfo(int64_t packet_id,
+                   uint32_t ssrc,
+                   uint16_t transport_sequence_number)
+        : ssrc(ssrc),
+          transport_sequence_number(transport_sequence_number),
+          packet_id(packet_id) {}
+
+    // Packet info without SSRC and transport sequence number used for RTCP
+    // packets, RTP packets when transport sequence number is not provided or
+    // when feedback translation is disabled.
+    explicit SentPacketInfo(int64_t packet_id) : packet_id(packet_id) {}
+
+    SentPacketInfo() = default;
+
+    absl::optional<uint32_t> ssrc;
+
+    // Transport sequence number (if it was provided in outgoing RTP packet).
+    // It is used to re-create RTCP feedback packets from datagram ACKs.
+    absl::optional<uint16_t> transport_sequence_number;
+
+    // Packet id from rtc::PacketOptions. It is required to propagage sent
+    // notification up the stack (SignalSentPacket).
+    int64_t packet_id = 0;
+  };
+
+  // Finds SentPacketInfo for given |datagram_id| and removes map entry.
+  // Returns false if entry was not found.
+  bool GetAndRemoveSentPacketInfo(webrtc::DatagramId datagram_id,
+                                  SentPacketInfo* sent_packet_info);
+
+  // Sends datagram to datagram_transport.
+  bool SendDatagram(rtc::ArrayView<const uint8_t> data,
+                    webrtc::DatagramId datagram_id);
+
+  // Propagates network route changes from ICE.
+  void OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route);
+
+  rtc::ThreadChecker thread_checker_;
+  cricket::IceTransportInternal* ice_transport_;
+  webrtc::DatagramTransportInterface* datagram_transport_;
+
+  RtpDemuxer rtp_demuxer_;
+
+  MediaTransportState state_ = MediaTransportState::kPending;
+
+  // Extension map for parsing transport sequence numbers.
+  webrtc::RtpHeaderExtensionMap rtp_header_extension_map_;
+
+  // Keeps information about sent RTP packet until they are Acked or Lost.
+  std::map<webrtc::DatagramId, SentPacketInfo> sent_rtp_packet_map_;
+
+  // Current datagram_id, incremented after each sent RTP packets.
+  // Datagram id is passed to datagram transport when we send datagram and we
+  // get it back in notifications about Sent, Acked and Lost datagrams.
+  int64_t current_datagram_id_ = 0;
+
+  // TODO(sukhanov): Previous nonzero timestamp is required for workaround for
+  // zero timestamps received, which sometimes are received from datagram
+  // transport. Investigate if we can eliminate zero timestamps.
+  int64_t previous_nonzero_timestamp_us_ = 0;
+
+  // Disable datagram to RTCP feedback translation and enable RTCP feedback
+  // loop (note that having both RTCP and datagram feedback loops is
+  // inefficient, but can be useful in tests and experiments).
+  const bool disable_datagram_to_rtcp_feeback_translation_;
+};
+
+}  // namespace webrtc
+
+#endif  // PC_DATAGRAM_RTP_TRANSPORT_H_
diff --git a/pc/jsep_transport.cc b/pc/jsep_transport.cc
index e32f279..e710f09 100644
--- a/pc/jsep_transport.cc
+++ b/pc/jsep_transport.cc
@@ -99,10 +99,9 @@
     std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport,
     std::unique_ptr<webrtc::SrtpTransport> sdes_transport,
     std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport,
-    std::unique_ptr<webrtc::RtpTransport> datagram_rtp_transport,
+    std::unique_ptr<webrtc::RtpTransportInternal> datagram_rtp_transport,
     std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport,
     std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport,
-    std::unique_ptr<DtlsTransportInternal> datagram_dtls_transport,
     std::unique_ptr<webrtc::MediaTransportInterface> media_transport,
     std::unique_ptr<webrtc::DatagramTransportInterface> datagram_transport)
     : network_thread_(rtc::Thread::Current()),
@@ -123,11 +122,6 @@
               ? new rtc::RefCountedObject<webrtc::DtlsTransport>(
                     std::move(rtcp_dtls_transport))
               : nullptr),
-      datagram_dtls_transport_(
-          datagram_dtls_transport
-              ? new rtc::RefCountedObject<webrtc::DtlsTransport>(
-                    std::move(datagram_dtls_transport))
-              : nullptr),
       media_transport_(std::move(media_transport)),
       datagram_transport_(std::move(datagram_transport)) {
   RTC_DCHECK(ice_transport_);
@@ -176,13 +170,8 @@
     rtcp_dtls_transport_->Clear();
   }
 
-  // Datagram dtls transport must be disconnected before the datagram transport
-  // is released.
-  if (datagram_dtls_transport_) {
-    datagram_dtls_transport_->Clear();
-  }
-
-  // Delete datagram transport before ICE, but after DTLS transport.
+  // Delete datagram transport before ICE, but after its RTP transport.
+  datagram_rtp_transport_.reset();
   datagram_transport_.reset();
 
   // ICE will be the last transport to be deleted.
@@ -533,9 +522,6 @@
   }
   {
     rtc::CritScope scope(&accessor_lock_);
-    if (datagram_rtp_transport_) {
-      datagram_rtp_transport_->SetRtcpPacketTransport(nullptr);
-    }
     if (unencrypted_rtp_transport_) {
       RTC_DCHECK(!sdes_transport_);
       RTC_DCHECK(!dtls_srtp_transport_);
@@ -822,9 +808,6 @@
     RTC_LOG(INFO) << "Datagram transport rejected";
     composite_rtp_transport_->RemoveTransport(datagram_rtp_transport_.get());
     datagram_rtp_transport_ = nullptr;
-    // This one is ref-counted, so it can't be deleted directly.
-    datagram_dtls_transport_->Clear();
-    datagram_dtls_transport_ = nullptr;
     datagram_transport_ = nullptr;
   }
 }
diff --git a/pc/jsep_transport.h b/pc/jsep_transport.h
index 479c0ae..59b2276 100644
--- a/pc/jsep_transport.h
+++ b/pc/jsep_transport.h
@@ -93,10 +93,9 @@
       std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport,
       std::unique_ptr<webrtc::SrtpTransport> sdes_transport,
       std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport,
-      std::unique_ptr<webrtc::RtpTransport> datagram_rtp_transport,
+      std::unique_ptr<webrtc::RtpTransportInternal> datagram_rtp_transport,
       std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport,
       std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport,
-      std::unique_ptr<DtlsTransportInternal> datagram_dtls_transport,
       std::unique_ptr<webrtc::MediaTransportInterface> media_transport,
       std::unique_ptr<webrtc::DatagramTransportInterface> datagram_transport);
 
@@ -349,7 +348,7 @@
       RTC_GUARDED_BY(accessor_lock_);
   std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport_
       RTC_GUARDED_BY(accessor_lock_);
-  std::unique_ptr<webrtc::RtpTransport> datagram_rtp_transport_
+  std::unique_ptr<webrtc::RtpTransportInternal> datagram_rtp_transport_
       RTC_GUARDED_BY(accessor_lock_);
 
   // If multiple RTP transports are in use, |composite_rtp_transport_| will be
diff --git a/pc/jsep_transport_controller.cc b/pc/jsep_transport_controller.cc
index 980deb6..ea14523 100644
--- a/pc/jsep_transport_controller.cc
+++ b/pc/jsep_transport_controller.cc
@@ -20,7 +20,7 @@
 #include "p2p/base/ice_transport_internal.h"
 #include "p2p/base/no_op_dtls_transport.h"
 #include "p2p/base/port.h"
-#include "pc/datagram_dtls_adaptor.h"
+#include "pc/datagram_rtp_transport.h"
 #include "pc/srtp_filter.h"
 #include "rtc_base/bind.h"
 #include "rtc_base/checks.h"
@@ -483,11 +483,6 @@
 
   if (datagram_transport) {
     RTC_DCHECK(config_.use_datagram_transport);
-
-    // Create DTLS wrapper around DatagramTransportInterface.
-    dtls = absl::make_unique<cricket::DatagramDtlsAdaptor>(
-        content_info.media_description()->rtp_header_extensions(), ice,
-        datagram_transport, config_.crypto_options, config_.event_log);
   } else if (config_.media_transport_factory &&
              config_.use_media_transport_for_media &&
              config_.use_media_transport_for_data_channels) {
@@ -1164,11 +1159,8 @@
 
   std::unique_ptr<DatagramTransportInterface> datagram_transport =
       MaybeCreateDatagramTransport(content_info, description, local);
-  std::unique_ptr<cricket::DtlsTransportInternal> datagram_dtls_transport;
   if (datagram_transport) {
     datagram_transport->Connect(ice.get());
-    datagram_dtls_transport =
-        CreateDtlsTransport(content_info, ice.get(), datagram_transport.get());
   }
 
   std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
@@ -1178,7 +1170,7 @@
   std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
   std::unique_ptr<SrtpTransport> sdes_transport;
   std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
-  std::unique_ptr<RtpTransport> datagram_rtp_transport;
+  std::unique_ptr<RtpTransportInternal> datagram_rtp_transport;
 
   std::unique_ptr<cricket::IceTransportInternal> rtcp_ice;
   if (config_.rtcp_mux_policy !=
@@ -1202,8 +1194,9 @@
     RTC_LOG(LS_INFO) << "Creating UnencryptedRtpTransport, because datagram "
                         "transport is used.";
     RTC_DCHECK(!rtcp_dtls_transport);
-    datagram_rtp_transport = CreateUnencryptedRtpTransport(
-        content_info.name, datagram_dtls_transport.get(), nullptr);
+    datagram_rtp_transport = absl::make_unique<DatagramRtpTransport>(
+        content_info.media_description()->rtp_header_extensions(), ice.get(),
+        datagram_transport.get());
   }
 
   if (config_.disable_encryption) {
@@ -1227,8 +1220,7 @@
           std::move(unencrypted_rtp_transport), std::move(sdes_transport),
           std::move(dtls_srtp_transport), std::move(datagram_rtp_transport),
           std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
-          std::move(datagram_dtls_transport), std::move(media_transport),
-          std::move(datagram_transport));
+          std::move(media_transport), std::move(datagram_transport));
 
   jsep_transport->SignalRtcpMuxActive.connect(
       this, &JsepTransportController::UpdateAggregateStates_n);
diff --git a/pc/jsep_transport_unittest.cc b/pc/jsep_transport_unittest.cc
index 0680027..1e51392 100644
--- a/pc/jsep_transport_unittest.cc
+++ b/pc/jsep_transport_unittest.cc
@@ -111,7 +111,6 @@
         std::move(sdes_transport), std::move(dtls_srtp_transport),
         /*datagram_rtp_transport=*/nullptr, std::move(rtp_dtls_transport),
         std::move(rtcp_dtls_transport),
-        /*datagram_dtls_transport=*/nullptr,
         /*media_transport=*/nullptr,
         /*datagram_transport=*/nullptr);