mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-05 04:10:16 +00:00
Temp
This commit is contained in:
parent
5f9565853d
commit
a422fac01f
@ -183,10 +183,10 @@ public:
|
||||
std::unique_ptr<rtc::Thread> _networkThread;
|
||||
std::unique_ptr<rtc::Thread> _workerThread;
|
||||
std::unique_ptr<rtc::Thread> _signalingThread;
|
||||
rtc::scoped_refptr<webrtc::TgPeerConnectionFactory> _nativeFactory;
|
||||
rtc::scoped_refptr<webrtc::TgPeerConnectionFactoryInterface> _nativeFactory;
|
||||
|
||||
std::unique_ptr<PeerConnectionObserverImpl> _observer;
|
||||
rtc::scoped_refptr<webrtc::PeerConnectionInterface> _peerConnection;
|
||||
rtc::scoped_refptr<webrtc::TgPeerConnectionInterface> _peerConnection;
|
||||
std::unique_ptr<webrtc::MediaConstraints> _nativeConstraints;
|
||||
bool _hasStartedRtcEventLog;
|
||||
|
||||
@ -255,7 +255,7 @@ public:
|
||||
if (!result) {
|
||||
return nil;
|
||||
}
|
||||
_nativeFactory = pc_factory;
|
||||
_nativeFactory = webrtc::TgPeerConnectionFactoryProxy::Create(pc_factory->signaling_thread(), pc_factory);
|
||||
|
||||
webrtc::PeerConnectionInterface::RTCConfiguration config;
|
||||
config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
|
||||
|
811
submodules/TgVoipWebrtcCustom/Sources/tg_dtls_transport.cpp
Normal file
811
submodules/TgVoipWebrtcCustom/Sources/tg_dtls_transport.cpp
Normal file
@ -0,0 +1,811 @@
|
||||
/*
|
||||
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "tg_dtls_transport.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "api/rtc_event_log/rtc_event_log.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_dtls_transport_state.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_dtls_writable_state.h"
|
||||
#include "p2p/base/packet_transport_internal.h"
|
||||
#include "rtc_base/buffer.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/dscp.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/message_queue.h"
|
||||
#include "rtc_base/rtc_certificate.h"
|
||||
#include "rtc_base/ssl_stream_adapter.h"
|
||||
#include "rtc_base/stream.h"
|
||||
#include "rtc_base/thread.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
// We don't pull the RTP constants from rtputils.h, to avoid a layer violation.
|
||||
static const size_t kDtlsRecordHeaderLen = 13;
|
||||
static const size_t kMaxDtlsPacketLen = 2048;
|
||||
static const size_t kMinRtpPacketLen = 12;
|
||||
|
||||
// Maximum number of pending packets in the queue. Packets are read immediately
|
||||
// after they have been written, so a capacity of "1" is sufficient.
|
||||
static const size_t kMaxPendingPackets = 1;
|
||||
|
||||
// Minimum and maximum values for the initial DTLS handshake timeout. We'll pick
|
||||
// an initial timeout based on ICE RTT estimates, but clamp it to this range.
|
||||
static const int kMinHandshakeTimeout = 50;
|
||||
static const int kMaxHandshakeTimeout = 3000;
|
||||
|
||||
static bool IsDtlsPacket(const char* data, size_t len) {
|
||||
const uint8_t* u = reinterpret_cast<const uint8_t*>(data);
|
||||
return (len >= kDtlsRecordHeaderLen && (u[0] > 19 && u[0] < 64));
|
||||
}
|
||||
static bool IsDtlsClientHelloPacket(const char* data, size_t len) {
|
||||
if (!IsDtlsPacket(data, len)) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t* u = reinterpret_cast<const uint8_t*>(data);
|
||||
return len > 17 && u[0] == 22 && u[13] == 1;
|
||||
}
|
||||
static bool IsRtpPacket(const char* data, size_t len) {
|
||||
const uint8_t* u = reinterpret_cast<const uint8_t*>(data);
|
||||
return (len >= kMinRtpPacketLen && (u[0] & 0xC0) == 0x80);
|
||||
}
|
||||
|
||||
/*StreamInterfaceChannel::StreamInterfaceChannel(
|
||||
IceTransportInternal* ice_transport)
|
||||
: ice_transport_(ice_transport),
|
||||
state_(rtc::SS_OPEN),
|
||||
packets_(kMaxPendingPackets, kMaxDtlsPacketLen) {}
|
||||
|
||||
rtc::StreamResult StreamInterfaceChannel::Read(void* buffer,
|
||||
size_t buffer_len,
|
||||
size_t* read,
|
||||
int* error) {
|
||||
if (state_ == rtc::SS_CLOSED)
|
||||
return rtc::SR_EOS;
|
||||
if (state_ == rtc::SS_OPENING)
|
||||
return rtc::SR_BLOCK;
|
||||
|
||||
if (!packets_.ReadFront(buffer, buffer_len, read)) {
|
||||
return rtc::SR_BLOCK;
|
||||
}
|
||||
|
||||
return rtc::SR_SUCCESS;
|
||||
}
|
||||
|
||||
rtc::StreamResult StreamInterfaceChannel::Write(const void* data,
|
||||
size_t data_len,
|
||||
size_t* written,
|
||||
int* error) {
|
||||
// Always succeeds, since this is an unreliable transport anyway.
|
||||
// TODO(zhihuang): Should this block if ice_transport_'s temporarily
|
||||
// unwritable?
|
||||
rtc::PacketOptions packet_options;
|
||||
ice_transport_->SendPacket(static_cast<const char*>(data), data_len,
|
||||
packet_options);
|
||||
if (written) {
|
||||
*written = data_len;
|
||||
}
|
||||
return rtc::SR_SUCCESS;
|
||||
}
|
||||
|
||||
bool StreamInterfaceChannel::OnPacketReceived(const char* data, size_t size) {
|
||||
// We force a read event here to ensure that we don't overflow our queue.
|
||||
bool ret = packets_.WriteBack(data, size, NULL);
|
||||
RTC_CHECK(ret) << "Failed to write packet to queue.";
|
||||
if (ret) {
|
||||
SignalEvent(this, rtc::SE_READ, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtc::StreamState StreamInterfaceChannel::GetState() const {
|
||||
return state_;
|
||||
}
|
||||
|
||||
void StreamInterfaceChannel::Close() {
|
||||
packets_.Clear();
|
||||
state_ = rtc::SS_CLOSED;
|
||||
}*/
|
||||
|
||||
TgDtlsTransport::TgDtlsTransport(IceTransportInternal* ice_transport,
|
||||
const webrtc::CryptoOptions& crypto_options,
|
||||
webrtc::RtcEventLog* event_log)
|
||||
: transport_name_(ice_transport->transport_name()),
|
||||
component_(ice_transport->component()),
|
||||
ice_transport_(ice_transport),
|
||||
downward_(NULL),
|
||||
srtp_ciphers_(crypto_options.GetSupportedDtlsSrtpCryptoSuites()),
|
||||
ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_12),
|
||||
crypto_options_(crypto_options),
|
||||
event_log_(event_log) {
|
||||
RTC_DCHECK(ice_transport_);
|
||||
ConnectToIceTransport();
|
||||
}
|
||||
|
||||
TgDtlsTransport::~TgDtlsTransport() = default;
|
||||
|
||||
const webrtc::CryptoOptions& TgDtlsTransport::crypto_options() const {
|
||||
return crypto_options_;
|
||||
}
|
||||
|
||||
DtlsTransportState TgDtlsTransport::dtls_state() const {
|
||||
return dtls_state_;
|
||||
}
|
||||
|
||||
const std::string& TgDtlsTransport::transport_name() const {
|
||||
return transport_name_;
|
||||
}
|
||||
|
||||
int TgDtlsTransport::component() const {
|
||||
return component_;
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::IsDtlsActive() const {
|
||||
return dtls_active_;
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::SetLocalCertificate(
|
||||
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
|
||||
if (dtls_active_) {
|
||||
if (certificate == local_certificate_) {
|
||||
// This may happen during renegotiation.
|
||||
RTC_LOG(LS_INFO) << ToString() << ": Ignoring identical DTLS identity";
|
||||
return true;
|
||||
} else {
|
||||
RTC_LOG(LS_ERROR) << ToString()
|
||||
<< ": Can't change DTLS local identity in this state";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (certificate) {
|
||||
local_certificate_ = certificate;
|
||||
dtls_active_ = true;
|
||||
} else {
|
||||
RTC_LOG(LS_INFO) << ToString()
|
||||
<< ": NULL DTLS identity supplied. Not doing DTLS";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<rtc::RTCCertificate> TgDtlsTransport::GetLocalCertificate()
|
||||
const {
|
||||
return local_certificate_;
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) {
|
||||
if (dtls_active_) {
|
||||
RTC_LOG(LS_ERROR) << "Not changing max. protocol version "
|
||||
"while DTLS is negotiating";
|
||||
return false;
|
||||
}
|
||||
|
||||
ssl_max_version_ = version;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::SetDtlsRole(rtc::SSLRole role) {
|
||||
if (dtls_) {
|
||||
RTC_DCHECK(dtls_role_);
|
||||
if (*dtls_role_ != role) {
|
||||
RTC_LOG(LS_ERROR)
|
||||
<< "SSL Role can't be reversed after the session is setup.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
dtls_role_ = role;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::GetDtlsRole(rtc::SSLRole* role) const {
|
||||
if (!dtls_role_) {
|
||||
return false;
|
||||
}
|
||||
*role = *dtls_role_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::GetSslCipherSuite(int* cipher) {
|
||||
if (dtls_state() != DTLS_TRANSPORT_CONNECTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return dtls_->GetSslCipherSuite(cipher);
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::SetRemoteFingerprint(const std::string& digest_alg,
|
||||
const uint8_t* digest,
|
||||
size_t digest_len) {
|
||||
rtc::Buffer remote_fingerprint_value(digest, digest_len);
|
||||
|
||||
// Once we have the local certificate, the same remote fingerprint can be set
|
||||
// multiple times.
|
||||
if (dtls_active_ && remote_fingerprint_value_ == remote_fingerprint_value &&
|
||||
!digest_alg.empty()) {
|
||||
// This may happen during renegotiation.
|
||||
RTC_LOG(LS_INFO) << ToString()
|
||||
<< ": Ignoring identical remote DTLS fingerprint";
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the other side doesn't support DTLS, turn off |dtls_active_|.
|
||||
// TODO(deadbeef): Remove this. It's dangerous, because it relies on higher
|
||||
// level code to ensure DTLS is actually used, but there are tests that
|
||||
// depend on it, for the case where an m= section is rejected. In that case
|
||||
// SetRemoteFingerprint shouldn't even be called though.
|
||||
if (digest_alg.empty()) {
|
||||
RTC_DCHECK(!digest_len);
|
||||
RTC_LOG(LS_INFO) << ToString() << ": Other side didn't support DTLS.";
|
||||
dtls_active_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, we must have a local certificate before setting remote
|
||||
// fingerprint.
|
||||
if (!dtls_active_) {
|
||||
RTC_LOG(LS_ERROR) << ToString()
|
||||
<< ": Can't set DTLS remote settings in this state.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// At this point we know we are doing DTLS
|
||||
bool fingerprint_changing = remote_fingerprint_value_.size() > 0u;
|
||||
remote_fingerprint_value_ = std::move(remote_fingerprint_value);
|
||||
remote_fingerprint_algorithm_ = digest_alg;
|
||||
|
||||
if (dtls_ && !fingerprint_changing) {
|
||||
// This can occur if DTLS is set up before a remote fingerprint is
|
||||
// received. For instance, if we set up DTLS due to receiving an early
|
||||
// ClientHello.
|
||||
rtc::SSLPeerCertificateDigestError err;
|
||||
if (!dtls_->SetPeerCertificateDigest(
|
||||
remote_fingerprint_algorithm_,
|
||||
reinterpret_cast<unsigned char*>(remote_fingerprint_value_.data()),
|
||||
remote_fingerprint_value_.size(), &err)) {
|
||||
RTC_LOG(LS_ERROR) << ToString()
|
||||
<< ": Couldn't set DTLS certificate digest.";
|
||||
set_dtls_state(DTLS_TRANSPORT_FAILED);
|
||||
// If the error is "verification failed", don't return false, because
|
||||
// this means the fingerprint was formatted correctly but didn't match
|
||||
// the certificate from the DTLS handshake. Thus the DTLS state should go
|
||||
// to "failed", but SetRemoteDescription shouldn't fail.
|
||||
return err == rtc::SSLPeerCertificateDigestError::VERIFICATION_FAILED;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the fingerprint is changing, we'll tear down the DTLS association and
|
||||
// create a new one, resetting our state.
|
||||
if (dtls_ && fingerprint_changing) {
|
||||
dtls_.reset(nullptr);
|
||||
set_dtls_state(DTLS_TRANSPORT_NEW);
|
||||
set_writable(false);
|
||||
}
|
||||
|
||||
if (!SetupDtls()) {
|
||||
set_dtls_state(DTLS_TRANSPORT_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<rtc::SSLCertChain> TgDtlsTransport::GetRemoteSSLCertChain()
|
||||
const {
|
||||
if (!dtls_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return dtls_->GetPeerSSLCertChain();
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::ExportKeyingMaterial(const std::string& label,
|
||||
const uint8_t* context,
|
||||
size_t context_len,
|
||||
bool use_context,
|
||||
uint8_t* result,
|
||||
size_t result_len) {
|
||||
return (dtls_.get())
|
||||
? dtls_->ExportKeyingMaterial(label, context, context_len,
|
||||
use_context, result, result_len)
|
||||
: false;
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::SetupDtls() {
|
||||
RTC_DCHECK(dtls_role_);
|
||||
StreamInterfaceChannel* downward = new StreamInterfaceChannel(ice_transport_);
|
||||
|
||||
dtls_.reset(rtc::SSLStreamAdapter::Create(downward));
|
||||
if (!dtls_) {
|
||||
RTC_LOG(LS_ERROR) << ToString() << ": Failed to create DTLS adapter.";
|
||||
delete downward;
|
||||
return false;
|
||||
}
|
||||
|
||||
downward_ = downward;
|
||||
|
||||
dtls_->SetIdentity(local_certificate_->identity()->GetReference());
|
||||
dtls_->SetMode(rtc::SSL_MODE_DTLS);
|
||||
dtls_->SetMaxProtocolVersion(ssl_max_version_);
|
||||
dtls_->SetServerRole(*dtls_role_);
|
||||
dtls_->SignalEvent.connect(this, &TgDtlsTransport::OnDtlsEvent);
|
||||
dtls_->SignalSSLHandshakeError.connect(this,
|
||||
&TgDtlsTransport::OnDtlsHandshakeError);
|
||||
if (remote_fingerprint_value_.size() &&
|
||||
!dtls_->SetPeerCertificateDigest(
|
||||
remote_fingerprint_algorithm_,
|
||||
reinterpret_cast<unsigned char*>(remote_fingerprint_value_.data()),
|
||||
remote_fingerprint_value_.size())) {
|
||||
RTC_LOG(LS_ERROR) << ToString()
|
||||
<< ": Couldn't set DTLS certificate digest.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up DTLS-SRTP, if it's been enabled.
|
||||
if (!srtp_ciphers_.empty()) {
|
||||
if (!dtls_->SetDtlsSrtpCryptoSuites(srtp_ciphers_)) {
|
||||
RTC_LOG(LS_ERROR) << ToString() << ": Couldn't set DTLS-SRTP ciphers.";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
RTC_LOG(LS_INFO) << ToString() << ": Not using DTLS-SRTP.";
|
||||
}
|
||||
|
||||
RTC_LOG(LS_INFO) << ToString() << ": DTLS setup complete.";
|
||||
|
||||
// If the underlying ice_transport is already writable at this point, we may
|
||||
// be able to start DTLS right away.
|
||||
MaybeStartDtls();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::GetSrtpCryptoSuite(int* cipher) {
|
||||
if (dtls_state() != DTLS_TRANSPORT_CONNECTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return dtls_->GetDtlsSrtpCryptoSuite(cipher);
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::GetSslVersionBytes(int* version) const {
|
||||
if (dtls_state() != DTLS_TRANSPORT_CONNECTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return dtls_->GetSslVersionBytes(version);
|
||||
}
|
||||
|
||||
// Called from upper layers to send a media packet.
|
||||
int TgDtlsTransport::SendPacket(const char* data,
|
||||
size_t size,
|
||||
const rtc::PacketOptions& options,
|
||||
int flags) {
|
||||
if (!dtls_active_) {
|
||||
// Not doing DTLS.
|
||||
return ice_transport_->SendPacket(data, size, options);
|
||||
}
|
||||
|
||||
switch (dtls_state()) {
|
||||
case DTLS_TRANSPORT_NEW:
|
||||
// Can't send data until the connection is active.
|
||||
// TODO(ekr@rtfm.com): assert here if dtls_ is NULL?
|
||||
return -1;
|
||||
case DTLS_TRANSPORT_CONNECTING:
|
||||
// Can't send data until the connection is active.
|
||||
return -1;
|
||||
case DTLS_TRANSPORT_CONNECTED:
|
||||
if (flags & PF_SRTP_BYPASS) {
|
||||
RTC_DCHECK(!srtp_ciphers_.empty());
|
||||
if (!IsRtpPacket(data, size)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ice_transport_->SendPacket(data, size, options);
|
||||
} else {
|
||||
return (dtls_->WriteAll(data, size, NULL, NULL) == rtc::SR_SUCCESS)
|
||||
? static_cast<int>(size)
|
||||
: -1;
|
||||
}
|
||||
case DTLS_TRANSPORT_FAILED:
|
||||
case DTLS_TRANSPORT_CLOSED:
|
||||
// Can't send anything when we're closed.
|
||||
return -1;
|
||||
default:
|
||||
RTC_NOTREACHED();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
IceTransportInternal* TgDtlsTransport::ice_transport() {
|
||||
return ice_transport_;
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::IsDtlsConnected() {
|
||||
return dtls_ && dtls_->IsTlsConnected();
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::receiving() const {
|
||||
return receiving_;
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::writable() const {
|
||||
return writable_;
|
||||
}
|
||||
|
||||
int TgDtlsTransport::GetError() {
|
||||
return ice_transport_->GetError();
|
||||
}
|
||||
|
||||
absl::optional<rtc::NetworkRoute> TgDtlsTransport::network_route() const {
|
||||
return ice_transport_->network_route();
|
||||
}
|
||||
|
||||
bool TgDtlsTransport::GetOption(rtc::Socket::Option opt, int* value) {
|
||||
return ice_transport_->GetOption(opt, value);
|
||||
}
|
||||
|
||||
int TgDtlsTransport::SetOption(rtc::Socket::Option opt, int value) {
|
||||
return ice_transport_->SetOption(opt, value);
|
||||
}
|
||||
|
||||
void TgDtlsTransport::ConnectToIceTransport() {
|
||||
RTC_DCHECK(ice_transport_);
|
||||
ice_transport_->SignalWritableState.connect(this,
|
||||
&TgDtlsTransport::OnWritableState);
|
||||
ice_transport_->SignalReadPacket.connect(this, &TgDtlsTransport::OnReadPacket);
|
||||
ice_transport_->SignalSentPacket.connect(this, &TgDtlsTransport::OnSentPacket);
|
||||
ice_transport_->SignalReadyToSend.connect(this,
|
||||
&TgDtlsTransport::OnReadyToSend);
|
||||
ice_transport_->SignalReceivingState.connect(
|
||||
this, &TgDtlsTransport::OnReceivingState);
|
||||
ice_transport_->SignalNetworkRouteChanged.connect(
|
||||
this, &TgDtlsTransport::OnNetworkRouteChanged);
|
||||
}
|
||||
|
||||
// The state transition logic here is as follows:
|
||||
// (1) If we're not doing DTLS-SRTP, then the state is just the
|
||||
// state of the underlying impl()
|
||||
// (2) If we're doing DTLS-SRTP:
|
||||
// - Prior to the DTLS handshake, the state is neither receiving nor
|
||||
// writable
|
||||
// - When the impl goes writable for the first time we
|
||||
// start the DTLS handshake
|
||||
// - Once the DTLS handshake completes, the state is that of the
|
||||
// impl again
|
||||
void TgDtlsTransport::OnWritableState(rtc::PacketTransportInternal* transport) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
RTC_DCHECK(transport == ice_transport_);
|
||||
RTC_LOG(LS_VERBOSE) << ToString()
|
||||
<< ": ice_transport writable state changed to "
|
||||
<< ice_transport_->writable();
|
||||
|
||||
if (!dtls_active_) {
|
||||
// Not doing DTLS.
|
||||
// Note: SignalWritableState fired by set_writable.
|
||||
set_writable(ice_transport_->writable());
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dtls_state()) {
|
||||
case DTLS_TRANSPORT_NEW:
|
||||
MaybeStartDtls();
|
||||
break;
|
||||
case DTLS_TRANSPORT_CONNECTED:
|
||||
// Note: SignalWritableState fired by set_writable.
|
||||
set_writable(ice_transport_->writable());
|
||||
break;
|
||||
case DTLS_TRANSPORT_CONNECTING:
|
||||
// Do nothing.
|
||||
break;
|
||||
case DTLS_TRANSPORT_FAILED:
|
||||
case DTLS_TRANSPORT_CLOSED:
|
||||
// Should not happen. Do nothing.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TgDtlsTransport::OnReceivingState(rtc::PacketTransportInternal* transport) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
RTC_DCHECK(transport == ice_transport_);
|
||||
RTC_LOG(LS_VERBOSE) << ToString()
|
||||
<< ": ice_transport "
|
||||
"receiving state changed to "
|
||||
<< ice_transport_->receiving();
|
||||
if (!dtls_active_ || dtls_state() == DTLS_TRANSPORT_CONNECTED) {
|
||||
// Note: SignalReceivingState fired by set_receiving.
|
||||
set_receiving(ice_transport_->receiving());
|
||||
}
|
||||
}
|
||||
|
||||
void TgDtlsTransport::OnReadPacket(rtc::PacketTransportInternal* transport,
|
||||
const char* data,
|
||||
size_t size,
|
||||
const int64_t& packet_time_us,
|
||||
int flags) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
RTC_DCHECK(transport == ice_transport_);
|
||||
RTC_DCHECK(flags == 0);
|
||||
|
||||
if (!dtls_active_) {
|
||||
// Not doing DTLS.
|
||||
SignalReadPacket(this, data, size, packet_time_us, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dtls_state()) {
|
||||
case DTLS_TRANSPORT_NEW:
|
||||
if (dtls_) {
|
||||
RTC_LOG(LS_INFO) << ToString()
|
||||
<< ": Packet received before DTLS started.";
|
||||
} else {
|
||||
RTC_LOG(LS_WARNING) << ToString()
|
||||
<< ": Packet received before we know if we are "
|
||||
"doing DTLS or not.";
|
||||
}
|
||||
// Cache a client hello packet received before DTLS has actually started.
|
||||
if (IsDtlsClientHelloPacket(data, size)) {
|
||||
RTC_LOG(LS_INFO) << ToString()
|
||||
<< ": Caching DTLS ClientHello packet until DTLS is "
|
||||
"started.";
|
||||
cached_client_hello_.SetData(data, size);
|
||||
// If we haven't started setting up DTLS yet (because we don't have a
|
||||
// remote fingerprint/role), we can use the client hello as a clue that
|
||||
// the peer has chosen the client role, and proceed with the handshake.
|
||||
// The fingerprint will be verified when it's set.
|
||||
if (!dtls_ && local_certificate_) {
|
||||
SetDtlsRole(rtc::SSL_SERVER);
|
||||
SetupDtls();
|
||||
}
|
||||
} else {
|
||||
RTC_LOG(LS_INFO) << ToString()
|
||||
<< ": Not a DTLS ClientHello packet; dropping.";
|
||||
}
|
||||
break;
|
||||
|
||||
case DTLS_TRANSPORT_CONNECTING:
|
||||
case DTLS_TRANSPORT_CONNECTED:
|
||||
// We should only get DTLS or SRTP packets; STUN's already been demuxed.
|
||||
// Is this potentially a DTLS packet?
|
||||
if (IsDtlsPacket(data, size)) {
|
||||
if (!HandleDtlsPacket(data, size)) {
|
||||
RTC_LOG(LS_ERROR) << ToString() << ": Failed to handle DTLS packet.";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Not a DTLS packet; our handshake should be complete by now.
|
||||
if (dtls_state() != DTLS_TRANSPORT_CONNECTED) {
|
||||
RTC_LOG(LS_ERROR) << ToString()
|
||||
<< ": Received non-DTLS packet before DTLS "
|
||||
"complete.";
|
||||
return;
|
||||
}
|
||||
|
||||
// And it had better be a SRTP packet.
|
||||
if (!IsRtpPacket(data, size)) {
|
||||
RTC_LOG(LS_ERROR)
|
||||
<< ToString() << ": Received unexpected non-DTLS packet.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanity check.
|
||||
RTC_DCHECK(!srtp_ciphers_.empty());
|
||||
|
||||
// Signal this upwards as a bypass packet.
|
||||
SignalReadPacket(this, data, size, packet_time_us, PF_SRTP_BYPASS);
|
||||
}
|
||||
break;
|
||||
case DTLS_TRANSPORT_FAILED:
|
||||
case DTLS_TRANSPORT_CLOSED:
|
||||
// This shouldn't be happening. Drop the packet.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TgDtlsTransport::OnSentPacket(rtc::PacketTransportInternal* transport,
|
||||
const rtc::SentPacket& sent_packet) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
SignalSentPacket(this, sent_packet);
|
||||
}
|
||||
|
||||
void TgDtlsTransport::OnReadyToSend(rtc::PacketTransportInternal* transport) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
if (writable()) {
|
||||
SignalReadyToSend(this);
|
||||
}
|
||||
}
|
||||
|
||||
void TgDtlsTransport::OnDtlsEvent(rtc::StreamInterface* dtls, int sig, int err) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
RTC_DCHECK(dtls == dtls_.get());
|
||||
if (sig & rtc::SE_OPEN) {
|
||||
// This is the first time.
|
||||
RTC_LOG(LS_INFO) << ToString() << ": DTLS handshake complete.";
|
||||
if (dtls_->GetState() == rtc::SS_OPEN) {
|
||||
// The check for OPEN shouldn't be necessary but let's make
|
||||
// sure we don't accidentally frob the state if it's closed.
|
||||
set_dtls_state(DTLS_TRANSPORT_CONNECTED);
|
||||
set_writable(true);
|
||||
}
|
||||
}
|
||||
if (sig & rtc::SE_READ) {
|
||||
char buf[kMaxDtlsPacketLen];
|
||||
size_t read;
|
||||
int read_error;
|
||||
rtc::StreamResult ret;
|
||||
// The underlying DTLS stream may have received multiple DTLS records in
|
||||
// one packet, so read all of them.
|
||||
do {
|
||||
ret = dtls_->Read(buf, sizeof(buf), &read, &read_error);
|
||||
if (ret == rtc::SR_SUCCESS) {
|
||||
SignalReadPacket(this, buf, read, rtc::TimeMicros(), 0);
|
||||
} else if (ret == rtc::SR_EOS) {
|
||||
// Remote peer shut down the association with no error.
|
||||
RTC_LOG(LS_INFO) << ToString() << ": DTLS transport closed by remote";
|
||||
set_writable(false);
|
||||
set_dtls_state(DTLS_TRANSPORT_CLOSED);
|
||||
} else if (ret == rtc::SR_ERROR) {
|
||||
// Remote peer shut down the association with an error.
|
||||
RTC_LOG(LS_INFO)
|
||||
<< ToString()
|
||||
<< ": Closed by remote with DTLS transport error, code="
|
||||
<< read_error;
|
||||
set_writable(false);
|
||||
set_dtls_state(DTLS_TRANSPORT_FAILED);
|
||||
}
|
||||
} while (ret == rtc::SR_SUCCESS);
|
||||
}
|
||||
if (sig & rtc::SE_CLOSE) {
|
||||
RTC_DCHECK(sig == rtc::SE_CLOSE); // SE_CLOSE should be by itself.
|
||||
set_writable(false);
|
||||
if (!err) {
|
||||
RTC_LOG(LS_INFO) << ToString() << ": DTLS transport closed";
|
||||
set_dtls_state(DTLS_TRANSPORT_CLOSED);
|
||||
} else {
|
||||
RTC_LOG(LS_INFO) << ToString() << ": DTLS transport error, code=" << err;
|
||||
set_dtls_state(DTLS_TRANSPORT_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TgDtlsTransport::OnNetworkRouteChanged(
|
||||
absl::optional<rtc::NetworkRoute> network_route) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
SignalNetworkRouteChanged(network_route);
|
||||
}
|
||||
|
||||
void TgDtlsTransport::MaybeStartDtls() {
|
||||
if (dtls_ && ice_transport_->writable()) {
|
||||
ConfigureHandshakeTimeout();
|
||||
|
||||
if (dtls_->StartSSL()) {
|
||||
// This should never fail:
|
||||
// Because we are operating in a nonblocking mode and all
|
||||
// incoming packets come in via OnReadPacket(), which rejects
|
||||
// packets in this state, the incoming queue must be empty. We
|
||||
// ignore write errors, thus any errors must be because of
|
||||
// configuration and therefore are our fault.
|
||||
RTC_NOTREACHED() << "StartSSL failed.";
|
||||
RTC_LOG(LS_ERROR) << ToString() << ": Couldn't start DTLS handshake";
|
||||
set_dtls_state(DTLS_TRANSPORT_FAILED);
|
||||
return;
|
||||
}
|
||||
RTC_LOG(LS_INFO) << ToString() << ": DtlsTransport: Started DTLS handshake";
|
||||
set_dtls_state(DTLS_TRANSPORT_CONNECTING);
|
||||
// Now that the handshake has started, we can process a cached ClientHello
|
||||
// (if one exists).
|
||||
if (cached_client_hello_.size()) {
|
||||
if (*dtls_role_ == rtc::SSL_SERVER) {
|
||||
RTC_LOG(LS_INFO) << ToString()
|
||||
<< ": Handling cached DTLS ClientHello packet.";
|
||||
if (!HandleDtlsPacket(cached_client_hello_.data<char>(),
|
||||
cached_client_hello_.size())) {
|
||||
RTC_LOG(LS_ERROR) << ToString() << ": Failed to handle DTLS packet.";
|
||||
}
|
||||
} else {
|
||||
RTC_LOG(LS_WARNING) << ToString()
|
||||
<< ": Discarding cached DTLS ClientHello packet "
|
||||
"because we don't have the server role.";
|
||||
}
|
||||
cached_client_hello_.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called from OnReadPacket when a DTLS packet is received.
|
||||
bool TgDtlsTransport::HandleDtlsPacket(const char* data, size_t size) {
|
||||
// Sanity check we're not passing junk that
|
||||
// just looks like DTLS.
|
||||
const uint8_t* tmp_data = reinterpret_cast<const uint8_t*>(data);
|
||||
size_t tmp_size = size;
|
||||
while (tmp_size > 0) {
|
||||
if (tmp_size < kDtlsRecordHeaderLen)
|
||||
return false; // Too short for the header
|
||||
|
||||
size_t record_len = (tmp_data[11] << 8) | (tmp_data[12]);
|
||||
if ((record_len + kDtlsRecordHeaderLen) > tmp_size)
|
||||
return false; // Body too short
|
||||
|
||||
tmp_data += record_len + kDtlsRecordHeaderLen;
|
||||
tmp_size -= record_len + kDtlsRecordHeaderLen;
|
||||
}
|
||||
|
||||
// Looks good. Pass to the SIC which ends up being passed to
|
||||
// the DTLS stack.
|
||||
return downward_->OnPacketReceived(data, size);
|
||||
}
|
||||
|
||||
void TgDtlsTransport::set_receiving(bool receiving) {
|
||||
if (receiving_ == receiving) {
|
||||
return;
|
||||
}
|
||||
receiving_ = receiving;
|
||||
SignalReceivingState(this);
|
||||
}
|
||||
|
||||
void TgDtlsTransport::set_writable(bool writable) {
|
||||
if (writable_ == writable) {
|
||||
return;
|
||||
}
|
||||
if (event_log_) {
|
||||
event_log_->Log(
|
||||
std::make_unique<webrtc::RtcEventDtlsWritableState>(writable));
|
||||
}
|
||||
RTC_LOG(LS_VERBOSE) << ToString() << ": set_writable to: " << writable;
|
||||
writable_ = writable;
|
||||
if (writable_) {
|
||||
SignalReadyToSend(this);
|
||||
}
|
||||
SignalWritableState(this);
|
||||
}
|
||||
|
||||
void TgDtlsTransport::set_dtls_state(DtlsTransportState state) {
|
||||
if (dtls_state_ == state) {
|
||||
return;
|
||||
}
|
||||
if (event_log_) {
|
||||
event_log_->Log(std::make_unique<webrtc::RtcEventDtlsTransportState>(
|
||||
ConvertDtlsTransportState(state)));
|
||||
}
|
||||
RTC_LOG(LS_VERBOSE) << ToString() << ": set_dtls_state from:" << dtls_state_
|
||||
<< " to " << state;
|
||||
dtls_state_ = state;
|
||||
SignalDtlsState(this, state);
|
||||
}
|
||||
|
||||
void TgDtlsTransport::OnDtlsHandshakeError(rtc::SSLHandshakeError error) {
|
||||
SignalDtlsHandshakeError(error);
|
||||
}
|
||||
|
||||
void TgDtlsTransport::ConfigureHandshakeTimeout() {
|
||||
RTC_DCHECK(dtls_);
|
||||
absl::optional<int> rtt = ice_transport_->GetRttEstimate();
|
||||
if (rtt) {
|
||||
// Limit the timeout to a reasonable range in case the ICE RTT takes
|
||||
// extreme values.
|
||||
int initial_timeout = std::max(kMinHandshakeTimeout,
|
||||
std::min(kMaxHandshakeTimeout, 2 * (*rtt)));
|
||||
RTC_LOG(LS_INFO) << ToString() << ": configuring DTLS handshake timeout "
|
||||
<< initial_timeout << " based on ICE RTT " << *rtt;
|
||||
|
||||
dtls_->SetInitialRetransmissionTimeout(initial_timeout);
|
||||
} else {
|
||||
RTC_LOG(LS_INFO)
|
||||
<< ToString()
|
||||
<< ": no RTT estimate - using default DTLS handshake timeout";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cricket
|
229
submodules/TgVoipWebrtcCustom/Sources/tg_dtls_transport.h
Normal file
229
submodules/TgVoipWebrtcCustom/Sources/tg_dtls_transport.h
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef TG_P2P_BASE_DTLS_TRANSPORT_H_
|
||||
#define TG_P2P_BASE_DTLS_TRANSPORT_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "p2p/base/dtls_transport.h"
|
||||
#include "api/crypto/crypto_options.h"
|
||||
#include "p2p/base/dtls_transport_internal.h"
|
||||
#include "p2p/base/ice_transport_internal.h"
|
||||
#include "rtc_base/buffer.h"
|
||||
#include "rtc_base/buffer_queue.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "rtc_base/ssl_stream_adapter.h"
|
||||
#include "rtc_base/stream.h"
|
||||
#include "rtc_base/strings/string_builder.h"
|
||||
#include "rtc_base/thread_checker.h"
|
||||
|
||||
namespace rtc {
|
||||
class PacketTransportInternal;
|
||||
}
|
||||
|
||||
namespace cricket {
|
||||
|
||||
// This class provides a DTLS SSLStreamAdapter inside a TransportChannel-style
|
||||
// packet-based interface, wrapping an existing TransportChannel instance
|
||||
// (e.g a P2PTransportChannel)
|
||||
// Here's the way this works:
|
||||
//
|
||||
// DtlsTransport {
|
||||
// SSLStreamAdapter* dtls_ {
|
||||
// StreamInterfaceChannel downward_ {
|
||||
// IceTransportInternal* ice_transport_;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// - Data which comes into DtlsTransport from the underlying
|
||||
// ice_transport_ via OnReadPacket() is checked for whether it is DTLS
|
||||
// or not, and if it is, is passed to DtlsTransport::HandleDtlsPacket,
|
||||
// which pushes it into to downward_. dtls_ is listening for events on
|
||||
// downward_, so it immediately calls downward_->Read().
|
||||
//
|
||||
// - Data written to DtlsTransport is passed either to downward_ or directly
|
||||
// to ice_transport_, depending on whether DTLS is negotiated and whether
|
||||
// the flags include PF_SRTP_BYPASS
|
||||
//
|
||||
// - The SSLStreamAdapter writes to downward_->Write() which translates it
|
||||
// into packet writes on ice_transport_.
|
||||
//
|
||||
// This class is not thread safe; all methods must be called on the same thread
|
||||
// as the constructor.
|
||||
class TgDtlsTransport : public DtlsTransportInternal {
|
||||
public:
|
||||
// |ice_transport| is the ICE transport this DTLS transport is wrapping. It
|
||||
// must outlive this DTLS transport.
|
||||
//
|
||||
// |crypto_options| are the options used for the DTLS handshake. This affects
|
||||
// whether GCM crypto suites are negotiated.
|
||||
//
|
||||
// |event_log| is an optional RtcEventLog for logging state changes. It should
|
||||
// outlive the DtlsTransport.
|
||||
explicit TgDtlsTransport(IceTransportInternal* ice_transport,
|
||||
const webrtc::CryptoOptions& crypto_options,
|
||||
webrtc::RtcEventLog* event_log);
|
||||
|
||||
~TgDtlsTransport() override;
|
||||
|
||||
const webrtc::CryptoOptions& crypto_options() const override;
|
||||
DtlsTransportState dtls_state() const override;
|
||||
const std::string& transport_name() const override;
|
||||
int component() const override;
|
||||
|
||||
// DTLS is active if a local certificate was set. Otherwise this acts in a
|
||||
// "passthrough" mode, sending packets directly through the underlying ICE
|
||||
// transport.
|
||||
// TODO(deadbeef): Remove this weirdness, and handle it in the upper layers.
|
||||
bool IsDtlsActive() const override;
|
||||
|
||||
// SetLocalCertificate is what makes DTLS active. It must be called before
|
||||
// SetRemoteFinterprint.
|
||||
// TODO(deadbeef): Once DtlsTransport no longer has the concept of being
|
||||
// "active" or not (acting as a passthrough if not active), just require this
|
||||
// certificate on construction or "Start".
|
||||
bool SetLocalCertificate(
|
||||
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override;
|
||||
rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const override;
|
||||
|
||||
// SetRemoteFingerprint must be called after SetLocalCertificate, and any
|
||||
// other methods like SetDtlsRole. It's what triggers the actual DTLS setup.
|
||||
// TODO(deadbeef): Rename to "Start" like in ORTC?
|
||||
bool SetRemoteFingerprint(const std::string& digest_alg,
|
||||
const uint8_t* digest,
|
||||
size_t digest_len) override;
|
||||
|
||||
// Called to send a packet (via DTLS, if turned on).
|
||||
int SendPacket(const char* data,
|
||||
size_t size,
|
||||
const rtc::PacketOptions& options,
|
||||
int flags) override;
|
||||
|
||||
bool GetOption(rtc::Socket::Option opt, int* value) override;
|
||||
|
||||
bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override;
|
||||
|
||||
// Find out which TLS version was negotiated
|
||||
bool GetSslVersionBytes(int* version) const override;
|
||||
// Find out which DTLS-SRTP cipher was negotiated
|
||||
bool GetSrtpCryptoSuite(int* cipher) override;
|
||||
|
||||
bool GetDtlsRole(rtc::SSLRole* role) const override;
|
||||
bool SetDtlsRole(rtc::SSLRole role) override;
|
||||
|
||||
// Find out which DTLS cipher was negotiated
|
||||
bool GetSslCipherSuite(int* cipher) override;
|
||||
|
||||
// Once DTLS has been established, this method retrieves the certificate
|
||||
// chain in use by the remote peer, for use in external identity
|
||||
// verification.
|
||||
std::unique_ptr<rtc::SSLCertChain> GetRemoteSSLCertChain() const override;
|
||||
|
||||
// Once DTLS has established (i.e., this ice_transport is writable), this
|
||||
// method extracts the keys negotiated during the DTLS handshake, for use in
|
||||
// external encryption. DTLS-SRTP uses this to extract the needed SRTP keys.
|
||||
// See the SSLStreamAdapter documentation for info on the specific parameters.
|
||||
bool ExportKeyingMaterial(const std::string& label,
|
||||
const uint8_t* context,
|
||||
size_t context_len,
|
||||
bool use_context,
|
||||
uint8_t* result,
|
||||
size_t result_len) override;
|
||||
|
||||
IceTransportInternal* ice_transport() override;
|
||||
|
||||
// For informational purposes. Tells if the DTLS handshake has finished.
|
||||
// This may be true even if writable() is false, if the remote fingerprint
|
||||
// has not yet been verified.
|
||||
bool IsDtlsConnected();
|
||||
|
||||
bool receiving() const override;
|
||||
bool writable() const override;
|
||||
|
||||
int GetError() override;
|
||||
|
||||
absl::optional<rtc::NetworkRoute> network_route() const override;
|
||||
|
||||
int SetOption(rtc::Socket::Option opt, int value) override;
|
||||
|
||||
std::string ToString() const {
|
||||
const absl::string_view RECEIVING_ABBREV[2] = {"_", "R"};
|
||||
const absl::string_view WRITABLE_ABBREV[2] = {"_", "W"};
|
||||
rtc::StringBuilder sb;
|
||||
sb << "DtlsTransport[" << transport_name_ << "|" << component_ << "|"
|
||||
<< RECEIVING_ABBREV[receiving()] << WRITABLE_ABBREV[writable()] << "]";
|
||||
return sb.Release();
|
||||
}
|
||||
|
||||
private:
|
||||
void ConnectToIceTransport();
|
||||
|
||||
void OnWritableState(rtc::PacketTransportInternal* transport);
|
||||
void OnReadPacket(rtc::PacketTransportInternal* transport,
|
||||
const char* data,
|
||||
size_t size,
|
||||
const int64_t& packet_time_us,
|
||||
int flags);
|
||||
void OnSentPacket(rtc::PacketTransportInternal* transport,
|
||||
const rtc::SentPacket& sent_packet);
|
||||
void OnReadyToSend(rtc::PacketTransportInternal* transport);
|
||||
void OnReceivingState(rtc::PacketTransportInternal* transport);
|
||||
void OnDtlsEvent(rtc::StreamInterface* stream_, int sig, int err);
|
||||
void OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route);
|
||||
bool SetupDtls();
|
||||
void MaybeStartDtls();
|
||||
bool HandleDtlsPacket(const char* data, size_t size);
|
||||
void OnDtlsHandshakeError(rtc::SSLHandshakeError error);
|
||||
void ConfigureHandshakeTimeout();
|
||||
|
||||
void set_receiving(bool receiving);
|
||||
void set_writable(bool writable);
|
||||
// Sets the DTLS state, signaling if necessary.
|
||||
void set_dtls_state(DtlsTransportState state);
|
||||
|
||||
rtc::ThreadChecker thread_checker_;
|
||||
|
||||
std::string transport_name_;
|
||||
int component_;
|
||||
DtlsTransportState dtls_state_ = DTLS_TRANSPORT_NEW;
|
||||
// Underlying ice_transport, not owned by this class.
|
||||
IceTransportInternal* ice_transport_;
|
||||
std::unique_ptr<rtc::SSLStreamAdapter> dtls_; // The DTLS stream
|
||||
StreamInterfaceChannel*
|
||||
downward_; // Wrapper for ice_transport_, owned by dtls_.
|
||||
std::vector<int> srtp_ciphers_; // SRTP ciphers to use with DTLS.
|
||||
bool dtls_active_ = false;
|
||||
rtc::scoped_refptr<rtc::RTCCertificate> local_certificate_;
|
||||
absl::optional<rtc::SSLRole> dtls_role_;
|
||||
rtc::SSLProtocolVersion ssl_max_version_;
|
||||
webrtc::CryptoOptions crypto_options_;
|
||||
rtc::Buffer remote_fingerprint_value_;
|
||||
std::string remote_fingerprint_algorithm_;
|
||||
|
||||
// Cached DTLS ClientHello packet that was received before we started the
|
||||
// DTLS handshake. This could happen if the hello was received before the
|
||||
// ice transport became writable, or before a remote fingerprint was received.
|
||||
rtc::Buffer cached_client_hello_;
|
||||
|
||||
bool receiving_ = false;
|
||||
bool writable_ = false;
|
||||
|
||||
webrtc::RtcEventLog* const event_log_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(TgDtlsTransport);
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // P2P_BASE_DTLS_TRANSPORT_H_
|
@ -25,6 +25,8 @@
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/thread.h"
|
||||
|
||||
#include "tg_dtls_transport.h"
|
||||
|
||||
using webrtc::SdpType;
|
||||
|
||||
namespace {
|
||||
@ -481,7 +483,7 @@ TgJsepTransportController::CreateDtlsTransport(
|
||||
dtls = config_.dtls_transport_factory->CreateDtlsTransport(
|
||||
ice, config_.crypto_options);
|
||||
} else {
|
||||
dtls = std::make_unique<cricket::DtlsTransport>(ice, config_.crypto_options,
|
||||
dtls = std::make_unique<cricket::TgDtlsTransport>(ice, config_.crypto_options,
|
||||
config_.event_log);
|
||||
}
|
||||
|
||||
@ -1153,9 +1155,9 @@ RTCError TgJsepTransportController::MaybeCreateJsepTransport(
|
||||
CreateDtlsTransport(content_info, ice->internal(), nullptr);
|
||||
|
||||
//std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
|
||||
std::unique_ptr<TgRtpTransport> unencrypted_rtp_transport;
|
||||
//std::unique_ptr<TgRtpTransport> unencrypted_rtp_transport;
|
||||
//std::unique_ptr<SrtpTransport> sdes_transport;
|
||||
//std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
|
||||
std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
|
||||
//std::unique_ptr<RtpTransportInternal> datagram_rtp_transport;
|
||||
|
||||
//rtc::scoped_refptr<webrtc::IceTransportInterface> rtcp_ice;
|
||||
@ -1189,18 +1191,18 @@ RTCError TgJsepTransportController::MaybeCreateJsepTransport(
|
||||
|
||||
/*if (config_.disable_encryption) {
|
||||
RTC_LOG(LS_INFO)
|
||||
<< "Creating UnencryptedRtpTransport, becayse encryption is disabled.";*/
|
||||
<< "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
|
||||
unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
|
||||
content_info.name, rtp_dtls_transport.get(), /*rtcp_dtls_transport.get()*/nullptr);
|
||||
/*} else if (!content_desc->cryptos().empty()) {
|
||||
content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
|
||||
} else if (!content_desc->cryptos().empty()) {
|
||||
sdes_transport = CreateSdesTransport(
|
||||
content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
|
||||
RTC_LOG(LS_INFO) << "Creating SdesTransport.";
|
||||
} else {
|
||||
} else {*/
|
||||
RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
|
||||
dtls_srtp_transport = CreateDtlsSrtpTransport(
|
||||
content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
|
||||
}*/
|
||||
content_info.name, rtp_dtls_transport.get(), nullptr);
|
||||
//}
|
||||
|
||||
/*std::unique_ptr<cricket::SctpTransportInternal> sctp_transport;
|
||||
if (config_.sctp_factory) {
|
||||
@ -1216,8 +1218,8 @@ RTCError TgJsepTransportController::MaybeCreateJsepTransport(
|
||||
std::unique_ptr<cricket::TgJsepTransport> jsep_transport =
|
||||
std::make_unique<cricket::TgJsepTransport>(
|
||||
content_info.name, certificate_, std::move(ice), /*std::move(rtcp_ice)*/nullptr,
|
||||
std::move(unencrypted_rtp_transport), /*std::move(sdes_transport)*/nullptr,
|
||||
/*std::move(dtls_srtp_transport)*/nullptr, /*std::move(datagram_rtp_transport)*/nullptr,
|
||||
/*std::move(unencrypted_rtp_transport)*/nullptr, /*std::move(sdes_transport)*/nullptr,
|
||||
std::move(dtls_srtp_transport), /*std::move(datagram_rtp_transport)*/nullptr,
|
||||
std::move(rtp_dtls_transport), /*std::move(rtcp_dtls_transport)*/nullptr,
|
||||
/*std::move(sctp_transport)*/nullptr, /*std::move(datagram_transport)*/nullptr,
|
||||
/*data_channel_transport*/nullptr);
|
||||
|
@ -87,6 +87,34 @@ using cricket::STUN_PORT_TYPE;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
RTCError TgPeerConnectionInterface::RemoveTrackNew(
|
||||
rtc::scoped_refptr<RtpSenderInterface> sender) {
|
||||
return RTCError(RemoveTrack(sender) ? RTCErrorType::NONE
|
||||
: RTCErrorType::INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
RTCError TgPeerConnectionInterface::SetConfiguration(
|
||||
const PeerConnectionInterface::RTCConfiguration& config) {
|
||||
return RTCError();
|
||||
}
|
||||
|
||||
RTCError TgPeerConnectionInterface::SetBitrate(const BitrateSettings& bitrate) {
|
||||
PeerConnectionInterface::BitrateParameters bitrate_parameters;
|
||||
bitrate_parameters.min_bitrate_bps = bitrate.min_bitrate_bps;
|
||||
bitrate_parameters.current_bitrate_bps = bitrate.start_bitrate_bps;
|
||||
bitrate_parameters.max_bitrate_bps = bitrate.max_bitrate_bps;
|
||||
return SetBitrate(bitrate_parameters);
|
||||
}
|
||||
|
||||
RTCError TgPeerConnectionInterface::SetBitrate(
|
||||
const PeerConnectionInterface::BitrateParameters& bitrate_parameters) {
|
||||
BitrateSettings bitrate;
|
||||
bitrate.min_bitrate_bps = bitrate_parameters.min_bitrate_bps;
|
||||
bitrate.start_bitrate_bps = bitrate_parameters.current_bitrate_bps;
|
||||
bitrate.max_bitrate_bps = bitrate_parameters.max_bitrate_bps;
|
||||
return SetBitrate(bitrate);
|
||||
}
|
||||
|
||||
// Error messages
|
||||
const char kBundleWithoutRtcpMux[] =
|
||||
"rtcp-mux must be enabled when BUNDLE "
|
||||
@ -375,100 +403,6 @@ bool MediaSectionsHaveSameCount(const SessionDescription& desc1,
|
||||
return desc1.contents().size() == desc2.contents().size();
|
||||
}
|
||||
|
||||
void NoteKeyProtocolAndMedia(KeyExchangeProtocolType protocol_type,
|
||||
cricket::MediaType media_type) {
|
||||
// Array of structs needed to map {KeyExchangeProtocolType,
|
||||
// cricket::MediaType} to KeyExchangeProtocolMedia without using std::map in
|
||||
// order to avoid -Wglobal-constructors and -Wexit-time-destructors.
|
||||
static constexpr struct {
|
||||
KeyExchangeProtocolType protocol_type;
|
||||
cricket::MediaType media_type;
|
||||
KeyExchangeProtocolMedia protocol_media;
|
||||
} kEnumCounterKeyProtocolMediaMap[] = {
|
||||
{kEnumCounterKeyProtocolDtls, cricket::MEDIA_TYPE_AUDIO,
|
||||
kEnumCounterKeyProtocolMediaTypeDtlsAudio},
|
||||
{kEnumCounterKeyProtocolDtls, cricket::MEDIA_TYPE_VIDEO,
|
||||
kEnumCounterKeyProtocolMediaTypeDtlsVideo},
|
||||
{kEnumCounterKeyProtocolDtls, cricket::MEDIA_TYPE_DATA,
|
||||
kEnumCounterKeyProtocolMediaTypeDtlsData},
|
||||
{kEnumCounterKeyProtocolSdes, cricket::MEDIA_TYPE_AUDIO,
|
||||
kEnumCounterKeyProtocolMediaTypeSdesAudio},
|
||||
{kEnumCounterKeyProtocolSdes, cricket::MEDIA_TYPE_VIDEO,
|
||||
kEnumCounterKeyProtocolMediaTypeSdesVideo},
|
||||
{kEnumCounterKeyProtocolSdes, cricket::MEDIA_TYPE_DATA,
|
||||
kEnumCounterKeyProtocolMediaTypeSdesData},
|
||||
};
|
||||
|
||||
RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.KeyProtocol", protocol_type,
|
||||
kEnumCounterKeyProtocolMax);
|
||||
|
||||
for (const auto& i : kEnumCounterKeyProtocolMediaMap) {
|
||||
if (i.protocol_type == protocol_type && i.media_type == media_type) {
|
||||
RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.KeyProtocolByMedia",
|
||||
i.protocol_media,
|
||||
kEnumCounterKeyProtocolMediaTypeMax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NoteAddIceCandidateResult(int result) {
|
||||
RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.AddIceCandidate", result,
|
||||
kAddIceCandidateMax);
|
||||
}
|
||||
|
||||
// Checks that each non-rejected content has SDES crypto keys or a DTLS
|
||||
// fingerprint, unless it's in a BUNDLE group, in which case only the
|
||||
// BUNDLE-tag section (first media section/description in the BUNDLE group)
|
||||
// needs a ufrag and pwd. Mismatches, such as replying with a DTLS fingerprint
|
||||
// to SDES keys, will be caught in TgJsepTransport negotiation, and backstopped
|
||||
// by Channel's |srtp_required| check.
|
||||
RTCError VerifyCrypto(const SessionDescription* desc, bool dtls_enabled) {
|
||||
const cricket::ContentGroup* bundle =
|
||||
desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
|
||||
for (const cricket::ContentInfo& content_info : desc->contents()) {
|
||||
if (content_info.rejected) {
|
||||
continue;
|
||||
}
|
||||
// Note what media is used with each crypto protocol, for all sections.
|
||||
NoteKeyProtocolAndMedia(dtls_enabled ? webrtc::kEnumCounterKeyProtocolDtls
|
||||
: webrtc::kEnumCounterKeyProtocolSdes,
|
||||
content_info.media_description()->type());
|
||||
const std::string& mid = content_info.name;
|
||||
if (bundle && bundle->HasContentName(mid) &&
|
||||
mid != *(bundle->FirstContentName())) {
|
||||
// This isn't the first media section in the BUNDLE group, so it's not
|
||||
// required to have crypto attributes, since only the crypto attributes
|
||||
// from the first section actually get used.
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the content isn't rejected or bundled into another m= section, crypto
|
||||
// must be present.
|
||||
const MediaContentDescription* media = content_info.media_description();
|
||||
const TransportInfo* tinfo = desc->GetTransportInfoByName(mid);
|
||||
if (!media || !tinfo) {
|
||||
// Something is not right.
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, kInvalidSdp);
|
||||
}
|
||||
if (dtls_enabled) {
|
||||
if (!tinfo->description.identity_fingerprint) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Session description must have DTLS fingerprint if "
|
||||
"DTLS enabled.";
|
||||
return RTCError(RTCErrorType::INVALID_PARAMETER,
|
||||
kSdpWithoutDtlsFingerprint);
|
||||
}
|
||||
} else {
|
||||
if (media->cryptos().empty()) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Session description must have SDES when DTLS disabled.";
|
||||
return RTCError(RTCErrorType::INVALID_PARAMETER, kSdpWithoutSdesCrypto);
|
||||
}
|
||||
}
|
||||
}
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
// Checks that each non-rejected content has ice-ufrag and ice-pwd set, unless
|
||||
// it's in a BUNDLE group, in which case only the BUNDLE-tag section (first
|
||||
// media section/description in the BUNDLE group) needs a ufrag and pwd.
|
||||
@ -809,140 +743,6 @@ private:
|
||||
rtc::scoped_refptr<SetSessionDescriptionObserver> wrapper_;
|
||||
};
|
||||
|
||||
bool PeerConnectionInterface::RTCConfiguration::operator==(
|
||||
const PeerConnectionInterface::RTCConfiguration& o) const {
|
||||
// This static_assert prevents us from accidentally breaking operator==.
|
||||
// Note: Order matters! Fields must be ordered the same as RTCConfiguration.
|
||||
struct stuff_being_tested_for_equality {
|
||||
IceServers servers;
|
||||
IceTransportsType type;
|
||||
BundlePolicy bundle_policy;
|
||||
RtcpMuxPolicy rtcp_mux_policy;
|
||||
std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> certificates;
|
||||
int ice_candidate_pool_size;
|
||||
bool disable_ipv6;
|
||||
bool disable_ipv6_on_wifi;
|
||||
int max_ipv6_networks;
|
||||
bool disable_link_local_networks;
|
||||
bool enable_rtp_data_channel;
|
||||
absl::optional<int> screencast_min_bitrate;
|
||||
absl::optional<bool> combined_audio_video_bwe;
|
||||
absl::optional<bool> enable_dtls_srtp;
|
||||
TcpCandidatePolicy tcp_candidate_policy;
|
||||
CandidateNetworkPolicy candidate_network_policy;
|
||||
int audio_jitter_buffer_max_packets;
|
||||
bool audio_jitter_buffer_fast_accelerate;
|
||||
int audio_jitter_buffer_min_delay_ms;
|
||||
bool audio_jitter_buffer_enable_rtx_handling;
|
||||
int ice_connection_receiving_timeout;
|
||||
int ice_backup_candidate_pair_ping_interval;
|
||||
ContinualGatheringPolicy continual_gathering_policy;
|
||||
bool prioritize_most_likely_ice_candidate_pairs;
|
||||
struct cricket::MediaConfig media_config;
|
||||
bool prune_turn_ports;
|
||||
PortPrunePolicy turn_port_prune_policy;
|
||||
bool presume_writable_when_fully_relayed;
|
||||
bool enable_ice_renomination;
|
||||
bool redetermine_role_on_ice_restart;
|
||||
bool surface_ice_candidates_on_ice_transport_type_changed;
|
||||
absl::optional<int> ice_check_interval_strong_connectivity;
|
||||
absl::optional<int> ice_check_interval_weak_connectivity;
|
||||
absl::optional<int> ice_check_min_interval;
|
||||
absl::optional<int> ice_unwritable_timeout;
|
||||
absl::optional<int> ice_unwritable_min_checks;
|
||||
absl::optional<int> ice_inactive_timeout;
|
||||
absl::optional<int> stun_candidate_keepalive_interval;
|
||||
absl::optional<rtc::IntervalRange> ice_regather_interval_range;
|
||||
webrtc::TurnCustomizer* turn_customizer;
|
||||
SdpSemantics sdp_semantics;
|
||||
absl::optional<rtc::AdapterType> network_preference;
|
||||
bool active_reset_srtp_params;
|
||||
bool use_media_transport;
|
||||
bool use_media_transport_for_data_channels;
|
||||
absl::optional<bool> use_datagram_transport;
|
||||
absl::optional<bool> use_datagram_transport_for_data_channels;
|
||||
absl::optional<bool> use_datagram_transport_for_data_channels_receive_only;
|
||||
absl::optional<CryptoOptions> crypto_options;
|
||||
bool offer_extmap_allow_mixed;
|
||||
std::string turn_logging_id;
|
||||
bool enable_implicit_rollback;
|
||||
absl::optional<bool> allow_codec_switching;
|
||||
};
|
||||
static_assert(sizeof(stuff_being_tested_for_equality) == sizeof(*this),
|
||||
"Did you add something to RTCConfiguration and forget to "
|
||||
"update operator==?");
|
||||
return type == o.type && servers == o.servers &&
|
||||
bundle_policy == o.bundle_policy &&
|
||||
rtcp_mux_policy == o.rtcp_mux_policy &&
|
||||
tcp_candidate_policy == o.tcp_candidate_policy &&
|
||||
candidate_network_policy == o.candidate_network_policy &&
|
||||
audio_jitter_buffer_max_packets == o.audio_jitter_buffer_max_packets &&
|
||||
audio_jitter_buffer_fast_accelerate ==
|
||||
o.audio_jitter_buffer_fast_accelerate &&
|
||||
audio_jitter_buffer_min_delay_ms ==
|
||||
o.audio_jitter_buffer_min_delay_ms &&
|
||||
audio_jitter_buffer_enable_rtx_handling ==
|
||||
o.audio_jitter_buffer_enable_rtx_handling &&
|
||||
ice_connection_receiving_timeout ==
|
||||
o.ice_connection_receiving_timeout &&
|
||||
ice_backup_candidate_pair_ping_interval ==
|
||||
o.ice_backup_candidate_pair_ping_interval &&
|
||||
continual_gathering_policy == o.continual_gathering_policy &&
|
||||
certificates == o.certificates &&
|
||||
prioritize_most_likely_ice_candidate_pairs ==
|
||||
o.prioritize_most_likely_ice_candidate_pairs &&
|
||||
media_config == o.media_config && disable_ipv6 == o.disable_ipv6 &&
|
||||
disable_ipv6_on_wifi == o.disable_ipv6_on_wifi &&
|
||||
max_ipv6_networks == o.max_ipv6_networks &&
|
||||
disable_link_local_networks == o.disable_link_local_networks &&
|
||||
enable_rtp_data_channel == o.enable_rtp_data_channel &&
|
||||
screencast_min_bitrate == o.screencast_min_bitrate &&
|
||||
combined_audio_video_bwe == o.combined_audio_video_bwe &&
|
||||
enable_dtls_srtp == o.enable_dtls_srtp &&
|
||||
ice_candidate_pool_size == o.ice_candidate_pool_size &&
|
||||
prune_turn_ports == o.prune_turn_ports &&
|
||||
turn_port_prune_policy == o.turn_port_prune_policy &&
|
||||
presume_writable_when_fully_relayed ==
|
||||
o.presume_writable_when_fully_relayed &&
|
||||
enable_ice_renomination == o.enable_ice_renomination &&
|
||||
redetermine_role_on_ice_restart == o.redetermine_role_on_ice_restart &&
|
||||
surface_ice_candidates_on_ice_transport_type_changed ==
|
||||
o.surface_ice_candidates_on_ice_transport_type_changed &&
|
||||
ice_check_interval_strong_connectivity ==
|
||||
o.ice_check_interval_strong_connectivity &&
|
||||
ice_check_interval_weak_connectivity ==
|
||||
o.ice_check_interval_weak_connectivity &&
|
||||
ice_check_min_interval == o.ice_check_min_interval &&
|
||||
ice_unwritable_timeout == o.ice_unwritable_timeout &&
|
||||
ice_unwritable_min_checks == o.ice_unwritable_min_checks &&
|
||||
ice_inactive_timeout == o.ice_inactive_timeout &&
|
||||
stun_candidate_keepalive_interval ==
|
||||
o.stun_candidate_keepalive_interval &&
|
||||
ice_regather_interval_range == o.ice_regather_interval_range &&
|
||||
turn_customizer == o.turn_customizer &&
|
||||
sdp_semantics == o.sdp_semantics &&
|
||||
network_preference == o.network_preference &&
|
||||
active_reset_srtp_params == o.active_reset_srtp_params &&
|
||||
use_media_transport == o.use_media_transport &&
|
||||
use_media_transport_for_data_channels ==
|
||||
o.use_media_transport_for_data_channels &&
|
||||
use_datagram_transport == o.use_datagram_transport &&
|
||||
use_datagram_transport_for_data_channels ==
|
||||
o.use_datagram_transport_for_data_channels &&
|
||||
use_datagram_transport_for_data_channels_receive_only ==
|
||||
o.use_datagram_transport_for_data_channels_receive_only &&
|
||||
crypto_options == o.crypto_options &&
|
||||
offer_extmap_allow_mixed == o.offer_extmap_allow_mixed &&
|
||||
turn_logging_id == o.turn_logging_id &&
|
||||
enable_implicit_rollback == o.enable_implicit_rollback &&
|
||||
allow_codec_switching == o.allow_codec_switching;
|
||||
}
|
||||
|
||||
bool PeerConnectionInterface::RTCConfiguration::operator!=(
|
||||
const PeerConnectionInterface::RTCConfiguration& o) const {
|
||||
return !(*this == o);
|
||||
}
|
||||
|
||||
void TgPeerConnection::TransceiverStableState::set_newly_created() {
|
||||
RTC_DCHECK(!has_m_section_);
|
||||
newly_created_ = true;
|
||||
@ -966,7 +766,7 @@ void TgPeerConnection::TransceiverStableState::SetRemoteStreamIdsIfUnset(
|
||||
}
|
||||
|
||||
// Generate a RTCP CNAME when a TgPeerConnection is created.
|
||||
std::string GenerateRtcpCname() {
|
||||
std::string TgGenerateRtcpCname() {
|
||||
std::string cname;
|
||||
if (!rtc::CreateRandomString(kRtcpCnameLength, &cname)) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to generate CNAME.";
|
||||
@ -975,7 +775,7 @@ std::string GenerateRtcpCname() {
|
||||
return cname;
|
||||
}
|
||||
|
||||
bool ValidateOfferAnswerOptions(
|
||||
bool TgValidateOfferAnswerOptions(
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options) {
|
||||
return IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) &&
|
||||
IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video);
|
||||
@ -983,7 +783,7 @@ bool ValidateOfferAnswerOptions(
|
||||
|
||||
// From |rtc_options|, fill parts of |session_options| shared by all generated
|
||||
// m= sections (in other words, nothing that involves a map/array).
|
||||
void ExtractSharedMediaSessionOptions(
|
||||
void TgExtractSharedMediaSessionOptions(
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
|
||||
cricket::MediaSessionOptions* session_options) {
|
||||
session_options->vad_enabled = rtc_options.voice_activity_detection;
|
||||
@ -1003,7 +803,7 @@ datagram_transport_config_(
|
||||
field_trial::FindFullName(kDatagramTransportFieldTrial)),
|
||||
datagram_transport_data_channel_config_(
|
||||
field_trial::FindFullName(kDatagramTransportDataChannelFieldTrial)),
|
||||
rtcp_cname_(GenerateRtcpCname()),
|
||||
rtcp_cname_(TgGenerateRtcpCname()),
|
||||
local_streams_(StreamCollection::Create()),
|
||||
remote_streams_(StreamCollection::Create()),
|
||||
call_(std::move(call)),
|
||||
@ -1717,7 +1517,7 @@ TgPeerConnection::AddTransceiver(
|
||||
}
|
||||
}
|
||||
|
||||
if (UnimplementedRtpParameterHasValue(parameters)) {
|
||||
if (TgUnimplementedRtpParameterHasValue(parameters)) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
"Attempted to set an unimplemented parameter of RtpParameters.");
|
||||
@ -1748,7 +1548,7 @@ TgPeerConnection::AddTransceiver(
|
||||
return rtc::scoped_refptr<RtpTransceiverInterface>(transceiver);
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
TgPeerConnection::CreateSender(
|
||||
cricket::MediaType media_type,
|
||||
const std::string& id,
|
||||
@ -1756,19 +1556,19 @@ TgPeerConnection::CreateSender(
|
||||
const std::vector<std::string>& stream_ids,
|
||||
const std::vector<RtpEncodingParameters>& send_encodings) {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>> sender;
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender;
|
||||
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
|
||||
RTC_DCHECK(!track ||
|
||||
(track->kind() == MediaStreamTrackInterface::kAudioKind));
|
||||
sender = RtpSenderProxyWithInternal<TgRtpSenderInternal>::Create(
|
||||
sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
|
||||
signaling_thread(),
|
||||
TgAudioRtpSender::Create(worker_thread(), id, stats_.get(), this));
|
||||
TgAudioRtpSender::Create(worker_thread(), id, this));
|
||||
NoteUsageEvent(UsageEvent::AUDIO_ADDED);
|
||||
} else {
|
||||
RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
|
||||
RTC_DCHECK(!track ||
|
||||
(track->kind() == MediaStreamTrackInterface::kVideoKind));
|
||||
sender = RtpSenderProxyWithInternal<TgRtpSenderInternal>::Create(
|
||||
sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
|
||||
signaling_thread(), TgVideoRtpSender::Create(worker_thread(), id, this));
|
||||
NoteUsageEvent(UsageEvent::VIDEO_ADDED);
|
||||
}
|
||||
@ -1801,7 +1601,7 @@ TgPeerConnection::CreateReceiver(cricket::MediaType media_type,
|
||||
|
||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
|
||||
TgPeerConnection::CreateAndAddTransceiver(
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>> sender,
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
|
||||
rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
|
||||
receiver) {
|
||||
// Ensure that the new sender does not have an ID that is already in use by
|
||||
@ -1849,19 +1649,19 @@ rtc::scoped_refptr<RtpSenderInterface> TgPeerConnection::CreateSender(
|
||||
}
|
||||
|
||||
// TODO(steveanton): Move construction of the RtpSenders to RtpTransceiver.
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>> new_sender;
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender;
|
||||
if (kind == MediaStreamTrackInterface::kAudioKind) {
|
||||
auto audio_sender = TgAudioRtpSender::Create(
|
||||
worker_thread(), rtc::CreateRandomUuid(), stats_.get(), this);
|
||||
worker_thread(), rtc::CreateRandomUuid(), this);
|
||||
audio_sender->SetMediaChannel(voice_media_channel());
|
||||
new_sender = RtpSenderProxyWithInternal<TgRtpSenderInternal>::Create(
|
||||
new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
|
||||
signaling_thread(), audio_sender);
|
||||
GetAudioTransceiver()->internal()->AddSender(new_sender);
|
||||
} else if (kind == MediaStreamTrackInterface::kVideoKind) {
|
||||
auto video_sender =
|
||||
TgVideoRtpSender::Create(worker_thread(), rtc::CreateRandomUuid(), this);
|
||||
video_sender->SetMediaChannel(video_media_channel());
|
||||
new_sender = RtpSenderProxyWithInternal<TgRtpSenderInternal>::Create(
|
||||
new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
|
||||
signaling_thread(), video_sender);
|
||||
GetVideoTransceiver()->internal()->AddSender(new_sender);
|
||||
} else {
|
||||
@ -1883,9 +1683,9 @@ const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>>
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
|
||||
TgPeerConnection::GetSendersInternal() const {
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>>
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
|
||||
all_senders;
|
||||
for (const auto& transceiver : transceivers_) {
|
||||
auto senders = transceiver->internal()->senders();
|
||||
@ -2031,7 +1831,7 @@ void TgPeerConnection::DoCreateOffer(
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateOfferAnswerOptions(options)) {
|
||||
if (!TgValidateOfferAnswerOptions(options)) {
|
||||
std::string error = "CreateOffer called with invalid options.";
|
||||
RTC_LOG(LS_ERROR) << error;
|
||||
PostCreateSessionDescriptionFailure(
|
||||
@ -3305,7 +3105,7 @@ static std::vector<RtpEncodingParameters> GetSendEncodingsFromRemoteDescription(
|
||||
|
||||
static RTCError UpdateSimulcastLayerStatusInSender(
|
||||
const std::vector<SimulcastLayer>& layers,
|
||||
rtc::scoped_refptr<TgRtpSenderInternal> sender) {
|
||||
rtc::scoped_refptr<RtpSenderInternal> sender) {
|
||||
RTC_DCHECK(sender);
|
||||
RtpParameters parameters = sender->GetParametersInternal();
|
||||
std::vector<std::string> disabled_layers;
|
||||
@ -3347,7 +3147,7 @@ static bool SimulcastIsRejected(
|
||||
}
|
||||
|
||||
static RTCError DisableSimulcastInSender(
|
||||
rtc::scoped_refptr<TgRtpSenderInternal> sender) {
|
||||
rtc::scoped_refptr<RtpSenderInternal> sender) {
|
||||
RTC_DCHECK(sender);
|
||||
RtpParameters parameters = sender->GetParametersInternal();
|
||||
if (parameters.encodings.size() <= 1) {
|
||||
@ -3783,34 +3583,29 @@ bool TgPeerConnection::AddIceCandidate(
|
||||
TRACE_EVENT0("webrtc", "TgPeerConnection::AddIceCandidate");
|
||||
if (IsClosed()) {
|
||||
RTC_LOG(LS_ERROR) << "AddIceCandidate: TgPeerConnection is closed.";
|
||||
NoteAddIceCandidateResult(kAddIceCandidateFailClosed);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!remote_description()) {
|
||||
RTC_LOG(LS_ERROR) << "AddIceCandidate: ICE candidates can't be added "
|
||||
"without any remote session description.";
|
||||
NoteAddIceCandidateResult(kAddIceCandidateFailNoRemoteDescription);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ice_candidate) {
|
||||
RTC_LOG(LS_ERROR) << "AddIceCandidate: Candidate is null.";
|
||||
NoteAddIceCandidateResult(kAddIceCandidateFailNullCandidate);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool valid = false;
|
||||
bool ready = ReadyToUseRemoteCandidate(ice_candidate, nullptr, &valid);
|
||||
if (!valid) {
|
||||
NoteAddIceCandidateResult(kAddIceCandidateFailNotValid);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add this candidate to the remote session description.
|
||||
if (!mutable_remote_description()->AddCandidate(ice_candidate)) {
|
||||
RTC_LOG(LS_ERROR) << "AddIceCandidate: Candidate cannot be used.";
|
||||
NoteAddIceCandidateResult(kAddIceCandidateFailInAddition);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3818,14 +3613,11 @@ bool TgPeerConnection::AddIceCandidate(
|
||||
bool result = UseCandidate(ice_candidate);
|
||||
if (result) {
|
||||
NoteUsageEvent(UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED);
|
||||
NoteAddIceCandidateResult(kAddIceCandidateSuccess);
|
||||
} else {
|
||||
NoteAddIceCandidateResult(kAddIceCandidateFailNotUsable);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
RTC_LOG(LS_INFO) << "AddIceCandidate: Not ready to use candidate.";
|
||||
NoteAddIceCandidateResult(kAddIceCandidateFailNotReady);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -4508,7 +4300,7 @@ void TgPeerConnection::PostCreateSessionDescriptionFailure(
|
||||
void TgPeerConnection::GetOptionsForOffer(
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
|
||||
cricket::MediaSessionOptions* session_options) {
|
||||
ExtractSharedMediaSessionOptions(offer_answer_options, session_options);
|
||||
TgExtractSharedMediaSessionOptions(offer_answer_options, session_options);
|
||||
|
||||
GetOptionsForUnifiedPlanOffer(offer_answer_options, session_options);
|
||||
|
||||
@ -4720,7 +4512,7 @@ void TgPeerConnection::GetOptionsForUnifiedPlanOffer(
|
||||
void TgPeerConnection::GetOptionsForAnswer(
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
|
||||
cricket::MediaSessionOptions* session_options) {
|
||||
ExtractSharedMediaSessionOptions(offer_answer_options, session_options);
|
||||
TgExtractSharedMediaSessionOptions(offer_answer_options, session_options);
|
||||
|
||||
GetOptionsForUnifiedPlanAnswer(offer_answer_options, session_options);
|
||||
|
||||
@ -5118,7 +4910,7 @@ bool TgPeerConnection::HasRtpSender(cricket::MediaType type) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
TgPeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) const {
|
||||
for (const auto& transceiver : transceivers_) {
|
||||
for (auto sender : transceiver->internal()->senders()) {
|
||||
@ -5130,7 +4922,7 @@ TgPeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
TgPeerConnection::FindSenderById(const std::string& sender_id) const {
|
||||
for (const auto& transceiver : transceivers_) {
|
||||
for (auto sender : transceiver->internal()->senders()) {
|
||||
@ -6058,13 +5850,6 @@ RTCError TgPeerConnection::ValidateSessionDescription(
|
||||
|
||||
// Verify crypto settings.
|
||||
std::string crypto_error;
|
||||
if (webrtc_session_desc_factory_->SdesPolicy() == cricket::SEC_REQUIRED ||
|
||||
dtls_enabled_) {
|
||||
RTCError crypto_error = VerifyCrypto(sdesc->description(), dtls_enabled_);
|
||||
if (!crypto_error.ok()) {
|
||||
return crypto_error;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify ice-ufrag and ice-pwd.
|
||||
if (!VerifyIceUfragPwdPresent(sdesc->description())) {
|
||||
|
@ -63,9 +63,370 @@ class RtcEventLog;
|
||||
// - Generating offers and answers based on the current state.
|
||||
// - The ICE state machine.
|
||||
// - Generating stats.
|
||||
class TgPeerConnection : public rtc::RefCountInterface,
|
||||
|
||||
class RTC_EXPORT TgPeerConnectionInterface : public rtc::RefCountInterface {
|
||||
public:
|
||||
// Accessor methods to active local streams.
|
||||
// This method is not supported with kUnifiedPlan semantics. Please use
|
||||
// GetSenders() instead.
|
||||
virtual rtc::scoped_refptr<StreamCollectionInterface> local_streams() = 0;
|
||||
|
||||
// Accessor methods to remote streams.
|
||||
// This method is not supported with kUnifiedPlan semantics. Please use
|
||||
// GetReceivers() instead.
|
||||
virtual rtc::scoped_refptr<StreamCollectionInterface> remote_streams() = 0;
|
||||
|
||||
// Add a new MediaStream to be sent on this PeerConnection.
|
||||
// Note that a SessionDescription negotiation is needed before the
|
||||
// remote peer can receive the stream.
|
||||
//
|
||||
// This has been removed from the standard in favor of a track-based API. So,
|
||||
// this is equivalent to simply calling AddTrack for each track within the
|
||||
// stream, with the one difference that if "stream->AddTrack(...)" is called
|
||||
// later, the PeerConnection will automatically pick up the new track. Though
|
||||
// this functionality will be deprecated in the future.
|
||||
//
|
||||
// This method is not supported with kUnifiedPlan semantics. Please use
|
||||
// AddTrack instead.
|
||||
virtual bool AddStream(MediaStreamInterface* stream) = 0;
|
||||
|
||||
// Remove a MediaStream from this PeerConnection.
|
||||
// Note that a SessionDescription negotiation is needed before the
|
||||
// remote peer is notified.
|
||||
//
|
||||
// This method is not supported with kUnifiedPlan semantics. Please use
|
||||
// RemoveTrack instead.
|
||||
virtual void RemoveStream(MediaStreamInterface* stream) = 0;
|
||||
|
||||
// Add a new MediaStreamTrack to be sent on this PeerConnection, and return
|
||||
// the newly created RtpSender. The RtpSender will be associated with the
|
||||
// streams specified in the |stream_ids| list.
|
||||
//
|
||||
// Errors:
|
||||
// - INVALID_PARAMETER: |track| is null, has a kind other than audio or video,
|
||||
// or a sender already exists for the track.
|
||||
// - INVALID_STATE: The PeerConnection is closed.
|
||||
virtual RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack(
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track,
|
||||
const std::vector<std::string>& stream_ids) = 0;
|
||||
|
||||
// Remove an RtpSender from this PeerConnection.
|
||||
// Returns true on success.
|
||||
// TODO(steveanton): Replace with signature that returns RTCError.
|
||||
virtual bool RemoveTrack(RtpSenderInterface* sender) = 0;
|
||||
|
||||
// Plan B semantics: Removes the RtpSender from this PeerConnection.
|
||||
// Unified Plan semantics: Stop sending on the RtpSender and mark the
|
||||
// corresponding RtpTransceiver direction as no longer sending.
|
||||
//
|
||||
// Errors:
|
||||
// - INVALID_PARAMETER: |sender| is null or (Plan B only) the sender is not
|
||||
// associated with this PeerConnection.
|
||||
// - INVALID_STATE: PeerConnection is closed.
|
||||
// TODO(bugs.webrtc.org/9534): Rename to RemoveTrack once the other signature
|
||||
// is removed.
|
||||
virtual RTCError RemoveTrackNew(
|
||||
rtc::scoped_refptr<RtpSenderInterface> sender);
|
||||
|
||||
// AddTransceiver creates a new RtpTransceiver and adds it to the set of
|
||||
// transceivers. Adding a transceiver will cause future calls to CreateOffer
|
||||
// to add a media description for the corresponding transceiver.
|
||||
//
|
||||
// The initial value of |mid| in the returned transceiver is null. Setting a
|
||||
// new session description may change it to a non-null value.
|
||||
//
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtransceiver
|
||||
//
|
||||
// Optionally, an RtpTransceiverInit structure can be specified to configure
|
||||
// the transceiver from construction. If not specified, the transceiver will
|
||||
// default to having a direction of kSendRecv and not be part of any streams.
|
||||
//
|
||||
// These methods are only available when Unified Plan is enabled (see
|
||||
// RTCConfiguration).
|
||||
//
|
||||
// Common errors:
|
||||
// - INTERNAL_ERROR: The configuration does not have Unified Plan enabled.
|
||||
|
||||
// Adds a transceiver with a sender set to transmit the given track. The kind
|
||||
// of the transceiver (and sender/receiver) will be derived from the kind of
|
||||
// the track.
|
||||
// Errors:
|
||||
// - INVALID_PARAMETER: |track| is null.
|
||||
virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
|
||||
AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface> track) = 0;
|
||||
virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
|
||||
AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface> track,
|
||||
const RtpTransceiverInit& init) = 0;
|
||||
|
||||
// Adds a transceiver with the given kind. Can either be MEDIA_TYPE_AUDIO or
|
||||
// MEDIA_TYPE_VIDEO.
|
||||
// Errors:
|
||||
// - INVALID_PARAMETER: |media_type| is not MEDIA_TYPE_AUDIO or
|
||||
// MEDIA_TYPE_VIDEO.
|
||||
virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
|
||||
AddTransceiver(cricket::MediaType media_type) = 0;
|
||||
virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
|
||||
AddTransceiver(cricket::MediaType media_type,
|
||||
const RtpTransceiverInit& init) = 0;
|
||||
|
||||
// Creates a sender without a track. Can be used for "early media"/"warmup"
|
||||
// use cases, where the application may want to negotiate video attributes
|
||||
// before a track is available to send.
|
||||
//
|
||||
// The standard way to do this would be through "addTransceiver", but we
|
||||
// don't support that API yet.
|
||||
//
|
||||
// |kind| must be "audio" or "video".
|
||||
//
|
||||
// |stream_id| is used to populate the msid attribute; if empty, one will
|
||||
// be generated automatically.
|
||||
//
|
||||
// This method is not supported with kUnifiedPlan semantics. Please use
|
||||
// AddTransceiver instead.
|
||||
virtual rtc::scoped_refptr<RtpSenderInterface> CreateSender(
|
||||
const std::string& kind,
|
||||
const std::string& stream_id) = 0;
|
||||
|
||||
// If Plan B semantics are specified, gets all RtpSenders, created either
|
||||
// through AddStream, AddTrack, or CreateSender. All senders of a specific
|
||||
// media type share the same media description.
|
||||
//
|
||||
// If Unified Plan semantics are specified, gets the RtpSender for each
|
||||
// RtpTransceiver.
|
||||
virtual std::vector<rtc::scoped_refptr<RtpSenderInterface>> GetSenders()
|
||||
const = 0;
|
||||
|
||||
// If Plan B semantics are specified, gets all RtpReceivers created when a
|
||||
// remote description is applied. All receivers of a specific media type share
|
||||
// the same media description. It is also possible to have a media description
|
||||
// with no associated RtpReceivers, if the directional attribute does not
|
||||
// indicate that the remote peer is sending any media.
|
||||
//
|
||||
// If Unified Plan semantics are specified, gets the RtpReceiver for each
|
||||
// RtpTransceiver.
|
||||
virtual std::vector<rtc::scoped_refptr<RtpReceiverInterface>> GetReceivers()
|
||||
const = 0;
|
||||
|
||||
// Get all RtpTransceivers, created either through AddTransceiver, AddTrack or
|
||||
// by a remote description applied with SetRemoteDescription.
|
||||
//
|
||||
// Note: This method is only available when Unified Plan is enabled (see
|
||||
// RTCConfiguration).
|
||||
virtual std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>
|
||||
GetTransceivers() const = 0;
|
||||
|
||||
|
||||
// Clear cached stats in the RTCStatsCollector.
|
||||
// Exposed for testing while waiting for automatic cache clear to work.
|
||||
// https://bugs.webrtc.org/8693
|
||||
virtual void ClearStatsCache() {}
|
||||
|
||||
// Create a data channel with the provided config, or default config if none
|
||||
// is provided. Note that an offer/answer negotiation is still necessary
|
||||
// before the data channel can be used.
|
||||
//
|
||||
// Also, calling CreateDataChannel is the only way to get a data "m=" section
|
||||
// in SDP, so it should be done before CreateOffer is called, if the
|
||||
// application plans to use data channels.
|
||||
virtual rtc::scoped_refptr<DataChannelInterface> CreateDataChannel(
|
||||
const std::string& label,
|
||||
const DataChannelInit* config) = 0;
|
||||
|
||||
// Returns the more recently applied description; "pending" if it exists, and
|
||||
// otherwise "current". See below.
|
||||
virtual const SessionDescriptionInterface* local_description() const = 0;
|
||||
virtual const SessionDescriptionInterface* remote_description() const = 0;
|
||||
|
||||
// A "current" description the one currently negotiated from a complete
|
||||
// offer/answer exchange.
|
||||
virtual const SessionDescriptionInterface* current_local_description()
|
||||
const = 0;
|
||||
virtual const SessionDescriptionInterface* current_remote_description()
|
||||
const = 0;
|
||||
|
||||
// A "pending" description is one that's part of an incomplete offer/answer
|
||||
// exchange (thus, either an offer or a pranswer). Once the offer/answer
|
||||
// exchange is finished, the "pending" description will become "current".
|
||||
virtual const SessionDescriptionInterface* pending_local_description()
|
||||
const = 0;
|
||||
virtual const SessionDescriptionInterface* pending_remote_description()
|
||||
const = 0;
|
||||
|
||||
// Tells the PeerConnection that ICE should be restarted. This triggers a need
|
||||
// for negotiation and subsequent CreateOffer() calls will act as if
|
||||
// RTCOfferAnswerOptions::ice_restart is true.
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-restartice
|
||||
// TODO(hbos): Remove default implementation when downstream projects
|
||||
// implement this.
|
||||
virtual void RestartIce() = 0;
|
||||
|
||||
// Create a new offer.
|
||||
// The CreateSessionDescriptionObserver callback will be called when done.
|
||||
virtual void CreateOffer(CreateSessionDescriptionObserver* observer,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options) = 0;
|
||||
|
||||
// Create an answer to an offer.
|
||||
// The CreateSessionDescriptionObserver callback will be called when done.
|
||||
virtual void CreateAnswer(CreateSessionDescriptionObserver* observer,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options) = 0;
|
||||
|
||||
// Sets the local session description.
|
||||
// The PeerConnection takes the ownership of |desc| even if it fails.
|
||||
// The |observer| callback will be called when done.
|
||||
// TODO(deadbeef): Change |desc| to be a unique_ptr, to make it clear
|
||||
// that this method always takes ownership of it.
|
||||
virtual void SetLocalDescription(SetSessionDescriptionObserver* observer,
|
||||
SessionDescriptionInterface* desc) = 0;
|
||||
// Implicitly creates an offer or answer (depending on the current signaling
|
||||
// state) and performs SetLocalDescription() with the newly generated session
|
||||
// description.
|
||||
// TODO(hbos): Make pure virtual when implemented by downstream projects.
|
||||
virtual void SetLocalDescription(SetSessionDescriptionObserver* observer) {}
|
||||
// Sets the remote session description.
|
||||
// The PeerConnection takes the ownership of |desc| even if it fails.
|
||||
// The |observer| callback will be called when done.
|
||||
// TODO(hbos): Remove when Chrome implements the new signature.
|
||||
virtual void SetRemoteDescription(SetSessionDescriptionObserver* observer,
|
||||
SessionDescriptionInterface* desc) {}
|
||||
virtual void SetRemoteDescription(
|
||||
std::unique_ptr<SessionDescriptionInterface> desc,
|
||||
rtc::scoped_refptr<SetRemoteDescriptionObserverInterface> observer) = 0;
|
||||
|
||||
virtual PeerConnectionInterface::RTCConfiguration GetConfiguration() = 0;
|
||||
|
||||
// Sets the PeerConnection's global configuration to |config|.
|
||||
//
|
||||
// The members of |config| that may be changed are |type|, |servers|,
|
||||
// |ice_candidate_pool_size| and |prune_turn_ports| (though the candidate
|
||||
// pool size can't be changed after the first call to SetLocalDescription).
|
||||
// Note that this means the BUNDLE and RTCP-multiplexing policies cannot be
|
||||
// changed with this method.
|
||||
//
|
||||
// Any changes to STUN/TURN servers or ICE candidate policy will affect the
|
||||
// next gathering phase, and cause the next call to createOffer to generate
|
||||
// new ICE credentials, as described in JSEP. This also occurs when
|
||||
// |prune_turn_ports| changes, for the same reasoning.
|
||||
//
|
||||
// If an error occurs, returns false and populates |error| if non-null:
|
||||
// - INVALID_MODIFICATION if |config| contains a modified parameter other
|
||||
// than one of the parameters listed above.
|
||||
// - INVALID_RANGE if |ice_candidate_pool_size| is out of range.
|
||||
// - SYNTAX_ERROR if parsing an ICE server URL failed.
|
||||
// - INVALID_PARAMETER if a TURN server is missing |username| or |password|.
|
||||
// - INTERNAL_ERROR if an unexpected error occurred.
|
||||
//
|
||||
// TODO(nisse): Make this pure virtual once all Chrome subclasses of
|
||||
// PeerConnectionInterface implement it.
|
||||
virtual RTCError SetConfiguration(
|
||||
const PeerConnectionInterface::RTCConfiguration& config);
|
||||
|
||||
// Provides a remote candidate to the ICE Agent.
|
||||
// A copy of the |candidate| will be created and added to the remote
|
||||
// description. So the caller of this method still has the ownership of the
|
||||
// |candidate|.
|
||||
// TODO(hbos): The spec mandates chaining this operation onto the operations
|
||||
// chain; deprecate and remove this version in favor of the callback-based
|
||||
// signature.
|
||||
virtual bool AddIceCandidate(const IceCandidateInterface* candidate) = 0;
|
||||
// TODO(hbos): Remove default implementation once implemented by downstream
|
||||
// projects.
|
||||
virtual void AddIceCandidate(std::unique_ptr<IceCandidateInterface> candidate,
|
||||
std::function<void(RTCError)> callback) {}
|
||||
|
||||
// Removes a group of remote candidates from the ICE agent. Needed mainly for
|
||||
// continual gathering, to avoid an ever-growing list of candidates as
|
||||
// networks come and go.
|
||||
virtual bool RemoveIceCandidates(
|
||||
const std::vector<cricket::Candidate>& candidates) = 0;
|
||||
|
||||
// SetBitrate limits the bandwidth allocated for all RTP streams sent by
|
||||
// this PeerConnection. Other limitations might affect these limits and
|
||||
// are respected (for example "b=AS" in SDP).
|
||||
//
|
||||
// Setting |current_bitrate_bps| will reset the current bitrate estimate
|
||||
// to the provided value.
|
||||
virtual RTCError SetBitrate(const BitrateSettings& bitrate);
|
||||
|
||||
// TODO(nisse): Deprecated - use version above. These two default
|
||||
// implementations require subclasses to implement one or the other
|
||||
// of the methods.
|
||||
virtual RTCError SetBitrate(const PeerConnectionInterface::BitrateParameters& bitrate_parameters);
|
||||
|
||||
// Enable/disable playout of received audio streams. Enabled by default. Note
|
||||
// that even if playout is enabled, streams will only be played out if the
|
||||
// appropriate SDP is also applied. Setting |playout| to false will stop
|
||||
// playout of the underlying audio device but starts a task which will poll
|
||||
// for audio data every 10ms to ensure that audio processing happens and the
|
||||
// audio statistics are updated.
|
||||
// TODO(henrika): deprecate and remove this.
|
||||
virtual void SetAudioPlayout(bool playout) {}
|
||||
|
||||
// Enable/disable recording of transmitted audio streams. Enabled by default.
|
||||
// Note that even if recording is enabled, streams will only be recorded if
|
||||
// the appropriate SDP is also applied.
|
||||
// TODO(henrika): deprecate and remove this.
|
||||
virtual void SetAudioRecording(bool recording) {}
|
||||
|
||||
// Looks up the DtlsTransport associated with a MID value.
|
||||
// In the Javascript API, DtlsTransport is a property of a sender, but
|
||||
// because the PeerConnection owns the DtlsTransport in this implementation,
|
||||
// it is better to look them up on the PeerConnection.
|
||||
virtual rtc::scoped_refptr<DtlsTransportInterface> LookupDtlsTransportByMid(
|
||||
const std::string& mid) = 0;
|
||||
|
||||
// Returns the SCTP transport, if any.
|
||||
virtual rtc::scoped_refptr<SctpTransportInterface> GetSctpTransport()
|
||||
const = 0;
|
||||
|
||||
// Returns the current SignalingState.
|
||||
virtual PeerConnectionInterface::SignalingState signaling_state() = 0;
|
||||
|
||||
// Returns an aggregate state of all ICE *and* DTLS transports.
|
||||
// This is left in place to avoid breaking native clients who expect our old,
|
||||
// nonstandard behavior.
|
||||
// TODO(jonasolsson): deprecate and remove this.
|
||||
virtual PeerConnectionInterface::IceConnectionState ice_connection_state() = 0;
|
||||
|
||||
// Returns an aggregated state of all ICE transports.
|
||||
virtual PeerConnectionInterface::IceConnectionState standardized_ice_connection_state() = 0;
|
||||
|
||||
// Returns an aggregated state of all ICE and DTLS transports.
|
||||
virtual PeerConnectionInterface::PeerConnectionState peer_connection_state() = 0;
|
||||
|
||||
virtual PeerConnectionInterface::IceGatheringState ice_gathering_state() = 0;
|
||||
|
||||
// Start RtcEventLog using an existing output-sink. Takes ownership of
|
||||
// |output| and passes it on to Call, which will take the ownership. If the
|
||||
// operation fails the output will be closed and deallocated. The event log
|
||||
// will send serialized events to the output object every |output_period_ms|.
|
||||
// Applications using the event log should generally make their own trade-off
|
||||
// regarding the output period. A long period is generally more efficient,
|
||||
// with potential drawbacks being more bursty thread usage, and more events
|
||||
// lost in case the application crashes. If the |output_period_ms| argument is
|
||||
// omitted, webrtc selects a default deemed to be workable in most cases.
|
||||
virtual bool StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output,
|
||||
int64_t output_period_ms) = 0;
|
||||
virtual bool StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output) = 0;
|
||||
|
||||
// Stops logging the RtcEventLog.
|
||||
virtual void StopRtcEventLog() = 0;
|
||||
|
||||
// Terminates all media, closes the transports, and in general releases any
|
||||
// resources used by the PeerConnection. This is an irreversible operation.
|
||||
//
|
||||
// Note that after this method completes, the PeerConnection will no longer
|
||||
// use the PeerConnectionObserver interface passed in on construction, and
|
||||
// thus the observer object can be safely destroyed.
|
||||
virtual void Close() = 0;
|
||||
|
||||
protected:
|
||||
// Dtor protected as objects shouldn't be deleted via this interface.
|
||||
~TgPeerConnectionInterface() override = default;
|
||||
};
|
||||
|
||||
class TgPeerConnection : public TgPeerConnectionInterface,
|
||||
public TgJsepTransportController::Observer,
|
||||
public TgRtpSenderBase::SetStreamsObserver,
|
||||
public RtpSenderBase::SetStreamsObserver,
|
||||
public rtc::MessageHandler,
|
||||
public sigslot::has_slots<> {
|
||||
public:
|
||||
@ -458,7 +819,7 @@ public sigslot::has_slots<> {
|
||||
cricket::VideoMediaChannel* video_media_channel() const
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>>
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
|
||||
GetSendersInternal() const RTC_RUN_ON(signaling_thread());
|
||||
std::vector<
|
||||
rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
|
||||
@ -541,7 +902,7 @@ public sigslot::has_slots<> {
|
||||
const RtpTransceiverInit& init,
|
||||
bool fire_callback = true) RTC_RUN_ON(signaling_thread());
|
||||
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
CreateSender(cricket::MediaType media_type,
|
||||
const std::string& id,
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track,
|
||||
@ -555,7 +916,7 @@ public sigslot::has_slots<> {
|
||||
// transceivers.
|
||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
|
||||
CreateAndAddTransceiver(
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>> sender,
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
|
||||
rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
|
||||
receiver) RTC_RUN_ON(signaling_thread());
|
||||
|
||||
@ -855,12 +1216,12 @@ public sigslot::has_slots<> {
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
// Return the RtpSender with the given track attached.
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
FindSenderForTrack(MediaStreamTrackInterface* track) const
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
// Return the RtpSender with the given id, or null if none exists.
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
FindSenderById(const std::string& sender_id) const
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
@ -1139,7 +1500,7 @@ public sigslot::has_slots<> {
|
||||
rtc::scoped_refptr<DtlsTransport> dtls_transport,
|
||||
DataChannelTransportInterface* data_channel_transport) override;
|
||||
|
||||
// TgRtpSenderBase::SetStreamsObserver override.
|
||||
// RtpSenderBase::SetStreamsObserver override.
|
||||
void OnSetStreams() override;
|
||||
|
||||
// Returns the CryptoOptions for this TgPeerConnection. This will always
|
||||
|
@ -48,6 +48,136 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
rtc::scoped_refptr<TgPeerConnectionInterface>
|
||||
TgPeerConnectionFactoryInterface::CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
std::unique_ptr<cricket::PortAllocator> allocator,
|
||||
std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
|
||||
PeerConnectionObserver* observer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<TgPeerConnectionInterface>
|
||||
TgPeerConnectionFactoryInterface::CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
PeerConnectionDependencies dependencies) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RtpCapabilities TgPeerConnectionFactoryInterface::GetRtpSenderCapabilities(
|
||||
cricket::MediaType kind) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
RtpCapabilities TgPeerConnectionFactoryInterface::GetRtpReceiverCapabilities(
|
||||
cricket::MediaType kind) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
BEGIN_SIGNALING_PROXY_MAP(TgPeerConnection)
|
||||
PROXY_SIGNALING_THREAD_DESTRUCTOR()
|
||||
PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, local_streams)
|
||||
PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, remote_streams)
|
||||
PROXY_METHOD1(bool, AddStream, MediaStreamInterface*)
|
||||
PROXY_METHOD1(void, RemoveStream, MediaStreamInterface*)
|
||||
PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>,
|
||||
AddTrack,
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface>,
|
||||
const std::vector<std::string>&)
|
||||
PROXY_METHOD1(bool, RemoveTrack, RtpSenderInterface*)
|
||||
PROXY_METHOD1(RTCError, RemoveTrackNew, rtc::scoped_refptr<RtpSenderInterface>)
|
||||
PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
|
||||
AddTransceiver,
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface>)
|
||||
PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
|
||||
AddTransceiver,
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface>,
|
||||
const RtpTransceiverInit&)
|
||||
PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
|
||||
AddTransceiver,
|
||||
cricket::MediaType)
|
||||
PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
|
||||
AddTransceiver,
|
||||
cricket::MediaType,
|
||||
const RtpTransceiverInit&)
|
||||
PROXY_METHOD2(rtc::scoped_refptr<RtpSenderInterface>,
|
||||
CreateSender,
|
||||
const std::string&,
|
||||
const std::string&)
|
||||
PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpSenderInterface>>,
|
||||
GetSenders)
|
||||
PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpReceiverInterface>>,
|
||||
GetReceivers)
|
||||
PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>,
|
||||
GetTransceivers)
|
||||
PROXY_METHOD0(void, ClearStatsCache)
|
||||
PROXY_METHOD2(rtc::scoped_refptr<DataChannelInterface>,
|
||||
CreateDataChannel,
|
||||
const std::string&,
|
||||
const DataChannelInit*)
|
||||
PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, local_description)
|
||||
PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, remote_description)
|
||||
PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
|
||||
current_local_description)
|
||||
PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
|
||||
current_remote_description)
|
||||
PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
|
||||
pending_local_description)
|
||||
PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
|
||||
pending_remote_description)
|
||||
PROXY_METHOD0(void, RestartIce)
|
||||
PROXY_METHOD2(void,
|
||||
CreateOffer,
|
||||
CreateSessionDescriptionObserver*,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions&)
|
||||
PROXY_METHOD2(void,
|
||||
CreateAnswer,
|
||||
CreateSessionDescriptionObserver*,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions&)
|
||||
PROXY_METHOD2(void,
|
||||
SetLocalDescription,
|
||||
SetSessionDescriptionObserver*,
|
||||
SessionDescriptionInterface*)
|
||||
PROXY_METHOD1(void, SetLocalDescription, SetSessionDescriptionObserver*)
|
||||
PROXY_METHOD2(void,
|
||||
SetRemoteDescription,
|
||||
SetSessionDescriptionObserver*,
|
||||
SessionDescriptionInterface*)
|
||||
PROXY_METHOD2(void,
|
||||
SetRemoteDescription,
|
||||
std::unique_ptr<SessionDescriptionInterface>,
|
||||
rtc::scoped_refptr<SetRemoteDescriptionObserverInterface>)
|
||||
PROXY_METHOD0(PeerConnectionInterface::RTCConfiguration, GetConfiguration)
|
||||
PROXY_METHOD1(RTCError,
|
||||
SetConfiguration,
|
||||
const PeerConnectionInterface::RTCConfiguration&)
|
||||
PROXY_METHOD1(bool, AddIceCandidate, const IceCandidateInterface*)
|
||||
PROXY_METHOD2(void,
|
||||
AddIceCandidate,
|
||||
std::unique_ptr<IceCandidateInterface>,
|
||||
std::function<void(RTCError)>)
|
||||
PROXY_METHOD1(bool, RemoveIceCandidates, const std::vector<cricket::Candidate>&)
|
||||
PROXY_METHOD1(RTCError, SetBitrate, const BitrateSettings&)
|
||||
PROXY_METHOD1(void, SetAudioPlayout, bool)
|
||||
PROXY_METHOD1(void, SetAudioRecording, bool)
|
||||
PROXY_METHOD1(rtc::scoped_refptr<DtlsTransportInterface>,
|
||||
LookupDtlsTransportByMid,
|
||||
const std::string&)
|
||||
PROXY_CONSTMETHOD0(rtc::scoped_refptr<SctpTransportInterface>, GetSctpTransport)
|
||||
PROXY_METHOD0(PeerConnectionInterface::SignalingState, signaling_state)
|
||||
PROXY_METHOD0(PeerConnectionInterface::IceConnectionState, ice_connection_state)
|
||||
PROXY_METHOD0(PeerConnectionInterface::IceConnectionState, standardized_ice_connection_state)
|
||||
PROXY_METHOD0(PeerConnectionInterface::PeerConnectionState, peer_connection_state)
|
||||
PROXY_METHOD0(PeerConnectionInterface::IceGatheringState, ice_gathering_state)
|
||||
PROXY_METHOD2(bool,
|
||||
StartRtcEventLog,
|
||||
std::unique_ptr<RtcEventLogOutput>,
|
||||
int64_t)
|
||||
PROXY_METHOD1(bool, StartRtcEventLog, std::unique_ptr<RtcEventLogOutput>)
|
||||
PROXY_METHOD0(void, StopRtcEventLog)
|
||||
PROXY_METHOD0(void, Close)
|
||||
END_PROXY_MAP()
|
||||
|
||||
TgPeerConnectionFactory::TgPeerConnectionFactory(
|
||||
PeerConnectionFactoryDependencies dependencies)
|
||||
: wraps_current_thread_(false),
|
||||
@ -210,7 +340,7 @@ void TgPeerConnectionFactory::StopAecDump() {
|
||||
channel_manager_->StopAecDump();
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<TgPeerConnection>
|
||||
rtc::scoped_refptr<TgPeerConnectionInterface>
|
||||
TgPeerConnectionFactory::CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
std::unique_ptr<cricket::PortAllocator> allocator,
|
||||
@ -224,7 +354,7 @@ TgPeerConnectionFactory::CreatePeerConnection(
|
||||
return CreatePeerConnection(configuration, std::move(dependencies));
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<TgPeerConnection>
|
||||
rtc::scoped_refptr<TgPeerConnectionInterface>
|
||||
TgPeerConnectionFactory::CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
PeerConnectionDependencies dependencies) {
|
||||
@ -284,7 +414,7 @@ TgPeerConnectionFactory::CreatePeerConnection(
|
||||
if (!pc->Initialize(configuration, std::move(dependencies))) {
|
||||
return nullptr;
|
||||
}
|
||||
return pc;
|
||||
return TgPeerConnectionProxy::Create(signaling_thread(), pc);
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<MediaStreamInterface>
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "pc/channel_manager.h"
|
||||
#include "rtc_base/rtc_certificate_generator.h"
|
||||
#include "rtc_base/thread.h"
|
||||
#include "pc/peer_connection_factory.h"
|
||||
|
||||
namespace rtc {
|
||||
class BasicNetworkManager;
|
||||
@ -33,18 +34,102 @@ namespace webrtc {
|
||||
|
||||
class RtcEventLog;
|
||||
class TgPeerConnection;
|
||||
class TgPeerConnectionInterface;
|
||||
|
||||
class TgPeerConnectionFactory: public rtc::RefCountInterface {
|
||||
class RTC_EXPORT TgPeerConnectionFactoryInterface
|
||||
: public rtc::RefCountInterface {
|
||||
public:
|
||||
void SetOptions(const PeerConnectionFactoryInterface::Options& options);
|
||||
// Set the options to be used for subsequently created PeerConnections.
|
||||
virtual void SetOptions(const PeerConnectionFactoryInterface::Options& options) = 0;
|
||||
|
||||
rtc::scoped_refptr<TgPeerConnection> CreatePeerConnection(
|
||||
// The preferred way to create a new peer connection. Simply provide the
|
||||
// configuration and a PeerConnectionDependencies structure.
|
||||
// TODO(benwright): Make pure virtual once downstream mock PC factory classes
|
||||
// are updated.
|
||||
virtual rtc::scoped_refptr<TgPeerConnectionInterface> CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
PeerConnectionDependencies dependencies);
|
||||
|
||||
// Deprecated; |allocator| and |cert_generator| may be null, in which case
|
||||
// default implementations will be used.
|
||||
//
|
||||
// |observer| must not be null.
|
||||
//
|
||||
// Note that this method does not take ownership of |observer|; it's the
|
||||
// responsibility of the caller to delete it. It can be safely deleted after
|
||||
// Close has been called on the returned PeerConnection, which ensures no
|
||||
// more observer callbacks will be invoked.
|
||||
virtual rtc::scoped_refptr<TgPeerConnectionInterface> CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
std::unique_ptr<cricket::PortAllocator> allocator,
|
||||
std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
|
||||
PeerConnectionObserver* observer);
|
||||
|
||||
rtc::scoped_refptr<TgPeerConnection> CreatePeerConnection(
|
||||
// Returns the capabilities of an RTP sender of type |kind|.
|
||||
// If for some reason you pass in MEDIA_TYPE_DATA, returns an empty structure.
|
||||
// TODO(orphis): Make pure virtual when all subclasses implement it.
|
||||
virtual RtpCapabilities GetRtpSenderCapabilities(
|
||||
cricket::MediaType kind) const;
|
||||
|
||||
// Returns the capabilities of an RTP receiver of type |kind|.
|
||||
// If for some reason you pass in MEDIA_TYPE_DATA, returns an empty structure.
|
||||
// TODO(orphis): Make pure virtual when all subclasses implement it.
|
||||
virtual RtpCapabilities GetRtpReceiverCapabilities(
|
||||
cricket::MediaType kind) const;
|
||||
|
||||
virtual rtc::scoped_refptr<MediaStreamInterface> CreateLocalMediaStream(
|
||||
const std::string& stream_id) = 0;
|
||||
|
||||
// Creates an AudioSourceInterface.
|
||||
// |options| decides audio processing settings.
|
||||
virtual rtc::scoped_refptr<AudioSourceInterface> CreateAudioSource(
|
||||
const cricket::AudioOptions& options) = 0;
|
||||
|
||||
// Creates a new local VideoTrack. The same |source| can be used in several
|
||||
// tracks.
|
||||
virtual rtc::scoped_refptr<VideoTrackInterface> CreateVideoTrack(
|
||||
const std::string& label,
|
||||
VideoTrackSourceInterface* source) = 0;
|
||||
|
||||
// Creates an new AudioTrack. At the moment |source| can be null.
|
||||
virtual rtc::scoped_refptr<AudioTrackInterface> CreateAudioTrack(
|
||||
const std::string& label,
|
||||
AudioSourceInterface* source) = 0;
|
||||
|
||||
// Starts AEC dump using existing file. Takes ownership of |file| and passes
|
||||
// it on to VoiceEngine (via other objects) immediately, which will take
|
||||
// the ownerhip. If the operation fails, the file will be closed.
|
||||
// A maximum file size in bytes can be specified. When the file size limit is
|
||||
// reached, logging is stopped automatically. If max_size_bytes is set to a
|
||||
// value <= 0, no limit will be used, and logging will continue until the
|
||||
// StopAecDump function is called.
|
||||
// TODO(webrtc:6463): Delete default implementation when downstream mocks
|
||||
// classes are updated.
|
||||
virtual bool StartAecDump(FILE* file, int64_t max_size_bytes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stops logging the AEC dump.
|
||||
virtual void StopAecDump() = 0;
|
||||
|
||||
protected:
|
||||
// Dtor and ctor protected as objects shouldn't be created or deleted via
|
||||
// this interface.
|
||||
TgPeerConnectionFactoryInterface() {}
|
||||
~TgPeerConnectionFactoryInterface() override = default;
|
||||
};
|
||||
|
||||
class TgPeerConnectionFactory: public TgPeerConnectionFactoryInterface {
|
||||
public:
|
||||
void SetOptions(const PeerConnectionFactoryInterface::Options& options);
|
||||
|
||||
rtc::scoped_refptr<TgPeerConnectionInterface> CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
std::unique_ptr<cricket::PortAllocator> allocator,
|
||||
std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
|
||||
PeerConnectionObserver* observer);
|
||||
|
||||
rtc::scoped_refptr<TgPeerConnectionInterface> CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
PeerConnectionDependencies dependencies);
|
||||
|
||||
@ -134,6 +219,43 @@ class TgPeerConnectionFactory: public rtc::RefCountInterface {
|
||||
const std::unique_ptr<WebRtcKeyValueConfig> trials_;
|
||||
};
|
||||
|
||||
BEGIN_SIGNALING_PROXY_MAP(TgPeerConnectionFactory)
|
||||
PROXY_SIGNALING_THREAD_DESTRUCTOR()
|
||||
PROXY_METHOD1(void, SetOptions, const PeerConnectionFactory::Options&)
|
||||
PROXY_METHOD4(rtc::scoped_refptr<TgPeerConnectionInterface>,
|
||||
CreatePeerConnection,
|
||||
const PeerConnectionInterface::RTCConfiguration&,
|
||||
std::unique_ptr<cricket::PortAllocator>,
|
||||
std::unique_ptr<rtc::RTCCertificateGeneratorInterface>,
|
||||
PeerConnectionObserver*)
|
||||
PROXY_METHOD2(rtc::scoped_refptr<TgPeerConnectionInterface>,
|
||||
CreatePeerConnection,
|
||||
const PeerConnectionInterface::RTCConfiguration&,
|
||||
PeerConnectionDependencies)
|
||||
PROXY_CONSTMETHOD1(webrtc::RtpCapabilities,
|
||||
GetRtpSenderCapabilities,
|
||||
cricket::MediaType)
|
||||
PROXY_CONSTMETHOD1(webrtc::RtpCapabilities,
|
||||
GetRtpReceiverCapabilities,
|
||||
cricket::MediaType)
|
||||
PROXY_METHOD1(rtc::scoped_refptr<MediaStreamInterface>,
|
||||
CreateLocalMediaStream,
|
||||
const std::string&)
|
||||
PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>,
|
||||
CreateAudioSource,
|
||||
const cricket::AudioOptions&)
|
||||
PROXY_METHOD2(rtc::scoped_refptr<VideoTrackInterface>,
|
||||
CreateVideoTrack,
|
||||
const std::string&,
|
||||
VideoTrackSourceInterface*)
|
||||
PROXY_METHOD2(rtc::scoped_refptr<AudioTrackInterface>,
|
||||
CreateAudioTrack,
|
||||
const std::string&,
|
||||
AudioSourceInterface*)
|
||||
PROXY_METHOD2(bool, StartAecDump, FILE*, int64_t)
|
||||
PROXY_METHOD0(void, StopAecDump)
|
||||
END_PROXY_MAP()
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // PC_PEER_CONNECTION_FACTORY_H_
|
||||
|
@ -73,15 +73,7 @@ TgRtpDataMediaChannel::~TgRtpDataMediaChannel() {
|
||||
}
|
||||
}
|
||||
|
||||
void RTC_NO_SANITIZE("float-cast-overflow") // bugs.webrtc.org/8204
|
||||
RtpClock::Tick(double now, int* seq_num, uint32_t* timestamp) {
|
||||
*seq_num = ++last_seq_num_;
|
||||
*timestamp = timestamp_offset_ + static_cast<uint32_t>(now * clockrate_);
|
||||
// UBSan: 5.92374e+10 is outside the range of representable values of type
|
||||
// 'unsigned int'
|
||||
}
|
||||
|
||||
const DataCodec* FindUnknownCodec(const std::vector<DataCodec>& codecs) {
|
||||
const DataCodec* TgFindUnknownCodec(const std::vector<DataCodec>& codecs) {
|
||||
DataCodec data_codec(kGoogleRtpDataCodecPlType, kGoogleRtpDataCodecName);
|
||||
std::vector<DataCodec>::const_iterator iter;
|
||||
for (iter = codecs.begin(); iter != codecs.end(); ++iter) {
|
||||
@ -92,7 +84,7 @@ const DataCodec* FindUnknownCodec(const std::vector<DataCodec>& codecs) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const DataCodec* FindKnownCodec(const std::vector<DataCodec>& codecs) {
|
||||
const DataCodec* TgFindKnownCodec(const std::vector<DataCodec>& codecs) {
|
||||
DataCodec data_codec(kGoogleRtpDataCodecPlType, kGoogleRtpDataCodecName);
|
||||
std::vector<DataCodec>::const_iterator iter;
|
||||
for (iter = codecs.begin(); iter != codecs.end(); ++iter) {
|
||||
@ -104,7 +96,7 @@ const DataCodec* FindKnownCodec(const std::vector<DataCodec>& codecs) {
|
||||
}
|
||||
|
||||
bool TgRtpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) {
|
||||
const DataCodec* unknown_codec = FindUnknownCodec(codecs);
|
||||
const DataCodec* unknown_codec = TgFindUnknownCodec(codecs);
|
||||
if (unknown_codec) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to SetRecvCodecs because of unknown codec: "
|
||||
<< unknown_codec->ToString();
|
||||
@ -116,7 +108,7 @@ bool TgRtpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs)
|
||||
}
|
||||
|
||||
bool TgRtpDataMediaChannel::SetSendCodecs(const std::vector<DataCodec>& codecs) {
|
||||
const DataCodec* known_codec = FindKnownCodec(codecs);
|
||||
const DataCodec* known_codec = TgFindKnownCodec(codecs);
|
||||
if (!known_codec) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Failed to SetSendCodecs because there is no known codec.";
|
||||
|
@ -90,7 +90,7 @@ RtpParameters RestoreEncodingLayers(
|
||||
|
||||
// Returns true if any RtpParameters member that isn't implemented contains a
|
||||
// value.
|
||||
bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
|
||||
bool TgUnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
|
||||
if (!parameters.mid.empty()) {
|
||||
return true;
|
||||
}
|
||||
@ -105,265 +105,6 @@ bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TgRtpSenderBase::TgRtpSenderBase(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
SetStreamsObserver* set_streams_observer)
|
||||
: worker_thread_(worker_thread),
|
||||
id_(id),
|
||||
set_streams_observer_(set_streams_observer) {
|
||||
RTC_DCHECK(worker_thread);
|
||||
init_parameters_.encodings.emplace_back();
|
||||
}
|
||||
|
||||
void TgRtpSenderBase::SetFrameEncryptor(
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) {
|
||||
frame_encryptor_ = std::move(frame_encryptor);
|
||||
// Special Case: Set the frame encryptor to any value on any existing channel.
|
||||
if (media_channel_ && ssrc_ && !stopped_) {
|
||||
worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
media_channel_->SetFrameEncryptor(ssrc_, frame_encryptor_);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void TgRtpSenderBase::SetMediaChannel(cricket::MediaChannel* media_channel) {
|
||||
RTC_DCHECK(media_channel == nullptr ||
|
||||
media_channel->media_type() == media_type());
|
||||
media_channel_ = media_channel;
|
||||
}
|
||||
|
||||
RtpParameters TgRtpSenderBase::GetParametersInternal() const {
|
||||
if (stopped_) {
|
||||
return RtpParameters();
|
||||
}
|
||||
if (!media_channel_ || !ssrc_) {
|
||||
return init_parameters_;
|
||||
}
|
||||
return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
|
||||
RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
|
||||
RemoveEncodingLayers(disabled_rids_, &result.encodings);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
RtpParameters TgRtpSenderBase::GetParameters() const {
|
||||
RtpParameters result = GetParametersInternal();
|
||||
last_transaction_id_ = rtc::CreateRandomUuid();
|
||||
result.transaction_id = last_transaction_id_.value();
|
||||
return result;
|
||||
}
|
||||
|
||||
RTCError TgRtpSenderBase::SetParametersInternal(const RtpParameters& parameters) {
|
||||
RTC_DCHECK(!stopped_);
|
||||
|
||||
if (UnimplementedRtpParameterHasValue(parameters)) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
"Attempted to set an unimplemented parameter of RtpParameters.");
|
||||
}
|
||||
if (!media_channel_ || !ssrc_) {
|
||||
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
|
||||
init_parameters_, parameters);
|
||||
if (result.ok()) {
|
||||
init_parameters_ = parameters;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
|
||||
RtpParameters rtp_parameters = parameters;
|
||||
if (!disabled_rids_.empty()) {
|
||||
// Need to add the inactive layers.
|
||||
RtpParameters old_parameters =
|
||||
media_channel_->GetRtpSendParameters(ssrc_);
|
||||
rtp_parameters = RestoreEncodingLayers(parameters, disabled_rids_,
|
||||
old_parameters.encodings);
|
||||
}
|
||||
return media_channel_->SetRtpSendParameters(ssrc_, rtp_parameters);
|
||||
});
|
||||
}
|
||||
|
||||
RTCError TgRtpSenderBase::SetParameters(const RtpParameters& parameters) {
|
||||
TRACE_EVENT0("webrtc", "TgRtpSenderBase::SetParameters");
|
||||
if (stopped_) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
|
||||
"Cannot set parameters on a stopped sender.");
|
||||
}
|
||||
if (!last_transaction_id_) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_STATE,
|
||||
"Failed to set parameters since getParameters() has never been called"
|
||||
" on this sender");
|
||||
}
|
||||
if (last_transaction_id_ != parameters.transaction_id) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Failed to set parameters since the transaction_id doesn't match"
|
||||
" the last value returned from getParameters()");
|
||||
}
|
||||
|
||||
RTCError result = SetParametersInternal(parameters);
|
||||
last_transaction_id_.reset();
|
||||
return result;
|
||||
}
|
||||
|
||||
void TgRtpSenderBase::SetStreams(const std::vector<std::string>& stream_ids) {
|
||||
set_stream_ids(stream_ids);
|
||||
if (set_streams_observer_)
|
||||
set_streams_observer_->OnSetStreams();
|
||||
}
|
||||
|
||||
bool TgRtpSenderBase::SetTrack(MediaStreamTrackInterface* track) {
|
||||
TRACE_EVENT0("webrtc", "TgRtpSenderBase::SetTrack");
|
||||
if (stopped_) {
|
||||
RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
|
||||
return false;
|
||||
}
|
||||
if (track && track->kind() != track_kind()) {
|
||||
RTC_LOG(LS_ERROR) << "SetTrack with " << track->kind()
|
||||
<< " called on RtpSender with " << track_kind()
|
||||
<< " track.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Detach from old track.
|
||||
if (track_) {
|
||||
DetachTrack();
|
||||
track_->UnregisterObserver(this);
|
||||
RemoveTrackFromStats();
|
||||
}
|
||||
|
||||
// Attach to new track.
|
||||
bool prev_can_send_track = can_send_track();
|
||||
// Keep a reference to the old track to keep it alive until we call SetSend.
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> old_track = track_;
|
||||
track_ = track;
|
||||
if (track_) {
|
||||
track_->RegisterObserver(this);
|
||||
AttachTrack();
|
||||
}
|
||||
|
||||
// Update channel.
|
||||
if (can_send_track()) {
|
||||
SetSend();
|
||||
AddTrackToStats();
|
||||
} else if (prev_can_send_track) {
|
||||
ClearSend();
|
||||
}
|
||||
attachment_id_ = (track_ ? GenerateUniqueId() : 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TgRtpSenderBase::SetSsrc(uint32_t ssrc) {
|
||||
TRACE_EVENT0("webrtc", "TgRtpSenderBase::SetSsrc");
|
||||
if (stopped_ || ssrc == ssrc_) {
|
||||
return;
|
||||
}
|
||||
// If we are already sending with a particular SSRC, stop sending.
|
||||
if (can_send_track()) {
|
||||
ClearSend();
|
||||
RemoveTrackFromStats();
|
||||
}
|
||||
ssrc_ = ssrc;
|
||||
if (can_send_track()) {
|
||||
SetSend();
|
||||
AddTrackToStats();
|
||||
}
|
||||
if (!init_parameters_.encodings.empty()) {
|
||||
worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
RTC_DCHECK(media_channel_);
|
||||
// Get the current parameters, which are constructed from the SDP.
|
||||
// The number of layers in the SDP is currently authoritative to support
|
||||
// SDP munging for Plan-B simulcast with "a=ssrc-group:SIM <ssrc-id>..."
|
||||
// lines as described in RFC 5576.
|
||||
// All fields should be default constructed and the SSRC field set, which
|
||||
// we need to copy.
|
||||
RtpParameters current_parameters =
|
||||
media_channel_->GetRtpSendParameters(ssrc_);
|
||||
RTC_DCHECK_GE(current_parameters.encodings.size(),
|
||||
init_parameters_.encodings.size());
|
||||
for (size_t i = 0; i < init_parameters_.encodings.size(); ++i) {
|
||||
init_parameters_.encodings[i].ssrc =
|
||||
current_parameters.encodings[i].ssrc;
|
||||
init_parameters_.encodings[i].rid = current_parameters.encodings[i].rid;
|
||||
current_parameters.encodings[i] = init_parameters_.encodings[i];
|
||||
}
|
||||
current_parameters.degradation_preference =
|
||||
init_parameters_.degradation_preference;
|
||||
media_channel_->SetRtpSendParameters(ssrc_, current_parameters);
|
||||
init_parameters_.encodings.clear();
|
||||
});
|
||||
}
|
||||
// Attempt to attach the frame decryptor to the current media channel.
|
||||
if (frame_encryptor_) {
|
||||
SetFrameEncryptor(frame_encryptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void TgRtpSenderBase::Stop() {
|
||||
TRACE_EVENT0("webrtc", "TgRtpSenderBase::Stop");
|
||||
// TODO(deadbeef): Need to do more here to fully stop sending packets.
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
if (track_) {
|
||||
DetachTrack();
|
||||
track_->UnregisterObserver(this);
|
||||
}
|
||||
if (can_send_track()) {
|
||||
ClearSend();
|
||||
RemoveTrackFromStats();
|
||||
}
|
||||
media_channel_ = nullptr;
|
||||
set_streams_observer_ = nullptr;
|
||||
stopped_ = true;
|
||||
}
|
||||
|
||||
RTCError TgRtpSenderBase::DisableEncodingLayers(
|
||||
const std::vector<std::string>& rids) {
|
||||
if (stopped_) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
|
||||
"Cannot disable encodings on a stopped sender.");
|
||||
}
|
||||
|
||||
if (rids.empty()) {
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
// Check that all the specified layers exist and disable them in the channel.
|
||||
RtpParameters parameters = GetParametersInternal();
|
||||
for (const std::string& rid : rids) {
|
||||
if (absl::c_none_of(parameters.encodings,
|
||||
[&rid](const RtpEncodingParameters& encoding) {
|
||||
return encoding.rid == rid;
|
||||
})) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
|
||||
"RID: " + rid + " does not refer to a valid layer.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!media_channel_ || !ssrc_) {
|
||||
RemoveEncodingLayers(rids, &init_parameters_.encodings);
|
||||
// Invalidate any transaction upon success.
|
||||
last_transaction_id_.reset();
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
for (RtpEncodingParameters& encoding : parameters.encodings) {
|
||||
// Remain active if not in the disable list.
|
||||
encoding.active &= absl::c_none_of(
|
||||
rids,
|
||||
[&encoding](const std::string& rid) { return encoding.rid == rid; });
|
||||
}
|
||||
|
||||
RTCError result = SetParametersInternal(parameters);
|
||||
if (result.ok()) {
|
||||
disabled_rids_.insert(disabled_rids_.end(), rids.begin(), rids.end());
|
||||
// Invalidate any transaction upon success.
|
||||
last_transaction_id_.reset();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
TgLocalAudioSinkAdapter::TgLocalAudioSinkAdapter() : sink_(nullptr) {}
|
||||
|
||||
TgLocalAudioSinkAdapter::~TgLocalAudioSinkAdapter() {
|
||||
@ -393,19 +134,16 @@ void TgLocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
|
||||
rtc::scoped_refptr<TgAudioRtpSender> TgAudioRtpSender::Create(
|
||||
rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
StatsCollector* stats,
|
||||
SetStreamsObserver* set_streams_observer) {
|
||||
return rtc::scoped_refptr<TgAudioRtpSender>(
|
||||
new rtc::RefCountedObject<TgAudioRtpSender>(worker_thread, id, stats,
|
||||
new rtc::RefCountedObject<TgAudioRtpSender>(worker_thread, id,
|
||||
set_streams_observer));
|
||||
}
|
||||
|
||||
TgAudioRtpSender::TgAudioRtpSender(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
StatsCollector* stats,
|
||||
SetStreamsObserver* set_streams_observer)
|
||||
: TgRtpSenderBase(worker_thread, id, set_streams_observer),
|
||||
stats_(stats),
|
||||
: RtpSenderBase(worker_thread, id, set_streams_observer),
|
||||
dtmf_sender_proxy_(DtmfSenderProxy::Create(
|
||||
rtc::Thread::Current(),
|
||||
DtmfSender::Create(rtc::Thread::Current(), this))),
|
||||
@ -477,15 +215,9 @@ void TgAudioRtpSender::AttachTrack() {
|
||||
}
|
||||
|
||||
void TgAudioRtpSender::AddTrackToStats() {
|
||||
if (can_send_track() && stats_) {
|
||||
stats_->AddLocalAudioTrack(audio_track().get(), ssrc_);
|
||||
}
|
||||
}
|
||||
|
||||
void TgAudioRtpSender::RemoveTrackFromStats() {
|
||||
if (can_send_track() && stats_) {
|
||||
stats_->RemoveLocalAudioTrack(audio_track().get(), ssrc_);
|
||||
}
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<DtmfSenderInterface> TgAudioRtpSender::GetDtmfSender() const {
|
||||
@ -550,7 +282,7 @@ rtc::scoped_refptr<TgVideoRtpSender> TgVideoRtpSender::Create(
|
||||
TgVideoRtpSender::TgVideoRtpSender(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
SetStreamsObserver* set_streams_observer)
|
||||
: TgRtpSenderBase(worker_thread, id, set_streams_observer) {}
|
||||
: RtpSenderBase(worker_thread, id, set_streams_observer) {}
|
||||
|
||||
TgVideoRtpSender::~TgVideoRtpSender() {
|
||||
Stop();
|
||||
|
@ -26,178 +26,13 @@
|
||||
#include "pc/dtmf_sender.h"
|
||||
#include "rtc_base/critical_section.h"
|
||||
|
||||
#include "pc/rtp_sender.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class StatsCollector;
|
||||
|
||||
bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters);
|
||||
|
||||
// Internal interface used by PeerConnection.
|
||||
class TgRtpSenderInternal : public RtpSenderInterface {
|
||||
public:
|
||||
// Sets the underlying MediaEngine channel associated with this RtpSender.
|
||||
// A VoiceMediaChannel should be used for audio RtpSenders and
|
||||
// a VideoMediaChannel should be used for video RtpSenders.
|
||||
// Must call SetMediaChannel(nullptr) before the media channel is destroyed.
|
||||
virtual void SetMediaChannel(cricket::MediaChannel* media_channel) = 0;
|
||||
|
||||
// Used to set the SSRC of the sender, once a local description has been set.
|
||||
// If |ssrc| is 0, this indiates that the sender should disconnect from the
|
||||
// underlying transport (this occurs if the sender isn't seen in a local
|
||||
// description).
|
||||
virtual void SetSsrc(uint32_t ssrc) = 0;
|
||||
|
||||
virtual void set_stream_ids(const std::vector<std::string>& stream_ids) = 0;
|
||||
virtual void set_init_send_encodings(
|
||||
const std::vector<RtpEncodingParameters>& init_send_encodings) = 0;
|
||||
virtual void set_transport(
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport) = 0;
|
||||
|
||||
virtual void Stop() = 0;
|
||||
|
||||
// |GetParameters| and |SetParameters| operate with a transactional model.
|
||||
// Allow access to get/set parameters without invalidating transaction id.
|
||||
virtual RtpParameters GetParametersInternal() const = 0;
|
||||
virtual RTCError SetParametersInternal(const RtpParameters& parameters) = 0;
|
||||
|
||||
// Returns an ID that changes every time SetTrack() is called, but
|
||||
// otherwise remains constant. Used to generate IDs for stats.
|
||||
// The special value zero means that no track is attached.
|
||||
virtual int AttachmentId() const = 0;
|
||||
|
||||
// Disables the layers identified by the specified RIDs.
|
||||
// If the specified list is empty, this is a no-op.
|
||||
virtual RTCError DisableEncodingLayers(
|
||||
const std::vector<std::string>& rid) = 0;
|
||||
};
|
||||
|
||||
// Shared implementation for RtpSenderInternal interface.
|
||||
class TgRtpSenderBase : public TgRtpSenderInternal, public ObserverInterface {
|
||||
public:
|
||||
class SetStreamsObserver {
|
||||
public:
|
||||
virtual ~SetStreamsObserver() = default;
|
||||
virtual void OnSetStreams() = 0;
|
||||
};
|
||||
|
||||
// Sets the underlying MediaEngine channel associated with this RtpSender.
|
||||
// A VoiceMediaChannel should be used for audio RtpSenders and
|
||||
// a VideoMediaChannel should be used for video RtpSenders.
|
||||
// Must call SetMediaChannel(nullptr) before the media channel is destroyed.
|
||||
void SetMediaChannel(cricket::MediaChannel* media_channel) override;
|
||||
|
||||
bool SetTrack(MediaStreamTrackInterface* track) override;
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track() const override {
|
||||
return track_;
|
||||
}
|
||||
|
||||
RtpParameters GetParameters() const override;
|
||||
RTCError SetParameters(const RtpParameters& parameters) override;
|
||||
|
||||
// |GetParameters| and |SetParameters| operate with a transactional model.
|
||||
// Allow access to get/set parameters without invalidating transaction id.
|
||||
RtpParameters GetParametersInternal() const override;
|
||||
RTCError SetParametersInternal(const RtpParameters& parameters) override;
|
||||
|
||||
// Used to set the SSRC of the sender, once a local description has been set.
|
||||
// If |ssrc| is 0, this indiates that the sender should disconnect from the
|
||||
// underlying transport (this occurs if the sender isn't seen in a local
|
||||
// description).
|
||||
void SetSsrc(uint32_t ssrc) override;
|
||||
uint32_t ssrc() const override { return ssrc_; }
|
||||
|
||||
std::vector<std::string> stream_ids() const override { return stream_ids_; }
|
||||
void set_stream_ids(const std::vector<std::string>& stream_ids) override {
|
||||
stream_ids_ = stream_ids;
|
||||
}
|
||||
void SetStreams(const std::vector<std::string>& stream_ids) override;
|
||||
|
||||
std::string id() const override { return id_; }
|
||||
|
||||
void set_init_send_encodings(
|
||||
const std::vector<RtpEncodingParameters>& init_send_encodings) override {
|
||||
init_parameters_.encodings = init_send_encodings;
|
||||
}
|
||||
std::vector<RtpEncodingParameters> init_send_encodings() const override {
|
||||
return init_parameters_.encodings;
|
||||
}
|
||||
|
||||
void set_transport(
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport) override {
|
||||
dtls_transport_ = dtls_transport;
|
||||
}
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const override {
|
||||
return dtls_transport_;
|
||||
}
|
||||
|
||||
void SetFrameEncryptor(
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) override;
|
||||
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> GetFrameEncryptor()
|
||||
const override {
|
||||
return frame_encryptor_;
|
||||
}
|
||||
|
||||
void Stop() override;
|
||||
|
||||
// Returns an ID that changes every time SetTrack() is called, but
|
||||
// otherwise remains constant. Used to generate IDs for stats.
|
||||
// The special value zero means that no track is attached.
|
||||
int AttachmentId() const override { return attachment_id_; }
|
||||
|
||||
// Disables the layers identified by the specified RIDs.
|
||||
// If the specified list is empty, this is a no-op.
|
||||
RTCError DisableEncodingLayers(const std::vector<std::string>& rid) override;
|
||||
|
||||
protected:
|
||||
// If |set_streams_observer| is not null, it is invoked when SetStreams()
|
||||
// is called. |set_streams_observer| is not owned by this object. If not
|
||||
// null, it must be valid at least until this sender becomes stopped.
|
||||
TgRtpSenderBase(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
SetStreamsObserver* set_streams_observer);
|
||||
// TODO(nisse): Since SSRC == 0 is technically valid, figure out
|
||||
// some other way to test if we have a valid SSRC.
|
||||
bool can_send_track() const { return track_ && ssrc_; }
|
||||
|
||||
virtual std::string track_kind() const = 0;
|
||||
|
||||
// Enable sending on the media channel.
|
||||
virtual void SetSend() = 0;
|
||||
// Disable sending on the media channel.
|
||||
virtual void ClearSend() = 0;
|
||||
|
||||
// Template method pattern to allow subclasses to add custom behavior for
|
||||
// when tracks are attached, detached, and for adding tracks to statistics.
|
||||
virtual void AttachTrack() {}
|
||||
virtual void DetachTrack() {}
|
||||
virtual void AddTrackToStats() {}
|
||||
virtual void RemoveTrackFromStats() {}
|
||||
|
||||
rtc::Thread* worker_thread_;
|
||||
uint32_t ssrc_ = 0;
|
||||
bool stopped_ = false;
|
||||
int attachment_id_ = 0;
|
||||
const std::string id_;
|
||||
|
||||
std::vector<std::string> stream_ids_;
|
||||
RtpParameters init_parameters_;
|
||||
|
||||
cricket::MediaChannel* media_channel_ = nullptr;
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track_;
|
||||
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport_;
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor_;
|
||||
// |last_transaction_id_| is used to verify that |SetParameters| is receiving
|
||||
// the parameters object that was last returned from |GetParameters|.
|
||||
// As such, it is used for internal verification and is not observable by the
|
||||
// the client. It is marked as mutable to enable |GetParameters| to be a
|
||||
// const method.
|
||||
mutable absl::optional<std::string> last_transaction_id_;
|
||||
std::vector<std::string> disabled_rids_;
|
||||
|
||||
SetStreamsObserver* set_streams_observer_ = nullptr;
|
||||
};
|
||||
bool TgUnimplementedRtpParameterHasValue(const RtpParameters& parameters);
|
||||
|
||||
// TgLocalAudioSinkAdapter receives data callback as a sink to the local
|
||||
// AudioTrack, and passes the data to the sink of AudioSource.
|
||||
@ -223,7 +58,7 @@ class TgLocalAudioSinkAdapter : public AudioTrackSinkInterface,
|
||||
rtc::CriticalSection lock_;
|
||||
};
|
||||
|
||||
class TgAudioRtpSender : public DtmfProviderInterface, public TgRtpSenderBase {
|
||||
class TgAudioRtpSender : public DtmfProviderInterface, public RtpSenderBase {
|
||||
public:
|
||||
// Construct an RtpSender for audio with the given sender ID.
|
||||
// The sender is initialized with no track to send and no associated streams.
|
||||
@ -235,7 +70,6 @@ class TgAudioRtpSender : public DtmfProviderInterface, public TgRtpSenderBase {
|
||||
static rtc::scoped_refptr<TgAudioRtpSender> Create(
|
||||
rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
StatsCollector* stats,
|
||||
SetStreamsObserver* set_streams_observer);
|
||||
virtual ~TgAudioRtpSender();
|
||||
|
||||
@ -259,7 +93,6 @@ class TgAudioRtpSender : public DtmfProviderInterface, public TgRtpSenderBase {
|
||||
protected:
|
||||
TgAudioRtpSender(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
StatsCollector* stats,
|
||||
SetStreamsObserver* set_streams_observer);
|
||||
|
||||
void SetSend() override;
|
||||
@ -281,7 +114,6 @@ class TgAudioRtpSender : public DtmfProviderInterface, public TgRtpSenderBase {
|
||||
}
|
||||
sigslot::signal0<> SignalDestroyed;
|
||||
|
||||
StatsCollector* stats_ = nullptr;
|
||||
rtc::scoped_refptr<DtmfSenderInterface> dtmf_sender_proxy_;
|
||||
bool cached_track_enabled_ = false;
|
||||
|
||||
@ -290,7 +122,7 @@ class TgAudioRtpSender : public DtmfProviderInterface, public TgRtpSenderBase {
|
||||
std::unique_ptr<TgLocalAudioSinkAdapter> sink_adapter_;
|
||||
};
|
||||
|
||||
class TgVideoRtpSender : public TgRtpSenderBase {
|
||||
class TgVideoRtpSender : public RtpSenderBase {
|
||||
public:
|
||||
// Construct an RtpSender for video with the given sender ID.
|
||||
// The sender is initialized with no track to send and no associated streams.
|
||||
|
Loading…
x
Reference in New Issue
Block a user