Add SCTP transport to the public API.
This involves inserting an extra layer between jsep_transport_controller and the cricket::SctpTransportInternal layer. The objects at this layer are reference counted. Bug: chromium:818643 Change-Id: Ibed57c4a538de981cee63e0f7f1f319f029cab39 Reviewed-on: https://webrtc-review.googlesource.com/c/123884 Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Henrik Boström <hbos@webrtc.org> Reviewed-by: Steve Anton <steveanton@webrtc.org> Commit-Queue: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26889}
This commit is contained in:
parent
60fd73a9fc
commit
c85328f2ca
@ -113,6 +113,8 @@ rtc_static_library("libjingle_peerconnection_api") {
|
||||
"rtp_sender_interface.h",
|
||||
"rtp_transceiver_interface.cc",
|
||||
"rtp_transceiver_interface.h",
|
||||
"sctp_transport_interface.cc",
|
||||
"sctp_transport_interface.h",
|
||||
"set_remote_description_observer_interface.h",
|
||||
"stats_types.cc",
|
||||
"stats_types.h",
|
||||
|
||||
4
api/DEPS
4
api/DEPS
@ -166,6 +166,10 @@ specific_include_rules = {
|
||||
"+rtc_base/ref_count.h",
|
||||
],
|
||||
|
||||
"sctp_transport_interface\.h": [
|
||||
"+rtc_base/ref_count.h",
|
||||
],
|
||||
|
||||
"set_remote_description_observer_interface\.h": [
|
||||
"+rtc_base/ref_count.h",
|
||||
],
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
#include "api/peer_connection_interface.h"
|
||||
#include "api/dtls_transport_interface.h"
|
||||
#include "api/sctp_transport_interface.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -187,6 +188,12 @@ PeerConnectionInterface::LookupDtlsTransportByMid(const std::string& mid) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<SctpTransportInterface>
|
||||
PeerConnectionInterface::GetSctpTransport() const {
|
||||
RTC_NOTREACHED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PeerConnectionInterface::BitrateParameters::BitrateParameters() = default;
|
||||
|
||||
PeerConnectionInterface::BitrateParameters::~BitrateParameters() = default;
|
||||
|
||||
@ -122,6 +122,7 @@ class AudioDeviceModule;
|
||||
class AudioMixer;
|
||||
class AudioProcessing;
|
||||
class DtlsTransportInterface;
|
||||
class SctpTransportInterface;
|
||||
class VideoDecoderFactory;
|
||||
class VideoEncoderFactory;
|
||||
|
||||
@ -1038,6 +1039,10 @@ class PeerConnectionInterface : public rtc::RefCountInterface {
|
||||
virtual rtc::scoped_refptr<DtlsTransportInterface> LookupDtlsTransportByMid(
|
||||
const std::string& mid);
|
||||
|
||||
// Returns the SCTP transport, if any.
|
||||
// TODO(hta): Remove default implementation after updating Chrome.
|
||||
virtual rtc::scoped_refptr<SctpTransportInterface> GetSctpTransport() const;
|
||||
|
||||
// Returns the current SignalingState.
|
||||
virtual SignalingState signaling_state() = 0;
|
||||
|
||||
|
||||
32
api/sctp_transport_interface.cc
Normal file
32
api/sctp_transport_interface.cc
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "api/sctp_transport_interface.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
SctpTransportInformation::SctpTransportInformation(SctpTransportState state)
|
||||
: state_(state) {}
|
||||
|
||||
SctpTransportInformation::SctpTransportInformation(
|
||||
SctpTransportState state,
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport,
|
||||
absl::optional<double> max_message_size,
|
||||
absl::optional<int> max_channels)
|
||||
: state_(state),
|
||||
dtls_transport_(std::move(dtls_transport)),
|
||||
max_message_size_(max_message_size),
|
||||
max_channels_(max_channels) {}
|
||||
|
||||
SctpTransportInformation::~SctpTransportInformation() {}
|
||||
|
||||
} // namespace webrtc
|
||||
90
api/sctp_transport_interface.h
Normal file
90
api/sctp_transport_interface.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef API_SCTP_TRANSPORT_INTERFACE_H_
|
||||
#define API_SCTP_TRANSPORT_INTERFACE_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/dtls_transport_interface.h"
|
||||
#include "api/rtc_error.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "rtc_base/ref_count.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// States of a SCTP transport, corresponding to the JS API specification.
|
||||
// http://w3c.github.io/webrtc-pc/#dom-rtcsctptransportstate
|
||||
enum class SctpTransportState {
|
||||
kNew, // Has not started negotiating yet. Non-standard state.
|
||||
kConnecting, // In the process of negotiating an association.
|
||||
kConnected, // Completed negotiation of an association.
|
||||
kClosed, // Closed by local or remote party.
|
||||
kNumValues
|
||||
};
|
||||
|
||||
// This object gives snapshot information about the changeable state of a
|
||||
// SctpTransport.
|
||||
// It reflects the readonly attributes of the object in the specification.
|
||||
// http://w3c.github.io/webrtc-pc/#rtcsctptransport-interface
|
||||
class SctpTransportInformation {
|
||||
public:
|
||||
explicit SctpTransportInformation(SctpTransportState state);
|
||||
SctpTransportInformation(
|
||||
SctpTransportState state,
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport,
|
||||
absl::optional<double> max_message_size,
|
||||
absl::optional<int> max_channels);
|
||||
~SctpTransportInformation();
|
||||
// The DTLS transport that supports this SCTP transport.
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const {
|
||||
return dtls_transport_;
|
||||
}
|
||||
SctpTransportState state() const { return state_; }
|
||||
absl::optional<double> MaxMessageSize() const { return max_message_size_; }
|
||||
absl::optional<int> MaxChannels() const { return max_channels_; }
|
||||
|
||||
private:
|
||||
SctpTransportState state_;
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport_;
|
||||
absl::optional<double> max_message_size_;
|
||||
absl::optional<int> max_channels_;
|
||||
};
|
||||
|
||||
class SctpTransportObserverInterface {
|
||||
public:
|
||||
// This callback carries information about the state of the transport.
|
||||
// The argument is a pass-by-value snapshot of the state.
|
||||
// The callback will be called on the network thread.
|
||||
virtual void OnStateChange(SctpTransportInformation info) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~SctpTransportObserverInterface() = default;
|
||||
};
|
||||
|
||||
// A SCTP transport, as represented to the outside world.
|
||||
// This object is created on the network thread, and can only be
|
||||
// accessed on that thread, except for functions explicitly marked otherwise.
|
||||
// References can be held by other threads, and destruction can therefore
|
||||
// be initiated by other threads.
|
||||
class SctpTransportInterface : public rtc::RefCountInterface {
|
||||
public:
|
||||
// This function can be called from other threads.
|
||||
virtual rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const = 0;
|
||||
// Returns information on the state of the SctpTransport.
|
||||
// This function can be called from other threads.
|
||||
virtual SctpTransportInformation Information() const = 0;
|
||||
// Observer management.
|
||||
virtual void RegisterObserver(SctpTransportObserverInterface* observer) = 0;
|
||||
virtual void UnregisterObserver() = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_SCTP_TRANSPORT_INTERFACE_H_
|
||||
@ -383,9 +383,8 @@ SctpTransport::SctpTransport(rtc::Thread* network_thread,
|
||||
rtc::PacketTransportInternal* transport)
|
||||
: network_thread_(network_thread),
|
||||
transport_(transport),
|
||||
was_ever_writable_(transport->writable()) {
|
||||
was_ever_writable_(transport ? transport->writable() : false) {
|
||||
RTC_DCHECK(network_thread_);
|
||||
RTC_DCHECK(transport_);
|
||||
RTC_DCHECK_RUN_ON(network_thread_);
|
||||
ConnectTransportSignals();
|
||||
}
|
||||
|
||||
@ -36,10 +36,10 @@ struct sctp_stream_reset_event;
|
||||
struct socket;
|
||||
namespace cricket {
|
||||
|
||||
// Holds data to be passed on to a channel.
|
||||
// Holds data to be passed on to a transport.
|
||||
struct SctpInboundPacket;
|
||||
|
||||
// From channel calls, data flows like this:
|
||||
// From transport calls, data flows like this:
|
||||
// [network thread (although it can in princple be another thread)]
|
||||
// 1. SctpTransport::SendData(data)
|
||||
// 2. usrsctp_sendv(data)
|
||||
@ -59,16 +59,15 @@ struct SctpInboundPacket;
|
||||
// 12. SctpTransport::SignalDataReceived(data)
|
||||
// [from the same thread, methods registered/connected to
|
||||
// SctpTransport are called with the recieved data]
|
||||
// TODO(zhihuang): Rename "channel" to "transport" on network-level.
|
||||
class SctpTransport : public SctpTransportInternal,
|
||||
public sigslot::has_slots<> {
|
||||
public:
|
||||
// |network_thread| is where packets will be processed and callbacks from
|
||||
// this transport will be posted, and is the only thread on which public
|
||||
// methods can be called.
|
||||
// |channel| is required (must not be null).
|
||||
// |transport| is not required (can be null).
|
||||
SctpTransport(rtc::Thread* network_thread,
|
||||
rtc::PacketTransportInternal* channel);
|
||||
rtc::PacketTransportInternal* transport);
|
||||
~SctpTransport() override;
|
||||
|
||||
// SctpTransportInternal overrides (see sctptransportinternal.h for comments).
|
||||
@ -108,7 +107,7 @@ class SctpTransport : public SctpTransportInternal,
|
||||
// Sets the "ready to send" flag and fires signal if needed.
|
||||
void SetReadyToSendData();
|
||||
|
||||
// Callbacks from DTLS channel.
|
||||
// Callbacks from DTLS transport.
|
||||
void OnWritableState(rtc::PacketTransportInternal* transport);
|
||||
virtual void OnPacketRead(rtc::PacketTransportInternal* transport,
|
||||
const char* data,
|
||||
@ -135,12 +134,12 @@ class SctpTransport : public SctpTransportInternal,
|
||||
|
||||
void OnStreamResetEvent(const struct sctp_stream_reset_event* evt);
|
||||
|
||||
// Responsible for marshalling incoming data to the channels listeners, and
|
||||
// Responsible for marshalling incoming data to the transports listeners, and
|
||||
// outgoing data to the network interface.
|
||||
rtc::Thread* network_thread_;
|
||||
// Helps pass inbound/outbound packets asynchronously to the network thread.
|
||||
rtc::AsyncInvoker invoker_;
|
||||
// Underlying DTLS channel.
|
||||
// Underlying DTLS transport.
|
||||
rtc::PacketTransportInternal* transport_ = nullptr;
|
||||
|
||||
// Track the data received from usrsctp between callbacks until the EOR bit
|
||||
|
||||
@ -55,6 +55,8 @@ rtc_static_library("rtc_pc_base") {
|
||||
"rtp_transport.cc",
|
||||
"rtp_transport.h",
|
||||
"rtp_transport_internal.h",
|
||||
"sctp_transport.cc",
|
||||
"sctp_transport.h",
|
||||
"session_description.cc",
|
||||
"session_description.h",
|
||||
"simulcast_description.cc",
|
||||
@ -258,6 +260,7 @@ if (rtc_include_tests) {
|
||||
"media_session_unittest.cc",
|
||||
"rtcp_mux_filter_unittest.cc",
|
||||
"rtp_transport_unittest.cc",
|
||||
"sctp_transport_unittest.cc",
|
||||
"session_description_unittest.cc",
|
||||
"srtp_filter_unittest.cc",
|
||||
"srtp_session_unittest.cc",
|
||||
|
||||
@ -818,8 +818,8 @@ bool JsepTransportController::SetTransportForMid(
|
||||
|
||||
mid_to_transport_[mid] = jsep_transport;
|
||||
return config_.transport_observer->OnTransportChanged(
|
||||
mid, jsep_transport->rtp_transport(),
|
||||
jsep_transport->rtp_dtls_transport(), jsep_transport->media_transport());
|
||||
mid, jsep_transport->rtp_transport(), jsep_transport->RtpDtlsTransport(),
|
||||
jsep_transport->media_transport());
|
||||
}
|
||||
|
||||
void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
|
||||
|
||||
@ -58,7 +58,7 @@ class JsepTransportController : public sigslot::has_slots<> {
|
||||
virtual bool OnTransportChanged(
|
||||
const std::string& mid,
|
||||
RtpTransportInternal* rtp_transport,
|
||||
cricket::DtlsTransportInternal* dtls_transport,
|
||||
rtc::scoped_refptr<DtlsTransport> dtls_transport,
|
||||
MediaTransportInterface* media_transport) = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -305,10 +305,14 @@ class JsepTransportControllerTest : public JsepTransportController::Observer,
|
||||
// JsepTransportController::Observer overrides.
|
||||
bool OnTransportChanged(const std::string& mid,
|
||||
RtpTransportInternal* rtp_transport,
|
||||
cricket::DtlsTransportInternal* dtls_transport,
|
||||
rtc::scoped_refptr<DtlsTransport> dtls_transport,
|
||||
MediaTransportInterface* media_transport) override {
|
||||
changed_rtp_transport_by_mid_[mid] = rtp_transport;
|
||||
changed_dtls_transport_by_mid_[mid] = dtls_transport;
|
||||
if (dtls_transport) {
|
||||
changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
|
||||
} else {
|
||||
changed_dtls_transport_by_mid_[mid] = nullptr;
|
||||
}
|
||||
changed_media_transport_by_mid_[mid] = media_transport;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
#include "pc/rtp_media_utils.h"
|
||||
#include "pc/rtp_receiver.h"
|
||||
#include "pc/rtp_sender.h"
|
||||
#include "pc/sctp_transport.h"
|
||||
#include "pc/sctp_utils.h"
|
||||
#include "pc/sdp_utils.h"
|
||||
#include "pc/stream_collection.h"
|
||||
@ -3658,6 +3659,11 @@ PeerConnection::LookupDtlsTransportByMidInternal(const std::string& mid) {
|
||||
return transport_controller_->LookupDtlsTransportByMid(mid);
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<SctpTransportInterface> PeerConnection::GetSctpTransport()
|
||||
const {
|
||||
return sctp_transport_;
|
||||
}
|
||||
|
||||
const SessionDescriptionInterface* PeerConnection::local_description() const {
|
||||
return pending_local_description_ ? pending_local_description_.get()
|
||||
: current_local_description_.get();
|
||||
@ -5497,7 +5503,7 @@ bool PeerConnection::PushdownSctpParameters_n(cricket::ContentSource source) {
|
||||
RTC_DCHECK(remote_description());
|
||||
// Apply the SCTP port (which is hidden inside a DataCodec structure...)
|
||||
// When we support "max-message-size", that would also be pushed down here.
|
||||
return sctp_transport_->Start(
|
||||
return cricket_sctp_transport()->Start(
|
||||
GetSctpPort(local_description()->description()),
|
||||
GetSctpPort(remote_description()->description()));
|
||||
}
|
||||
@ -5631,7 +5637,7 @@ bool PeerConnection::SendData(const cricket::SendDataParams& params,
|
||||
: network_thread()->Invoke<bool>(
|
||||
RTC_FROM_HERE,
|
||||
Bind(&cricket::SctpTransportInternal::SendData,
|
||||
sctp_transport_.get(), params, payload, result));
|
||||
cricket_sctp_transport(), params, payload, result));
|
||||
}
|
||||
|
||||
bool PeerConnection::ConnectDataChannel(DataChannel* webrtc_data_channel) {
|
||||
@ -5705,7 +5711,7 @@ void PeerConnection::AddSctpDataStream(int sid) {
|
||||
}
|
||||
network_thread()->Invoke<void>(
|
||||
RTC_FROM_HERE, rtc::Bind(&cricket::SctpTransportInternal::OpenStream,
|
||||
sctp_transport_.get(), sid));
|
||||
cricket_sctp_transport(), sid));
|
||||
}
|
||||
|
||||
void PeerConnection::RemoveSctpDataStream(int sid) {
|
||||
@ -5720,7 +5726,7 @@ void PeerConnection::RemoveSctpDataStream(int sid) {
|
||||
}
|
||||
network_thread()->Invoke<void>(
|
||||
RTC_FROM_HERE, rtc::Bind(&cricket::SctpTransportInternal::ResetStream,
|
||||
sctp_transport_.get(), sid));
|
||||
cricket_sctp_transport(), sid));
|
||||
}
|
||||
|
||||
bool PeerConnection::ReadyToSendData() const {
|
||||
@ -6243,32 +6249,38 @@ Call::Stats PeerConnection::GetCallStats() {
|
||||
bool PeerConnection::CreateSctpTransport_n(const std::string& mid) {
|
||||
RTC_DCHECK(network_thread()->IsCurrent());
|
||||
RTC_DCHECK(sctp_factory_);
|
||||
rtc::scoped_refptr<DtlsTransport> webrtc_dtls_transport =
|
||||
transport_controller_->LookupDtlsTransportByMid(mid);
|
||||
cricket::DtlsTransportInternal* dtls_transport =
|
||||
transport_controller_->GetDtlsTransport(mid);
|
||||
webrtc_dtls_transport->internal();
|
||||
RTC_DCHECK(dtls_transport);
|
||||
sctp_transport_ = sctp_factory_->CreateSctpTransport(dtls_transport);
|
||||
RTC_DCHECK(sctp_transport_);
|
||||
std::unique_ptr<cricket::SctpTransportInternal> cricket_sctp_transport =
|
||||
sctp_factory_->CreateSctpTransport(dtls_transport);
|
||||
RTC_DCHECK(cricket_sctp_transport);
|
||||
sctp_invoker_.reset(new rtc::AsyncInvoker());
|
||||
sctp_transport_->SignalReadyToSendData.connect(
|
||||
cricket_sctp_transport->SignalReadyToSendData.connect(
|
||||
this, &PeerConnection::OnSctpTransportReadyToSendData_n);
|
||||
sctp_transport_->SignalDataReceived.connect(
|
||||
cricket_sctp_transport->SignalDataReceived.connect(
|
||||
this, &PeerConnection::OnSctpTransportDataReceived_n);
|
||||
// TODO(deadbeef): All we do here is AsyncInvoke to fire the signal on
|
||||
// another thread. Would be nice if there was a helper class similar to
|
||||
// sigslot::repeater that did this for us, eliminating a bunch of boilerplate
|
||||
// code.
|
||||
sctp_transport_->SignalClosingProcedureStartedRemotely.connect(
|
||||
cricket_sctp_transport->SignalClosingProcedureStartedRemotely.connect(
|
||||
this, &PeerConnection::OnSctpClosingProcedureStartedRemotely_n);
|
||||
sctp_transport_->SignalClosingProcedureComplete.connect(
|
||||
cricket_sctp_transport->SignalClosingProcedureComplete.connect(
|
||||
this, &PeerConnection::OnSctpClosingProcedureComplete_n);
|
||||
sctp_mid_ = mid;
|
||||
sctp_transport_->SetDtlsTransport(dtls_transport);
|
||||
sctp_transport_ = new rtc::RefCountedObject<SctpTransport>(
|
||||
std::move(cricket_sctp_transport));
|
||||
sctp_transport_->SetDtlsTransport(std::move(webrtc_dtls_transport));
|
||||
return true;
|
||||
}
|
||||
|
||||
void PeerConnection::DestroySctpTransport_n() {
|
||||
RTC_DCHECK(network_thread()->IsCurrent());
|
||||
sctp_transport_.reset(nullptr);
|
||||
sctp_transport_->Clear();
|
||||
sctp_transport_ = nullptr;
|
||||
sctp_mid_.reset();
|
||||
sctp_invoker_.reset(nullptr);
|
||||
sctp_ready_to_send_data_ = false;
|
||||
@ -6949,7 +6961,7 @@ void PeerConnection::DestroyChannelInterface(
|
||||
bool PeerConnection::OnTransportChanged(
|
||||
const std::string& mid,
|
||||
RtpTransportInternal* rtp_transport,
|
||||
cricket::DtlsTransportInternal* dtls_transport,
|
||||
rtc::scoped_refptr<DtlsTransport> dtls_transport,
|
||||
MediaTransportInterface* media_transport) {
|
||||
RTC_DCHECK_RUNS_SERIALIZED(&use_media_transport_race_checker_);
|
||||
bool ret = true;
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include "pc/peer_connection_internal.h"
|
||||
#include "pc/rtc_stats_collector.h"
|
||||
#include "pc/rtp_transceiver.h"
|
||||
#include "pc/sctp_transport.h"
|
||||
#include "pc/stats_collector.h"
|
||||
#include "pc/stream_collection.h"
|
||||
#include "pc/webrtc_session_description_factory.h"
|
||||
@ -201,6 +202,8 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
rtc::scoped_refptr<DtlsTransport> LookupDtlsTransportByMidInternal(
|
||||
const std::string& mid);
|
||||
|
||||
rtc::scoped_refptr<SctpTransportInterface> GetSctpTransport() const override;
|
||||
|
||||
RTC_DEPRECATED bool StartRtcEventLog(rtc::PlatformFile file,
|
||||
int64_t max_size_bytes) override;
|
||||
bool StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output,
|
||||
@ -1015,7 +1018,7 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
// rejected).
|
||||
bool OnTransportChanged(const std::string& mid,
|
||||
RtpTransportInternal* rtp_transport,
|
||||
cricket::DtlsTransportInternal* dtls_transport,
|
||||
rtc::scoped_refptr<DtlsTransport> dtls_transport,
|
||||
MediaTransportInterface* media_transport) override;
|
||||
|
||||
// Returns the observer. Will crash on CHECK if the observer is removed.
|
||||
@ -1149,7 +1152,10 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
// when using SCTP.
|
||||
cricket::RtpDataChannel* rtp_data_channel_ = nullptr;
|
||||
|
||||
std::unique_ptr<cricket::SctpTransportInternal> sctp_transport_;
|
||||
cricket::SctpTransportInternal* cricket_sctp_transport() {
|
||||
return sctp_transport_->internal();
|
||||
}
|
||||
rtc::scoped_refptr<SctpTransport> sctp_transport_;
|
||||
// |sctp_mid_| is the content name (MID) in SDP.
|
||||
absl::optional<std::string> sctp_mid_;
|
||||
// Value cached on signaling thread. Only updated when SctpReadyToSendData
|
||||
|
||||
119
pc/sctp_transport.cc
Normal file
119
pc/sctp_transport.cc
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "pc/sctp_transport.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
SctpTransport::SctpTransport(
|
||||
std::unique_ptr<cricket::SctpTransportInternal> internal)
|
||||
: owner_thread_(rtc::Thread::Current()),
|
||||
info_(SctpTransportState::kNew),
|
||||
internal_sctp_transport_(std::move(internal)) {
|
||||
RTC_DCHECK(internal_sctp_transport_.get());
|
||||
internal_sctp_transport_->SignalReadyToSendData.connect(
|
||||
this, &SctpTransport::OnInternalReadyToSendData);
|
||||
// TODO(https://bugs.webrtc.org/10360): Add handlers for transport closing.
|
||||
|
||||
if (dtls_transport_) {
|
||||
UpdateInformation(SctpTransportState::kConnecting);
|
||||
} else {
|
||||
UpdateInformation(SctpTransportState::kNew);
|
||||
}
|
||||
}
|
||||
|
||||
SctpTransport::~SctpTransport() {
|
||||
// We depend on the network thread to call Clear() before dropping
|
||||
// its last reference to this object.
|
||||
RTC_DCHECK(owner_thread_->IsCurrent() || !internal_sctp_transport_);
|
||||
}
|
||||
|
||||
SctpTransportInformation SctpTransport::Information() const {
|
||||
rtc::CritScope scope(&lock_);
|
||||
return info_;
|
||||
}
|
||||
|
||||
void SctpTransport::RegisterObserver(SctpTransportObserverInterface* observer) {
|
||||
RTC_DCHECK_RUN_ON(owner_thread_);
|
||||
RTC_DCHECK(observer);
|
||||
RTC_DCHECK(!observer_);
|
||||
observer_ = observer;
|
||||
}
|
||||
|
||||
void SctpTransport::UnregisterObserver() {
|
||||
RTC_DCHECK_RUN_ON(owner_thread_);
|
||||
observer_ = nullptr;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<DtlsTransportInterface> SctpTransport::dtls_transport()
|
||||
const {
|
||||
RTC_DCHECK_RUN_ON(owner_thread_);
|
||||
return dtls_transport_;
|
||||
}
|
||||
|
||||
// Internal functions
|
||||
void SctpTransport::Clear() {
|
||||
RTC_DCHECK_RUN_ON(owner_thread_);
|
||||
RTC_DCHECK(internal());
|
||||
{
|
||||
rtc::CritScope scope(&lock_);
|
||||
// Note that we delete internal_sctp_transport_, but
|
||||
// only drop the reference to dtls_transport_.
|
||||
dtls_transport_ = nullptr;
|
||||
internal_sctp_transport_ = nullptr;
|
||||
}
|
||||
UpdateInformation(SctpTransportState::kClosed);
|
||||
}
|
||||
|
||||
void SctpTransport::SetDtlsTransport(
|
||||
rtc::scoped_refptr<DtlsTransport> transport) {
|
||||
RTC_DCHECK_RUN_ON(owner_thread_);
|
||||
rtc::CritScope scope(&lock_);
|
||||
dtls_transport_ = transport;
|
||||
if (internal_sctp_transport_) {
|
||||
if (transport) {
|
||||
internal_sctp_transport_->SetDtlsTransport(transport->internal());
|
||||
if (info_.state() == SctpTransportState::kNew) {
|
||||
UpdateInformation(SctpTransportState::kConnecting);
|
||||
}
|
||||
} else {
|
||||
internal_sctp_transport_->SetDtlsTransport(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SctpTransport::UpdateInformation(SctpTransportState state) {
|
||||
RTC_DCHECK_RUN_ON(owner_thread_);
|
||||
bool must_send_update;
|
||||
SctpTransportInformation info_copy(SctpTransportState::kNew);
|
||||
{
|
||||
rtc::CritScope scope(&lock_);
|
||||
must_send_update = (state != info_.state());
|
||||
// TODO(https://bugs.webrtc.org/10358): Update max message size and
|
||||
// max channels from internal SCTP transport when available.
|
||||
info_ = SctpTransportInformation(
|
||||
state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
|
||||
if (observer_ && must_send_update) {
|
||||
info_copy = info_;
|
||||
}
|
||||
}
|
||||
// We call the observer without holding the lock.
|
||||
if (observer_ && must_send_update) {
|
||||
observer_->OnStateChange(info_copy);
|
||||
}
|
||||
}
|
||||
|
||||
void SctpTransport::OnInternalReadyToSendData() {
|
||||
UpdateInformation(SctpTransportState::kConnected);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
75
pc/sctp_transport.h
Normal file
75
pc/sctp_transport.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef PC_SCTP_TRANSPORT_H_
|
||||
#define PC_SCTP_TRANSPORT_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "api/sctp_transport_interface.h"
|
||||
#include "media/sctp/sctp_transport.h"
|
||||
#include "pc/dtls_transport.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// This implementation wraps a cricket::SctpTransport, and takes
|
||||
// ownership of it.
|
||||
// This object must be constructed and updated on the networking thread,
|
||||
// the same thread as the one the cricket::SctpTransportInternal object
|
||||
// lives on.
|
||||
class SctpTransport : public SctpTransportInterface,
|
||||
public sigslot::has_slots<> {
|
||||
public:
|
||||
explicit SctpTransport(
|
||||
std::unique_ptr<cricket::SctpTransportInternal> internal);
|
||||
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const override;
|
||||
SctpTransportInformation Information() const override;
|
||||
void RegisterObserver(SctpTransportObserverInterface* observer) override;
|
||||
void UnregisterObserver() override;
|
||||
|
||||
void Clear();
|
||||
void SetDtlsTransport(rtc::scoped_refptr<DtlsTransport>);
|
||||
|
||||
cricket::SctpTransportInternal* internal() {
|
||||
rtc::CritScope scope(&lock_);
|
||||
return internal_sctp_transport_.get();
|
||||
}
|
||||
|
||||
const cricket::SctpTransportInternal* internal() const {
|
||||
rtc::CritScope scope(&lock_);
|
||||
return internal_sctp_transport_.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
~SctpTransport() override;
|
||||
|
||||
private:
|
||||
void UpdateInformation(SctpTransportState state);
|
||||
void OnInternalReadyToSendData();
|
||||
void OnInternalClosingProcedureStartedRemotely(int sid);
|
||||
void OnInternalClosingProcedureComplete(int sid);
|
||||
|
||||
const rtc::Thread* owner_thread_;
|
||||
rtc::CriticalSection lock_;
|
||||
// Variables accessible off-thread, guarded by lock_
|
||||
SctpTransportInformation info_ RTC_GUARDED_BY(lock_);
|
||||
std::unique_ptr<cricket::SctpTransportInternal> internal_sctp_transport_
|
||||
RTC_GUARDED_BY(lock_);
|
||||
// Variables only accessed on-thread
|
||||
SctpTransportObserverInterface* observer_ RTC_GUARDED_BY(owner_thread_) =
|
||||
nullptr;
|
||||
rtc::scoped_refptr<DtlsTransport> dtls_transport_
|
||||
RTC_GUARDED_BY(owner_thread_);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // PC_SCTP_TRANSPORT_H_
|
||||
149
pc/sctp_transport_unittest.cc
Normal file
149
pc/sctp_transport_unittest.cc
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "pc/sctp_transport.h"
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "p2p/base/fake_dtls_transport.h"
|
||||
#include "pc/dtls_transport.h"
|
||||
#include "rtc_base/gunit.h"
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
constexpr int kDefaultTimeout = 1000; // milliseconds
|
||||
|
||||
using cricket::FakeDtlsTransport;
|
||||
using ::testing::ElementsAre;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
class FakeCricketSctpTransport : public cricket::SctpTransportInternal {
|
||||
public:
|
||||
void SetDtlsTransport(rtc::PacketTransportInternal* transport) override {}
|
||||
bool Start(int local_port, int remote_port) override { return true; }
|
||||
bool OpenStream(int sid) override { return true; }
|
||||
bool ResetStream(int sid) override { return true; }
|
||||
bool SendData(const cricket::SendDataParams& params,
|
||||
const rtc::CopyOnWriteBuffer& payload,
|
||||
cricket::SendDataResult* result = nullptr) override {
|
||||
return true;
|
||||
}
|
||||
bool ReadyToSendData() override { return true; }
|
||||
void set_debug_name_for_testing(const char* debug_name) override {}
|
||||
// Methods exposed for testing
|
||||
void SendSignalReadyToSendData() { SignalReadyToSendData(); }
|
||||
|
||||
void SendSignalClosingProcedureStartedRemotely() {
|
||||
SignalClosingProcedureStartedRemotely(1);
|
||||
}
|
||||
|
||||
void SendSignalClosingProcedureComplete() {
|
||||
SignalClosingProcedureComplete(1);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class TestSctpTransportObserver : public SctpTransportObserverInterface {
|
||||
public:
|
||||
void OnStateChange(SctpTransportInformation info) override {
|
||||
states_.push_back(info.state());
|
||||
}
|
||||
|
||||
SctpTransportState State() {
|
||||
if (states_.size() > 0) {
|
||||
return states_[states_.size() - 1];
|
||||
} else {
|
||||
return SctpTransportState::kNew;
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<SctpTransportState>& States() { return states_; }
|
||||
|
||||
private:
|
||||
std::vector<SctpTransportState> states_;
|
||||
};
|
||||
|
||||
class SctpTransportTest : public testing::Test {
|
||||
public:
|
||||
SctpTransport* transport() { return transport_.get(); }
|
||||
SctpTransportObserverInterface* observer() { return &observer_; }
|
||||
|
||||
void CreateTransport() {
|
||||
auto cricket_sctp_transport =
|
||||
absl::WrapUnique(new FakeCricketSctpTransport());
|
||||
transport_ = new rtc::RefCountedObject<SctpTransport>(
|
||||
std::move(cricket_sctp_transport));
|
||||
}
|
||||
|
||||
void AddDtlsTransport() {
|
||||
std::unique_ptr<cricket::DtlsTransportInternal> cricket_transport =
|
||||
absl::make_unique<FakeDtlsTransport>(
|
||||
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
||||
dtls_transport_ =
|
||||
new rtc::RefCountedObject<DtlsTransport>(std::move(cricket_transport));
|
||||
transport_->SetDtlsTransport(dtls_transport_);
|
||||
}
|
||||
|
||||
void CompleteSctpHandshake() {
|
||||
CricketSctpTransport()->SendSignalReadyToSendData();
|
||||
}
|
||||
|
||||
FakeCricketSctpTransport* CricketSctpTransport() {
|
||||
return static_cast<FakeCricketSctpTransport*>(transport_->internal());
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<SctpTransport> transport_;
|
||||
rtc::scoped_refptr<DtlsTransport> dtls_transport_;
|
||||
TestSctpTransportObserver observer_;
|
||||
};
|
||||
|
||||
TEST(SctpTransportSimpleTest, CreateClearDelete) {
|
||||
std::unique_ptr<cricket::SctpTransportInternal> fake_cricket_sctp_transport =
|
||||
absl::WrapUnique(new FakeCricketSctpTransport());
|
||||
rtc::scoped_refptr<SctpTransport> sctp_transport =
|
||||
new rtc::RefCountedObject<SctpTransport>(
|
||||
std::move(fake_cricket_sctp_transport));
|
||||
ASSERT_TRUE(sctp_transport->internal());
|
||||
ASSERT_EQ(SctpTransportState::kNew, sctp_transport->Information().state());
|
||||
sctp_transport->Clear();
|
||||
ASSERT_FALSE(sctp_transport->internal());
|
||||
ASSERT_EQ(SctpTransportState::kClosed, sctp_transport->Information().state());
|
||||
}
|
||||
|
||||
TEST_F(SctpTransportTest, EventsObservedWhenConnecting) {
|
||||
CreateTransport();
|
||||
transport()->RegisterObserver(observer());
|
||||
AddDtlsTransport();
|
||||
CompleteSctpHandshake();
|
||||
ASSERT_EQ_WAIT(SctpTransportState::kConnected, observer_.State(),
|
||||
kDefaultTimeout);
|
||||
EXPECT_THAT(observer_.States(), ElementsAre(SctpTransportState::kConnecting,
|
||||
SctpTransportState::kConnected));
|
||||
}
|
||||
|
||||
TEST_F(SctpTransportTest, CloseWhenClearing) {
|
||||
CreateTransport();
|
||||
transport()->RegisterObserver(observer());
|
||||
AddDtlsTransport();
|
||||
CompleteSctpHandshake();
|
||||
ASSERT_EQ_WAIT(SctpTransportState::kConnected, observer_.State(),
|
||||
kDefaultTimeout);
|
||||
transport()->Clear();
|
||||
ASSERT_EQ_WAIT(SctpTransportState::kClosed, observer_.State(),
|
||||
kDefaultTimeout);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
Loading…
x
Reference in New Issue
Block a user