diff --git a/pc/BUILD.gn b/pc/BUILD.gn index dbfd096d90..732640961c 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -72,7 +72,6 @@ rtc_static_library("rtc_pc_base") { ] deps = [ - ":media_protocol_names", "../api:array_view", "../api:audio_options_api", "../api:call_api", @@ -121,13 +120,6 @@ rtc_source_set("rtc_pc") { ] } -rtc_source_set("media_protocol_names") { - sources = [ - "media_protocol_names.cc", - "media_protocol_names.h", - ] -} - rtc_static_library("peerconnection") { visibility = [ "*" ] cflags = [] diff --git a/pc/media_protocol_names.cc b/pc/media_protocol_names.cc deleted file mode 100644 index 6ce2f02517..0000000000 --- a/pc/media_protocol_names.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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/media_protocol_names.h" - -namespace cricket { - -const char kMediaProtocolRtpPrefix[] = "RTP/"; - -const char kMediaProtocolSctp[] = "SCTP"; -const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP"; -const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP"; -const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP"; - -bool IsDtlsSctp(const std::string& protocol) { - return protocol == kMediaProtocolDtlsSctp || - protocol == kMediaProtocolUdpDtlsSctp || - protocol == kMediaProtocolTcpDtlsSctp; -} - -bool IsPlainSctp(const std::string& protocol) { - return protocol == kMediaProtocolSctp; -} - -bool IsRtpProtocol(const std::string& protocol) { - return protocol.empty() || - (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos); -} - -bool IsSctpProtocol(const std::string& protocol) { - return IsPlainSctp(protocol) || IsDtlsSctp(protocol); -} - -} // namespace cricket diff --git a/pc/media_protocol_names.h b/pc/media_protocol_names.h deleted file mode 100644 index f97055d3bd..0000000000 --- a/pc/media_protocol_names.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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_MEDIA_PROTOCOL_NAMES_H_ -#define PC_MEDIA_PROTOCOL_NAMES_H_ - -#include - -namespace cricket { - -// Names or name prefixes of protocols as defined by SDP specifications. -extern const char kMediaProtocolRtpPrefix[]; -extern const char kMediaProtocolSctp[]; -extern const char kMediaProtocolDtlsSctp[]; -extern const char kMediaProtocolUdpDtlsSctp[]; -extern const char kMediaProtocolTcpDtlsSctp[]; - -// Returns true if the given media section protocol indicates use of RTP. -bool IsRtpProtocol(const std::string& protocol); -// Returns true if the given media section protocol indicates use of SCTP. -bool IsSctpProtocol(const std::string& protocol); - -bool IsDtlsSctp(const std::string& protocol); -bool IsPlainSctp(const std::string& protocol); - -} // namespace cricket - -#endif // PC_MEDIA_PROTOCOL_NAMES_H_ diff --git a/pc/media_session.cc b/pc/media_session.cc index b739e904fd..8377f1003f 100644 --- a/pc/media_session.cc +++ b/pc/media_session.cc @@ -27,7 +27,6 @@ #include "media/base/media_constants.h" #include "p2p/base/p2p_constants.h" #include "pc/channel_manager.h" -#include "pc/media_protocol_names.h" #include "pc/rtp_media_utils.h" #include "pc/srtp_filter.h" #include "rtc_base/checks.h" @@ -69,6 +68,13 @@ const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF"; // but we tolerate "RTP/SAVPF" in offers we receive, for compatibility. const char kMediaProtocolSavpf[] = "RTP/SAVPF"; +const char kMediaProtocolRtpPrefix[] = "RTP/"; + +const char kMediaProtocolSctp[] = "SCTP"; +const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP"; +const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP"; +const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP"; + // Note that the below functions support some protocol strings purely for // legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names // and Interoperability. @@ -85,6 +91,20 @@ static bool IsPlainRtp(const std::string& protocol) { protocol == "RTP/SAVP" || protocol == "RTP/AVP"; } +static bool IsDtlsSctp(const std::string& protocol) { + return protocol == kMediaProtocolDtlsSctp || + protocol == kMediaProtocolUdpDtlsSctp || + protocol == kMediaProtocolTcpDtlsSctp; +} + +static bool IsPlainSctp(const std::string& protocol) { + return protocol == kMediaProtocolSctp; +} + +static bool IsSctp(const std::string& protocol) { + return IsPlainSctp(protocol) || IsDtlsSctp(protocol); +} + static RtpTransceiverDirection NegotiateRtpTransceiverDirection( RtpTransceiverDirection offer, RtpTransceiverDirection wants) { @@ -469,7 +489,7 @@ static bool AddStreamParams( StreamParamsVec* current_streams, MediaContentDescriptionImpl* content_description) { // SCTP streams are not negotiated using SDP/ContentDescriptions. - if (IsSctpProtocol(content_description->protocol())) { + if (IsSctp(content_description->protocol())) { return true; } @@ -588,6 +608,11 @@ static void PruneCryptos(const CryptoParamsVec& filter, target_cryptos->end()); } +bool IsRtpProtocol(const std::string& protocol) { + return protocol.empty() || + (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos); +} + static bool IsRtpContent(SessionDescription* sdesc, const std::string& content_name) { bool is_rtp = false; @@ -716,22 +741,32 @@ static bool IsFlexfecCodec(const C& codec) { // crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is // created (according to crypto_suites). The created content is added to the // offer. -static bool CreateContentOffer( +template +static bool CreateMediaContentOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, + const std::vector& codecs, const SecurePolicy& secure_policy, const CryptoParamsVec* current_cryptos, const std::vector& crypto_suites, const RtpHeaderExtensions& rtp_extensions, UniqueRandomIdGenerator* ssrc_generator, StreamParamsVec* current_streams, - MediaContentDescription* offer) { + MediaContentDescriptionImpl* offer) { + offer->AddCodecs(codecs); + offer->set_rtcp_mux(session_options.rtcp_mux_enabled); if (offer->type() == cricket::MEDIA_TYPE_VIDEO) { offer->set_rtcp_reduced_size(true); } offer->set_rtp_header_extensions(rtp_extensions); + if (!AddStreamParams(media_description_options.sender_options, + session_options.rtcp_cname, ssrc_generator, + current_streams, offer)) { + return false; + } + AddSimulcastToMediaDescription(media_description_options, offer); if (secure_policy != SEC_DISABLED) { @@ -750,30 +785,6 @@ static bool CreateContentOffer( } return true; } -template -static bool CreateMediaContentOffer( - const MediaDescriptionOptions& media_description_options, - const MediaSessionOptions& session_options, - const std::vector& codecs, - const SecurePolicy& secure_policy, - const CryptoParamsVec* current_cryptos, - const std::vector& crypto_suites, - const RtpHeaderExtensions& rtp_extensions, - UniqueRandomIdGenerator* ssrc_generator, - StreamParamsVec* current_streams, - MediaContentDescriptionImpl* offer) { - offer->AddCodecs(codecs); - if (!AddStreamParams(media_description_options.sender_options, - session_options.rtcp_cname, ssrc_generator, - current_streams, offer)) { - return false; - } - - return CreateContentOffer(media_description_options, session_options, - secure_policy, current_cryptos, crypto_suites, - rtp_extensions, ssrc_generator, current_streams, - offer); -} template static bool ReferencedCodecsMatch(const std::vector& codecs1, @@ -1126,27 +1137,6 @@ static void StripCNCodecs(AudioCodecs* audio_codecs) { audio_codecs->end()); } -template -static bool SetCodecsInAnswer( - const MediaContentDescriptionImpl* offer, - const std::vector& local_codecs, - const MediaDescriptionOptions& media_description_options, - const MediaSessionOptions& session_options, - UniqueRandomIdGenerator* ssrc_generator, - StreamParamsVec* current_streams, - MediaContentDescriptionImpl* answer) { - std::vector negotiated_codecs; - NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs); - answer->AddCodecs(negotiated_codecs); - answer->set_protocol(offer->protocol()); - if (!AddStreamParams(media_description_options.sender_options, - session_options.rtcp_cname, ssrc_generator, - current_streams, answer)) { - return false; // Something went seriously wrong. - } - return true; -} - // Create a media content to be answered for the given |sender_options| // according to the given session_options.rtcp_mux, session_options.streams, // codecs, crypto, and current_streams. If we don't currently have crypto (in @@ -1154,10 +1144,12 @@ static bool SetCodecsInAnswer( // (according to crypto_suites). The codecs, rtcp_mux, and crypto are all // negotiated with the offer. If the negotiation fails, this method returns // false. The created content is added to the offer. +template static bool CreateMediaContentAnswer( - const MediaContentDescription* offer, + const MediaContentDescriptionImpl* offer, const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, + const std::vector& local_codecs, const SecurePolicy& sdes_policy, const CryptoParamsVec* current_cryptos, const RtpHeaderExtensions& local_rtp_extenstions, @@ -1165,7 +1157,12 @@ static bool CreateMediaContentAnswer( bool enable_encrypted_rtp_header_extensions, StreamParamsVec* current_streams, bool bundle_enabled, - MediaContentDescription* answer) { + MediaContentDescriptionImpl* answer) { + std::vector negotiated_codecs; + NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs); + answer->AddCodecs(negotiated_codecs); + answer->set_protocol(offer->protocol()); + answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum()); RtpHeaderExtensions negotiated_rtp_extensions; NegotiateRtpHeaderExtensions( @@ -1193,6 +1190,12 @@ static bool CreateMediaContentAnswer( return false; } + if (!AddStreamParams(media_description_options.sender_options, + session_options.rtcp_cname, ssrc_generator, + current_streams, answer)) { + return false; // Something went seriously wrong. + } + AddSimulcastToMediaDescription(media_description_options, answer); answer->set_direction(NegotiateRtpTransceiverDirection( @@ -1777,10 +1780,7 @@ void MergeCodecsFromDescription( } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) { const DataContentDescription* data = content->media_description()->as_data(); - if (data) { - // Only relevant for RTP datachannels - MergeCodecs(data->codecs(), data_codecs, used_pltypes); - } + MergeCodecs(data->codecs(), data_codecs, used_pltypes); } } } @@ -1861,16 +1861,13 @@ void MediaSessionDescriptionFactory::GetCodecsForAnswer( } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) { const DataContentDescription* data = content.media_description()->as_data(); - if (data) { - // RTP data. This part is inactive for SCTP data. - for (const DataCodec& offered_data_codec : data->codecs()) { - if (!FindMatchingCodec(data->codecs(), - filtered_offered_data_codecs, - offered_data_codec, nullptr) && - FindMatchingCodec(data->codecs(), data_codecs_, - offered_data_codec, nullptr)) { - filtered_offered_data_codecs.push_back(offered_data_codec); - } + for (const DataCodec& offered_data_codec : data->codecs()) { + if (!FindMatchingCodec(data->codecs(), + filtered_offered_data_codecs, + offered_data_codec, nullptr) && + FindMatchingCodec(data->codecs(), data_codecs_, + offered_data_codec, nullptr)) { + filtered_offered_data_codecs.push_back(offered_data_codec); } } } @@ -2143,90 +2140,6 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer( return true; } -bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer( - const MediaDescriptionOptions& media_description_options, - const MediaSessionOptions& session_options, - const ContentInfo* current_content, - const SessionDescription* current_description, - StreamParamsVec* current_streams, - SessionDescription* desc, - IceCredentialsIterator* ice_credentials) const { - std::unique_ptr data( - new SctpDataContentDescription()); - - bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED); - - cricket::SecurePolicy sdes_policy = - IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED - : secure(); - std::vector crypto_suites; - // SDES doesn't make sense for SCTP, so we disable it, and we only - // get SDES crypto suites for RTP-based data channels. - sdes_policy = cricket::SEC_DISABLED; - // Unlike SetMediaProtocol below, we need to set the protocol - // before we call CreateMediaContentOffer. Otherwise, - // CreateMediaContentOffer won't know this is SCTP and will - // generate SSRCs rather than SIDs. - // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once - // it's safe to do so. Older versions of webrtc would reject these - // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706. - data->set_protocol(secure_transport ? kMediaProtocolDtlsSctp - : kMediaProtocolSctp); - - if (!CreateContentOffer(media_description_options, session_options, - sdes_policy, GetCryptos(current_content), - crypto_suites, RtpHeaderExtensions(), ssrc_generator_, - current_streams, data.get())) { - return false; - } - - desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp, - data.release()); - if (!AddTransportOffer(media_description_options.mid, - media_description_options.transport_options, - current_description, desc, ice_credentials)) { - return false; - } - return true; -} - -bool MediaSessionDescriptionFactory::AddRtpDataContentForOffer( - const MediaDescriptionOptions& media_description_options, - const MediaSessionOptions& session_options, - const ContentInfo* current_content, - const SessionDescription* current_description, - const DataCodecs& data_codecs, - StreamParamsVec* current_streams, - SessionDescription* desc, - IceCredentialsIterator* ice_credentials) const { - std::unique_ptr data(new DataContentDescription()); - bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED); - - cricket::SecurePolicy sdes_policy = - IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED - : secure(); - std::vector crypto_suites; - GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options, - &crypto_suites); - if (!CreateMediaContentOffer( - media_description_options, session_options, data_codecs, sdes_policy, - GetCryptos(current_content), crypto_suites, RtpHeaderExtensions(), - ssrc_generator_, current_streams, data.get())) { - return false; - } - - data->set_bandwidth(kDataMaxBandwidth); - SetMediaProtocol(secure_transport, data.get()); - desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp, - media_description_options.stopped, data.release()); - if (!AddTransportOffer(media_description_options.mid, - media_description_options.transport_options, - current_description, desc, ice_credentials)) { - return false; - } - return true; -} - bool MediaSessionDescriptionFactory::AddDataContentForOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, @@ -2236,6 +2149,9 @@ bool MediaSessionDescriptionFactory::AddDataContentForOffer( StreamParamsVec* current_streams, SessionDescription* desc, IceCredentialsIterator* ice_credentials) const { + bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED); + + std::unique_ptr data(new DataContentDescription()); bool is_sctp = (session_options.data_channel_type == DCT_SCTP); // If the DataChannel type is not specified, use the DataChannel type in // the current description. @@ -2244,16 +2160,52 @@ bool MediaSessionDescriptionFactory::AddDataContentForOffer( is_sctp = (current_content->media_description()->protocol() == kMediaProtocolSctp); } + + cricket::SecurePolicy sdes_policy = + IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED + : secure(); + std::vector crypto_suites; if (is_sctp) { - return AddSctpDataContentForOffer( - media_description_options, session_options, current_content, - current_description, current_streams, desc, ice_credentials); + // SDES doesn't make sense for SCTP, so we disable it, and we only + // get SDES crypto suites for RTP-based data channels. + sdes_policy = cricket::SEC_DISABLED; + // Unlike SetMediaProtocol below, we need to set the protocol + // before we call CreateMediaContentOffer. Otherwise, + // CreateMediaContentOffer won't know this is SCTP and will + // generate SSRCs rather than SIDs. + // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once + // it's safe to do so. Older versions of webrtc would reject these + // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706. + data->set_protocol(secure_transport ? kMediaProtocolDtlsSctp + : kMediaProtocolSctp); } else { - return AddRtpDataContentForOffer(media_description_options, session_options, - current_content, current_description, - data_codecs, current_streams, desc, - ice_credentials); + GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options, + &crypto_suites); } + + // Even SCTP uses a "codec". + if (!CreateMediaContentOffer( + media_description_options, session_options, data_codecs, sdes_policy, + GetCryptos(current_content), crypto_suites, RtpHeaderExtensions(), + ssrc_generator_, current_streams, data.get())) { + return false; + } + + if (is_sctp) { + desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp, + data.release()); + } else { + data->set_bandwidth(kDataMaxBandwidth); + SetMediaProtocol(secure_transport, data.get()); + desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp, + media_description_options.stopped, data.release()); + } + if (!AddTransportOffer(media_description_options.mid, + media_description_options.transport_options, + current_description, desc, ice_credentials)) { + return false; + } + return true; } // |audio_codecs| = set of all possible codecs that can be used, with correct @@ -2335,15 +2287,9 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( // Do not require or create SDES cryptos if DTLS is used. cricket::SecurePolicy sdes_policy = audio_transport->secure() ? cricket::SEC_DISABLED : secure(); - if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs, - media_description_options, session_options, - ssrc_generator_, current_streams, - audio_answer.get())) { - return false; - } if (!CreateMediaContentAnswer( offer_audio_description, media_description_options, session_options, - sdes_policy, GetCryptos(current_content), + filtered_codecs, sdes_policy, GetCryptos(current_content), audio_rtp_header_extensions(), ssrc_generator_, enable_encrypted_rtp_header_extensions_, current_streams, bundle_enabled, audio_answer.get())) { @@ -2430,15 +2376,9 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( // Do not require or create SDES cryptos if DTLS is used. cricket::SecurePolicy sdes_policy = video_transport->secure() ? cricket::SEC_DISABLED : secure(); - if (!SetCodecsInAnswer(offer_video_description, filtered_codecs, - media_description_options, session_options, - ssrc_generator_, current_streams, - video_answer.get())) { - return false; - } if (!CreateMediaContentAnswer( offer_video_description, media_description_options, session_options, - sdes_policy, GetCryptos(current_content), + filtered_codecs, sdes_policy, GetCryptos(current_content), video_rtp_header_extensions(), ssrc_generator_, enable_encrypted_rtp_header_extensions_, current_streams, bundle_enabled, video_answer.get())) { @@ -2486,52 +2426,29 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer( return false; } + std::unique_ptr data_answer( + new DataContentDescription()); // Do not require or create SDES cryptos if DTLS is used. cricket::SecurePolicy sdes_policy = data_transport->secure() ? cricket::SEC_DISABLED : secure(); bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) && session_options.bundle_enabled; RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA)); - std::unique_ptr data_answer; - if (offer_content->media_description()->as_sctp()) { - // SCTP data content - data_answer = absl::make_unique(); - const SctpDataContentDescription* offer_data_description = - offer_content->media_description()->as_sctp(); - // Respond with the offerer's proto, whatever it is. - data_answer->as_sctp()->set_protocol(offer_data_description->protocol()); - if (!CreateMediaContentAnswer( - offer_data_description, media_description_options, session_options, - sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(), - ssrc_generator_, enable_encrypted_rtp_header_extensions_, - current_streams, bundle_enabled, data_answer.get())) { - return false; // Fails the session setup. - } - // Respond with sctpmap if the offer uses sctpmap. - bool offer_uses_sctpmap = offer_data_description->use_sctpmap(); - data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap); - } else { - // RTP offer - data_answer = absl::make_unique(); - - RTC_CHECK(offer_content->media_description()->as_data()); - const DataContentDescription* offer_data_description = - offer_content->media_description()->as_data(); - if (!SetCodecsInAnswer(offer_data_description, data_codecs, - media_description_options, session_options, - ssrc_generator_, current_streams, - data_answer->as_data())) { - return false; - } - if (!CreateMediaContentAnswer( - offer_data_description, media_description_options, session_options, - sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(), - ssrc_generator_, enable_encrypted_rtp_header_extensions_, - current_streams, bundle_enabled, data_answer.get())) { - return false; // Fails the session setup. - } + const DataContentDescription* offer_data_description = + offer_content->media_description()->as_data(); + if (!CreateMediaContentAnswer( + offer_data_description, media_description_options, session_options, + data_codecs, sdes_policy, GetCryptos(current_content), + RtpHeaderExtensions(), ssrc_generator_, + enable_encrypted_rtp_header_extensions_, current_streams, + bundle_enabled, data_answer.get())) { + return false; // Fails the session setup. } + // Respond with sctpmap if the offer uses sctpmap. + bool offer_uses_sctpmap = offer_data_description->use_sctpmap(); + data_answer->set_use_sctpmap(offer_uses_sctpmap); + bool secure = bundle_transport ? bundle_transport->description.secure() : data_transport->secure(); @@ -2654,26 +2571,20 @@ const MediaContentDescription* GetFirstMediaContentDescription( const AudioContentDescription* GetFirstAudioContentDescription( const SessionDescription* sdesc) { - auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO); - return desc ? desc->as_audio() : nullptr; + return static_cast( + GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO)); } const VideoContentDescription* GetFirstVideoContentDescription( const SessionDescription* sdesc) { - auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO); - return desc ? desc->as_video() : nullptr; + return static_cast( + GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO)); } const DataContentDescription* GetFirstDataContentDescription( const SessionDescription* sdesc) { - auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA); - return desc ? desc->as_data() : nullptr; -} - -const SctpDataContentDescription* GetFirstSctpDataContentDescription( - const SessionDescription* sdesc) { - auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA); - return desc ? desc->as_sctp() : nullptr; + return static_cast( + GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA)); } // @@ -2732,26 +2643,20 @@ MediaContentDescription* GetFirstMediaContentDescription( AudioContentDescription* GetFirstAudioContentDescription( SessionDescription* sdesc) { - auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO); - return desc ? desc->as_audio() : nullptr; + return static_cast( + GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO)); } VideoContentDescription* GetFirstVideoContentDescription( SessionDescription* sdesc) { - auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO); - return desc ? desc->as_video() : nullptr; + return static_cast( + GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO)); } DataContentDescription* GetFirstDataContentDescription( SessionDescription* sdesc) { - auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA); - return desc ? desc->as_data() : nullptr; -} - -SctpDataContentDescription* GetFirstSctpDataContentDescription( - SessionDescription* sdesc) { - auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA); - return desc ? desc->as_sctp() : nullptr; + return static_cast( + GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA)); } } // namespace cricket diff --git a/pc/media_session.h b/pc/media_session.h index 112508e5a4..33c8c17d37 100644 --- a/pc/media_session.h +++ b/pc/media_session.h @@ -24,7 +24,6 @@ #include "p2p/base/ice_credentials_iterator.h" #include "p2p/base/transport_description_factory.h" #include "pc/jsep_transport.h" -#include "pc/media_protocol_names.h" #include "pc/session_description.h" #include "rtc_base/unique_id_generator.h" @@ -240,23 +239,6 @@ class MediaSessionDescriptionFactory { SessionDescription* desc, IceCredentialsIterator* ice_credentials) const; - bool AddSctpDataContentForOffer( - const MediaDescriptionOptions& media_description_options, - const MediaSessionOptions& session_options, - const ContentInfo* current_content, - const SessionDescription* current_description, - StreamParamsVec* current_streams, - SessionDescription* desc, - IceCredentialsIterator* ice_credentials) const; - bool AddRtpDataContentForOffer( - const MediaDescriptionOptions& media_description_options, - const MediaSessionOptions& session_options, - const ContentInfo* current_content, - const SessionDescription* current_description, - const DataCodecs& data_codecs, - StreamParamsVec* current_streams, - SessionDescription* desc, - IceCredentialsIterator* ice_credentials) const; bool AddDataContentForOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, @@ -349,8 +331,6 @@ const VideoContentDescription* GetFirstVideoContentDescription( const SessionDescription* sdesc); const DataContentDescription* GetFirstDataContentDescription( const SessionDescription* sdesc); -const SctpDataContentDescription* GetFirstSctpDataContentDescription( - const SessionDescription* sdesc); // Non-const versions of the above functions. // Useful when modifying an existing description. ContentInfo* GetFirstMediaContent(ContentInfos* contents, MediaType media_type); @@ -368,8 +348,6 @@ VideoContentDescription* GetFirstVideoContentDescription( SessionDescription* sdesc); DataContentDescription* GetFirstDataContentDescription( SessionDescription* sdesc); -SctpDataContentDescription* GetFirstSctpDataContentDescription( - SessionDescription* sdesc); // Helper functions to return crypto suites used for SDES. void GetSupportedAudioSdesCryptoSuites( @@ -391,6 +369,9 @@ void GetSupportedDataSdesCryptoSuiteNames( const webrtc::CryptoOptions& crypto_options, std::vector* crypto_suite_names); +// Returns true if the given media section protocol indicates use of RTP. +bool IsRtpProtocol(const std::string& protocol); + } // namespace cricket #endif // PC_MEDIA_SESSION_H_ diff --git a/pc/media_session_unittest.cc b/pc/media_session_unittest.cc index bd01041488..11366071ce 100644 --- a/pc/media_session_unittest.cc +++ b/pc/media_session_unittest.cc @@ -62,7 +62,6 @@ using cricket::MediaSessionOptions; using cricket::MediaType; using cricket::RidDescription; using cricket::RidDirection; -using cricket::SctpDataContentDescription; using cricket::SEC_DISABLED; using cricket::SEC_ENABLED; using cricket::SEC_REQUIRED; @@ -1337,16 +1336,15 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) { ASSERT_TRUE(offer.get() != NULL); ContentInfo* dc_offer = offer->GetContentByName("data"); ASSERT_TRUE(dc_offer != NULL); - SctpDataContentDescription* dcd_offer = - dc_offer->media_description()->as_sctp(); + DataContentDescription* dcd_offer = dc_offer->media_description()->as_data(); EXPECT_TRUE(dcd_offer->use_sctpmap()); std::unique_ptr answer = f2_.CreateAnswer(offer.get(), opts, NULL); const ContentInfo* dc_answer = answer->GetContentByName("data"); ASSERT_TRUE(dc_answer != NULL); - const SctpDataContentDescription* dcd_answer = - dc_answer->media_description()->as_sctp(); + const DataContentDescription* dcd_answer = + dc_answer->media_description()->as_data(); EXPECT_TRUE(dcd_answer->use_sctpmap()); } @@ -1358,16 +1356,15 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) { ASSERT_TRUE(offer.get() != NULL); ContentInfo* dc_offer = offer->GetContentByName("data"); ASSERT_TRUE(dc_offer != NULL); - SctpDataContentDescription* dcd_offer = - dc_offer->media_description()->as_sctp(); + DataContentDescription* dcd_offer = dc_offer->media_description()->as_data(); dcd_offer->set_use_sctpmap(false); std::unique_ptr answer = f2_.CreateAnswer(offer.get(), opts, NULL); const ContentInfo* dc_answer = answer->GetContentByName("data"); ASSERT_TRUE(dc_answer != NULL); - const SctpDataContentDescription* dcd_answer = - dc_answer->media_description()->as_sctp(); + const DataContentDescription* dcd_answer = + dc_answer->media_description()->as_data(); EXPECT_FALSE(dcd_answer->use_sctpmap()); } @@ -1388,9 +1385,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, ASSERT_TRUE(offer.get() != nullptr); ContentInfo* dc_offer = offer->GetContentByName("data"); ASSERT_TRUE(dc_offer != nullptr); - SctpDataContentDescription* dcd_offer = - dc_offer->media_description()->as_sctp(); - ASSERT_TRUE(dcd_offer); + DataContentDescription* dcd_offer = dc_offer->media_description()->as_data(); std::vector protos = {"DTLS/SCTP", "UDP/DTLS/SCTP", "TCP/DTLS/SCTP"}; @@ -1400,8 +1395,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, f2_.CreateAnswer(offer.get(), opts, nullptr); const ContentInfo* dc_answer = answer->GetContentByName("data"); ASSERT_TRUE(dc_answer != nullptr); - const SctpDataContentDescription* dcd_answer = - dc_answer->media_description()->as_sctp(); + const DataContentDescription* dcd_answer = + dc_answer->media_description()->as_data(); EXPECT_FALSE(dc_answer->rejected); EXPECT_EQ(proto, dcd_answer->protocol()); } @@ -1485,8 +1480,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, ASSERT_TRUE(dc_offer != NULL); DataContentDescription* dcd_offer = dc_offer->media_description()->as_data(); ASSERT_TRUE(dcd_offer != NULL); - // Offer must be acceptable as an RTP protocol in order to be set. - std::string protocol = "RTP/a weird unknown protocol"; + std::string protocol = "a weird unknown protocol"; dcd_offer->set_protocol(protocol); std::unique_ptr answer = diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc index 21dfcd463d..8ac1e83543 100644 --- a/pc/peer_connection.cc +++ b/pc/peer_connection.cc @@ -558,13 +558,24 @@ bool VerifyIceUfragPwdPresent(const SessionDescription* desc) { // Get the SCTP port out of a SessionDescription. // Return -1 if not found. int GetSctpPort(const SessionDescription* session_description) { - const cricket::SctpDataContentDescription* data_desc = - GetFirstSctpDataContentDescription(session_description); + const cricket::DataContentDescription* data_desc = + GetFirstDataContentDescription(session_description); RTC_DCHECK(data_desc); if (!data_desc) { return -1; } - return data_desc->port(); + std::string value; + cricket::DataCodec match_pattern(cricket::kGoogleSctpDataCodecPlType, + cricket::kGoogleSctpDataCodecName); + for (const cricket::DataCodec& codec : data_desc->codecs()) { + if (!codec.Matches(match_pattern)) { + continue; + } + if (codec.GetParam(cricket::kCodecParamPort, &value)) { + return rtc::FromString(value); + } + } + return -1; } // Returns true if |new_desc| requests an ICE restart (i.e., new ufrag/pwd). @@ -2404,9 +2415,8 @@ RTCError PeerConnection::ApplyLocalDescription( if (data_content) { const cricket::DataContentDescription* data_desc = data_content->media_description()->as_data(); - // data_desc will be null if this is an SCTP description. - if (data_desc && absl::StartsWith(data_desc->protocol(), - cricket::kMediaProtocolRtpPrefix)) { + if (absl::StartsWith(data_desc->protocol(), + cricket::kMediaProtocolRtpPrefix)) { UpdateLocalRtpDataChannels(data_desc->streams()); } } diff --git a/pc/peer_connection_data_channel_unittest.cc b/pc/peer_connection_data_channel_unittest.cc index 4080dd98bb..ad3817e5b5 100644 --- a/pc/peer_connection_data_channel_unittest.cc +++ b/pc/peer_connection_data_channel_unittest.cc @@ -193,11 +193,14 @@ class PeerConnectionDataChannelBaseTest : public ::testing::Test { // Changes the SCTP data channel port on the given session description. void ChangeSctpPortOnDescription(cricket::SessionDescription* desc, int port) { + cricket::DataCodec sctp_codec(cricket::kGoogleSctpDataCodecPlType, + cricket::kGoogleSctpDataCodecName); + sctp_codec.SetParam(cricket::kCodecParamPort, port); + auto* data_content = cricket::GetFirstDataContent(desc); RTC_DCHECK(data_content); - auto* data_desc = data_content->media_description()->as_sctp(); - RTC_DCHECK(data_desc); - data_desc->set_port(port); + auto* data_desc = data_content->media_description()->as_data(); + data_desc->set_codecs({sctp_codec}); } std::unique_ptr vss_; diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc index a49ee39505..8aa76754bf 100644 --- a/pc/peer_connection_integrationtest.cc +++ b/pc/peer_connection_integrationtest.cc @@ -3443,8 +3443,8 @@ TEST_P(PeerConnectionIntegrationTest, SctpDataChannelToAudioVideoUpgrade) { } static void MakeSpecCompliantSctpOffer(cricket::SessionDescription* desc) { - cricket::SctpDataContentDescription* dcd_offer = - GetFirstSctpDataContentDescription(desc); + cricket::DataContentDescription* dcd_offer = + GetFirstDataContentDescription(desc); ASSERT_TRUE(dcd_offer); dcd_offer->set_use_sctpmap(false); dcd_offer->set_protocol("UDP/DTLS/SCTP"); diff --git a/pc/session_description.h b/pc/session_description.h index e5a7dfa3ee..7b70ddf556 100644 --- a/pc/session_description.h +++ b/pc/session_description.h @@ -26,7 +26,6 @@ #include "media/base/stream_params.h" #include "p2p/base/transport_description.h" #include "p2p/base/transport_info.h" -#include "pc/media_protocol_names.h" #include "pc/simulcast_description.h" #include "rtc_base/socket_address.h" @@ -45,6 +44,12 @@ extern const char kMediaProtocolSavpf[]; extern const char kMediaProtocolDtlsSavpf[]; +extern const char kMediaProtocolRtpPrefix[]; + +extern const char kMediaProtocolSctp[]; +extern const char kMediaProtocolDtlsSctp[]; +extern const char kMediaProtocolUdpDtlsSctp[]; +extern const char kMediaProtocolTcpDtlsSctp[]; // Options to control how session descriptions are generated. const int kAutoBandwidth = -1; @@ -52,7 +57,6 @@ const int kAutoBandwidth = -1; class AudioContentDescription; class DataContentDescription; class VideoContentDescription; -class SctpDataContentDescription; // Describes a session description media section. There are subclasses for each // media type (audio, video, data) that will have additional information. @@ -78,9 +82,6 @@ class MediaContentDescription { virtual DataContentDescription* as_data() { return nullptr; } virtual const DataContentDescription* as_data() const { return nullptr; } - virtual SctpDataContentDescription* as_sctp() { return nullptr; } - virtual const SctpDataContentDescription* as_sctp() const { return nullptr; } - virtual bool has_codecs() const = 0; virtual MediaContentDescription* Copy() const = 0; @@ -88,9 +89,7 @@ class MediaContentDescription { // |protocol| is the expected media transport protocol, such as RTP/AVPF, // RTP/SAVPF or SCTP/DTLS. std::string protocol() const { return protocol_; } - virtual void set_protocol(const std::string& protocol) { - protocol_ = protocol; - } + void set_protocol(const std::string& protocol) { protocol_ = protocol; } webrtc::RtpTransceiverDirection direction() const { return direction_; } void set_direction(webrtc::RtpTransceiverDirection direction) { @@ -248,17 +247,12 @@ using ContentDescription = MediaContentDescription; template class MediaContentDescriptionImpl : public MediaContentDescription { public: - void set_protocol(const std::string& protocol) override { - RTC_DCHECK(IsRtpProtocol(protocol)); - protocol_ = protocol; - } - typedef C CodecType; // Codecs should be in preference order (most preferred codec first). const std::vector& codecs() const { return codecs_; } void set_codecs(const std::vector& codecs) { codecs_ = codecs; } - bool has_codecs() const override { return !codecs_.empty(); } + virtual bool has_codecs() const { return !codecs_.empty(); } bool HasCodec(int id) { bool found = false; for (typename std::vector::iterator iter = codecs_.begin(); @@ -324,37 +318,12 @@ class DataContentDescription : public MediaContentDescriptionImpl { virtual MediaType type() const { return MEDIA_TYPE_DATA; } virtual DataContentDescription* as_data() { return this; } virtual const DataContentDescription* as_data() const { return this; } -}; - -class SctpDataContentDescription : public MediaContentDescription { - public: - SctpDataContentDescription() {} - SctpDataContentDescription* Copy() const override { - return new SctpDataContentDescription(*this); - } - MediaType type() const override { return MEDIA_TYPE_DATA; } - SctpDataContentDescription* as_sctp() override { return this; } - const SctpDataContentDescription* as_sctp() const override { return this; } - bool has_codecs() const override { return false; } - void set_protocol(const std::string& protocol) override { - RTC_DCHECK(IsSctpProtocol(protocol)); - protocol_ = protocol; - } bool use_sctpmap() const { return use_sctpmap_; } void set_use_sctpmap(bool enable) { use_sctpmap_ = enable; } - int port() const { return port_; } - void set_port(int port) { port_ = port; } - int max_message_size() const { return max_message_size_; } - void set_max_message_size(int max_message_size) { - max_message_size_ = max_message_size; - } private: - bool use_sctpmap_ = true; // Note: "true" is no longer conformant. - // Defaults should be constants imported from SCTP. Quick hack. - int port_ = 5000; - int max_message_size_ = 256 * 1024; + bool use_sctpmap_ = true; }; // Protocol used for encoding media. This is the "top level" protocol that may diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc index 7c65f87ca5..984a1e14a1 100644 --- a/pc/webrtc_sdp.cc +++ b/pc/webrtc_sdp.cc @@ -54,30 +54,29 @@ using cricket::Candidates; using cricket::ContentInfo; using cricket::CryptoParams; using cricket::DataContentDescription; -using cricket::ICE_CANDIDATE_COMPONENT_RTCP; using cricket::ICE_CANDIDATE_COMPONENT_RTP; -using cricket::kCodecParamAssociatedPayloadType; -using cricket::kCodecParamMaxAverageBitrate; +using cricket::ICE_CANDIDATE_COMPONENT_RTCP; using cricket::kCodecParamMaxBitrate; -using cricket::kCodecParamMaxPlaybackRate; using cricket::kCodecParamMaxPTime; using cricket::kCodecParamMaxQuantization; using cricket::kCodecParamMinBitrate; using cricket::kCodecParamMinPTime; using cricket::kCodecParamPTime; -using cricket::kCodecParamSctpProtocol; -using cricket::kCodecParamSctpStreams; using cricket::kCodecParamSPropStereo; using cricket::kCodecParamStartBitrate; using cricket::kCodecParamStereo; -using cricket::kCodecParamUseDtx; using cricket::kCodecParamUseInbandFec; +using cricket::kCodecParamUseDtx; +using cricket::kCodecParamSctpProtocol; +using cricket::kCodecParamSctpStreams; +using cricket::kCodecParamMaxAverageBitrate; +using cricket::kCodecParamMaxPlaybackRate; +using cricket::kCodecParamAssociatedPayloadType; using cricket::MediaContentDescription; -using cricket::MediaProtocolType; using cricket::MediaType; -using cricket::RidDescription; using cricket::RtpHeaderExtensions; -using cricket::SctpDataContentDescription; +using cricket::MediaProtocolType; +using cricket::RidDescription; using cricket::SimulcastDescription; using cricket::SimulcastLayer; using cricket::SimulcastLayerList; @@ -1338,6 +1337,8 @@ void BuildMediaDescription(const ContentInfo* content_info, const MediaContentDescription* media_desc = content_info->media_description(); RTC_DCHECK(media_desc); + int sctp_port = cricket::kSctpDefaultPort; + // RFC 4566 // m= // fmt is a list of payload type numbers that MAY be used in the session. @@ -1365,18 +1366,24 @@ void BuildMediaDescription(const ContentInfo* content_info, fmt.append(rtc::ToString(codec.id)); } } else if (media_type == cricket::MEDIA_TYPE_DATA) { + const DataContentDescription* data_desc = media_desc->as_data(); if (IsDtlsSctp(media_desc->protocol())) { - const cricket::SctpDataContentDescription* data_desc = - media_desc->as_sctp(); fmt.append(" "); if (data_desc->use_sctpmap()) { - fmt.append(rtc::ToString(data_desc->port())); + for (const cricket::DataCodec& codec : data_desc->codecs()) { + if (absl::EqualsIgnoreCase(codec.name, + cricket::kGoogleSctpDataCodecName) && + codec.GetParam(cricket::kCodecParamPort, &sctp_port)) { + break; + } + } + + fmt.append(rtc::ToString(sctp_port)); } else { fmt.append(kDefaultSctpmapProtocol); } } else { - const DataContentDescription* data_desc = media_desc->as_data(); for (const cricket::DataCodec& codec : data_desc->codecs()) { fmt.append(" "); fmt.append(rtc::ToString(codec.id)); @@ -1516,10 +1523,9 @@ void BuildMediaDescription(const ContentInfo* content_info, AddLine(os.str(), message); if (IsDtlsSctp(media_desc->protocol())) { - const cricket::SctpDataContentDescription* data_desc = - media_desc->as_sctp(); + const DataContentDescription* data_desc = media_desc->as_data(); bool use_sctpmap = data_desc->use_sctpmap(); - BuildSctpContentAttributes(message, data_desc->port(), use_sctpmap); + BuildSctpContentAttributes(message, sctp_port, use_sctpmap); } else if (IsRtp(media_desc->protocol())) { BuildRtpContentAttributes(media_desc, media_type, msid_signaling, message); } @@ -1828,6 +1834,43 @@ void AddRtcpFbLines(const T& codec, std::string* message) { } } +cricket::DataCodec FindOrMakeSctpDataCodec(DataContentDescription* media_desc) { + for (const auto& codec : media_desc->codecs()) { + if (absl::EqualsIgnoreCase(codec.name, cricket::kGoogleSctpDataCodecName)) { + return codec; + } + } + cricket::DataCodec codec_port(cricket::kGoogleSctpDataCodecPlType, + cricket::kGoogleSctpDataCodecName); + return codec_port; +} + +bool AddOrModifySctpDataCodecPort(DataContentDescription* media_desc, + int sctp_port) { + // Add the SCTP Port number as a pseudo-codec "port" parameter + auto codec = FindOrMakeSctpDataCodec(media_desc); + int dummy; + if (codec.GetParam(cricket::kCodecParamPort, &dummy)) { + return false; + } + codec.SetParam(cricket::kCodecParamPort, sctp_port); + media_desc->AddOrReplaceCodec(codec); + return true; +} + +bool AddOrModifySctpDataMaxMessageSize(DataContentDescription* media_desc, + int max_message_size) { + // Add the SCTP Max Message Size as a pseudo-parameter to the codec + auto codec = FindOrMakeSctpDataCodec(media_desc); + int dummy; + if (codec.GetParam(cricket::kCodecParamMaxMessageSize, &dummy)) { + return false; + } + codec.SetParam(cricket::kCodecParamMaxMessageSize, max_message_size); + media_desc->AddOrReplaceCodec(codec); + return true; +} + bool GetMinValue(const std::vector& values, int* value) { if (values.empty()) { return false; @@ -2705,30 +2748,24 @@ bool ParseMediaDescription( payload_types, pos, &content_name, &bundle_only, §ion_msid_signaling, &transport, candidates, error); } else if (HasAttribute(line, kMediaTypeData)) { - if (IsDtlsSctp(protocol)) { - auto data_desc = absl::make_unique(); + std::unique_ptr data_desc = + ParseContentDescription( + message, cricket::MEDIA_TYPE_DATA, mline_index, protocol, + payload_types, pos, &content_name, &bundle_only, + §ion_msid_signaling, &transport, candidates, error); + + if (data_desc && IsDtlsSctp(protocol)) { int p; if (rtc::FromString(fields[3], &p)) { - data_desc->set_port(p); + if (!AddOrModifySctpDataCodecPort(data_desc.get(), p)) { + return false; + } } else if (fields[3] == kDefaultSctpmapProtocol) { data_desc->set_use_sctpmap(false); } - if (!ParseContent(message, cricket::MEDIA_TYPE_DATA, mline_index, - protocol, payload_types, pos, &content_name, - &bundle_only, §ion_msid_signaling, - data_desc.get(), &transport, candidates, error)) { - return false; - } - content = std::move(data_desc); - } else { - // RTP - std::unique_ptr data_desc = - ParseContentDescription( - message, cricket::MEDIA_TYPE_DATA, mline_index, protocol, - payload_types, pos, &content_name, &bundle_only, - §ion_msid_signaling, &transport, candidates, error); - content = std::move(data_desc); } + + content = std::move(data_desc); } else { RTC_LOG(LS_WARNING) << "Unsupported media type: " << line; continue; @@ -3101,15 +3138,13 @@ bool ParseContent(const std::string& message, line, "sctp-port attribute found in non-data media description.", error); } - if (media_desc->as_sctp()->use_sctpmap()) { - return ParseFailed( - line, "sctp-port attribute can't be used with sctpmap.", error); - } int sctp_port; if (!ParseSctpPort(line, &sctp_port, error)) { return false; } - media_desc->as_sctp()->set_port(sctp_port); + if (!AddOrModifySctpDataCodecPort(media_desc->as_data(), sctp_port)) { + return false; + } } else if (IsDtlsSctp(protocol) && HasAttribute(line, kAttributeMaxMessageSize)) { if (media_type != cricket::MEDIA_TYPE_DATA) { @@ -3122,7 +3157,10 @@ bool ParseContent(const std::string& message, if (!ParseSctpMaxMessageSize(line, &max_message_size, error)) { return false; } - media_desc->as_sctp()->set_max_message_size(max_message_size); + if (!AddOrModifySctpDataMaxMessageSize(media_desc->as_data(), + max_message_size)) { + return false; + } } else if (IsRtp(protocol)) { // // RTP specific attrubtes diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc index 78fc8e0764..3de2b602dd 100644 --- a/pc/webrtc_sdp_unittest.cc +++ b/pc/webrtc_sdp_unittest.cc @@ -65,7 +65,6 @@ using cricket::MediaProtocolType; using cricket::RELAY_PORT_TYPE; using cricket::RidDescription; using cricket::RidDirection; -using cricket::SctpDataContentDescription; using cricket::SessionDescription; using cricket::SimulcastDescription; using cricket::SimulcastLayer; @@ -1446,15 +1445,8 @@ class WebRtcSdpTest : public ::testing::Test { void CompareDataContentDescription(const DataContentDescription* dcd1, const DataContentDescription* dcd2) { - CompareMediaContentDescription(dcd1, dcd2); - } - - void CompareSctpDataContentDescription( - const SctpDataContentDescription* dcd1, - const SctpDataContentDescription* dcd2) { EXPECT_EQ(dcd1->use_sctpmap(), dcd2->use_sctpmap()); - EXPECT_EQ(dcd1->port(), dcd2->port()); - EXPECT_EQ(dcd1->max_message_size(), dcd2->max_message_size()); + CompareMediaContentDescription(dcd1, dcd2); } void CompareSessionDescription(const SessionDescription& desc1, @@ -1492,21 +1484,10 @@ class WebRtcSdpTest : public ::testing::Test { } ASSERT_EQ(IsDataContent(&c1), IsDataContent(&c2)); - if (c1.media_description()->as_sctp()) { - ASSERT_TRUE(c2.media_description()->as_sctp()); - const SctpDataContentDescription* scd1 = - c1.media_description()->as_sctp(); - const SctpDataContentDescription* scd2 = - c2.media_description()->as_sctp(); - CompareSctpDataContentDescription(scd1, scd2); - } else { - if (IsDataContent(&c1)) { - const DataContentDescription* dcd1 = - c1.media_description()->as_data(); - const DataContentDescription* dcd2 = - c2.media_description()->as_data(); - CompareDataContentDescription(dcd1, dcd2); - } + if (IsDataContent(&c1)) { + const DataContentDescription* dcd1 = c1.media_description()->as_data(); + const DataContentDescription* dcd2 = c2.media_description()->as_data(); + CompareDataContentDescription(dcd1, dcd2); } CompareSimulcastDescription( @@ -1779,12 +1760,14 @@ class WebRtcSdpTest : public ::testing::Test { } void AddSctpDataChannel(bool use_sctpmap) { - std::unique_ptr data( - new SctpDataContentDescription()); - sctp_desc_ = data.get(); - sctp_desc_->set_use_sctpmap(use_sctpmap); - sctp_desc_->set_protocol(cricket::kMediaProtocolDtlsSctp); - sctp_desc_->set_port(kDefaultSctpPort); + std::unique_ptr data(new DataContentDescription()); + data_desc_ = data.get(); + data_desc_->set_use_sctpmap(use_sctpmap); + data_desc_->set_protocol(cricket::kMediaProtocolDtlsSctp); + DataCodec codec(cricket::kGoogleSctpDataCodecPlType, + cricket::kGoogleSctpDataCodecName); + codec.SetParam(cricket::kCodecParamPort, kDefaultSctpPort); + data_desc_->AddCodec(codec); desc_.AddContent(kDataContentName, MediaProtocolType::kSctp, data.release()); desc_.AddTransportInfo(TransportInfo( @@ -2061,7 +2044,6 @@ class WebRtcSdpTest : public ::testing::Test { AudioContentDescription* audio_desc_; VideoContentDescription* video_desc_; DataContentDescription* data_desc_; - SctpDataContentDescription* sctp_desc_; Candidates candidates_; std::unique_ptr jcandidate_; JsepSessionDescription jdesc_; @@ -2233,26 +2215,21 @@ TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) { EXPECT_EQ(message, expected_sdp); } -void MutateJsepSctpPort(JsepSessionDescription* jdesc, - const SessionDescription& desc, - int port) { - // Take our pre-built session description and change the SCTP port. - cricket::SessionDescription* mutant = desc.Copy(); - SctpDataContentDescription* dcdesc = - mutant->GetContentDescriptionByName(kDataContentName)->as_sctp(); - dcdesc->set_port(port); - // Note: mutant's owned by jdesc now. - ASSERT_TRUE(jdesc->Initialize(mutant, kSessionId, kSessionVersion)); -} - TEST_F(WebRtcSdpTest, SerializeWithSctpDataChannelAndNewPort) { bool use_sctpmap = true; AddSctpDataChannel(use_sctpmap); JsepSessionDescription jsep_desc(kDummyType); MakeDescriptionWithoutCandidates(&jsep_desc); + DataContentDescription* dcdesc = + jsep_desc.description() + ->GetContentDescriptionByName(kDataContentName) + ->as_data(); const int kNewPort = 1234; - MutateJsepSctpPort(&jsep_desc, desc_, kNewPort); + cricket::DataCodec codec(cricket::kGoogleSctpDataCodecPlType, + cricket::kGoogleSctpDataCodecName); + codec.SetParam(cricket::kCodecParamPort, kNewPort); + dcdesc->AddOrReplaceCodec(codec); std::string message = webrtc::SdpSerialize(jsep_desc); @@ -2891,12 +2868,14 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpColonPort) { // Helper function to set the max-message-size parameter in the // SCTP data codec. void MutateJsepSctpMaxMessageSize(const SessionDescription& desc, - int new_value, + const std::string& new_value, JsepSessionDescription* jdesc) { cricket::SessionDescription* mutant = desc.Copy(); - SctpDataContentDescription* dcdesc = - mutant->GetContentDescriptionByName(kDataContentName)->as_sctp(); - dcdesc->set_max_message_size(new_value); + DataContentDescription* dcdesc = + mutant->GetContentDescriptionByName(kDataContentName)->as_data(); + std::vector codecs(dcdesc->codecs()); + codecs[0].SetParam(cricket::kCodecParamMaxMessageSize, new_value); + dcdesc->set_codecs(codecs); jdesc->Initialize(mutant, kSessionId, kSessionVersion); } @@ -2908,7 +2887,7 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithMaxMessageSize) { sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort); sdp_with_data.append("a=max-message-size:12345\r\n"); - MutateJsepSctpMaxMessageSize(desc_, 12345, &jdesc); + MutateJsepSctpMaxMessageSize(desc_, "12345", &jdesc); JsepSessionDescription jdesc_output(kDummyType); // Verify with DTLS/SCTP. @@ -2958,13 +2937,29 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithCorruptedSctpDataChannels) { // No crash is a pass. } +void MutateJsepSctpPort(JsepSessionDescription* jdesc, + const SessionDescription& desc) { + // take our pre-built session description and change the SCTP port. + std::unique_ptr mutant = desc.Clone(); + DataContentDescription* dcdesc = + mutant->GetContentDescriptionByName(kDataContentName)->as_data(); + std::vector codecs(dcdesc->codecs()); + EXPECT_EQ(1U, codecs.size()); + EXPECT_EQ(cricket::kGoogleSctpDataCodecPlType, codecs[0].id); + codecs[0].SetParam(cricket::kCodecParamPort, kUnusualSctpPort); + dcdesc->set_codecs(codecs); + + ASSERT_TRUE( + jdesc->Initialize(std::move(mutant), kSessionId, kSessionVersion)); +} + TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndUnusualPort) { bool use_sctpmap = true; AddSctpDataChannel(use_sctpmap); // First setup the expected JsepSessionDescription. JsepSessionDescription jdesc(kDummyType); - MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort); + MutateJsepSctpPort(&jdesc, desc_); // Then get the deserialized JsepSessionDescription. std::string sdp_with_data = kSdpString; @@ -2984,7 +2979,7 @@ TEST_F(WebRtcSdpTest, AddSctpDataChannel(use_sctpmap); JsepSessionDescription jdesc(kDummyType); - MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort); + MutateJsepSctpPort(&jdesc, desc_); // We need to test the deserialized JsepSessionDescription from // kSdpSctpDataChannelStringWithSctpPort for @@ -3020,7 +3015,7 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) { bool use_sctpmap = true; AddSctpDataChannel(use_sctpmap); JsepSessionDescription jdesc(kDummyType); - SctpDataContentDescription* dcd = GetFirstSctpDataContentDescription(&desc_); + DataContentDescription* dcd = GetFirstDataContentDescription(&desc_); dcd->set_bandwidth(100 * 1000); ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));