| Index: webrtc/api/webrtcsession.cc
|
| diff --git a/webrtc/api/webrtcsession.cc b/webrtc/api/webrtcsession.cc
|
| index 5d414baac2f89c60df48bfd9d451132eeb7d7b8b..5d67fef3d8595f3869b402f788df567517b22330 100644
|
| --- a/webrtc/api/webrtcsession.cc
|
| +++ b/webrtc/api/webrtcsession.cc
|
| @@ -33,6 +33,7 @@
|
| #include "webrtc/call/call.h"
|
| #include "webrtc/media/base/mediaconstants.h"
|
| #include "webrtc/media/base/videocapturer.h"
|
| +#include "webrtc/media/sctp/sctptransportinternal.h"
|
| #include "webrtc/p2p/base/portallocator.h"
|
| #include "webrtc/p2p/base/transportchannel.h"
|
| #include "webrtc/pc/channel.h"
|
| @@ -74,9 +75,9 @@ const char kSdpWithoutIceUfragPwd[] =
|
| "Called with SDP without ice-ufrag and ice-pwd.";
|
| const char kSessionError[] = "Session error code: ";
|
| const char kSessionErrorDesc[] = "Session error description: ";
|
| -const char kDtlsSetupFailureRtp[] =
|
| +const char kDtlsSrtpSetupFailureRtp[] =
|
| "Couldn't set up DTLS-SRTP on RTP channel.";
|
| -const char kDtlsSetupFailureRtcp[] =
|
| +const char kDtlsSrtpSetupFailureRtcp[] =
|
| "Couldn't set up DTLS-SRTP on RTCP channel.";
|
| const char kEnableBundleFailed[] = "Failed to enable BUNDLE.";
|
|
|
| @@ -291,6 +292,31 @@ static bool GetTrackIdBySsrc(const SessionDescription* session_description,
|
| return false;
|
| }
|
|
|
| +// Get the SCTP port out of a SessionDescription.
|
| +// Return -1 if not found.
|
| +static int GetSctpPort(const SessionDescription* session_description) {
|
| + const ContentInfo* content_info = GetFirstDataContent(session_description);
|
| + RTC_DCHECK(content_info);
|
| + if (!content_info) {
|
| + return -1;
|
| + }
|
| + const cricket::DataContentDescription* data =
|
| + static_cast<const cricket::DataContentDescription*>(
|
| + (content_info->description));
|
| + std::string value;
|
| + cricket::DataCodec match_pattern(cricket::kGoogleSctpDataCodecPlType,
|
| + cricket::kGoogleSctpDataCodecName);
|
| + for (const cricket::DataCodec& codec : data->codecs()) {
|
| + if (!codec.Matches(match_pattern)) {
|
| + continue;
|
| + }
|
| + if (codec.GetParam(cricket::kCodecParamPort, &value)) {
|
| + return rtc::FromString<int>(value);
|
| + }
|
| + }
|
| + return -1;
|
| +}
|
| +
|
| static bool BadSdp(const std::string& source,
|
| const std::string& type,
|
| const std::string& reason,
|
| @@ -440,7 +466,8 @@ WebRtcSession::WebRtcSession(
|
| rtc::Thread* worker_thread,
|
| rtc::Thread* signaling_thread,
|
| cricket::PortAllocator* port_allocator,
|
| - std::unique_ptr<cricket::TransportController> transport_controller)
|
| + std::unique_ptr<cricket::TransportController> transport_controller,
|
| + std::unique_ptr<cricket::SctpTransportInternalFactory> sctp_factory)
|
| : network_thread_(network_thread),
|
| worker_thread_(worker_thread),
|
| signaling_thread_(signaling_thread),
|
| @@ -449,6 +476,7 @@ WebRtcSession::WebRtcSession(
|
| // Due to this constraint session id |sid_| is max limited to LLONG_MAX.
|
| sid_(rtc::ToString(rtc::CreateRandomId64() & LLONG_MAX)),
|
| transport_controller_(std::move(transport_controller)),
|
| + sctp_factory_(std::move(sctp_factory)),
|
| media_controller_(media_controller),
|
| channel_manager_(media_controller_->channel_manager()),
|
| ice_observer_(NULL),
|
| @@ -470,7 +498,7 @@ WebRtcSession::WebRtcSession(
|
| transport_controller_->SignalCandidatesRemoved.connect(
|
| this, &WebRtcSession::OnTransportControllerCandidatesRemoved);
|
| transport_controller_->SignalDtlsHandshakeError.connect(
|
| - this, &WebRtcSession::OnDtlsHandshakeError);
|
| + this, &WebRtcSession::OnTransportControllerDtlsHandshakeError);
|
| }
|
|
|
| WebRtcSession::~WebRtcSession() {
|
| @@ -485,9 +513,14 @@ WebRtcSession::~WebRtcSession() {
|
| SignalVoiceChannelDestroyed();
|
| channel_manager_->DestroyVoiceChannel(voice_channel_.release());
|
| }
|
| - if (data_channel_) {
|
| + if (rtp_data_channel_) {
|
| + SignalDataChannelDestroyed();
|
| + channel_manager_->DestroyRtpDataChannel(rtp_data_channel_.release());
|
| + }
|
| + if (sctp_transport_) {
|
| SignalDataChannelDestroyed();
|
| - channel_manager_->DestroyDataChannel(data_channel_.release());
|
| + network_thread_->Invoke<void>(
|
| + RTC_FROM_HERE, rtc::Bind(&WebRtcSession::DestroySctpTransport_n, this));
|
| }
|
| #ifdef HAVE_QUIC
|
| if (quic_data_transport_) {
|
| @@ -597,9 +630,10 @@ bool WebRtcSession::Initialize(
|
| void WebRtcSession::Close() {
|
| SetState(STATE_CLOSED);
|
| RemoveUnusedChannels(nullptr);
|
| - ASSERT(!voice_channel_);
|
| - ASSERT(!video_channel_);
|
| - ASSERT(!data_channel_);
|
| + RTC_DCHECK(!voice_channel_);
|
| + RTC_DCHECK(!video_channel_);
|
| + RTC_DCHECK(!rtp_data_channel_);
|
| + RTC_DCHECK(!sctp_transport_);
|
| media_controller_->Close();
|
| }
|
|
|
| @@ -611,8 +645,9 @@ cricket::BaseChannel* WebRtcSession::GetChannel(
|
| if (video_channel() && video_channel()->content_name() == content_name) {
|
| return video_channel();
|
| }
|
| - if (data_channel() && data_channel()->content_name() == content_name) {
|
| - return data_channel();
|
| + if (rtp_data_channel() &&
|
| + rtp_data_channel()->content_name() == content_name) {
|
| + return rtp_data_channel();
|
| }
|
| return nullptr;
|
| }
|
| @@ -621,20 +656,31 @@ cricket::SecurePolicy WebRtcSession::SdesPolicy() const {
|
| return webrtc_session_desc_factory_->SdesPolicy();
|
| }
|
|
|
| -bool WebRtcSession::GetSslRole(const std::string& transport_name,
|
| - rtc::SSLRole* role) {
|
| +bool WebRtcSession::GetSctpSslRole(rtc::SSLRole* role) {
|
| if (!local_description() || !remote_description()) {
|
| - LOG(LS_INFO) << "Local and Remote descriptions must be applied to get "
|
| - << "SSL Role of the session.";
|
| + LOG(LS_INFO) << "Local and Remote descriptions must be applied to get the "
|
| + << "SSL Role of the SCTP transport.";
|
| + return false;
|
| + }
|
| + if (!sctp_transport_) {
|
| + LOG(LS_INFO) << "Non-rejected SCTP m= section is needed to get the "
|
| + << "SSL Role of the SCTP transport.";
|
| return false;
|
| }
|
|
|
| - return transport_controller_->GetSslRole(transport_name, role);
|
| + return transport_controller_->GetSslRole(*sctp_transport_name_, role);
|
| }
|
|
|
| -bool WebRtcSession::GetSslRole(const cricket::BaseChannel* channel,
|
| +bool WebRtcSession::GetSslRole(const std::string& content_name,
|
| rtc::SSLRole* role) {
|
| - return channel && GetSslRole(channel->transport_name(), role);
|
| + if (!local_description() || !remote_description()) {
|
| + LOG(LS_INFO) << "Local and Remote descriptions must be applied to get the "
|
| + << "SSL Role of the session.";
|
| + return false;
|
| + }
|
| +
|
| + return transport_controller_->GetSslRole(GetTransportName(content_name),
|
| + role);
|
| }
|
|
|
| void WebRtcSession::CreateOffer(
|
| @@ -918,9 +964,29 @@ bool WebRtcSession::PushdownMediaDescription(
|
| }
|
| };
|
|
|
| - return (set_content(voice_channel()) &&
|
| - set_content(video_channel()) &&
|
| - set_content(data_channel()));
|
| + bool ret = (set_content(voice_channel()) && set_content(video_channel()) &&
|
| + set_content(rtp_data_channel()));
|
| + // Need complete offer/answer with an SCTP m= section before starting SCTP,
|
| + // according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19
|
| + if (sctp_transport_ && local_description() && remote_description() &&
|
| + cricket::GetFirstDataContent(local_description()->description()) &&
|
| + cricket::GetFirstDataContent(remote_description()->description())) {
|
| + ret &= network_thread_->Invoke<bool>(
|
| + RTC_FROM_HERE,
|
| + rtc::Bind(&WebRtcSession::PushdownSctpParameters_n, this, source));
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| +bool WebRtcSession::PushdownSctpParameters_n(cricket::ContentSource source) {
|
| + RTC_DCHECK(network_thread_->IsCurrent());
|
| + RTC_DCHECK(local_description());
|
| + 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(
|
| + GetSctpPort(local_description()->description()),
|
| + GetSctpPort(remote_description()->description()));
|
| }
|
|
|
| bool WebRtcSession::PushdownTransportDescription(cricket::ContentSource source,
|
| @@ -992,46 +1058,6 @@ bool WebRtcSession::GetTransportDescription(
|
| return true;
|
| }
|
|
|
| -std::unique_ptr<SessionStats> WebRtcSession::GetStats_s() {
|
| - ASSERT(signaling_thread()->IsCurrent());
|
| - ChannelNamePairs channel_name_pairs;
|
| - if (voice_channel()) {
|
| - channel_name_pairs.voice = rtc::Optional<ChannelNamePair>(ChannelNamePair(
|
| - voice_channel()->content_name(), voice_channel()->transport_name()));
|
| - }
|
| - if (video_channel()) {
|
| - channel_name_pairs.video = rtc::Optional<ChannelNamePair>(ChannelNamePair(
|
| - video_channel()->content_name(), video_channel()->transport_name()));
|
| - }
|
| - if (data_channel()) {
|
| - channel_name_pairs.data = rtc::Optional<ChannelNamePair>(ChannelNamePair(
|
| - data_channel()->content_name(), data_channel()->transport_name()));
|
| - }
|
| - return GetStats(channel_name_pairs);
|
| -}
|
| -
|
| -std::unique_ptr<SessionStats> WebRtcSession::GetStats(
|
| - const ChannelNamePairs& channel_name_pairs) {
|
| - if (network_thread()->IsCurrent()) {
|
| - return GetStats_n(channel_name_pairs);
|
| - }
|
| - return network_thread()->Invoke<std::unique_ptr<SessionStats>>(
|
| - RTC_FROM_HERE,
|
| - rtc::Bind(&WebRtcSession::GetStats_n, this, channel_name_pairs));
|
| -}
|
| -
|
| -bool WebRtcSession::GetLocalCertificate(
|
| - const std::string& transport_name,
|
| - rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
|
| - return transport_controller_->GetLocalCertificate(transport_name,
|
| - certificate);
|
| -}
|
| -
|
| -std::unique_ptr<rtc::SSLCertificate> WebRtcSession::GetRemoteSSLCertificate(
|
| - const std::string& transport_name) {
|
| - return transport_controller_->GetRemoteSSLCertificate(transport_name);
|
| -}
|
| -
|
| bool WebRtcSession::EnableBundle(const cricket::ContentGroup& bundle) {
|
| const std::string* first_content_name = bundle.FirstContentName();
|
| if (!first_content_name) {
|
| @@ -1039,7 +1065,6 @@ bool WebRtcSession::EnableBundle(const cricket::ContentGroup& bundle) {
|
| return false;
|
| }
|
| const std::string& transport_name = *first_content_name;
|
| - cricket::BaseChannel* first_channel = GetChannel(transport_name);
|
|
|
| #ifdef HAVE_QUIC
|
| if (quic_data_transport_ &&
|
| @@ -1050,8 +1075,8 @@ bool WebRtcSession::EnableBundle(const cricket::ContentGroup& bundle) {
|
| }
|
| #endif
|
|
|
| - auto maybe_set_transport = [this, bundle, transport_name,
|
| - first_channel](cricket::BaseChannel* ch) {
|
| + auto maybe_set_transport = [this, bundle,
|
| + transport_name](cricket::BaseChannel* ch) {
|
| if (!ch || !bundle.HasContentName(ch->content_name())) {
|
| return true;
|
| }
|
| @@ -1073,9 +1098,21 @@ bool WebRtcSession::EnableBundle(const cricket::ContentGroup& bundle) {
|
|
|
| if (!maybe_set_transport(voice_channel()) ||
|
| !maybe_set_transport(video_channel()) ||
|
| - !maybe_set_transport(data_channel())) {
|
| + !maybe_set_transport(rtp_data_channel())) {
|
| return false;
|
| }
|
| + // For SCTP, transport creation/deletion happens here instead of in the
|
| + // object itself.
|
| + if (sctp_transport_) {
|
| + RTC_DCHECK(sctp_transport_name_);
|
| + RTC_DCHECK(sctp_content_name_);
|
| + if (transport_name != *sctp_transport_name_ &&
|
| + bundle.HasContentName(*sctp_content_name_)) {
|
| + network_thread_->Invoke<void>(
|
| + RTC_FROM_HERE, rtc::Bind(&WebRtcSession::ChangeSctpTransport_n, this,
|
| + transport_name));
|
| + }
|
| + }
|
|
|
| return true;
|
| }
|
| @@ -1248,60 +1285,129 @@ sigslot::signal0<>* WebRtcSession::GetOnDestroyedSignal() {
|
| bool WebRtcSession::SendData(const cricket::SendDataParams& params,
|
| const rtc::CopyOnWriteBuffer& payload,
|
| cricket::SendDataResult* result) {
|
| - if (!data_channel_) {
|
| - LOG(LS_ERROR) << "SendData called when data_channel_ is NULL.";
|
| + if (!rtp_data_channel_ && !sctp_transport_) {
|
| + LOG(LS_ERROR) << "SendData called when rtp_data_channel_ "
|
| + << "and sctp_transport_ are NULL.";
|
| return false;
|
| }
|
| - return data_channel_->SendData(params, payload, result);
|
| + return rtp_data_channel_
|
| + ? rtp_data_channel_->SendData(params, payload, result)
|
| + : network_thread_->Invoke<bool>(
|
| + RTC_FROM_HERE,
|
| + Bind(&cricket::SctpTransportInternal::SendData,
|
| + sctp_transport_.get(), params, payload, result));
|
| }
|
|
|
| bool WebRtcSession::ConnectDataChannel(DataChannel* webrtc_data_channel) {
|
| - if (!data_channel_) {
|
| + if (!rtp_data_channel_ && !sctp_transport_) {
|
| // Don't log an error here, because DataChannels are expected to call
|
| // ConnectDataChannel in this state. It's the only way to initially tell
|
| // whether or not the underlying transport is ready.
|
| return false;
|
| }
|
| - data_channel_->SignalReadyToSendData.connect(webrtc_data_channel,
|
| - &DataChannel::OnChannelReady);
|
| - data_channel_->SignalDataReceived.connect(webrtc_data_channel,
|
| - &DataChannel::OnDataReceived);
|
| - data_channel_->SignalStreamClosedRemotely.connect(
|
| - webrtc_data_channel, &DataChannel::OnStreamClosedRemotely);
|
| + if (rtp_data_channel_) {
|
| + rtp_data_channel_->SignalReadyToSendData.connect(
|
| + webrtc_data_channel, &DataChannel::OnChannelReady);
|
| + rtp_data_channel_->SignalDataReceived.connect(webrtc_data_channel,
|
| + &DataChannel::OnDataReceived);
|
| + } else {
|
| + SignalSctpReadyToSendData.connect(webrtc_data_channel,
|
| + &DataChannel::OnChannelReady);
|
| + SignalSctpDataReceived.connect(webrtc_data_channel,
|
| + &DataChannel::OnDataReceived);
|
| + SignalSctpStreamClosedRemotely.connect(
|
| + webrtc_data_channel, &DataChannel::OnStreamClosedRemotely);
|
| + }
|
| return true;
|
| }
|
|
|
| void WebRtcSession::DisconnectDataChannel(DataChannel* webrtc_data_channel) {
|
| - if (!data_channel_) {
|
| - LOG(LS_ERROR) << "DisconnectDataChannel called when data_channel_ is NULL.";
|
| + if (!rtp_data_channel_ && !sctp_transport_) {
|
| + LOG(LS_ERROR) << "DisconnectDataChannel called when rtp_data_channel_ and "
|
| + "sctp_transport_ are NULL.";
|
| return;
|
| }
|
| - data_channel_->SignalReadyToSendData.disconnect(webrtc_data_channel);
|
| - data_channel_->SignalDataReceived.disconnect(webrtc_data_channel);
|
| - data_channel_->SignalStreamClosedRemotely.disconnect(webrtc_data_channel);
|
| + if (rtp_data_channel_) {
|
| + rtp_data_channel_->SignalReadyToSendData.disconnect(webrtc_data_channel);
|
| + rtp_data_channel_->SignalDataReceived.disconnect(webrtc_data_channel);
|
| + } else {
|
| + SignalSctpReadyToSendData.disconnect(webrtc_data_channel);
|
| + SignalSctpDataReceived.disconnect(webrtc_data_channel);
|
| + SignalSctpStreamClosedRemotely.disconnect(webrtc_data_channel);
|
| + }
|
| }
|
|
|
| void WebRtcSession::AddSctpDataStream(int sid) {
|
| - if (!data_channel_) {
|
| - LOG(LS_ERROR) << "AddDataChannelStreams called when data_channel_ is NULL.";
|
| + if (!sctp_transport_) {
|
| + LOG(LS_ERROR) << "AddSctpDataStream called when sctp_transport_ is NULL.";
|
| return;
|
| }
|
| - data_channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(sid));
|
| - data_channel_->AddSendStream(cricket::StreamParams::CreateLegacy(sid));
|
| + network_thread_->Invoke<void>(
|
| + RTC_FROM_HERE, rtc::Bind(&cricket::SctpTransportInternal::OpenStream,
|
| + sctp_transport_.get(), sid));
|
| }
|
|
|
| void WebRtcSession::RemoveSctpDataStream(int sid) {
|
| - if (!data_channel_) {
|
| - LOG(LS_ERROR) << "RemoveDataChannelStreams called when data_channel_ is "
|
| + if (!sctp_transport_) {
|
| + LOG(LS_ERROR) << "RemoveSctpDataStream called when sctp_transport_ is "
|
| << "NULL.";
|
| return;
|
| }
|
| - data_channel_->RemoveRecvStream(sid);
|
| - data_channel_->RemoveSendStream(sid);
|
| + network_thread_->Invoke<void>(
|
| + RTC_FROM_HERE, rtc::Bind(&cricket::SctpTransportInternal::ResetStream,
|
| + sctp_transport_.get(), sid));
|
| }
|
|
|
| bool WebRtcSession::ReadyToSendData() const {
|
| - return data_channel_ && data_channel_->ready_to_send_data();
|
| + return (rtp_data_channel_ && rtp_data_channel_->ready_to_send_data()) ||
|
| + sctp_ready_to_send_data_;
|
| +}
|
| +
|
| +std::unique_ptr<SessionStats> WebRtcSession::GetStats_s() {
|
| + ASSERT(signaling_thread()->IsCurrent());
|
| + ChannelNamePairs channel_name_pairs;
|
| + if (voice_channel()) {
|
| + channel_name_pairs.voice = rtc::Optional<ChannelNamePair>(ChannelNamePair(
|
| + voice_channel()->content_name(), voice_channel()->transport_name()));
|
| + }
|
| + if (video_channel()) {
|
| + channel_name_pairs.video = rtc::Optional<ChannelNamePair>(ChannelNamePair(
|
| + video_channel()->content_name(), video_channel()->transport_name()));
|
| + }
|
| + if (rtp_data_channel()) {
|
| + channel_name_pairs.data = rtc::Optional<ChannelNamePair>(
|
| + ChannelNamePair(rtp_data_channel()->content_name(),
|
| + rtp_data_channel()->transport_name()));
|
| + }
|
| + if (sctp_transport_) {
|
| + RTC_DCHECK(sctp_content_name_);
|
| + RTC_DCHECK(sctp_transport_name_);
|
| + channel_name_pairs.data = rtc::Optional<ChannelNamePair>(
|
| + ChannelNamePair(*sctp_content_name_, *sctp_transport_name_));
|
| + }
|
| + return GetStats(channel_name_pairs);
|
| +}
|
| +
|
| +std::unique_ptr<SessionStats> WebRtcSession::GetStats(
|
| + const ChannelNamePairs& channel_name_pairs) {
|
| + if (network_thread()->IsCurrent()) {
|
| + return GetStats_n(channel_name_pairs);
|
| + }
|
| + return network_thread()->Invoke<std::unique_ptr<SessionStats>>(
|
| + RTC_FROM_HERE,
|
| + rtc::Bind(&WebRtcSession::GetStats_n, this, channel_name_pairs));
|
| +}
|
| +
|
| +bool WebRtcSession::GetLocalCertificate(
|
| + const std::string& transport_name,
|
| + rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
|
| + return transport_controller_->GetLocalCertificate(transport_name,
|
| + certificate);
|
| +}
|
| +
|
| +std::unique_ptr<rtc::SSLCertificate> WebRtcSession::GetRemoteSSLCertificate(
|
| + const std::string& transport_name) {
|
| + return transport_controller_->GetRemoteSSLCertificate(transport_name);
|
| }
|
|
|
| cricket::DataChannelType WebRtcSession::data_channel_type() const {
|
| @@ -1326,6 +1432,11 @@ void WebRtcSession::OnCertificateReady(
|
| transport_controller_->SetLocalCertificate(certificate);
|
| }
|
|
|
| +void WebRtcSession::OnDtlsSrtpSetupFailure(cricket::BaseChannel*, bool rtcp) {
|
| + SetError(ERROR_TRANSPORT,
|
| + rtcp ? kDtlsSrtpSetupFailureRtcp : kDtlsSrtpSetupFailureRtp);
|
| +}
|
| +
|
| bool WebRtcSession::waiting_for_certificate_for_testing() const {
|
| return webrtc_session_desc_factory_->waiting_for_certificate_for_testing();
|
| }
|
| @@ -1455,7 +1566,16 @@ void WebRtcSession::OnTransportControllerCandidatesRemoved(
|
| }
|
| }
|
|
|
| -// Enabling voice and video channel.
|
| +void WebRtcSession::OnTransportControllerDtlsHandshakeError(
|
| + rtc::SSLHandshakeError error) {
|
| + if (metrics_observer_) {
|
| + metrics_observer_->IncrementEnumCounter(
|
| + webrtc::kEnumCounterDtlsHandshakeError, static_cast<int>(error),
|
| + static_cast<int>(rtc::SSLHandshakeError::MAX_VALUE));
|
| + }
|
| +}
|
| +
|
| +// Enabling voice and video (and RTP data) channel.
|
| void WebRtcSession::EnableChannels() {
|
| if (voice_channel_ && !voice_channel_->enabled())
|
| voice_channel_->Enable(true);
|
| @@ -1463,8 +1583,8 @@ void WebRtcSession::EnableChannels() {
|
| if (video_channel_ && !video_channel_->enabled())
|
| video_channel_->Enable(true);
|
|
|
| - if (data_channel_ && !data_channel_->enabled())
|
| - data_channel_->Enable(true);
|
| + if (rtp_data_channel_ && !rtp_data_channel_->enabled())
|
| + rtp_data_channel_->Enable(true);
|
| }
|
|
|
| // Returns the media index for a local ice candidate given the content name.
|
| @@ -1574,9 +1694,15 @@ void WebRtcSession::RemoveUnusedChannels(const SessionDescription* desc) {
|
| const cricket::ContentInfo* data_info =
|
| cricket::GetFirstDataContent(desc);
|
| if (!data_info || data_info->rejected) {
|
| - if (data_channel_) {
|
| + if (rtp_data_channel_) {
|
| SignalDataChannelDestroyed();
|
| - channel_manager_->DestroyDataChannel(data_channel_.release());
|
| + channel_manager_->DestroyRtpDataChannel(rtp_data_channel_.release());
|
| + }
|
| + if (sctp_transport_) {
|
| + SignalDataChannelDestroyed();
|
| + network_thread_->Invoke<void>(
|
| + RTC_FROM_HERE,
|
| + rtc::Bind(&WebRtcSession::DestroySctpTransport_n, this));
|
| }
|
| #ifdef HAVE_QUIC
|
| // Clean up the existing QuicDataTransport and its QuicTransportChannels.
|
| @@ -1637,8 +1763,8 @@ bool WebRtcSession::CreateChannels(const SessionDescription* desc) {
|
| }
|
|
|
| const cricket::ContentInfo* data = cricket::GetFirstDataContent(desc);
|
| - if (data_channel_type_ != cricket::DCT_NONE &&
|
| - data && !data->rejected && !data_channel_) {
|
| + if (data_channel_type_ != cricket::DCT_NONE && data && !data->rejected &&
|
| + !rtp_data_channel_ && !sctp_transport_) {
|
| if (!CreateDataChannel(data, GetBundleTransportName(data, bundle_group))) {
|
| LOG(LS_ERROR) << "Failed to create data channel.";
|
| return false;
|
| @@ -1664,8 +1790,8 @@ bool WebRtcSession::CreateVoiceChannel(const cricket::ContentInfo* content,
|
| voice_channel_->ActivateRtcpMux();
|
| }
|
|
|
| - voice_channel_->SignalDtlsSetupFailure.connect(
|
| - this, &WebRtcSession::OnDtlsSetupFailure);
|
| + voice_channel_->SignalDtlsSrtpSetupFailure.connect(
|
| + this, &WebRtcSession::OnDtlsSrtpSetupFailure);
|
|
|
| SignalVoiceChannelCreated();
|
| voice_channel_->SignalSentPacket.connect(this,
|
| @@ -1688,8 +1814,8 @@ bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content,
|
| if (require_rtcp_mux) {
|
| video_channel_->ActivateRtcpMux();
|
| }
|
| - video_channel_->SignalDtlsSetupFailure.connect(
|
| - this, &WebRtcSession::OnDtlsSetupFailure);
|
| + video_channel_->SignalDtlsSrtpSetupFailure.connect(
|
| + this, &WebRtcSession::OnDtlsSrtpSetupFailure);
|
|
|
| SignalVideoChannelCreated();
|
| video_channel_->SignalSentPacket.connect(this,
|
| @@ -1699,40 +1825,48 @@ bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content,
|
|
|
| bool WebRtcSession::CreateDataChannel(const cricket::ContentInfo* content,
|
| const std::string* bundle_transport) {
|
| + const std::string transport_name =
|
| + bundle_transport ? *bundle_transport : content->name;
|
| #ifdef HAVE_QUIC
|
| if (data_channel_type_ == cricket::DCT_QUIC) {
|
| RTC_DCHECK(transport_controller_->quic());
|
| - const std::string transport_name =
|
| - bundle_transport ? *bundle_transport : content->name;
|
| quic_data_transport_->SetTransport(transport_name);
|
| return true;
|
| }
|
| #endif // HAVE_QUIC
|
| bool sctp = (data_channel_type_ == cricket::DCT_SCTP);
|
| - bool require_rtcp_mux =
|
| - rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire;
|
| - bool create_rtcp_transport_channel = !sctp && !require_rtcp_mux;
|
| - data_channel_.reset(channel_manager_->CreateDataChannel(
|
| - media_controller_, transport_controller_.get(), content->name,
|
| - bundle_transport, create_rtcp_transport_channel, SrtpRequired(),
|
| - data_channel_type_));
|
| - if (!data_channel_) {
|
| - return false;
|
| - }
|
| - if (require_rtcp_mux) {
|
| - data_channel_->ActivateRtcpMux();
|
| - }
|
| -
|
| if (sctp) {
|
| - data_channel_->SignalDataReceived.connect(
|
| - this, &WebRtcSession::OnDataChannelMessageReceived);
|
| + if (!sctp_factory_) {
|
| + LOG(LS_ERROR)
|
| + << "Trying to create SCTP transport, but didn't compile with "
|
| + "SCTP support (HAVE_SCTP)";
|
| + return false;
|
| + }
|
| + if (!network_thread_->Invoke<bool>(
|
| + RTC_FROM_HERE, rtc::Bind(&WebRtcSession::CreateSctpTransport_n,
|
| + this, content->name, transport_name))) {
|
| + return false;
|
| + };
|
| + } else {
|
| + bool require_rtcp_mux =
|
| + rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire;
|
| + bool create_rtcp_transport_channel = !sctp && !require_rtcp_mux;
|
| + rtp_data_channel_.reset(channel_manager_->CreateRtpDataChannel(
|
| + media_controller_, transport_controller_.get(), content->name,
|
| + bundle_transport, create_rtcp_transport_channel, SrtpRequired()));
|
| + if (!rtp_data_channel_) {
|
| + return false;
|
| + }
|
| + if (require_rtcp_mux) {
|
| + rtp_data_channel_->ActivateRtcpMux();
|
| + }
|
| + rtp_data_channel_->SignalDtlsSrtpSetupFailure.connect(
|
| + this, &WebRtcSession::OnDtlsSrtpSetupFailure);
|
| + rtp_data_channel_->SignalSentPacket.connect(this,
|
| + &WebRtcSession::OnSentPacket_w);
|
| }
|
|
|
| - data_channel_->SignalDtlsSetupFailure.connect(
|
| - this, &WebRtcSession::OnDtlsSetupFailure);
|
| -
|
| SignalDataChannelCreated();
|
| - data_channel_->SignalSentPacket.connect(this, &WebRtcSession::OnSentPacket_w);
|
| return true;
|
| }
|
|
|
| @@ -1758,16 +1892,79 @@ std::unique_ptr<SessionStats> WebRtcSession::GetStats_n(
|
| return session_stats;
|
| }
|
|
|
| -void WebRtcSession::OnDtlsSetupFailure(cricket::BaseChannel*, bool rtcp) {
|
| - SetError(ERROR_TRANSPORT,
|
| - rtcp ? kDtlsSetupFailureRtcp : kDtlsSetupFailureRtp);
|
| +bool WebRtcSession::CreateSctpTransport_n(const std::string& content_name,
|
| + const std::string& transport_name) {
|
| + RTC_DCHECK(network_thread_->IsCurrent());
|
| + RTC_DCHECK(sctp_factory_);
|
| + cricket::TransportChannel* tc =
|
| + transport_controller_->CreateTransportChannel_n(
|
| + transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
| + sctp_transport_ = sctp_factory_->CreateSctpTransport(tc);
|
| + RTC_DCHECK(sctp_transport_);
|
| + sctp_invoker_.reset(new rtc::AsyncInvoker());
|
| + sctp_transport_->SignalReadyToSendData.connect(
|
| + this, &WebRtcSession::OnSctpTransportReadyToSendData_n);
|
| + sctp_transport_->SignalDataReceived.connect(
|
| + this, &WebRtcSession::OnSctpTransportDataReceived_n);
|
| + sctp_transport_->SignalStreamClosedRemotely.connect(
|
| + this, &WebRtcSession::OnSctpStreamClosedRemotely_n);
|
| + sctp_transport_name_ = rtc::Optional<std::string>(transport_name);
|
| + sctp_content_name_ = rtc::Optional<std::string>(content_name);
|
| + return true;
|
| +}
|
| +
|
| +void WebRtcSession::ChangeSctpTransport_n(const std::string& transport_name) {
|
| + RTC_DCHECK(network_thread_->IsCurrent());
|
| + RTC_DCHECK(sctp_transport_);
|
| + RTC_DCHECK(sctp_transport_name_);
|
| + std::string old_sctp_transport_name = *sctp_transport_name_;
|
| + sctp_transport_name_ = rtc::Optional<std::string>(transport_name);
|
| + cricket::TransportChannel* tc =
|
| + transport_controller_->CreateTransportChannel_n(
|
| + transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
| + sctp_transport_->SetTransportChannel(tc);
|
| + transport_controller_->DestroyTransportChannel_n(
|
| + old_sctp_transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
| +}
|
| +
|
| +void WebRtcSession::DestroySctpTransport_n() {
|
| + RTC_DCHECK(network_thread_->IsCurrent());
|
| + sctp_transport_.reset(nullptr);
|
| + sctp_content_name_.reset();
|
| + sctp_transport_name_.reset();
|
| + sctp_invoker_.reset(nullptr);
|
| + sctp_ready_to_send_data_ = false;
|
| +}
|
| +
|
| +void WebRtcSession::OnSctpTransportReadyToSendData_n() {
|
| + RTC_DCHECK(data_channel_type_ == cricket::DCT_SCTP);
|
| + RTC_DCHECK(network_thread_->IsCurrent());
|
| + sctp_invoker_->AsyncInvoke<void>(
|
| + RTC_FROM_HERE, signaling_thread_,
|
| + rtc::Bind(&WebRtcSession::OnSctpTransportReadyToSendData_s, this, true));
|
| }
|
|
|
| -void WebRtcSession::OnDataChannelMessageReceived(
|
| - cricket::DataChannel* channel,
|
| +void WebRtcSession::OnSctpTransportReadyToSendData_s(bool ready) {
|
| + RTC_DCHECK(signaling_thread_->IsCurrent());
|
| + sctp_ready_to_send_data_ = ready;
|
| + SignalSctpReadyToSendData(ready);
|
| +}
|
| +
|
| +void WebRtcSession::OnSctpTransportDataReceived_n(
|
| const cricket::ReceiveDataParams& params,
|
| const rtc::CopyOnWriteBuffer& payload) {
|
| RTC_DCHECK(data_channel_type_ == cricket::DCT_SCTP);
|
| + RTC_DCHECK(network_thread_->IsCurrent());
|
| + sctp_invoker_->AsyncInvoke<void>(
|
| + RTC_FROM_HERE, signaling_thread_,
|
| + rtc::Bind(&WebRtcSession::OnSctpTransportDataReceived_s, this, params,
|
| + payload));
|
| +}
|
| +
|
| +void WebRtcSession::OnSctpTransportDataReceived_s(
|
| + const cricket::ReceiveDataParams& params,
|
| + const rtc::CopyOnWriteBuffer& payload) {
|
| + RTC_DCHECK(signaling_thread_->IsCurrent());
|
| if (params.type == cricket::DMT_CONTROL && IsOpenMessage(payload)) {
|
| // Received OPEN message; parse and signal that a new data channel should
|
| // be created.
|
| @@ -1781,8 +1978,19 @@ void WebRtcSession::OnDataChannelMessageReceived(
|
| }
|
| config.open_handshake_role = InternalDataChannelInit::kAcker;
|
| SignalDataChannelOpenMessage(label, config);
|
| + } else {
|
| + // Otherwise just forward the signal.
|
| + SignalSctpDataReceived(params, payload);
|
| }
|
| - // Otherwise ignore the message.
|
| +}
|
| +
|
| +void WebRtcSession::OnSctpStreamClosedRemotely_n(int sid) {
|
| + RTC_DCHECK(data_channel_type_ == cricket::DCT_SCTP);
|
| + RTC_DCHECK(network_thread_->IsCurrent());
|
| + sctp_invoker_->AsyncInvoke<void>(
|
| + RTC_FROM_HERE, signaling_thread_,
|
| + rtc::Bind(&sigslot::signal1<int>::operator(),
|
| + &SignalSctpStreamClosedRemotely, sid));
|
| }
|
|
|
| // Returns false if bundle is enabled and rtcp_mux is disabled.
|
| @@ -1976,8 +2184,11 @@ void WebRtcSession::ReportTransportStats() {
|
| if (video_channel()) {
|
| transport_names.insert(video_channel()->transport_name());
|
| }
|
| - if (data_channel()) {
|
| - transport_names.insert(data_channel()->transport_name());
|
| + if (rtp_data_channel()) {
|
| + transport_names.insert(rtp_data_channel()->transport_name());
|
| + }
|
| + if (sctp_transport_name_) {
|
| + transport_names.insert(*sctp_transport_name_);
|
| }
|
| for (const auto& name : transport_names) {
|
| cricket::TransportStats stats;
|
| @@ -2094,17 +2305,17 @@ const std::string WebRtcSession::GetTransportName(
|
| return quic_data_transport_->transport_name();
|
| }
|
| #endif
|
| + if (sctp_transport_) {
|
| + RTC_DCHECK(sctp_content_name_);
|
| + RTC_DCHECK(sctp_transport_name_);
|
| + if (content_name == *sctp_content_name_) {
|
| + return *sctp_transport_name_;
|
| + }
|
| + }
|
| // Return an empty string if failed to retrieve the transport name.
|
| return "";
|
| }
|
| return channel->transport_name();
|
| }
|
|
|
| -void WebRtcSession::OnDtlsHandshakeError(rtc::SSLHandshakeError error) {
|
| - if (metrics_observer_) {
|
| - metrics_observer_->IncrementEnumCounter(
|
| - webrtc::kEnumCounterDtlsHandshakeError, static_cast<int>(error),
|
| - static_cast<int>(rtc::SSLHandshakeError::MAX_VALUE));
|
| - }
|
| -}
|
| } // namespace webrtc
|
|
|