This commit is contained in:
Ali 2020-06-02 19:49:54 +04:00
parent 5f9565853d
commit a422fac01f
11 changed files with 1749 additions and 753 deletions

View File

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

View 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

View 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_

View File

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

View File

@ -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())) {

View File

@ -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

View File

@ -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>

View File

@ -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_

View File

@ -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.";

View File

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

View File

@ -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.