2018-02-22 15:26:27 -08:00
|
|
|
/*
|
|
|
|
|
* Copyright 2017 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "pc/jsep_transport_controller.h"
|
2018-02-22 15:26:27 -08:00
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
2019-01-28 17:25:26 -08:00
|
|
|
#include "absl/algorithm/container.h"
|
2019-09-12 13:59:36 +02:00
|
|
|
#include "api/transport/datagram_transport_interface.h"
|
|
|
|
|
#include "api/transport/media/media_transport_interface.h"
|
2019-01-16 08:25:21 -08:00
|
|
|
#include "p2p/base/ice_transport_internal.h"
|
|
|
|
|
#include "p2p/base/no_op_dtls_transport.h"
|
2018-02-22 15:26:27 -08:00
|
|
|
#include "p2p/base/port.h"
|
2019-08-20 16:58:03 -07:00
|
|
|
#include "pc/datagram_rtp_transport.h"
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "pc/srtp_filter.h"
|
2018-02-22 15:26:27 -08:00
|
|
|
#include "rtc_base/bind.h"
|
|
|
|
|
#include "rtc_base/checks.h"
|
|
|
|
|
#include "rtc_base/thread.h"
|
|
|
|
|
|
|
|
|
|
using webrtc::SdpType;
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
|
|
|
|
|
// No address zero.
|
|
|
|
|
if (cand.address().IsNil() || cand.address().IsAnyIP()) {
|
|
|
|
|
return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"candidate has address of zero");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Disallow all ports below 1024, except for 80 and 443 on public addresses.
|
|
|
|
|
int port = cand.address().port();
|
|
|
|
|
if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
|
|
|
|
|
(cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
|
|
|
|
|
// Expected for active-only candidates per
|
|
|
|
|
// http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
|
|
|
|
|
// Libjingle clients emit port 0, in "active" mode.
|
|
|
|
|
return webrtc::RTCError::OK();
|
|
|
|
|
}
|
|
|
|
|
if (port < 1024) {
|
|
|
|
|
if ((port != 80) && (port != 443)) {
|
|
|
|
|
return webrtc::RTCError(
|
|
|
|
|
webrtc::RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"candidate has port below 1024, but not 80 or 443");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cand.address().IsPrivateIP()) {
|
|
|
|
|
return webrtc::RTCError(
|
|
|
|
|
webrtc::RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"candidate has port of 80 or 443 with private IP address");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return webrtc::RTCError::OK();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
|
|
|
|
|
for (const cricket::Candidate& candidate : candidates) {
|
|
|
|
|
webrtc::RTCError error = VerifyCandidate(candidate);
|
|
|
|
|
if (!error.ok()) {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return webrtc::RTCError::OK();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
|
|
|
|
|
JsepTransportController::JsepTransportController(
|
|
|
|
|
rtc::Thread* signaling_thread,
|
|
|
|
|
rtc::Thread* network_thread,
|
|
|
|
|
cricket::PortAllocator* port_allocator,
|
2018-08-02 13:20:15 -07:00
|
|
|
AsyncResolverFactory* async_resolver_factory,
|
2018-02-22 15:26:27 -08:00
|
|
|
Config config)
|
|
|
|
|
: signaling_thread_(signaling_thread),
|
|
|
|
|
network_thread_(network_thread),
|
|
|
|
|
port_allocator_(port_allocator),
|
2018-08-02 13:20:15 -07:00
|
|
|
async_resolver_factory_(async_resolver_factory),
|
2018-04-13 16:44:34 -07:00
|
|
|
config_(config) {
|
|
|
|
|
// The |transport_observer| is assumed to be non-null.
|
|
|
|
|
RTC_DCHECK(config_.transport_observer);
|
2019-09-18 18:22:12 +02:00
|
|
|
RTC_DCHECK(config_.rtcp_handler);
|
2018-04-13 16:44:34 -07:00
|
|
|
}
|
2018-02-22 15:26:27 -08:00
|
|
|
|
|
|
|
|
JsepTransportController::~JsepTransportController() {
|
|
|
|
|
// Channel destructors may try to send packets, so this needs to happen on
|
|
|
|
|
// the network thread.
|
|
|
|
|
network_thread_->Invoke<void>(
|
|
|
|
|
RTC_FROM_HERE,
|
|
|
|
|
rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTCError JsepTransportController::SetLocalDescription(
|
|
|
|
|
SdpType type,
|
|
|
|
|
const cricket::SessionDescription* description) {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
|
|
|
|
return network_thread_->Invoke<RTCError>(
|
|
|
|
|
RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!initial_offerer_.has_value()) {
|
|
|
|
|
initial_offerer_.emplace(type == SdpType::kOffer);
|
|
|
|
|
if (*initial_offerer_) {
|
|
|
|
|
SetIceRole_n(cricket::ICEROLE_CONTROLLING);
|
|
|
|
|
} else {
|
|
|
|
|
SetIceRole_n(cricket::ICEROLE_CONTROLLED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ApplyDescription_n(/*local=*/true, type, description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTCError JsepTransportController::SetRemoteDescription(
|
|
|
|
|
SdpType type,
|
|
|
|
|
const cricket::SessionDescription* description) {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
|
|
|
|
return network_thread_->Invoke<RTCError>(
|
|
|
|
|
RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ApplyDescription_n(/*local=*/false, type, description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtpTransportInternal* JsepTransportController::GetRtpTransport(
|
|
|
|
|
const std::string& mid) const {
|
2018-03-30 10:48:35 -07:00
|
|
|
auto jsep_transport = GetJsepTransportForMid(mid);
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!jsep_transport) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return jsep_transport->rtp_transport();
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-23 15:50:38 -07:00
|
|
|
MediaTransportConfig JsepTransportController::GetMediaTransportConfig(
|
2018-10-10 10:34:49 -07:00
|
|
|
const std::string& mid) const {
|
|
|
|
|
auto jsep_transport = GetJsepTransportForMid(mid);
|
|
|
|
|
if (!jsep_transport) {
|
2019-05-23 15:50:38 -07:00
|
|
|
return MediaTransportConfig();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MediaTransportInterface* media_transport = nullptr;
|
|
|
|
|
if (config_.use_media_transport_for_media) {
|
|
|
|
|
media_transport = jsep_transport->media_transport();
|
|
|
|
|
}
|
|
|
|
|
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
DatagramTransportInterface* datagram_transport = nullptr;
|
|
|
|
|
if (config_.use_datagram_transport) {
|
|
|
|
|
datagram_transport = jsep_transport->datagram_transport();
|
|
|
|
|
}
|
2019-05-23 15:50:38 -07:00
|
|
|
|
|
|
|
|
// Media transport and datagram transports can not be used together.
|
|
|
|
|
RTC_DCHECK(!media_transport || !datagram_transport);
|
|
|
|
|
|
|
|
|
|
if (media_transport) {
|
|
|
|
|
return MediaTransportConfig(media_transport);
|
|
|
|
|
} else if (datagram_transport) {
|
|
|
|
|
return MediaTransportConfig(
|
|
|
|
|
/*rtp_max_packet_size=*/datagram_transport->GetLargestDatagramSize());
|
|
|
|
|
} else {
|
|
|
|
|
return MediaTransportConfig();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
DataChannelTransportInterface* JsepTransportController::GetDataChannelTransport(
|
2019-05-23 15:50:38 -07:00
|
|
|
const std::string& mid) const {
|
|
|
|
|
auto jsep_transport = GetJsepTransportForMid(mid);
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
if (!jsep_transport) {
|
2018-10-10 10:34:49 -07:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
2019-09-23 14:53:54 -07:00
|
|
|
return jsep_transport->data_channel_transport();
|
2018-10-10 10:34:49 -07:00
|
|
|
}
|
|
|
|
|
|
2018-11-08 11:23:22 -08:00
|
|
|
MediaTransportState JsepTransportController::GetMediaTransportState(
|
|
|
|
|
const std::string& mid) const {
|
|
|
|
|
auto jsep_transport = GetJsepTransportForMid(mid);
|
|
|
|
|
if (!jsep_transport) {
|
|
|
|
|
return MediaTransportState::kPending;
|
|
|
|
|
}
|
|
|
|
|
return jsep_transport->media_transport_state();
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-22 15:26:27 -08:00
|
|
|
cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
|
2018-11-28 16:47:46 +01:00
|
|
|
const std::string& mid) {
|
2018-03-30 10:48:35 -07:00
|
|
|
auto jsep_transport = GetJsepTransportForMid(mid);
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!jsep_transport) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return jsep_transport->rtp_dtls_transport();
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-28 16:47:46 +01:00
|
|
|
const cricket::DtlsTransportInternal*
|
|
|
|
|
JsepTransportController::GetRtcpDtlsTransport(const std::string& mid) const {
|
2018-03-30 10:48:35 -07:00
|
|
|
auto jsep_transport = GetJsepTransportForMid(mid);
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!jsep_transport) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return jsep_transport->rtcp_dtls_transport();
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-17 10:39:40 +01:00
|
|
|
rtc::scoped_refptr<webrtc::DtlsTransport>
|
2018-11-28 16:47:46 +01:00
|
|
|
JsepTransportController::LookupDtlsTransportByMid(const std::string& mid) {
|
|
|
|
|
auto jsep_transport = GetJsepTransportForMid(mid);
|
|
|
|
|
if (!jsep_transport) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return jsep_transport->RtpDtlsTransport();
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-23 14:53:54 -07:00
|
|
|
rtc::scoped_refptr<SctpTransport> JsepTransportController::GetSctpTransport(
|
|
|
|
|
const std::string& mid) const {
|
|
|
|
|
auto jsep_transport = GetJsepTransportForMid(mid);
|
|
|
|
|
if (!jsep_transport) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return jsep_transport->SctpTransport();
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-22 15:26:27 -08:00
|
|
|
void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
|
|
|
|
network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ice_config_ = config;
|
|
|
|
|
for (auto& dtls : GetDtlsTransports()) {
|
|
|
|
|
dtls->ice_transport()->SetIceConfig(ice_config_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsepTransportController::SetNeedsIceRestartFlag() {
|
2018-03-30 10:48:35 -07:00
|
|
|
for (auto& kv : jsep_transports_by_name_) {
|
2018-02-22 15:26:27 -08:00
|
|
|
kv.second->SetNeedsIceRestartFlag();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JsepTransportController::NeedsIceRestart(
|
|
|
|
|
const std::string& transport_name) const {
|
2018-04-13 16:44:34 -07:00
|
|
|
const cricket::JsepTransport* transport =
|
2018-03-30 10:48:35 -07:00
|
|
|
GetJsepTransportByName(transport_name);
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!transport) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return transport->needs_ice_restart();
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-19 16:47:43 +02:00
|
|
|
absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
|
2018-03-30 10:48:35 -07:00
|
|
|
const std::string& mid) const {
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!network_thread_->IsCurrent()) {
|
2018-06-19 16:47:43 +02:00
|
|
|
return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
|
2018-03-30 10:48:35 -07:00
|
|
|
RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:44:34 -07:00
|
|
|
const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!t) {
|
2018-06-19 16:47:43 +02:00
|
|
|
return absl::optional<rtc::SSLRole>();
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
return t->GetDtlsRole();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JsepTransportController::SetLocalCertificate(
|
|
|
|
|
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
|
|
|
|
return network_thread_->Invoke<bool>(
|
|
|
|
|
RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Can't change a certificate, or set a null certificate.
|
|
|
|
|
if (certificate_ || !certificate) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
certificate_ = certificate;
|
|
|
|
|
|
|
|
|
|
// Set certificate for JsepTransport, which verifies it matches the
|
|
|
|
|
// fingerprint in SDP, and DTLS transport.
|
|
|
|
|
// Fallback from DTLS to SDES is not supported.
|
2018-03-30 10:48:35 -07:00
|
|
|
for (auto& kv : jsep_transports_by_name_) {
|
2018-02-22 15:26:27 -08:00
|
|
|
kv.second->SetLocalCertificate(certificate_);
|
|
|
|
|
}
|
|
|
|
|
for (auto& dtls : GetDtlsTransports()) {
|
|
|
|
|
bool set_cert_success = dtls->SetLocalCertificate(certificate_);
|
|
|
|
|
RTC_DCHECK(set_cert_success);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rtc::scoped_refptr<rtc::RTCCertificate>
|
|
|
|
|
JsepTransportController::GetLocalCertificate(
|
|
|
|
|
const std::string& transport_name) const {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
|
|
|
|
return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
|
|
|
|
|
RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:44:34 -07:00
|
|
|
const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!t) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return t->GetLocalCertificate();
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-23 13:04:51 -08:00
|
|
|
std::unique_ptr<rtc::SSLCertChain>
|
|
|
|
|
JsepTransportController::GetRemoteSSLCertChain(
|
2018-02-22 15:26:27 -08:00
|
|
|
const std::string& transport_name) const {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
2018-02-23 13:04:51 -08:00
|
|
|
return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
|
|
|
|
|
RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
2018-03-30 10:48:35 -07:00
|
|
|
// Get the certificate from the RTP transport's DTLS handshake. Should be
|
|
|
|
|
// identical to the RTCP transport's, since they were given the same remote
|
2018-02-22 15:26:27 -08:00
|
|
|
// fingerprint.
|
2018-03-30 10:48:35 -07:00
|
|
|
auto jsep_transport = GetJsepTransportByName(transport_name);
|
|
|
|
|
if (!jsep_transport) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
auto dtls = jsep_transport->rtp_dtls_transport();
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!dtls) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-23 13:04:51 -08:00
|
|
|
return dtls->GetRemoteSSLCertChain();
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsepTransportController::MaybeStartGathering() {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
|
|
|
|
network_thread_->Invoke<void>(RTC_FROM_HERE,
|
|
|
|
|
[&] { MaybeStartGathering(); });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto& dtls : GetDtlsTransports()) {
|
|
|
|
|
dtls->ice_transport()->MaybeStartGathering();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTCError JsepTransportController::AddRemoteCandidates(
|
|
|
|
|
const std::string& transport_name,
|
|
|
|
|
const cricket::Candidates& candidates) {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
|
|
|
|
return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
|
|
|
|
|
return AddRemoteCandidates(transport_name, candidates);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify each candidate before passing down to the transport layer.
|
|
|
|
|
RTCError error = VerifyCandidates(candidates);
|
|
|
|
|
if (!error.ok()) {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
2018-03-30 10:48:35 -07:00
|
|
|
auto jsep_transport = GetJsepTransportByName(transport_name);
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!jsep_transport) {
|
2018-03-30 10:48:35 -07:00
|
|
|
RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
|
|
|
|
|
"doesn't exist. Ignore it.";
|
|
|
|
|
return RTCError::OK();
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
return jsep_transport->AddRemoteCandidates(candidates);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTCError JsepTransportController::RemoveRemoteCandidates(
|
|
|
|
|
const cricket::Candidates& candidates) {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
|
|
|
|
return network_thread_->Invoke<RTCError>(
|
|
|
|
|
RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify each candidate before passing down to the transport layer.
|
|
|
|
|
RTCError error = VerifyCandidates(candidates);
|
|
|
|
|
if (!error.ok()) {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::map<std::string, cricket::Candidates> candidates_by_transport_name;
|
|
|
|
|
for (const cricket::Candidate& cand : candidates) {
|
|
|
|
|
if (!cand.transport_name().empty()) {
|
|
|
|
|
candidates_by_transport_name[cand.transport_name()].push_back(cand);
|
|
|
|
|
} else {
|
|
|
|
|
RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
|
|
|
|
|
"transport name set: "
|
2019-09-06 12:51:17 -07:00
|
|
|
<< cand.ToSensitiveString();
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const auto& kv : candidates_by_transport_name) {
|
|
|
|
|
const std::string& transport_name = kv.first;
|
|
|
|
|
const cricket::Candidates& candidates = kv.second;
|
2018-04-13 16:44:34 -07:00
|
|
|
cricket::JsepTransport* jsep_transport =
|
2018-03-30 10:48:35 -07:00
|
|
|
GetJsepTransportByName(transport_name);
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!jsep_transport) {
|
2018-03-30 10:48:35 -07:00
|
|
|
RTC_LOG(LS_WARNING)
|
|
|
|
|
<< "Not removing candidate because the JsepTransport doesn't exist.";
|
|
|
|
|
continue;
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
for (const cricket::Candidate& candidate : candidates) {
|
2018-11-28 16:47:46 +01:00
|
|
|
cricket::DtlsTransportInternal* dtls =
|
|
|
|
|
candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
|
|
|
|
|
? jsep_transport->rtp_dtls_transport()
|
|
|
|
|
: jsep_transport->rtcp_dtls_transport();
|
2018-02-22 15:26:27 -08:00
|
|
|
if (dtls) {
|
|
|
|
|
dtls->ice_transport()->RemoveRemoteCandidate(candidate);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return RTCError::OK();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JsepTransportController::GetStats(const std::string& transport_name,
|
|
|
|
|
cricket::TransportStats* stats) {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
|
|
|
|
return network_thread_->Invoke<bool>(
|
|
|
|
|
RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:44:34 -07:00
|
|
|
cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!transport) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return transport->GetStats(stats);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-12 11:41:11 -07:00
|
|
|
void JsepTransportController::SetActiveResetSrtpParams(
|
|
|
|
|
bool active_reset_srtp_params) {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
|
|
|
|
network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
|
|
|
|
|
SetActiveResetSrtpParams(active_reset_srtp_params);
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTC_LOG(INFO)
|
|
|
|
|
<< "Updating the active_reset_srtp_params for JsepTransportController: "
|
|
|
|
|
<< active_reset_srtp_params;
|
|
|
|
|
config_.active_reset_srtp_params = active_reset_srtp_params;
|
|
|
|
|
for (auto& kv : jsep_transports_by_name_) {
|
|
|
|
|
kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-25 13:31:15 -08:00
|
|
|
void JsepTransportController::SetMediaTransportSettings(
|
|
|
|
|
bool use_media_transport_for_media,
|
2019-05-23 15:50:38 -07:00
|
|
|
bool use_media_transport_for_data_channels,
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
bool use_datagram_transport,
|
2019-09-26 11:02:11 -07:00
|
|
|
bool use_datagram_transport_for_data_channels,
|
|
|
|
|
bool use_datagram_transport_for_data_channels_receive_only) {
|
2019-01-25 13:31:15 -08:00
|
|
|
RTC_DCHECK(use_media_transport_for_media ==
|
|
|
|
|
config_.use_media_transport_for_media ||
|
2018-10-18 12:57:59 -07:00
|
|
|
jsep_transports_by_name_.empty())
|
2019-01-25 13:31:15 -08:00
|
|
|
<< "You can only change media transport configuration before creating "
|
|
|
|
|
"the first transport.";
|
|
|
|
|
|
|
|
|
|
RTC_DCHECK(use_media_transport_for_data_channels ==
|
|
|
|
|
config_.use_media_transport_for_data_channels ||
|
|
|
|
|
jsep_transports_by_name_.empty())
|
|
|
|
|
<< "You can only change media transport configuration before creating "
|
|
|
|
|
"the first transport.";
|
|
|
|
|
|
|
|
|
|
config_.use_media_transport_for_media = use_media_transport_for_media;
|
|
|
|
|
config_.use_media_transport_for_data_channels =
|
|
|
|
|
use_media_transport_for_data_channels;
|
2019-05-23 15:50:38 -07:00
|
|
|
config_.use_datagram_transport = use_datagram_transport;
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
config_.use_datagram_transport_for_data_channels =
|
|
|
|
|
use_datagram_transport_for_data_channels;
|
2019-09-26 11:02:11 -07:00
|
|
|
config_.use_datagram_transport_for_data_channels_receive_only =
|
|
|
|
|
use_datagram_transport_for_data_channels_receive_only;
|
2018-10-18 12:57:59 -07:00
|
|
|
}
|
|
|
|
|
|
2019-10-09 18:29:44 +03:00
|
|
|
void JsepTransportController::RollbackTransportForMid(const std::string& mid) {
|
|
|
|
|
if (!network_thread_->IsCurrent()) {
|
|
|
|
|
network_thread_->Invoke<void>(RTC_FROM_HERE,
|
|
|
|
|
[=] { RollbackTransportForMid(mid); });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
RemoveTransportForMid(mid);
|
|
|
|
|
MaybeDestroyJsepTransport(mid);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-16 08:25:21 -08:00
|
|
|
std::unique_ptr<cricket::IceTransportInternal>
|
|
|
|
|
JsepTransportController::CreateIceTransport(const std::string transport_name,
|
|
|
|
|
bool rtcp) {
|
2018-02-22 15:26:27 -08:00
|
|
|
int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
|
|
|
|
|
: cricket::ICE_CANDIDATE_COMPONENT_RTP;
|
|
|
|
|
|
|
|
|
|
if (config_.external_transport_factory) {
|
2019-01-16 08:25:21 -08:00
|
|
|
return config_.external_transport_factory->CreateIceTransport(
|
2018-02-22 15:26:27 -08:00
|
|
|
transport_name, component);
|
|
|
|
|
} else {
|
2019-09-17 17:06:18 +02:00
|
|
|
return std::make_unique<cricket::P2PTransportChannel>(
|
2018-08-02 13:20:15 -07:00
|
|
|
transport_name, component, port_allocator_, async_resolver_factory_,
|
|
|
|
|
config_.event_log);
|
2019-01-16 08:25:21 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<cricket::DtlsTransportInternal>
|
|
|
|
|
JsepTransportController::CreateDtlsTransport(
|
2019-07-10 15:44:56 -07:00
|
|
|
const cricket::ContentInfo& content_info,
|
2019-05-29 17:34:13 -07:00
|
|
|
cricket::IceTransportInternal* ice,
|
2019-06-03 13:00:24 -07:00
|
|
|
DatagramTransportInterface* datagram_transport) {
|
2019-01-16 08:25:21 -08:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<cricket::DtlsTransportInternal> dtls;
|
2019-05-23 15:50:38 -07:00
|
|
|
|
|
|
|
|
if (datagram_transport) {
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
RTC_DCHECK(config_.use_datagram_transport ||
|
|
|
|
|
config_.use_datagram_transport_for_data_channels);
|
2019-05-23 15:50:38 -07:00
|
|
|
} else if (config_.media_transport_factory &&
|
|
|
|
|
config_.use_media_transport_for_media &&
|
|
|
|
|
config_.use_media_transport_for_data_channels) {
|
|
|
|
|
// If media transport is used for both media and data channels,
|
|
|
|
|
// then we don't need to create DTLS.
|
|
|
|
|
// Otherwise, DTLS is still created.
|
2019-09-17 17:06:18 +02:00
|
|
|
dtls = std::make_unique<cricket::NoOpDtlsTransport>(ice,
|
|
|
|
|
config_.crypto_options);
|
2019-01-16 08:25:21 -08:00
|
|
|
} else if (config_.external_transport_factory) {
|
|
|
|
|
dtls = config_.external_transport_factory->CreateDtlsTransport(
|
2019-05-29 17:34:13 -07:00
|
|
|
ice, config_.crypto_options);
|
2019-01-16 08:25:21 -08:00
|
|
|
} else {
|
2019-09-17 17:06:18 +02:00
|
|
|
dtls = std::make_unique<cricket::DtlsTransport>(ice, config_.crypto_options,
|
|
|
|
|
config_.event_log);
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTC_DCHECK(dtls);
|
|
|
|
|
dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
|
|
|
|
|
dtls->ice_transport()->SetIceRole(ice_role_);
|
|
|
|
|
dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
|
|
|
|
|
dtls->ice_transport()->SetIceConfig(ice_config_);
|
|
|
|
|
if (certificate_) {
|
|
|
|
|
bool set_cert_success = dtls->SetLocalCertificate(certificate_);
|
|
|
|
|
RTC_DCHECK(set_cert_success);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Connect to signals offered by the DTLS and ICE transport.
|
|
|
|
|
dtls->SignalWritableState.connect(
|
|
|
|
|
this, &JsepTransportController::OnTransportWritableState_n);
|
|
|
|
|
dtls->SignalReceivingState.connect(
|
|
|
|
|
this, &JsepTransportController::OnTransportReceivingState_n);
|
|
|
|
|
dtls->SignalDtlsHandshakeError.connect(
|
|
|
|
|
this, &JsepTransportController::OnDtlsHandshakeError);
|
|
|
|
|
dtls->ice_transport()->SignalGatheringState.connect(
|
|
|
|
|
this, &JsepTransportController::OnTransportGatheringState_n);
|
|
|
|
|
dtls->ice_transport()->SignalCandidateGathered.connect(
|
|
|
|
|
this, &JsepTransportController::OnTransportCandidateGathered_n);
|
2019-06-01 12:23:43 +03:00
|
|
|
dtls->ice_transport()->SignalCandidateError.connect(
|
|
|
|
|
this, &JsepTransportController::OnTransportCandidateError_n);
|
2018-02-22 15:26:27 -08:00
|
|
|
dtls->ice_transport()->SignalCandidatesRemoved.connect(
|
|
|
|
|
this, &JsepTransportController::OnTransportCandidatesRemoved_n);
|
|
|
|
|
dtls->ice_transport()->SignalRoleConflict.connect(
|
|
|
|
|
this, &JsepTransportController::OnTransportRoleConflict_n);
|
|
|
|
|
dtls->ice_transport()->SignalStateChanged.connect(
|
|
|
|
|
this, &JsepTransportController::OnTransportStateChanged_n);
|
2019-01-15 16:31:55 +01:00
|
|
|
dtls->ice_transport()->SignalIceTransportStateChanged.connect(
|
|
|
|
|
this, &JsepTransportController::OnTransportStateChanged_n);
|
2019-08-06 10:54:47 -07:00
|
|
|
dtls->ice_transport()->SignalCandidatePairChanged.connect(
|
|
|
|
|
this, &JsepTransportController::OnTransportCandidatePairChanged_n);
|
2018-02-22 15:26:27 -08:00
|
|
|
return dtls;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<webrtc::RtpTransport>
|
|
|
|
|
JsepTransportController::CreateUnencryptedRtpTransport(
|
|
|
|
|
const std::string& transport_name,
|
|
|
|
|
rtc::PacketTransportInternal* rtp_packet_transport,
|
|
|
|
|
rtc::PacketTransportInternal* rtcp_packet_transport) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2018-03-30 10:48:35 -07:00
|
|
|
auto unencrypted_rtp_transport =
|
2019-09-17 17:06:18 +02:00
|
|
|
std::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
|
2018-03-30 10:48:35 -07:00
|
|
|
unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
|
|
|
|
|
if (rtcp_packet_transport) {
|
|
|
|
|
unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
|
|
|
|
|
}
|
|
|
|
|
return unencrypted_rtp_transport;
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<webrtc::SrtpTransport>
|
|
|
|
|
JsepTransportController::CreateSdesTransport(
|
|
|
|
|
const std::string& transport_name,
|
2018-03-30 10:48:35 -07:00
|
|
|
cricket::DtlsTransportInternal* rtp_dtls_transport,
|
|
|
|
|
cricket::DtlsTransportInternal* rtcp_dtls_transport) {
|
2018-02-22 15:26:27 -08:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
auto srtp_transport =
|
2019-09-17 17:06:18 +02:00
|
|
|
std::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
|
2018-03-30 10:48:35 -07:00
|
|
|
RTC_DCHECK(rtp_dtls_transport);
|
|
|
|
|
srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
|
|
|
|
|
if (rtcp_dtls_transport) {
|
|
|
|
|
srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
if (config_.enable_external_auth) {
|
|
|
|
|
srtp_transport->EnableExternalAuth();
|
|
|
|
|
}
|
|
|
|
|
return srtp_transport;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<webrtc::DtlsSrtpTransport>
|
|
|
|
|
JsepTransportController::CreateDtlsSrtpTransport(
|
|
|
|
|
const std::string& transport_name,
|
|
|
|
|
cricket::DtlsTransportInternal* rtp_dtls_transport,
|
|
|
|
|
cricket::DtlsTransportInternal* rtcp_dtls_transport) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2019-09-17 17:06:18 +02:00
|
|
|
auto dtls_srtp_transport = std::make_unique<webrtc::DtlsSrtpTransport>(
|
2018-04-13 16:44:34 -07:00
|
|
|
rtcp_dtls_transport == nullptr);
|
2018-02-22 15:26:27 -08:00
|
|
|
if (config_.enable_external_auth) {
|
2018-04-13 16:44:34 -07:00
|
|
|
dtls_srtp_transport->EnableExternalAuth();
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
|
|
|
|
|
rtcp_dtls_transport);
|
2018-06-12 11:41:11 -07:00
|
|
|
dtls_srtp_transport->SetActiveResetSrtpParams(
|
|
|
|
|
config_.active_reset_srtp_params);
|
2018-10-18 15:58:17 +02:00
|
|
|
dtls_srtp_transport->SignalDtlsStateChange.connect(
|
|
|
|
|
this, &JsepTransportController::UpdateAggregateStates_n);
|
2018-02-22 15:26:27 -08:00
|
|
|
return dtls_srtp_transport;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<cricket::DtlsTransportInternal*>
|
|
|
|
|
JsepTransportController::GetDtlsTransports() {
|
|
|
|
|
std::vector<cricket::DtlsTransportInternal*> dtls_transports;
|
2018-03-30 10:48:35 -07:00
|
|
|
for (auto it = jsep_transports_by_name_.begin();
|
|
|
|
|
it != jsep_transports_by_name_.end(); ++it) {
|
2018-02-22 15:26:27 -08:00
|
|
|
auto jsep_transport = it->second.get();
|
|
|
|
|
RTC_DCHECK(jsep_transport);
|
|
|
|
|
if (jsep_transport->rtp_dtls_transport()) {
|
|
|
|
|
dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (jsep_transport->rtcp_dtls_transport()) {
|
|
|
|
|
dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return dtls_transports;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTCError JsepTransportController::ApplyDescription_n(
|
|
|
|
|
bool local,
|
|
|
|
|
SdpType type,
|
|
|
|
|
const cricket::SessionDescription* description) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
RTC_DCHECK(description);
|
|
|
|
|
|
|
|
|
|
if (local) {
|
|
|
|
|
local_desc_ = description;
|
|
|
|
|
} else {
|
|
|
|
|
remote_desc_ = description;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-30 10:48:35 -07:00
|
|
|
RTCError error;
|
2018-04-10 14:41:03 -07:00
|
|
|
error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
|
2018-03-30 10:48:35 -07:00
|
|
|
if (!error.ok()) {
|
|
|
|
|
return error;
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<int> merged_encrypted_extension_ids;
|
2019-09-30 15:12:47 -07:00
|
|
|
absl::optional<std::string> bundle_media_alt_protocol;
|
|
|
|
|
absl::optional<std::string> bundle_data_alt_protocol;
|
2018-02-22 15:26:27 -08:00
|
|
|
if (bundle_group_) {
|
|
|
|
|
merged_encrypted_extension_ids =
|
|
|
|
|
MergeEncryptedHeaderExtensionIdsForBundle(description);
|
2019-09-30 15:12:47 -07:00
|
|
|
error = GetAltProtocolsForBundle(description, &bundle_media_alt_protocol,
|
|
|
|
|
&bundle_data_alt_protocol);
|
|
|
|
|
if (!error.ok()) {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const cricket::ContentInfo& content_info : description->contents()) {
|
|
|
|
|
// Don't create transports for rejected m-lines and bundled m-lines."
|
|
|
|
|
if (content_info.rejected ||
|
|
|
|
|
(IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-02-27 14:26:15 -08:00
|
|
|
error = MaybeCreateJsepTransport(local, content_info, *description);
|
2018-03-30 10:48:35 -07:00
|
|
|
if (!error.ok()) {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTC_DCHECK(description->contents().size() ==
|
|
|
|
|
description->transport_infos().size());
|
|
|
|
|
for (size_t i = 0; i < description->contents().size(); ++i) {
|
|
|
|
|
const cricket::ContentInfo& content_info = description->contents()[i];
|
2019-09-30 15:12:47 -07:00
|
|
|
const cricket::MediaContentDescription* media_description =
|
|
|
|
|
content_info.media_description();
|
2018-02-22 15:26:27 -08:00
|
|
|
const cricket::TransportInfo& transport_info =
|
|
|
|
|
description->transport_infos()[i];
|
|
|
|
|
if (content_info.rejected) {
|
2018-04-16 16:42:14 -07:00
|
|
|
HandleRejectedContent(content_info, description);
|
2018-02-22 15:26:27 -08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
|
2018-04-13 16:44:34 -07:00
|
|
|
if (!HandleBundledContent(content_info)) {
|
|
|
|
|
return RTCError(RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"Failed to process the bundled m= section.");
|
|
|
|
|
}
|
2018-02-22 15:26:27 -08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-30 10:48:35 -07:00
|
|
|
error = ValidateContent(content_info);
|
|
|
|
|
if (!error.ok()) {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-22 15:26:27 -08:00
|
|
|
std::vector<int> extension_ids;
|
2019-09-30 15:12:47 -07:00
|
|
|
absl::optional<std::string> media_alt_protocol;
|
|
|
|
|
absl::optional<std::string> data_alt_protocol;
|
2018-04-12 10:30:48 -07:00
|
|
|
if (bundled_mid() && content_info.name == *bundled_mid()) {
|
2018-02-22 15:26:27 -08:00
|
|
|
extension_ids = merged_encrypted_extension_ids;
|
2019-09-30 15:12:47 -07:00
|
|
|
media_alt_protocol = bundle_media_alt_protocol;
|
|
|
|
|
data_alt_protocol = bundle_data_alt_protocol;
|
2018-02-22 15:26:27 -08:00
|
|
|
} else {
|
|
|
|
|
extension_ids = GetEncryptedHeaderExtensionIds(content_info);
|
2019-09-30 15:12:47 -07:00
|
|
|
switch (media_description->type()) {
|
|
|
|
|
case cricket::MEDIA_TYPE_AUDIO:
|
|
|
|
|
case cricket::MEDIA_TYPE_VIDEO:
|
|
|
|
|
media_alt_protocol = media_description->alt_protocol();
|
|
|
|
|
break;
|
|
|
|
|
case cricket::MEDIA_TYPE_DATA:
|
|
|
|
|
data_alt_protocol = media_description->alt_protocol();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
2018-03-30 10:48:35 -07:00
|
|
|
int rtp_abs_sendtime_extn_id =
|
|
|
|
|
GetRtpAbsSendTimeHeaderExtensionId(content_info);
|
|
|
|
|
|
2018-04-13 16:44:34 -07:00
|
|
|
cricket::JsepTransport* transport =
|
2018-03-30 10:48:35 -07:00
|
|
|
GetJsepTransportForMid(content_info.name);
|
2018-02-22 15:26:27 -08:00
|
|
|
RTC_DCHECK(transport);
|
|
|
|
|
|
|
|
|
|
SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
|
|
|
|
|
|
|
|
|
|
cricket::JsepTransportDescription jsep_description =
|
|
|
|
|
CreateJsepTransportDescription(content_info, transport_info,
|
2019-09-30 15:12:47 -07:00
|
|
|
extension_ids, rtp_abs_sendtime_extn_id,
|
|
|
|
|
media_alt_protocol, data_alt_protocol);
|
2018-02-22 15:26:27 -08:00
|
|
|
if (local) {
|
|
|
|
|
error =
|
|
|
|
|
transport->SetLocalJsepTransportDescription(jsep_description, type);
|
|
|
|
|
} else {
|
|
|
|
|
error =
|
|
|
|
|
transport->SetRemoteJsepTransportDescription(jsep_description, type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!error.ok()) {
|
|
|
|
|
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"Failed to apply the description for " +
|
|
|
|
|
content_info.name + ": " + error.message());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return RTCError::OK();
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-10 14:41:03 -07:00
|
|
|
RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
|
|
|
|
|
bool local,
|
|
|
|
|
SdpType type,
|
2018-03-30 10:48:35 -07:00
|
|
|
const cricket::SessionDescription* description) {
|
|
|
|
|
RTC_DCHECK(description);
|
2018-04-10 14:41:03 -07:00
|
|
|
const cricket::ContentGroup* new_bundle_group =
|
|
|
|
|
description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
|
|
|
|
|
|
|
|
|
|
// The BUNDLE group containing a MID that no m= section has is invalid.
|
|
|
|
|
if (new_bundle_group) {
|
2019-01-27 17:29:42 +01:00
|
|
|
for (const auto& content_name : new_bundle_group->content_names()) {
|
2018-04-10 14:41:03 -07:00
|
|
|
if (!description->GetContentByName(content_name)) {
|
|
|
|
|
return RTCError(RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"The BUNDLE group contains MID:" + content_name +
|
|
|
|
|
" matching no m= section.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type == SdpType::kAnswer) {
|
|
|
|
|
const cricket::ContentGroup* offered_bundle_group =
|
|
|
|
|
local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
|
|
|
|
|
: local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
|
|
|
|
|
|
|
|
|
|
if (new_bundle_group) {
|
|
|
|
|
// The BUNDLE group in answer should be a subset of offered group.
|
2019-01-27 17:29:42 +01:00
|
|
|
for (const auto& content_name : new_bundle_group->content_names()) {
|
2018-04-10 14:41:03 -07:00
|
|
|
if (!offered_bundle_group ||
|
|
|
|
|
!offered_bundle_group->HasContentName(content_name)) {
|
|
|
|
|
return RTCError(RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"The BUNDLE group in answer contains a MID that was "
|
|
|
|
|
"not in the offered group.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bundle_group_) {
|
2019-01-27 17:29:42 +01:00
|
|
|
for (const auto& content_name : bundle_group_->content_names()) {
|
2018-04-10 14:41:03 -07:00
|
|
|
// An answer that removes m= sections from pre-negotiated BUNDLE group
|
|
|
|
|
// without rejecting it, is invalid.
|
|
|
|
|
if (!new_bundle_group ||
|
|
|
|
|
!new_bundle_group->HasContentName(content_name)) {
|
|
|
|
|
auto* content_info = description->GetContentByName(content_name);
|
|
|
|
|
if (!content_info || !content_info->rejected) {
|
|
|
|
|
return RTCError(RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"Answer cannot remove m= section " + content_name +
|
|
|
|
|
" from already-established BUNDLE group.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config_.bundle_policy ==
|
|
|
|
|
PeerConnectionInterface::kBundlePolicyMaxBundle &&
|
|
|
|
|
!description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
|
|
|
|
|
return RTCError(RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"max-bundle is used but no bundle group found.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ShouldUpdateBundleGroup(type, description)) {
|
|
|
|
|
bundle_group_ = *new_bundle_group;
|
|
|
|
|
}
|
2018-03-30 10:48:35 -07:00
|
|
|
|
|
|
|
|
if (!bundled_mid()) {
|
|
|
|
|
return RTCError::OK();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto bundled_content = description->GetContentByName(*bundled_mid());
|
|
|
|
|
if (!bundled_content) {
|
|
|
|
|
return RTCError(
|
|
|
|
|
RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"An m= section associated with the BUNDLE-tag doesn't exist.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the |bundled_content| is rejected, other contents in the bundle group
|
|
|
|
|
// should be rejected.
|
|
|
|
|
if (bundled_content->rejected) {
|
2019-01-27 17:29:42 +01:00
|
|
|
for (const auto& content_name : bundle_group_->content_names()) {
|
2018-03-30 10:48:35 -07:00
|
|
|
auto other_content = description->GetContentByName(content_name);
|
|
|
|
|
if (!other_content->rejected) {
|
|
|
|
|
return RTCError(
|
|
|
|
|
RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"The m= section:" + content_name + " should be rejected.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return RTCError::OK();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTCError JsepTransportController::ValidateContent(
|
|
|
|
|
const cricket::ContentInfo& content_info) {
|
|
|
|
|
if (config_.rtcp_mux_policy ==
|
|
|
|
|
PeerConnectionInterface::kRtcpMuxPolicyRequire &&
|
|
|
|
|
content_info.type == cricket::MediaProtocolType::kRtp &&
|
|
|
|
|
!content_info.media_description()->rtcp_mux()) {
|
|
|
|
|
return RTCError(RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"The m= section:" + content_info.name +
|
|
|
|
|
" is invalid. RTCP-MUX is not "
|
|
|
|
|
"enabled when it is required.");
|
|
|
|
|
}
|
|
|
|
|
return RTCError::OK();
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-16 16:42:14 -07:00
|
|
|
void JsepTransportController::HandleRejectedContent(
|
2018-04-10 14:41:03 -07:00
|
|
|
const cricket::ContentInfo& content_info,
|
|
|
|
|
const cricket::SessionDescription* description) {
|
2018-02-22 15:26:27 -08:00
|
|
|
// If the content is rejected, let the
|
|
|
|
|
// BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
|
2018-04-13 16:44:34 -07:00
|
|
|
// then destroy the cricket::JsepTransport.
|
2018-04-16 16:42:14 -07:00
|
|
|
RemoveTransportForMid(content_info.name);
|
2018-03-30 10:48:35 -07:00
|
|
|
if (content_info.name == bundled_mid()) {
|
2019-01-27 17:29:42 +01:00
|
|
|
for (const auto& content_name : bundle_group_->content_names()) {
|
2018-04-16 16:42:14 -07:00
|
|
|
RemoveTransportForMid(content_name);
|
2018-03-30 10:48:35 -07:00
|
|
|
}
|
|
|
|
|
bundle_group_.reset();
|
|
|
|
|
} else if (IsBundled(content_info.name)) {
|
|
|
|
|
// Remove the rejected content from the |bundle_group_|.
|
2018-02-22 15:26:27 -08:00
|
|
|
bundle_group_->RemoveContentName(content_info.name);
|
2018-03-30 10:48:35 -07:00
|
|
|
// Reset the bundle group if nothing left.
|
|
|
|
|
if (!bundle_group_->FirstContentName()) {
|
|
|
|
|
bundle_group_.reset();
|
|
|
|
|
}
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
2018-04-16 16:42:14 -07:00
|
|
|
MaybeDestroyJsepTransport(content_info.name);
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:44:34 -07:00
|
|
|
bool JsepTransportController::HandleBundledContent(
|
2018-02-22 15:26:27 -08:00
|
|
|
const cricket::ContentInfo& content_info) {
|
2018-04-10 14:41:03 -07:00
|
|
|
auto jsep_transport = GetJsepTransportByName(*bundled_mid());
|
|
|
|
|
RTC_DCHECK(jsep_transport);
|
2018-02-22 15:26:27 -08:00
|
|
|
// If the content is bundled, let the
|
|
|
|
|
// BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
|
2018-04-13 16:44:34 -07:00
|
|
|
// then destroy the cricket::JsepTransport.
|
2018-04-16 16:42:14 -07:00
|
|
|
if (SetTransportForMid(content_info.name, jsep_transport)) {
|
2018-11-14 10:57:24 -08:00
|
|
|
// TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
|
|
|
|
|
// because it means that we first create media transport and start
|
|
|
|
|
// connecting it, and then we destroy it. We will need to address it before
|
|
|
|
|
// video path is enabled.
|
2018-04-13 16:44:34 -07:00
|
|
|
MaybeDestroyJsepTransport(content_info.name);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2018-04-10 14:41:03 -07:00
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:44:34 -07:00
|
|
|
bool JsepTransportController::SetTransportForMid(
|
2018-04-10 14:41:03 -07:00
|
|
|
const std::string& mid,
|
2018-04-16 16:42:14 -07:00
|
|
|
cricket::JsepTransport* jsep_transport) {
|
2018-04-13 16:44:34 -07:00
|
|
|
RTC_DCHECK(jsep_transport);
|
2018-04-10 14:41:03 -07:00
|
|
|
if (mid_to_transport_[mid] == jsep_transport) {
|
2018-04-13 16:44:34 -07:00
|
|
|
return true;
|
2018-04-10 14:41:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mid_to_transport_[mid] = jsep_transport;
|
2018-04-16 16:42:14 -07:00
|
|
|
return config_.transport_observer->OnTransportChanged(
|
2019-02-28 07:51:00 +01:00
|
|
|
mid, jsep_transport->rtp_transport(), jsep_transport->RtpDtlsTransport(),
|
2019-09-23 14:53:54 -07:00
|
|
|
jsep_transport->media_transport(),
|
|
|
|
|
jsep_transport->data_channel_transport());
|
2018-04-10 14:41:03 -07:00
|
|
|
}
|
|
|
|
|
|
2018-04-16 16:42:14 -07:00
|
|
|
void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
bool ret = config_.transport_observer->OnTransportChanged(
|
2019-09-23 14:53:54 -07:00
|
|
|
mid, nullptr, nullptr, nullptr, nullptr);
|
2018-04-16 16:42:14 -07:00
|
|
|
// Calling OnTransportChanged with nullptr should always succeed, since it is
|
|
|
|
|
// only expected to fail when adding media to a transport (not removing).
|
|
|
|
|
RTC_DCHECK(ret);
|
2018-04-10 14:41:03 -07:00
|
|
|
mid_to_transport_.erase(mid);
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cricket::JsepTransportDescription
|
|
|
|
|
JsepTransportController::CreateJsepTransportDescription(
|
2019-06-03 20:35:45 +02:00
|
|
|
const cricket::ContentInfo& content_info,
|
|
|
|
|
const cricket::TransportInfo& transport_info,
|
2018-03-30 10:48:35 -07:00
|
|
|
const std::vector<int>& encrypted_extension_ids,
|
2019-09-30 15:12:47 -07:00
|
|
|
int rtp_abs_sendtime_extn_id,
|
|
|
|
|
absl::optional<std::string> media_alt_protocol,
|
|
|
|
|
absl::optional<std::string> data_alt_protocol) {
|
2018-02-22 15:26:27 -08:00
|
|
|
const cricket::MediaContentDescription* content_desc =
|
2019-06-03 20:35:45 +02:00
|
|
|
content_info.media_description();
|
2018-02-22 15:26:27 -08:00
|
|
|
RTC_DCHECK(content_desc);
|
|
|
|
|
bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
|
|
|
|
|
? true
|
|
|
|
|
: content_desc->rtcp_mux();
|
|
|
|
|
|
|
|
|
|
return cricket::JsepTransportDescription(
|
|
|
|
|
rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
|
2019-09-30 15:12:47 -07:00
|
|
|
rtp_abs_sendtime_extn_id, transport_info.description, media_alt_protocol,
|
|
|
|
|
data_alt_protocol);
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JsepTransportController::ShouldUpdateBundleGroup(
|
|
|
|
|
SdpType type,
|
|
|
|
|
const cricket::SessionDescription* description) {
|
|
|
|
|
if (config_.bundle_policy ==
|
|
|
|
|
PeerConnectionInterface::kBundlePolicyMaxBundle) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type != SdpType::kAnswer) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTC_DCHECK(local_desc_ && remote_desc_);
|
|
|
|
|
const cricket::ContentGroup* local_bundle =
|
|
|
|
|
local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
|
|
|
|
|
const cricket::ContentGroup* remote_bundle =
|
|
|
|
|
remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
|
|
|
|
|
return local_bundle && remote_bundle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
|
|
|
|
|
const cricket::ContentInfo& content_info) {
|
|
|
|
|
const cricket::MediaContentDescription* content_desc =
|
2019-06-03 20:35:45 +02:00
|
|
|
content_info.media_description();
|
2018-02-22 15:26:27 -08:00
|
|
|
|
2018-10-11 15:33:17 -07:00
|
|
|
if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
|
2018-02-22 15:26:27 -08:00
|
|
|
return std::vector<int>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<int> encrypted_header_extension_ids;
|
2019-01-27 17:29:42 +01:00
|
|
|
for (const auto& extension : content_desc->rtp_header_extensions()) {
|
2018-02-22 15:26:27 -08:00
|
|
|
if (!extension.encrypt) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-01-28 17:25:26 -08:00
|
|
|
if (!absl::c_linear_search(encrypted_header_extension_ids, extension.id)) {
|
2018-02-22 15:26:27 -08:00
|
|
|
encrypted_header_extension_ids.push_back(extension.id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return encrypted_header_extension_ids;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<int>
|
|
|
|
|
JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
|
|
|
|
|
const cricket::SessionDescription* description) {
|
|
|
|
|
RTC_DCHECK(description);
|
|
|
|
|
RTC_DCHECK(bundle_group_);
|
|
|
|
|
|
|
|
|
|
std::vector<int> merged_ids;
|
|
|
|
|
// Union the encrypted header IDs in the group when bundle is enabled.
|
|
|
|
|
for (const cricket::ContentInfo& content_info : description->contents()) {
|
|
|
|
|
if (bundle_group_->HasContentName(content_info.name)) {
|
|
|
|
|
std::vector<int> extension_ids =
|
|
|
|
|
GetEncryptedHeaderExtensionIds(content_info);
|
|
|
|
|
for (int id : extension_ids) {
|
2019-01-28 17:25:26 -08:00
|
|
|
if (!absl::c_linear_search(merged_ids, id)) {
|
2018-02-22 15:26:27 -08:00
|
|
|
merged_ids.push_back(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return merged_ids;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-30 15:12:47 -07:00
|
|
|
RTCError JsepTransportController::GetAltProtocolsForBundle(
|
|
|
|
|
const cricket::SessionDescription* description,
|
|
|
|
|
absl::optional<std::string>* media_alt_protocol,
|
|
|
|
|
absl::optional<std::string>* data_alt_protocol) {
|
|
|
|
|
RTC_DCHECK(description);
|
|
|
|
|
RTC_DCHECK(bundle_group_);
|
|
|
|
|
RTC_DCHECK(media_alt_protocol);
|
|
|
|
|
RTC_DCHECK(data_alt_protocol);
|
|
|
|
|
|
|
|
|
|
bool found_media = false;
|
|
|
|
|
bool found_data = false;
|
|
|
|
|
for (const cricket::ContentInfo& content : description->contents()) {
|
|
|
|
|
if (bundle_group_->HasContentName(content.name)) {
|
|
|
|
|
const cricket::MediaContentDescription* media_description =
|
|
|
|
|
content.media_description();
|
|
|
|
|
switch (media_description->type()) {
|
|
|
|
|
case cricket::MEDIA_TYPE_AUDIO:
|
|
|
|
|
case cricket::MEDIA_TYPE_VIDEO:
|
|
|
|
|
if (found_media &&
|
|
|
|
|
*media_alt_protocol != media_description->alt_protocol()) {
|
|
|
|
|
return RTCError(RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"The BUNDLE group contains conflicting "
|
|
|
|
|
"alt-protocols for media ('" +
|
|
|
|
|
media_alt_protocol->value_or("") + "' and '" +
|
|
|
|
|
media_description->alt_protocol().value_or("") +
|
|
|
|
|
"')");
|
|
|
|
|
}
|
|
|
|
|
found_media = true;
|
|
|
|
|
*media_alt_protocol = media_description->alt_protocol();
|
|
|
|
|
break;
|
|
|
|
|
case cricket::MEDIA_TYPE_DATA:
|
|
|
|
|
if (found_data &&
|
|
|
|
|
*data_alt_protocol != media_description->alt_protocol()) {
|
|
|
|
|
return RTCError(RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"The BUNDLE group contains conflicting "
|
|
|
|
|
"alt-protocols for data ('" +
|
|
|
|
|
data_alt_protocol->value_or("") + "' and '" +
|
|
|
|
|
media_description->alt_protocol().value_or("") +
|
|
|
|
|
"')");
|
|
|
|
|
}
|
|
|
|
|
found_data = true;
|
|
|
|
|
*data_alt_protocol = media_description->alt_protocol();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return RTCError::OK();
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-30 10:48:35 -07:00
|
|
|
int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
|
|
|
|
|
const cricket::ContentInfo& content_info) {
|
|
|
|
|
if (!config_.enable_external_auth) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const cricket::MediaContentDescription* content_desc =
|
2019-06-03 20:35:45 +02:00
|
|
|
content_info.media_description();
|
2018-03-30 10:48:35 -07:00
|
|
|
|
|
|
|
|
const webrtc::RtpExtension* send_time_extension =
|
|
|
|
|
webrtc::RtpExtension::FindHeaderExtensionByUri(
|
|
|
|
|
content_desc->rtp_header_extensions(),
|
|
|
|
|
webrtc::RtpExtension::kAbsSendTimeUri);
|
|
|
|
|
return send_time_extension ? send_time_extension->id : -1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:44:34 -07:00
|
|
|
const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
|
2018-02-22 15:26:27 -08:00
|
|
|
const std::string& mid) const {
|
2018-04-10 14:41:03 -07:00
|
|
|
auto it = mid_to_transport_.find(mid);
|
|
|
|
|
return it == mid_to_transport_.end() ? nullptr : it->second;
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:44:34 -07:00
|
|
|
cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
|
2018-02-22 15:26:27 -08:00
|
|
|
const std::string& mid) {
|
2018-04-10 14:41:03 -07:00
|
|
|
auto it = mid_to_transport_.find(mid);
|
|
|
|
|
return it == mid_to_transport_.end() ? nullptr : it->second;
|
2018-03-30 10:48:35 -07:00
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:44:34 -07:00
|
|
|
const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
|
2018-03-30 10:48:35 -07:00
|
|
|
const std::string& transport_name) const {
|
|
|
|
|
auto it = jsep_transports_by_name_.find(transport_name);
|
|
|
|
|
return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:44:34 -07:00
|
|
|
cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
|
2018-03-30 10:48:35 -07:00
|
|
|
const std::string& transport_name) {
|
|
|
|
|
auto it = jsep_transports_by_name_.find(transport_name);
|
|
|
|
|
return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
2018-11-16 14:13:58 -08:00
|
|
|
std::unique_ptr<webrtc::MediaTransportInterface>
|
|
|
|
|
JsepTransportController::MaybeCreateMediaTransport(
|
|
|
|
|
const cricket::ContentInfo& content_info,
|
2019-02-27 14:26:15 -08:00
|
|
|
const cricket::SessionDescription& description,
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
bool local) {
|
2019-01-25 08:25:33 -08:00
|
|
|
if (config_.media_transport_factory == nullptr) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-25 13:31:15 -08:00
|
|
|
if (!config_.use_media_transport_for_media &&
|
|
|
|
|
!config_.use_media_transport_for_data_channels) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
// Caller (offerer) media transport.
|
|
|
|
|
if (local) {
|
|
|
|
|
if (offer_media_transport_) {
|
|
|
|
|
RTC_LOG(LS_INFO) << "Offered media transport has now been activated.";
|
|
|
|
|
return std::move(offer_media_transport_);
|
|
|
|
|
} else {
|
|
|
|
|
RTC_LOG(LS_INFO)
|
|
|
|
|
<< "Not returning media transport. Either SDES wasn't enabled, or "
|
|
|
|
|
"media transport didn't return an offer earlier.";
|
|
|
|
|
// Offer wasn't generated. Either because media transport didn't want it,
|
|
|
|
|
// or because SDES wasn't enabled.
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remote offer. If no x-mt lines, do not create media transport.
|
|
|
|
|
if (description.MediaTransportSettings().empty()) {
|
2019-01-25 08:25:33 -08:00
|
|
|
return nullptr;
|
2018-10-10 10:34:49 -07:00
|
|
|
}
|
|
|
|
|
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
// When bundle is enabled, two JsepTransports are created, and then
|
|
|
|
|
// the second transport is destroyed (right away).
|
|
|
|
|
// For media transport, we don't want to create the second
|
|
|
|
|
// media transport in the first place.
|
|
|
|
|
RTC_LOG(LS_INFO) << "Returning new, client media transport.";
|
|
|
|
|
|
|
|
|
|
RTC_DCHECK(!local)
|
|
|
|
|
<< "If media transport is used, you must call "
|
|
|
|
|
"GenerateOrGetLastMediaTransportOffer before SetLocalDescription. You "
|
|
|
|
|
"also "
|
|
|
|
|
"must use kRtcpMuxPolicyRequire and kBundlePolicyMaxBundle with media "
|
|
|
|
|
"transport.";
|
2019-01-25 08:25:33 -08:00
|
|
|
MediaTransportSettings settings;
|
|
|
|
|
settings.is_caller = local;
|
2019-02-15 12:05:50 -08:00
|
|
|
if (config_.use_media_transport_for_media) {
|
|
|
|
|
settings.event_log = config_.event_log;
|
|
|
|
|
}
|
2019-02-27 14:26:15 -08:00
|
|
|
|
|
|
|
|
// Assume there is only one media transport (or if more, use the first one).
|
|
|
|
|
if (!local && !description.MediaTransportSettings().empty() &&
|
|
|
|
|
config_.media_transport_factory->GetTransportName() ==
|
|
|
|
|
description.MediaTransportSettings()[0].transport_name) {
|
|
|
|
|
settings.remote_transport_parameters =
|
|
|
|
|
description.MediaTransportSettings()[0].transport_setting;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-25 08:25:33 -08:00
|
|
|
auto media_transport_result =
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
config_.media_transport_factory->CreateMediaTransport(network_thread_,
|
|
|
|
|
settings);
|
2019-01-25 08:25:33 -08:00
|
|
|
|
|
|
|
|
// TODO(sukhanov): Proper error handling.
|
|
|
|
|
RTC_CHECK(media_transport_result.ok());
|
|
|
|
|
|
|
|
|
|
return media_transport_result.MoveValue();
|
2018-11-16 14:13:58 -08:00
|
|
|
}
|
|
|
|
|
|
2019-05-23 15:50:38 -07:00
|
|
|
// TODO(sukhanov): Refactor to avoid code duplication for Media and Datagram
|
|
|
|
|
// transports setup.
|
|
|
|
|
std::unique_ptr<webrtc::DatagramTransportInterface>
|
|
|
|
|
JsepTransportController::MaybeCreateDatagramTransport(
|
|
|
|
|
const cricket::ContentInfo& content_info,
|
|
|
|
|
const cricket::SessionDescription& description,
|
|
|
|
|
bool local) {
|
|
|
|
|
if (config_.media_transport_factory == nullptr) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
if (!(config_.use_datagram_transport ||
|
|
|
|
|
config_.use_datagram_transport_for_data_channels)) {
|
2019-05-23 15:50:38 -07:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Caller (offerer) datagram transport.
|
Reland: Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Ifcc428c8d76fb77dcc8abaa79507c620bcfb31b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140920
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28198}
2019-06-07 10:28:06 -07:00
|
|
|
if (offer_datagram_transport_) {
|
|
|
|
|
RTC_DCHECK(local);
|
|
|
|
|
RTC_LOG(LS_INFO) << "Offered datagram transport has now been activated.";
|
|
|
|
|
return std::move(offer_datagram_transport_);
|
2019-05-23 15:50:38 -07:00
|
|
|
}
|
|
|
|
|
|
Reland: Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Ifcc428c8d76fb77dcc8abaa79507c620bcfb31b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140920
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28198}
2019-06-07 10:28:06 -07:00
|
|
|
const cricket::TransportDescription* transport_description =
|
|
|
|
|
description.GetTransportDescriptionByName(content_info.mid());
|
|
|
|
|
RTC_DCHECK(transport_description)
|
|
|
|
|
<< "Missing transport description for mid=" << content_info.mid();
|
|
|
|
|
|
|
|
|
|
if (!transport_description->opaque_parameters) {
|
|
|
|
|
RTC_LOG(LS_INFO)
|
|
|
|
|
<< "No opaque transport parameters, not creating datagram transport";
|
Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Id8996eb1871e79d93b7923a5d7eb3431548c798d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140700
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Anton Sukhanov <sukhanov@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28182}
2019-06-06 17:26:32 -07:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
Reland: Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Ifcc428c8d76fb77dcc8abaa79507c620bcfb31b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140920
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28198}
2019-06-07 10:28:06 -07:00
|
|
|
if (transport_description->opaque_parameters->protocol !=
|
|
|
|
|
config_.media_transport_factory->GetTransportName()) {
|
|
|
|
|
RTC_LOG(LS_INFO) << "Opaque transport parameters for protocol="
|
|
|
|
|
<< transport_description->opaque_parameters->protocol
|
|
|
|
|
<< ", which does not match supported protocol="
|
|
|
|
|
<< config_.media_transport_factory->GetTransportName();
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTC_DCHECK(!local);
|
2019-05-23 15:50:38 -07:00
|
|
|
// When bundle is enabled, two JsepTransports are created, and then
|
|
|
|
|
// the second transport is destroyed (right away).
|
|
|
|
|
// For datagram transport, we don't want to create the second
|
|
|
|
|
// datagram transport in the first place.
|
|
|
|
|
RTC_LOG(LS_INFO) << "Returning new, client datagram transport.";
|
|
|
|
|
|
|
|
|
|
MediaTransportSettings settings;
|
|
|
|
|
settings.is_caller = local;
|
Reland: Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Ifcc428c8d76fb77dcc8abaa79507c620bcfb31b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140920
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28198}
2019-06-07 10:28:06 -07:00
|
|
|
settings.remote_transport_parameters =
|
|
|
|
|
transport_description->opaque_parameters->parameters;
|
2019-05-23 15:50:38 -07:00
|
|
|
settings.event_log = config_.event_log;
|
|
|
|
|
|
|
|
|
|
auto datagram_transport_result =
|
|
|
|
|
config_.media_transport_factory->CreateDatagramTransport(network_thread_,
|
|
|
|
|
settings);
|
|
|
|
|
|
|
|
|
|
// TODO(sukhanov): Proper error handling.
|
|
|
|
|
RTC_CHECK(datagram_transport_result.ok());
|
|
|
|
|
|
|
|
|
|
return datagram_transport_result.MoveValue();
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 14:13:58 -08:00
|
|
|
RTCError JsepTransportController::MaybeCreateJsepTransport(
|
|
|
|
|
bool local,
|
2019-02-27 14:26:15 -08:00
|
|
|
const cricket::ContentInfo& content_info,
|
|
|
|
|
const cricket::SessionDescription& description) {
|
2018-11-16 14:13:58 -08:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
|
|
|
|
|
if (transport) {
|
|
|
|
|
return RTCError::OK();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const cricket::MediaContentDescription* content_desc =
|
2019-06-03 20:35:45 +02:00
|
|
|
content_info.media_description();
|
2018-11-16 14:13:58 -08:00
|
|
|
if (certificate_ && !content_desc->cryptos().empty()) {
|
|
|
|
|
return RTCError(RTCErrorType::INVALID_PARAMETER,
|
|
|
|
|
"SDES and DTLS-SRTP cannot be enabled at the same time.");
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-16 08:25:21 -08:00
|
|
|
std::unique_ptr<cricket::IceTransportInternal> ice =
|
|
|
|
|
CreateIceTransport(content_info.name, /*rtcp=*/false);
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<MediaTransportInterface> media_transport =
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
MaybeCreateMediaTransport(content_info, description, local);
|
|
|
|
|
if (media_transport) {
|
|
|
|
|
media_transport_created_once_ = true;
|
|
|
|
|
media_transport->Connect(ice.get());
|
|
|
|
|
}
|
2019-01-16 08:25:21 -08:00
|
|
|
|
2019-05-23 15:50:38 -07:00
|
|
|
std::unique_ptr<DatagramTransportInterface> datagram_transport =
|
|
|
|
|
MaybeCreateDatagramTransport(content_info, description, local);
|
|
|
|
|
if (datagram_transport) {
|
|
|
|
|
datagram_transport->Connect(ice.get());
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 14:13:58 -08:00
|
|
|
std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
|
2019-07-10 15:44:56 -07:00
|
|
|
CreateDtlsTransport(content_info, ice.get(), nullptr);
|
2018-11-16 14:13:58 -08:00
|
|
|
|
|
|
|
|
std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
|
|
|
|
|
std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
|
|
|
|
|
std::unique_ptr<SrtpTransport> sdes_transport;
|
|
|
|
|
std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
|
2019-08-20 16:58:03 -07:00
|
|
|
std::unique_ptr<RtpTransportInternal> datagram_rtp_transport;
|
2018-11-16 14:13:58 -08:00
|
|
|
|
2019-05-29 17:34:13 -07:00
|
|
|
std::unique_ptr<cricket::IceTransportInternal> rtcp_ice;
|
2018-11-16 14:13:58 -08:00
|
|
|
if (config_.rtcp_mux_policy !=
|
|
|
|
|
PeerConnectionInterface::kRtcpMuxPolicyRequire &&
|
|
|
|
|
content_info.type == cricket::MediaProtocolType::kRtp) {
|
2019-01-16 08:25:21 -08:00
|
|
|
RTC_DCHECK(media_transport == nullptr);
|
2019-05-23 15:50:38 -07:00
|
|
|
RTC_DCHECK(datagram_transport == nullptr);
|
2019-05-29 17:34:13 -07:00
|
|
|
rtcp_ice = CreateIceTransport(content_info.name, /*rtcp=*/true);
|
2019-07-10 15:44:56 -07:00
|
|
|
rtcp_dtls_transport = CreateDtlsTransport(content_info, rtcp_ice.get(),
|
2019-05-29 17:34:13 -07:00
|
|
|
/*datagram_transport=*/nullptr);
|
2019-05-23 15:50:38 -07:00
|
|
|
}
|
|
|
|
|
|
2019-08-23 10:31:11 -07:00
|
|
|
// Only create a datagram RTP transport if the datagram transport should be
|
|
|
|
|
// used for RTP.
|
|
|
|
|
if (datagram_transport && config_.use_datagram_transport) {
|
2019-05-23 15:50:38 -07:00
|
|
|
// TODO(sukhanov): We use unencrypted RTP transport over DatagramTransport,
|
|
|
|
|
// because MediaTransport encrypts. In the future we may want to
|
|
|
|
|
// implement our own version of RtpTransport over MediaTransport, because
|
|
|
|
|
// it will give us more control over things like:
|
|
|
|
|
// - Fusing
|
|
|
|
|
// - Rtp header compression
|
|
|
|
|
// - Handling Rtcp feedback.
|
|
|
|
|
RTC_LOG(LS_INFO) << "Creating UnencryptedRtpTransport, because datagram "
|
|
|
|
|
"transport is used.";
|
|
|
|
|
RTC_DCHECK(!rtcp_dtls_transport);
|
2019-09-17 17:06:18 +02:00
|
|
|
datagram_rtp_transport = std::make_unique<DatagramRtpTransport>(
|
2019-08-20 16:58:03 -07:00
|
|
|
content_info.media_description()->rtp_header_extensions(), ice.get(),
|
|
|
|
|
datagram_transport.get());
|
Reland: Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Ifcc428c8d76fb77dcc8abaa79507c620bcfb31b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140920
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28198}
2019-06-07 10:28:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config_.disable_encryption) {
|
2019-05-23 15:50:38 -07:00
|
|
|
RTC_LOG(LS_INFO)
|
|
|
|
|
<< "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
|
2018-02-22 15:26:27 -08:00
|
|
|
unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
|
2018-04-10 14:41:03 -07:00
|
|
|
content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
|
2018-02-22 15:26:27 -08:00
|
|
|
} else if (!content_desc->cryptos().empty()) {
|
2018-04-10 14:41:03 -07:00
|
|
|
sdes_transport = CreateSdesTransport(
|
|
|
|
|
content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
|
2019-05-23 15:50:38 -07:00
|
|
|
RTC_LOG(LS_INFO) << "Creating SdesTransport.";
|
2018-02-22 15:26:27 -08:00
|
|
|
} else {
|
2019-05-23 15:50:38 -07:00
|
|
|
RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
|
2018-04-10 14:41:03 -07:00
|
|
|
dtls_srtp_transport = CreateDtlsSrtpTransport(
|
|
|
|
|
content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
2019-09-23 14:53:54 -07:00
|
|
|
std::unique_ptr<cricket::SctpTransportInternal> sctp_transport;
|
|
|
|
|
if (config_.sctp_factory) {
|
|
|
|
|
sctp_transport =
|
|
|
|
|
config_.sctp_factory->CreateSctpTransport(rtp_dtls_transport.get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DataChannelTransportInterface* data_channel_transport = nullptr;
|
|
|
|
|
if (config_.use_datagram_transport_for_data_channels) {
|
|
|
|
|
data_channel_transport = datagram_transport.get();
|
|
|
|
|
} else if (config_.use_media_transport_for_data_channels) {
|
|
|
|
|
data_channel_transport = media_transport.get();
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:44:34 -07:00
|
|
|
std::unique_ptr<cricket::JsepTransport> jsep_transport =
|
2019-09-17 17:06:18 +02:00
|
|
|
std::make_unique<cricket::JsepTransport>(
|
2019-05-29 17:34:13 -07:00
|
|
|
content_info.name, certificate_, std::move(ice), std::move(rtcp_ice),
|
|
|
|
|
std::move(unencrypted_rtp_transport), std::move(sdes_transport),
|
Reland: Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Ifcc428c8d76fb77dcc8abaa79507c620bcfb31b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140920
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28198}
2019-06-07 10:28:06 -07:00
|
|
|
std::move(dtls_srtp_transport), std::move(datagram_rtp_transport),
|
|
|
|
|
std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
|
2019-09-23 14:53:54 -07:00
|
|
|
std::move(sctp_transport), std::move(media_transport),
|
|
|
|
|
std::move(datagram_transport), data_channel_transport);
|
2019-05-23 15:50:38 -07:00
|
|
|
|
2019-09-18 18:22:12 +02:00
|
|
|
jsep_transport->rtp_transport()->SignalRtcpPacketReceived.connect(
|
|
|
|
|
this, &JsepTransportController::OnRtcpPacketReceived_n);
|
|
|
|
|
|
2018-02-22 15:26:27 -08:00
|
|
|
jsep_transport->SignalRtcpMuxActive.connect(
|
|
|
|
|
this, &JsepTransportController::UpdateAggregateStates_n);
|
2018-11-01 07:26:03 -07:00
|
|
|
jsep_transport->SignalMediaTransportStateChanged.connect(
|
2018-11-08 11:23:22 -08:00
|
|
|
this, &JsepTransportController::OnMediaTransportStateChanged_n);
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
jsep_transport->SignalDataChannelTransportNegotiated.connect(
|
|
|
|
|
this, &JsepTransportController::OnDataChannelTransportNegotiated_n);
|
2018-04-16 16:42:14 -07:00
|
|
|
SetTransportForMid(content_info.name, jsep_transport.get());
|
2018-03-30 10:48:35 -07:00
|
|
|
|
2018-04-10 14:41:03 -07:00
|
|
|
jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
|
|
|
|
|
UpdateAggregateStates_n();
|
2018-03-30 10:48:35 -07:00
|
|
|
return RTCError::OK();
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsepTransportController::MaybeDestroyJsepTransport(
|
|
|
|
|
const std::string& mid) {
|
2018-04-10 14:41:03 -07:00
|
|
|
auto jsep_transport = GetJsepTransportByName(mid);
|
|
|
|
|
if (!jsep_transport) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't destroy the JsepTransport if there are still media sections referring
|
|
|
|
|
// to it.
|
|
|
|
|
for (const auto& kv : mid_to_transport_) {
|
|
|
|
|
if (kv.second == jsep_transport) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-11-15 08:26:19 -08:00
|
|
|
|
2018-03-30 10:48:35 -07:00
|
|
|
jsep_transports_by_name_.erase(mid);
|
2018-02-22 15:26:27 -08:00
|
|
|
UpdateAggregateStates_n();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsepTransportController::DestroyAllJsepTransports_n() {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2018-11-15 08:26:19 -08:00
|
|
|
|
|
|
|
|
for (const auto& jsep_transport : jsep_transports_by_name_) {
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
config_.transport_observer->OnTransportChanged(
|
2019-09-23 14:53:54 -07:00
|
|
|
jsep_transport.first, nullptr, nullptr, nullptr, nullptr);
|
2018-11-15 08:26:19 -08:00
|
|
|
}
|
|
|
|
|
|
2018-03-30 10:48:35 -07:00
|
|
|
jsep_transports_by_name_.clear();
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
|
|
|
|
|
ice_role_ = ice_role;
|
|
|
|
|
for (auto& dtls : GetDtlsTransports()) {
|
|
|
|
|
dtls->ice_transport()->SetIceRole(ice_role_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cricket::IceRole JsepTransportController::DetermineIceRole(
|
2018-04-13 16:44:34 -07:00
|
|
|
cricket::JsepTransport* jsep_transport,
|
2018-02-22 15:26:27 -08:00
|
|
|
const cricket::TransportInfo& transport_info,
|
|
|
|
|
SdpType type,
|
|
|
|
|
bool local) {
|
|
|
|
|
cricket::IceRole ice_role = ice_role_;
|
|
|
|
|
auto tdesc = transport_info.description;
|
|
|
|
|
if (local) {
|
|
|
|
|
// The initial offer side may use ICE Lite, in which case, per RFC5245
|
|
|
|
|
// Section 5.1.1, the answer side should take the controlling role if it is
|
|
|
|
|
// in the full ICE mode.
|
|
|
|
|
//
|
|
|
|
|
// When both sides use ICE Lite, the initial offer side must take the
|
|
|
|
|
// controlling role, and this is the default logic implemented in
|
|
|
|
|
// SetLocalDescription in JsepTransportController.
|
|
|
|
|
if (jsep_transport->remote_description() &&
|
|
|
|
|
jsep_transport->remote_description()->transport_desc.ice_mode ==
|
|
|
|
|
cricket::ICEMODE_LITE &&
|
|
|
|
|
ice_role_ == cricket::ICEROLE_CONTROLLED &&
|
|
|
|
|
tdesc.ice_mode == cricket::ICEMODE_FULL) {
|
|
|
|
|
ice_role = cricket::ICEROLE_CONTROLLING;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Older versions of Chrome expect the ICE role to be re-determined when an
|
|
|
|
|
// ICE restart occurs, and also don't perform conflict resolution correctly,
|
|
|
|
|
// so for now we can't safely stop doing this, unless the application opts
|
|
|
|
|
// in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
|
|
|
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=628676
|
|
|
|
|
// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
|
|
|
|
|
// enough population.
|
|
|
|
|
if (config_.redetermine_role_on_ice_restart &&
|
|
|
|
|
jsep_transport->local_description() &&
|
|
|
|
|
cricket::IceCredentialsChanged(
|
|
|
|
|
jsep_transport->local_description()->transport_desc.ice_ufrag,
|
|
|
|
|
jsep_transport->local_description()->transport_desc.ice_pwd,
|
|
|
|
|
tdesc.ice_ufrag, tdesc.ice_pwd) &&
|
|
|
|
|
// Don't change the ICE role if the remote endpoint is ICE lite; we
|
|
|
|
|
// should always be controlling in that case.
|
|
|
|
|
(!jsep_transport->remote_description() ||
|
|
|
|
|
jsep_transport->remote_description()->transport_desc.ice_mode !=
|
|
|
|
|
cricket::ICEMODE_LITE)) {
|
|
|
|
|
ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
|
|
|
|
|
: cricket::ICEROLE_CONTROLLED;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
|
|
|
|
|
// supports only ice_lite, this local endpoint should take the CONTROLLING
|
|
|
|
|
// role.
|
|
|
|
|
// TODO(deadbeef): This is a session-level attribute, so it really shouldn't
|
|
|
|
|
// be in a TransportDescription in the first place...
|
|
|
|
|
if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
|
|
|
|
|
tdesc.ice_mode == cricket::ICEMODE_LITE) {
|
|
|
|
|
ice_role = cricket::ICEROLE_CONTROLLING;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we use ICE Lite and the remote endpoint uses the full implementation
|
|
|
|
|
// of ICE, the local endpoint must take the controlled role, and the other
|
|
|
|
|
// side must be the controlling role.
|
|
|
|
|
if (jsep_transport->local_description() &&
|
|
|
|
|
jsep_transport->local_description()->transport_desc.ice_mode ==
|
|
|
|
|
cricket::ICEMODE_LITE &&
|
|
|
|
|
ice_role_ == cricket::ICEROLE_CONTROLLING &&
|
2018-03-30 10:48:35 -07:00
|
|
|
tdesc.ice_mode == cricket::ICEMODE_FULL) {
|
2018-02-22 15:26:27 -08:00
|
|
|
ice_role = cricket::ICEROLE_CONTROLLED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ice_role;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsepTransportController::OnTransportWritableState_n(
|
|
|
|
|
rtc::PacketTransportInternal* transport) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
|
|
|
|
|
<< " writability changed to " << transport->writable()
|
|
|
|
|
<< ".";
|
|
|
|
|
UpdateAggregateStates_n();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsepTransportController::OnTransportReceivingState_n(
|
|
|
|
|
rtc::PacketTransportInternal* transport) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
UpdateAggregateStates_n();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsepTransportController::OnTransportGatheringState_n(
|
|
|
|
|
cricket::IceTransportInternal* transport) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
UpdateAggregateStates_n();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsepTransportController::OnTransportCandidateGathered_n(
|
|
|
|
|
cricket::IceTransportInternal* transport,
|
|
|
|
|
const cricket::Candidate& candidate) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
|
|
|
|
|
// We should never signal peer-reflexive candidates.
|
|
|
|
|
if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
|
|
|
|
|
RTC_NOTREACHED();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-08-31 13:06:05 -07:00
|
|
|
std::string transport_name = transport->transport_name();
|
|
|
|
|
invoker_.AsyncInvoke<void>(
|
|
|
|
|
RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
|
|
|
|
|
SignalIceCandidatesGathered(transport_name, {candidate});
|
|
|
|
|
});
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
|
2019-06-01 12:23:43 +03:00
|
|
|
void JsepTransportController::OnTransportCandidateError_n(
|
|
|
|
|
cricket::IceTransportInternal* transport,
|
|
|
|
|
const cricket::IceCandidateErrorEvent& event) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
|
|
|
|
|
invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
|
|
|
|
|
[this, event] { SignalIceCandidateError(event); });
|
|
|
|
|
}
|
2018-02-22 15:26:27 -08:00
|
|
|
void JsepTransportController::OnTransportCandidatesRemoved_n(
|
|
|
|
|
cricket::IceTransportInternal* transport,
|
|
|
|
|
const cricket::Candidates& candidates) {
|
|
|
|
|
invoker_.AsyncInvoke<void>(
|
|
|
|
|
RTC_FROM_HERE, signaling_thread_,
|
2018-08-31 13:06:05 -07:00
|
|
|
[this, candidates] { SignalIceCandidatesRemoved(candidates); });
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
2019-08-06 10:54:47 -07:00
|
|
|
void JsepTransportController::OnTransportCandidatePairChanged_n(
|
|
|
|
|
const cricket::CandidatePairChangeEvent& event) {
|
|
|
|
|
invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this, event] {
|
|
|
|
|
SignalIceCandidatePairChanged(event);
|
|
|
|
|
});
|
|
|
|
|
}
|
2018-02-22 15:26:27 -08:00
|
|
|
|
|
|
|
|
void JsepTransportController::OnTransportRoleConflict_n(
|
|
|
|
|
cricket::IceTransportInternal* transport) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
// Note: since the role conflict is handled entirely on the network thread,
|
|
|
|
|
// we don't need to worry about role conflicts occurring on two ports at
|
|
|
|
|
// once. The first one encountered should immediately reverse the role.
|
|
|
|
|
cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
|
|
|
|
|
? cricket::ICEROLE_CONTROLLED
|
|
|
|
|
: cricket::ICEROLE_CONTROLLING;
|
|
|
|
|
RTC_LOG(LS_INFO) << "Got role conflict; switching to "
|
|
|
|
|
<< (reversed_role == cricket::ICEROLE_CONTROLLING
|
|
|
|
|
? "controlling"
|
|
|
|
|
: "controlled")
|
|
|
|
|
<< " role.";
|
|
|
|
|
SetIceRole_n(reversed_role);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsepTransportController::OnTransportStateChanged_n(
|
|
|
|
|
cricket::IceTransportInternal* transport) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
|
|
|
|
|
<< transport->component()
|
|
|
|
|
<< " state changed. Check if state is complete.";
|
|
|
|
|
UpdateAggregateStates_n();
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-08 11:23:22 -08:00
|
|
|
void JsepTransportController::OnMediaTransportStateChanged_n() {
|
|
|
|
|
UpdateAggregateStates_n();
|
|
|
|
|
}
|
|
|
|
|
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
void JsepTransportController::OnDataChannelTransportNegotiated_n(
|
|
|
|
|
cricket::JsepTransport* transport,
|
2019-09-23 14:53:54 -07:00
|
|
|
DataChannelTransportInterface* data_channel_transport) {
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
for (auto it : mid_to_transport_) {
|
|
|
|
|
if (it.second == transport) {
|
|
|
|
|
config_.transport_observer->OnTransportChanged(
|
|
|
|
|
it.first, transport->rtp_transport(), transport->RtpDtlsTransport(),
|
2019-09-23 14:53:54 -07:00
|
|
|
transport->media_transport(), data_channel_transport);
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-22 15:26:27 -08:00
|
|
|
void JsepTransportController::UpdateAggregateStates_n() {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
|
|
|
|
|
auto dtls_transports = GetDtlsTransports();
|
2018-11-23 16:18:59 +00:00
|
|
|
cricket::IceConnectionState new_connection_state =
|
|
|
|
|
cricket::kIceConnectionConnecting;
|
2018-10-18 15:58:17 +02:00
|
|
|
PeerConnectionInterface::IceConnectionState new_ice_connection_state =
|
|
|
|
|
PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
|
|
|
|
|
PeerConnectionInterface::PeerConnectionState new_combined_state =
|
|
|
|
|
PeerConnectionInterface::PeerConnectionState::kNew;
|
2018-02-22 15:26:27 -08:00
|
|
|
cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
|
2018-11-23 16:18:59 +00:00
|
|
|
bool any_failed = false;
|
|
|
|
|
|
|
|
|
|
// TODO(http://bugs.webrtc.org/9719) If(when) media_transport disables
|
|
|
|
|
// dtls_transports entirely, the below line will have to be changed to account
|
|
|
|
|
// for the fact that dtls transports might be absent.
|
|
|
|
|
bool all_connected = !dtls_transports.empty();
|
|
|
|
|
bool all_completed = !dtls_transports.empty();
|
2018-02-22 15:26:27 -08:00
|
|
|
bool any_gathering = false;
|
|
|
|
|
bool all_done_gathering = !dtls_transports.empty();
|
2018-10-18 15:58:17 +02:00
|
|
|
|
|
|
|
|
std::map<IceTransportState, int> ice_state_counts;
|
|
|
|
|
std::map<cricket::DtlsTransportState, int> dtls_state_counts;
|
|
|
|
|
|
2018-02-22 15:26:27 -08:00
|
|
|
for (const auto& dtls : dtls_transports) {
|
2018-11-23 16:18:59 +00:00
|
|
|
any_failed = any_failed || dtls->ice_transport()->GetState() ==
|
|
|
|
|
cricket::IceTransportState::STATE_FAILED;
|
|
|
|
|
all_connected = all_connected && dtls->writable();
|
|
|
|
|
all_completed =
|
|
|
|
|
all_completed && dtls->writable() &&
|
|
|
|
|
dtls->ice_transport()->GetState() ==
|
|
|
|
|
cricket::IceTransportState::STATE_COMPLETED &&
|
|
|
|
|
dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
|
|
|
|
|
dtls->ice_transport()->gathering_state() ==
|
|
|
|
|
cricket::kIceGatheringComplete;
|
2018-02-22 15:26:27 -08:00
|
|
|
any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
|
|
|
|
|
cricket::kIceGatheringNew;
|
|
|
|
|
all_done_gathering =
|
|
|
|
|
all_done_gathering && dtls->ice_transport()->gathering_state() ==
|
|
|
|
|
cricket::kIceGatheringComplete;
|
2018-10-18 15:58:17 +02:00
|
|
|
|
|
|
|
|
dtls_state_counts[dtls->dtls_state()]++;
|
|
|
|
|
ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
2018-11-01 07:26:03 -07:00
|
|
|
|
2019-08-16 15:47:45 -07:00
|
|
|
// Don't indicate that the call failed or isn't connected due to media
|
|
|
|
|
// transport state unless the media transport is used for media. If it's only
|
|
|
|
|
// used for data channels, it will signal those separately.
|
|
|
|
|
if (config_.use_media_transport_for_media || config_.use_datagram_transport) {
|
|
|
|
|
for (auto it = jsep_transports_by_name_.begin();
|
|
|
|
|
it != jsep_transports_by_name_.end(); ++it) {
|
|
|
|
|
auto jsep_transport = it->second.get();
|
|
|
|
|
if (!jsep_transport->media_transport()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2018-11-23 16:18:59 +00:00
|
|
|
|
2019-08-16 15:47:45 -07:00
|
|
|
// There is no 'kIceConnectionDisconnected', so we only need to handle
|
|
|
|
|
// connected and completed.
|
|
|
|
|
// We treat kClosed as failed, because if it happens before shutting down
|
|
|
|
|
// media transports it means that there was a failure.
|
|
|
|
|
// MediaTransportInterface allows to flip back and forth between kWritable
|
|
|
|
|
// and kPending, but there does not exist an implementation that does
|
|
|
|
|
// that, and the contract of jsep transport controller doesn't quite
|
|
|
|
|
// expect that. When this happens, we would go from connected to
|
|
|
|
|
// connecting state, but this may change in future.
|
|
|
|
|
any_failed |= jsep_transport->media_transport_state() ==
|
|
|
|
|
webrtc::MediaTransportState::kClosed;
|
|
|
|
|
all_completed &= jsep_transport->media_transport_state() ==
|
|
|
|
|
webrtc::MediaTransportState::kWritable;
|
|
|
|
|
all_connected &= jsep_transport->media_transport_state() ==
|
|
|
|
|
webrtc::MediaTransportState::kWritable;
|
|
|
|
|
}
|
2018-11-23 16:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (any_failed) {
|
|
|
|
|
new_connection_state = cricket::kIceConnectionFailed;
|
|
|
|
|
} else if (all_completed) {
|
|
|
|
|
new_connection_state = cricket::kIceConnectionCompleted;
|
|
|
|
|
} else if (all_connected) {
|
|
|
|
|
new_connection_state = cricket::kIceConnectionConnected;
|
|
|
|
|
}
|
|
|
|
|
if (ice_connection_state_ != new_connection_state) {
|
|
|
|
|
ice_connection_state_ = new_connection_state;
|
|
|
|
|
invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
|
|
|
|
|
[this, new_connection_state] {
|
|
|
|
|
SignalIceConnectionState(new_connection_state);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-18 15:58:17 +02:00
|
|
|
// Compute the current RTCIceConnectionState as described in
|
|
|
|
|
// https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
|
|
|
|
|
// The PeerConnection is responsible for handling the "closed" state.
|
|
|
|
|
int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
|
|
|
|
|
int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
|
|
|
|
|
int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
|
|
|
|
|
int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
|
|
|
|
|
int total_ice_disconnected =
|
|
|
|
|
ice_state_counts[IceTransportState::kDisconnected];
|
|
|
|
|
int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
|
|
|
|
|
int total_ice_new = ice_state_counts[IceTransportState::kNew];
|
|
|
|
|
int total_ice = dtls_transports.size();
|
|
|
|
|
|
|
|
|
|
if (total_ice_failed > 0) {
|
2018-12-07 13:11:44 +01:00
|
|
|
// Any RTCIceTransports are in the "failed" state.
|
2018-10-18 15:58:17 +02:00
|
|
|
new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
|
2018-11-23 16:18:59 +00:00
|
|
|
} else if (total_ice_disconnected > 0) {
|
2018-12-07 13:11:44 +01:00
|
|
|
// None of the previous states apply and any RTCIceTransports are in the
|
|
|
|
|
// "disconnected" state.
|
2018-10-18 15:58:17 +02:00
|
|
|
new_ice_connection_state =
|
|
|
|
|
PeerConnectionInterface::kIceConnectionDisconnected;
|
2018-12-07 13:11:44 +01:00
|
|
|
} else if (total_ice_new + total_ice_closed == total_ice) {
|
|
|
|
|
// None of the previous states apply and all RTCIceTransports are in the
|
|
|
|
|
// "new" or "closed" state, or there are no transports.
|
|
|
|
|
new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
|
|
|
|
|
} else if (total_ice_new + total_ice_checking > 0) {
|
|
|
|
|
// None of the previous states apply and any RTCIceTransports are in the
|
|
|
|
|
// "new" or "checking" state.
|
2018-10-18 15:58:17 +02:00
|
|
|
new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
|
2019-02-25 15:26:24 +01:00
|
|
|
} else if (total_ice_completed + total_ice_closed == total_ice ||
|
|
|
|
|
all_completed) {
|
2018-12-07 13:11:44 +01:00
|
|
|
// None of the previous states apply and all RTCIceTransports are in the
|
|
|
|
|
// "completed" or "closed" state.
|
2019-02-25 15:26:24 +01:00
|
|
|
//
|
|
|
|
|
// TODO(https://bugs.webrtc.org/10356): The all_completed condition is added
|
|
|
|
|
// to mimic the behavior of the old ICE connection state, and should be
|
|
|
|
|
// removed once we get end-of-candidates signaling in place.
|
2018-10-18 15:58:17 +02:00
|
|
|
new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
|
|
|
|
|
} else if (total_ice_connected + total_ice_completed + total_ice_closed ==
|
2018-12-07 13:11:44 +01:00
|
|
|
total_ice) {
|
|
|
|
|
// None of the previous states apply and all RTCIceTransports are in the
|
|
|
|
|
// "connected", "completed" or "closed" state.
|
2018-10-18 15:58:17 +02:00
|
|
|
new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
|
|
|
|
|
} else {
|
|
|
|
|
RTC_NOTREACHED();
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-23 16:18:59 +00:00
|
|
|
if (standardized_ice_connection_state_ != new_ice_connection_state) {
|
2019-02-25 15:26:24 +01:00
|
|
|
if (standardized_ice_connection_state_ ==
|
|
|
|
|
PeerConnectionInterface::kIceConnectionChecking &&
|
|
|
|
|
new_ice_connection_state ==
|
|
|
|
|
PeerConnectionInterface::kIceConnectionCompleted) {
|
|
|
|
|
// Ensure that we never skip over the "connected" state.
|
|
|
|
|
invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this] {
|
|
|
|
|
SignalStandardizedIceConnectionState(
|
|
|
|
|
PeerConnectionInterface::kIceConnectionConnected);
|
|
|
|
|
});
|
|
|
|
|
}
|
2018-11-23 16:18:59 +00:00
|
|
|
standardized_ice_connection_state_ = new_ice_connection_state;
|
2018-10-18 15:58:17 +02:00
|
|
|
invoker_.AsyncInvoke<void>(
|
|
|
|
|
RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
|
2018-11-23 16:18:59 +00:00
|
|
|
SignalStandardizedIceConnectionState(new_ice_connection_state);
|
2018-10-18 15:58:17 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compute the current RTCPeerConnectionState as described in
|
|
|
|
|
// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
|
|
|
|
|
// The PeerConnection is responsible for handling the "closed" state.
|
|
|
|
|
// Note that "connecting" is only a valid state for DTLS transports while
|
|
|
|
|
// "checking", "completed" and "disconnected" are only valid for ICE
|
|
|
|
|
// transports.
|
|
|
|
|
int total_connected = total_ice_connected +
|
|
|
|
|
dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
|
|
|
|
|
int total_dtls_connecting =
|
|
|
|
|
dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
|
|
|
|
|
int total_failed =
|
|
|
|
|
total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
|
|
|
|
|
int total_closed =
|
|
|
|
|
total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
|
|
|
|
|
int total_new =
|
|
|
|
|
total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
|
|
|
|
|
int total_transports = total_ice * 2;
|
|
|
|
|
|
|
|
|
|
if (total_failed > 0) {
|
|
|
|
|
// Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
|
|
|
|
|
new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
|
2018-12-07 13:11:44 +01:00
|
|
|
} else if (total_ice_disconnected > 0) {
|
|
|
|
|
// None of the previous states apply and any RTCIceTransports or
|
|
|
|
|
// RTCDtlsTransports are in the "disconnected" state.
|
2018-10-18 15:58:17 +02:00
|
|
|
new_combined_state =
|
|
|
|
|
PeerConnectionInterface::PeerConnectionState::kDisconnected;
|
2018-12-07 13:11:44 +01:00
|
|
|
} else if (total_new + total_closed == total_transports) {
|
|
|
|
|
// None of the previous states apply and all RTCIceTransports and
|
|
|
|
|
// RTCDtlsTransports are in the "new" or "closed" state, or there are no
|
|
|
|
|
// transports.
|
|
|
|
|
new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
|
|
|
|
|
} else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
|
|
|
|
|
// None of the previous states apply and all RTCIceTransports or
|
|
|
|
|
// RTCDtlsTransports are in the "new", "connecting" or "checking" state.
|
2018-10-18 15:58:17 +02:00
|
|
|
new_combined_state =
|
|
|
|
|
PeerConnectionInterface::PeerConnectionState::kConnecting;
|
|
|
|
|
} else if (total_connected + total_ice_completed + total_closed ==
|
2018-12-07 13:11:44 +01:00
|
|
|
total_transports) {
|
|
|
|
|
// None of the previous states apply and all RTCIceTransports and
|
|
|
|
|
// RTCDtlsTransports are in the "connected", "completed" or "closed" state.
|
2018-10-18 15:58:17 +02:00
|
|
|
new_combined_state =
|
|
|
|
|
PeerConnectionInterface::PeerConnectionState::kConnected;
|
|
|
|
|
} else {
|
|
|
|
|
RTC_NOTREACHED();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (combined_connection_state_ != new_combined_state) {
|
|
|
|
|
combined_connection_state_ = new_combined_state;
|
|
|
|
|
invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
|
|
|
|
|
[this, new_combined_state] {
|
|
|
|
|
SignalConnectionState(new_combined_state);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-22 15:26:27 -08:00
|
|
|
if (all_done_gathering) {
|
|
|
|
|
new_gathering_state = cricket::kIceGatheringComplete;
|
|
|
|
|
} else if (any_gathering) {
|
|
|
|
|
new_gathering_state = cricket::kIceGatheringGathering;
|
|
|
|
|
}
|
|
|
|
|
if (ice_gathering_state_ != new_gathering_state) {
|
|
|
|
|
ice_gathering_state_ = new_gathering_state;
|
2018-08-31 13:06:05 -07:00
|
|
|
invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
|
|
|
|
|
[this, new_gathering_state] {
|
|
|
|
|
SignalIceGatheringState(new_gathering_state);
|
|
|
|
|
});
|
2018-02-22 15:26:27 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 18:22:12 +02:00
|
|
|
void JsepTransportController::OnRtcpPacketReceived_n(
|
|
|
|
|
rtc::CopyOnWriteBuffer* packet,
|
|
|
|
|
int64_t packet_time_us) {
|
|
|
|
|
RTC_DCHECK(config_.rtcp_handler);
|
|
|
|
|
config_.rtcp_handler(*packet, packet_time_us);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-22 15:26:27 -08:00
|
|
|
void JsepTransportController::OnDtlsHandshakeError(
|
|
|
|
|
rtc::SSLHandshakeError error) {
|
|
|
|
|
SignalDtlsHandshakeError(error);
|
|
|
|
|
}
|
|
|
|
|
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
absl::optional<cricket::SessionDescription::MediaTransportSetting>
|
|
|
|
|
JsepTransportController::GenerateOrGetLastMediaTransportOffer() {
|
Reland: Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Ifcc428c8d76fb77dcc8abaa79507c620bcfb31b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140920
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28198}
2019-06-07 10:28:06 -07:00
|
|
|
if (media_transport_created_once_) {
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
RTC_LOG(LS_INFO) << "Not regenerating media transport for the new offer in "
|
|
|
|
|
"existing session.";
|
|
|
|
|
return media_transport_offer_settings_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTC_LOG(LS_INFO) << "Generating media transport offer!";
|
2019-05-23 15:50:38 -07:00
|
|
|
|
|
|
|
|
absl::optional<std::string> transport_parameters;
|
|
|
|
|
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
// Check that media transport is supposed to be used.
|
2019-05-23 15:50:38 -07:00
|
|
|
// Note that ICE is not available when media transport is created. It will
|
|
|
|
|
// only be available in 'Connect'. This may be a potential server config, if
|
|
|
|
|
// we decide to use this peer connection as a caller, not as a callee.
|
|
|
|
|
// TODO(sukhanov): Avoid code duplication with CreateMedia/MediaTransport.
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
if (config_.use_media_transport_for_media ||
|
|
|
|
|
config_.use_media_transport_for_data_channels) {
|
|
|
|
|
RTC_DCHECK(config_.media_transport_factory != nullptr);
|
2019-05-23 15:50:38 -07:00
|
|
|
RTC_DCHECK(!config_.use_datagram_transport);
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
webrtc::MediaTransportSettings settings;
|
|
|
|
|
settings.is_caller = true;
|
|
|
|
|
settings.pre_shared_key = rtc::CreateRandomString(32);
|
2019-07-02 09:50:35 -07:00
|
|
|
if (config_.use_media_transport_for_media) {
|
|
|
|
|
settings.event_log = config_.event_log;
|
|
|
|
|
}
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
auto media_transport_or_error =
|
|
|
|
|
config_.media_transport_factory->CreateMediaTransport(network_thread_,
|
|
|
|
|
settings);
|
|
|
|
|
|
|
|
|
|
if (media_transport_or_error.ok()) {
|
|
|
|
|
offer_media_transport_ = std::move(media_transport_or_error.value());
|
2019-05-23 15:50:38 -07:00
|
|
|
transport_parameters =
|
|
|
|
|
offer_media_transport_->GetTransportParametersOffer();
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
} else {
|
|
|
|
|
RTC_LOG(LS_INFO) << "Unable to create media transport, error="
|
|
|
|
|
<< media_transport_or_error.error().message();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Reland: Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Ifcc428c8d76fb77dcc8abaa79507c620bcfb31b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140920
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28198}
2019-06-07 10:28:06 -07:00
|
|
|
if (!offer_media_transport_) {
|
2019-05-23 15:50:38 -07:00
|
|
|
RTC_LOG(LS_INFO) << "Media and data transports do not exist";
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
return absl::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!transport_parameters) {
|
|
|
|
|
RTC_LOG(LS_INFO) << "Media transport didn't generate the offer";
|
|
|
|
|
// Media transport didn't generate the offer, and is not supposed to be
|
|
|
|
|
// used. Destroy the temporary media transport.
|
|
|
|
|
offer_media_transport_ = nullptr;
|
|
|
|
|
return absl::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cricket::SessionDescription::MediaTransportSetting setting;
|
|
|
|
|
setting.transport_name = config_.media_transport_factory->GetTransportName();
|
|
|
|
|
setting.transport_setting = *transport_parameters;
|
|
|
|
|
media_transport_offer_settings_ = setting;
|
|
|
|
|
return setting;
|
|
|
|
|
}
|
|
|
|
|
|
Reland: Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Ifcc428c8d76fb77dcc8abaa79507c620bcfb31b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140920
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28198}
2019-06-07 10:28:06 -07:00
|
|
|
absl::optional<cricket::OpaqueTransportParameters>
|
|
|
|
|
JsepTransportController::GetTransportParameters(const std::string& mid) {
|
Changes to enable use of DatagramTransport as a data channel transport.
PeerConnection now has a new setting in RTCConfiguration to enable use of
datagram transport for data channels. There is also a corresponding field
trial, which has both a kill-switch and a way to change the default value.
PeerConnection's interaction with MediaTransport for data channels has been
refactored to work with DataChannelTransportInterface instead.
Adds a DataChannelState and OnStateChanged() to the DataChannelSink
callbacks. This allows PeerConnection to listen to the data channel's
state directly, instead of indirectly by monitoring media transport
state. This is necessary to enable use of non-media-transport (eg.
datagram transport) data channel transports.
For now, PeerConnection watches the state through MediaTransport as well.
This will persist until MediaTransport implements the new callback.
Datagram transport use is negotiated. As such, an offer that requests to use
datagram transport for data channels may be rejected by the answerer. If the
offer includes DTLS, the data channels will be negotiated as SCTP/DTLS data
channels with an extra x-opaque parameter for datagram transport. If the
opaque parameter is rejected (by an answerer without datagram support), the
offerer may fall back to SCTP.
If DTLS is not enabled, there is no viable fallback. In this case, the data
channels are negotiated as media transport data channels. If the receiver does
not understand the x-opaque line, it will reject these data channels, and the
offerer's data channels will be closed.
Bug: webrtc:9719
Change-Id: Ic1bf3664c4bcf9d754482df59897f5f72fe68fcc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/147702
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28932}
2019-08-21 10:44:59 -07:00
|
|
|
if (!(config_.use_datagram_transport ||
|
|
|
|
|
config_.use_datagram_transport_for_data_channels)) {
|
Reland: Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Ifcc428c8d76fb77dcc8abaa79507c620bcfb31b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140920
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28198}
2019-06-07 10:28:06 -07:00
|
|
|
return absl::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cricket::JsepTransport* transport = GetJsepTransportForMid(mid);
|
|
|
|
|
if (transport) {
|
|
|
|
|
absl::optional<cricket::OpaqueTransportParameters> params =
|
|
|
|
|
transport->GetTransportParameters();
|
|
|
|
|
if (params) {
|
|
|
|
|
params->protocol = config_.media_transport_factory->GetTransportName();
|
|
|
|
|
}
|
|
|
|
|
return params;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RTC_DCHECK(!local_desc_ && !remote_desc_)
|
|
|
|
|
<< "JsepTransport should exist for every mid once any description is set";
|
|
|
|
|
|
2019-09-26 11:02:11 -07:00
|
|
|
if (config_.use_datagram_transport_for_data_channels_receive_only) {
|
|
|
|
|
return absl::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
Reland: Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that
uses datagram transport. If the answerer supports datagram transport, it will
parse this line and create a datagram transport. It will then echo the x-opaque
line into the answer (to indicate that it accepted use of datagram transport).
If the offer and answer contain exactly the same x-opaque line, both peers will
use datagram transport. If the x-opaque line is omitted from the answer (or is
different in the answer) they will fall back to RTP.
Note that a different x-opaque line in the answer means the answerer did not
understand something in the negotiation proto. Since WebRTC cannot know what
was misunderstood, or whether it's still possible to use the datagram transport,
it must fall back to RTP. This may change in the future, possibly by passing
the answer to the datagram transport, but it's good enough for now.
Negotiation consists of four parts:
1. DatagramTransport exposes transport parameters for both client and server
perspectives. The client just echoes what it received from the server (modulo
any fields it might not have understood).
2. SDP adds a x-opaque line for opaque transport parameters. Identical to
x-mt, but this is specific to datagram transport and goes in each m= section,
and appears in the answer as well as the offer.
- This is propagated to Jsep as part of the TransportDescription.
- SDP files: transport_description.h,cc, transport_description_factory.h,cc,
media_session.cc, webrtc_sdp.cc
3. JsepTransport/Controller:
- Exposes opaque parameters for each mid (m= section). On offerer, this means
pre-allocating a datagram transport and getting its parameters. On the
answerer, this means echoing the offerer's parameters.
- Uses a composite RTP transport to receive from either default RTP or
datagram transport until both offer and answer arrive.
- If a provisional answer arrives, sets the composite to send on the
provisionally selected transport.
- Once both offer and answer are set, deletes the unneeded transports and
keeps whichever transport is selected.
4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP.
Bug: webrtc:9719
Change-Id: Ifcc428c8d76fb77dcc8abaa79507c620bcfb31b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140920
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28198}
2019-06-07 10:28:06 -07:00
|
|
|
// Need to generate a transport for the offer.
|
|
|
|
|
if (!offer_datagram_transport_) {
|
|
|
|
|
webrtc::MediaTransportSettings settings;
|
|
|
|
|
settings.is_caller = true;
|
|
|
|
|
settings.pre_shared_key = rtc::CreateRandomString(32);
|
|
|
|
|
settings.event_log = config_.event_log;
|
|
|
|
|
auto datagram_transport_or_error =
|
|
|
|
|
config_.media_transport_factory->CreateDatagramTransport(
|
|
|
|
|
network_thread_, settings);
|
|
|
|
|
|
|
|
|
|
if (datagram_transport_or_error.ok()) {
|
|
|
|
|
offer_datagram_transport_ =
|
|
|
|
|
std::move(datagram_transport_or_error.value());
|
|
|
|
|
} else {
|
|
|
|
|
RTC_LOG(LS_INFO) << "Unable to create datagram transport, error="
|
|
|
|
|
<< datagram_transport_or_error.error().message();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We have prepared a transport for the offer, and can now use its parameters.
|
|
|
|
|
cricket::OpaqueTransportParameters params;
|
|
|
|
|
params.parameters = offer_datagram_transport_->GetTransportParameters();
|
|
|
|
|
params.protocol = config_.media_transport_factory->GetTransportName();
|
|
|
|
|
return params;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-22 15:26:27 -08:00
|
|
|
} // namespace webrtc
|