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);