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}
This commit is contained in:
parent
a310b388c0
commit
364b2673c0
@ -36,8 +36,8 @@ rtc_static_library("rtc_pc_base") {
|
||||
"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",
|
||||
|
||||
@ -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
|
||||
387
pc/datagram_rtp_transport.cc
Normal file
387
pc/datagram_rtp_transport.cc
Normal file
@ -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
|
||||
@ -8,8 +8,8 @@
|
||||
* 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_
|
||||
#ifndef PC_DATAGRAM_RTP_TRANSPORT_H_
|
||||
#define PC_DATAGRAM_RTP_TRANSPORT_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@ -20,9 +20,9 @@
|
||||
#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 "pc/rtp_transport_internal.h"
|
||||
#include "rtc_base/buffer.h"
|
||||
#include "rtc_base/buffer_queue.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
@ -31,31 +31,22 @@
|
||||
#include "rtc_base/strings/string_builder.h"
|
||||
#include "rtc_base/thread_checker.h"
|
||||
|
||||
namespace cricket {
|
||||
namespace webrtc {
|
||||
|
||||
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 {
|
||||
// RTP transport which uses the DatagramTransportInterface to send and receive
|
||||
// packets.
|
||||
class DatagramRtpTransport : public RtpTransportInternal,
|
||||
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(
|
||||
DatagramRtpTransport(
|
||||
const std::vector<webrtc::RtpExtension>& rtp_header_extensions,
|
||||
IceTransportInternal* ice_transport,
|
||||
webrtc::DatagramTransportInterface* datagram_transport,
|
||||
const webrtc::CryptoOptions& crypto_options,
|
||||
webrtc::RtcEventLog* event_log);
|
||||
cricket::IceTransportInternal* ice_transport,
|
||||
DatagramTransportInterface* datagram_transport);
|
||||
|
||||
~DatagramDtlsAdaptor() override;
|
||||
|
||||
// Connects to ICE transport callbacks.
|
||||
void ConnectToIceTransport();
|
||||
~DatagramRtpTransport() override;
|
||||
|
||||
// =====================================================
|
||||
// Overrides for webrtc::DatagramTransportSinkInterface
|
||||
@ -72,35 +63,38 @@ class DatagramDtlsAdaptor : public DtlsTransportInternal,
|
||||
void OnStateChanged(webrtc::MediaTransportState state) override;
|
||||
|
||||
// =====================================================
|
||||
// DtlsTransportInternal overrides
|
||||
// RtpTransportInternal 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;
|
||||
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;
|
||||
bool writable() const override;
|
||||
bool receiving() 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.
|
||||
@ -137,60 +131,19 @@ class DatagramDtlsAdaptor : public DtlsTransportInternal,
|
||||
SentPacketInfo* sent_packet_info);
|
||||
|
||||
// Sends datagram to datagram_transport.
|
||||
int SendDatagram(rtc::ArrayView<const uint8_t> data,
|
||||
webrtc::DatagramId datagram_id);
|
||||
bool 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);
|
||||
// Propagates network route changes from ICE.
|
||||
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_;
|
||||
|
||||
cricket::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;
|
||||
RtpDemuxer rtp_demuxer_;
|
||||
|
||||
// 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_;
|
||||
MediaTransportState state_ = MediaTransportState::kPending;
|
||||
|
||||
// Extension map for parsing transport sequence numbers.
|
||||
webrtc::RtpHeaderExtensionMap rtp_header_extension_map_;
|
||||
@ -214,6 +167,6 @@ class DatagramDtlsAdaptor : public DtlsTransportInternal,
|
||||
const bool disable_datagram_to_rtcp_feeback_translation_;
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // PC_DATAGRAM_DTLS_ADAPTOR_H_
|
||||
#endif // PC_DATAGRAM_RTP_TRANSPORT_H_
|
||||
@ -99,10 +99,9 @@ JsepTransport::JsepTransport(
|
||||
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 @@ JsepTransport::JsepTransport(
|
||||
? 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 @@ JsepTransport::~JsepTransport() {
|
||||
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 @@ void JsepTransport::ActivateRtcpMux() {
|
||||
}
|
||||
{
|
||||
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 @@ void JsepTransport::NegotiateRtpTransport(SdpType type) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,10 +93,9 @@ class JsepTransport : public sigslot::has_slots<>,
|
||||
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 @@ class JsepTransport : public sigslot::has_slots<>,
|
||||
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
|
||||
|
||||
@ -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 @@ JsepTransportController::CreateDtlsTransport(
|
||||
|
||||
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 @@ RTCError JsepTransportController::MaybeCreateJsepTransport(
|
||||
|
||||
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 @@ RTCError JsepTransportController::MaybeCreateJsepTransport(
|
||||
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 @@ RTCError JsepTransportController::MaybeCreateJsepTransport(
|
||||
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 @@ RTCError JsepTransportController::MaybeCreateJsepTransport(
|
||||
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);
|
||||
|
||||
@ -111,7 +111,6 @@ class JsepTransport2Test : public ::testing::Test, public sigslot::has_slots<> {
|
||||
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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user