From 14b2758726879d21671a21291dfed8fb4fd5c21c Mon Sep 17 00:00:00 2001 From: Harald Alvestrand Date: Sat, 4 May 2019 11:37:04 +0200 Subject: [PATCH] Version 2 "Refactoring DataContentDescription class" (substantial changes since version 1) This CL splits the cricket::DataContentDescription class into two classes: cricket::RtpDataContentDescription (used for RTP data) and cricket::SctpDataContentDescription (used for SCTP only). SctpDataContentDescription no longer inherits from MediaContentDescriptionImpl, and no longer contains "codecs". Due to usage of internal interfaces by consumers, shimming the old DataContentDescription API is needed. A new cricket::DataContentDescription class is defined, which is a shim over RtpDataContentDescription and SctpDataContentDescription. It exposes as little functionality as possible, but supports the concerned consumer's usage Design document: https://docs.google.com/document/d/1H5LfQxJA2ikMWTQ8FZ3_GAmaXM7knfVQWiSz6ph8VQ0/edit# Version 1 reviewed-on: https://webrtc-review.googlesource.com/c/src/+/132700 Bug: webrtc:10358 Change-Id: Icf95fb7308244d6f2ebfdb403aaffc544e358580 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/133900 Commit-Queue: Harald Alvestrand Reviewed-by: Steve Anton Cr-Commit-Position: refs/heads/master@{#27853} --- media/base/codec.cc | 16 +- media/base/codec.h | 20 +- media/base/rtp_data_engine.h | 3 +- pc/BUILD.gn | 8 + pc/channel.cc | 11 +- pc/channel.h | 2 +- pc/channel_unittest.cc | 12 +- pc/jsep_transport_controller_unittest.cc | 5 +- pc/media_protocol_names.cc | 41 ++ pc/media_protocol_names.h | 35 ++ pc/media_session.cc | 439 ++++++++++++-------- pc/media_session.h | 49 ++- pc/media_session_unittest.cc | 129 +++--- pc/peer_connection.cc | 41 +- pc/peer_connection_data_channel_unittest.cc | 9 +- pc/peer_connection_integrationtest.cc | 4 +- pc/session_description.cc | 419 +++++++++++++++++++ pc/session_description.h | 291 ++++++++++--- pc/session_description_unittest.cc | 61 ++- pc/webrtc_sdp.cc | 136 +++--- pc/webrtc_sdp_unittest.cc | 111 ++--- 21 files changed, 1350 insertions(+), 492 deletions(-) create mode 100644 pc/media_protocol_names.cc create mode 100644 pc/media_protocol_names.h diff --git a/media/base/codec.cc b/media/base/codec.cc index d0ca29b6f5..4380514957 100644 --- a/media/base/codec.cc +++ b/media/base/codec.cc @@ -334,22 +334,22 @@ bool VideoCodec::ValidateCodecFormat() const { return true; } -DataCodec::DataCodec(int id, const std::string& name) +RtpDataCodec::RtpDataCodec(int id, const std::string& name) : Codec(id, name, kDataCodecClockrate) {} -DataCodec::DataCodec() : Codec() { +RtpDataCodec::RtpDataCodec() : Codec() { clockrate = kDataCodecClockrate; } -DataCodec::DataCodec(const DataCodec& c) = default; -DataCodec::DataCodec(DataCodec&& c) = default; -DataCodec& DataCodec::operator=(const DataCodec& c) = default; -DataCodec& DataCodec::operator=(DataCodec&& c) = default; +RtpDataCodec::RtpDataCodec(const RtpDataCodec& c) = default; +RtpDataCodec::RtpDataCodec(RtpDataCodec&& c) = default; +RtpDataCodec& RtpDataCodec::operator=(const RtpDataCodec& c) = default; +RtpDataCodec& RtpDataCodec::operator=(RtpDataCodec&& c) = default; -std::string DataCodec::ToString() const { +std::string RtpDataCodec::ToString() const { char buf[256]; rtc::SimpleStringBuilder sb(buf); - sb << "DataCodec[" << id << ":" << name << "]"; + sb << "RtpDataCodec[" << id << ":" << name << "]"; return sb.str(); } diff --git a/media/base/codec.h b/media/base/codec.h index 091adb6cfa..bbb147d4a2 100644 --- a/media/base/codec.h +++ b/media/base/codec.h @@ -192,19 +192,23 @@ struct RTC_EXPORT VideoCodec : public Codec { void SetDefaultParameters(); }; -struct DataCodec : public Codec { - DataCodec(int id, const std::string& name); - DataCodec(); - DataCodec(const DataCodec& c); - DataCodec(DataCodec&& c); - ~DataCodec() override = default; +struct RtpDataCodec : public Codec { + RtpDataCodec(int id, const std::string& name); + RtpDataCodec(); + RtpDataCodec(const RtpDataCodec& c); + RtpDataCodec(RtpDataCodec&& c); + ~RtpDataCodec() override = default; - DataCodec& operator=(const DataCodec& c); - DataCodec& operator=(DataCodec&& c); + RtpDataCodec& operator=(const RtpDataCodec& c); + RtpDataCodec& operator=(RtpDataCodec&& c); std::string ToString() const; }; +// For backwards compatibility +// TODO(bugs.webrtc.org/10597): Remove when no longer needed. +typedef RtpDataCodec DataCodec; + // Get the codec setting associated with |payload_type|. If there // is no codec associated with that payload type it returns nullptr. template diff --git a/media/base/rtp_data_engine.h b/media/base/rtp_data_engine.h index a4647aef34..b8bfca2c03 100644 --- a/media/base/rtp_data_engine.h +++ b/media/base/rtp_data_engine.h @@ -16,6 +16,7 @@ #include #include +#include "media/base/codec.h" #include "media/base/media_channel.h" #include "media/base/media_constants.h" #include "media/base/media_engine.h" @@ -26,8 +27,6 @@ class DataRateLimiter; namespace cricket { -struct DataCodec; - class RtpDataEngine : public DataEngineInterface { public: RtpDataEngine(); diff --git a/pc/BUILD.gn b/pc/BUILD.gn index d4065208b2..e93fa7a0c1 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -72,6 +72,7 @@ rtc_static_library("rtc_pc_base") { ] deps = [ + ":media_protocol_names", "../api:array_view", "../api:audio_options_api", "../api:call_api", @@ -121,6 +122,13 @@ 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/channel.cc b/pc/channel.cc index 647663e250..82de7de381 100644 --- a/pc/channel.cc +++ b/pc/channel.cc @@ -1143,7 +1143,7 @@ bool RtpDataChannel::SendData(const SendDataParams& params, } bool RtpDataChannel::CheckDataChannelTypeFromContent( - const DataContentDescription* content, + const RtpDataContentDescription* content, std::string* error_desc) { bool is_sctp = ((content->protocol() == kMediaProtocolSctp) || (content->protocol() == kMediaProtocolDtlsSctp)); @@ -1169,7 +1169,7 @@ bool RtpDataChannel::SetLocalContent_w(const MediaContentDescription* content, return false; } - const DataContentDescription* data = content->as_data(); + const RtpDataContentDescription* data = content->as_rtp_data(); if (!CheckDataChannelTypeFromContent(data, error_desc)) { return false; @@ -1223,7 +1223,12 @@ bool RtpDataChannel::SetRemoteContent_w(const MediaContentDescription* content, return false; } - const DataContentDescription* data = content->as_data(); + const RtpDataContentDescription* data = content->as_rtp_data(); + + if (!data) { + RTC_LOG(LS_INFO) << "Accepting and ignoring non-RTP content description"; + return true; + } // If the remote data doesn't have codecs, it must be empty, so ignore it. if (!data->has_codecs()) { diff --git a/pc/channel.h b/pc/channel.h index 1a4cc72201..9747ec27cb 100644 --- a/pc/channel.h +++ b/pc/channel.h @@ -518,7 +518,7 @@ class RtpDataChannel : public BaseChannel { // overrides from BaseChannel // Checks that data channel type is RTP. - bool CheckDataChannelTypeFromContent(const DataContentDescription* content, + bool CheckDataChannelTypeFromContent(const RtpDataContentDescription* content, std::string* error_desc); bool SetLocalContent_w(const MediaContentDescription* content, webrtc::SdpType type, diff --git a/pc/channel_unittest.cc b/pc/channel_unittest.cc index 9c5f82b0d4..e31ab538e1 100644 --- a/pc/channel_unittest.cc +++ b/pc/channel_unittest.cc @@ -94,8 +94,8 @@ class VideoTraits : public Traits {}; @@ -2308,15 +2308,15 @@ void ChannelTest::CreateContent( int flags, const cricket::AudioCodec& audio_codec, const cricket::VideoCodec& video_codec, - cricket::DataContentDescription* data) { + cricket::RtpDataContentDescription* data) { data->AddCodec(kGoogleDataCodec); data->set_rtcp_mux((flags & RTCP_MUX) != 0); } template <> void ChannelTest::CopyContent( - const cricket::DataContentDescription& source, - cricket::DataContentDescription* data) { + const cricket::RtpDataContentDescription& source, + cricket::RtpDataContentDescription* data) { *data = source; } @@ -2330,7 +2330,7 @@ template <> void ChannelTest::AddLegacyStreamInContent( uint32_t ssrc, int flags, - cricket::DataContentDescription* data) { + cricket::RtpDataContentDescription* data) { data->AddLegacyStream(ssrc); } diff --git a/pc/jsep_transport_controller_unittest.cc b/pc/jsep_transport_controller_unittest.cc index e81b667514..c0927b9db4 100644 --- a/pc/jsep_transport_controller_unittest.cc +++ b/pc/jsep_transport_controller_unittest.cc @@ -175,8 +175,9 @@ class JsepTransportControllerTest : public JsepTransportController::Observer, cricket::IceMode ice_mode, cricket::ConnectionRole conn_role, rtc::scoped_refptr cert) { - std::unique_ptr data( - new cricket::DataContentDescription()); + RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp); + std::unique_ptr data( + new cricket::SctpDataContentDescription()); data->set_rtcp_mux(true); description->AddContent(mid, protocol_type, /*rejected=*/false, data.release()); diff --git a/pc/media_protocol_names.cc b/pc/media_protocol_names.cc new file mode 100644 index 0000000000..6ce2f02517 --- /dev/null +++ b/pc/media_protocol_names.cc @@ -0,0 +1,41 @@ +/* + * 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 new file mode 100644 index 0000000000..88f1c4659d --- /dev/null +++ b/pc/media_protocol_names.h @@ -0,0 +1,35 @@ +/* + * 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[]; + +bool IsDtlsSctp(const std::string& protocol); +bool IsPlainSctp(const std::string& protocol); + +// 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); + +} // namespace cricket + +#endif // PC_MEDIA_PROTOCOL_NAMES_H_ diff --git a/pc/media_session.cc b/pc/media_session.cc index 0eace22c6a..9c03a1e43a 100644 --- a/pc/media_session.cc +++ b/pc/media_session.cc @@ -27,6 +27,7 @@ #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" @@ -68,13 +69,6 @@ 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. @@ -91,20 +85,6 @@ 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) { @@ -489,7 +469,7 @@ static bool AddStreamParams( StreamParamsVec* current_streams, MediaContentDescriptionImpl* content_description) { // SCTP streams are not negotiated using SDP/ContentDescriptions. - if (IsSctp(content_description->protocol())) { + if (IsSctpProtocol(content_description->protocol())) { return true; } @@ -608,11 +588,6 @@ 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; @@ -741,32 +716,22 @@ 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. -template -static bool CreateMediaContentOffer( +static bool CreateContentOffer( 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); - + MediaContentDescription* offer) { 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) { @@ -785,6 +750,30 @@ static bool CreateMediaContentOffer( } 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, @@ -1186,6 +1175,28 @@ 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, + media_description_options.codec_preferences.empty()); + 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 @@ -1193,12 +1204,10 @@ static void StripCNCodecs(AudioCodecs* audio_codecs) { // (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 MediaContentDescriptionImpl* offer, + const MediaContentDescription* 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, @@ -1206,13 +1215,7 @@ static bool CreateMediaContentAnswer( bool enable_encrypted_rtp_header_extensions, StreamParamsVec* current_streams, bool bundle_enabled, - MediaContentDescriptionImpl* answer) { - std::vector negotiated_codecs; - NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs, - media_description_options.codec_preferences.empty()); - answer->AddCodecs(negotiated_codecs); - answer->set_protocol(offer->protocol()); - + MediaContentDescription* answer) { answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum()); RtpHeaderExtensions negotiated_rtp_extensions; NegotiateRtpHeaderExtensions( @@ -1240,12 +1243,6 @@ 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( @@ -1397,7 +1394,7 @@ MediaSessionDescriptionFactory::MediaSessionDescriptionFactory( channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_); channel_manager->GetSupportedVideoCodecs(&video_codecs_); channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_); - channel_manager->GetSupportedDataCodecs(&data_codecs_); + channel_manager->GetSupportedDataCodecs(&rtp_data_codecs_); ComputeAudioCodecsIntersectionAndUnion(); } @@ -1484,15 +1481,15 @@ std::unique_ptr MediaSessionDescriptionFactory::CreateOffer( AudioCodecs offer_audio_codecs; VideoCodecs offer_video_codecs; - DataCodecs offer_data_codecs; + RtpDataCodecs offer_rtp_data_codecs; GetCodecsForOffer(current_active_contents, &offer_audio_codecs, - &offer_video_codecs, &offer_data_codecs); + &offer_video_codecs, &offer_rtp_data_codecs); if (!session_options.vad_enabled) { // If application doesn't want CN codecs in offer. StripCNCodecs(&offer_audio_codecs); } - FilterDataCodecs(&offer_data_codecs, + FilterDataCodecs(&offer_rtp_data_codecs, session_options.data_channel_type == DCT_SCTP); RtpHeaderExtensions audio_rtp_extensions; @@ -1536,7 +1533,7 @@ std::unique_ptr MediaSessionDescriptionFactory::CreateOffer( case MEDIA_TYPE_DATA: if (!AddDataContentForOffer(media_description_options, session_options, current_content, current_description, - offer_data_codecs, ¤t_streams, + offer_rtp_data_codecs, ¤t_streams, offer.get(), &ice_credentials)) { return nullptr; } @@ -1634,15 +1631,15 @@ MediaSessionDescriptionFactory::CreateAnswer( // sections. AudioCodecs answer_audio_codecs; VideoCodecs answer_video_codecs; - DataCodecs answer_data_codecs; + RtpDataCodecs answer_rtp_data_codecs; GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs, - &answer_video_codecs, &answer_data_codecs); + &answer_video_codecs, &answer_rtp_data_codecs); if (!session_options.vad_enabled) { // If application doesn't want CN codecs in answer. StripCNCodecs(&answer_audio_codecs); } - FilterDataCodecs(&answer_data_codecs, + FilterDataCodecs(&answer_rtp_data_codecs, session_options.data_channel_type == DCT_SCTP); auto answer = absl::make_unique(); @@ -1695,8 +1692,8 @@ MediaSessionDescriptionFactory::CreateAnswer( if (!AddDataContentForAnswer( media_description_options, session_options, offer_content, offer, current_content, current_description, - bundle_transport.get(), answer_data_codecs, ¤t_streams, - answer.get(), &ice_credentials)) { + bundle_transport.get(), answer_rtp_data_codecs, + ¤t_streams, answer.get(), &ice_credentials)) { return nullptr; } break; @@ -1816,7 +1813,7 @@ void MergeCodecsFromDescription( const std::vector& current_active_contents, AudioCodecs* audio_codecs, VideoCodecs* video_codecs, - DataCodecs* data_codecs, + RtpDataCodecs* rtp_data_codecs, UsedPayloadTypes* used_pltypes) { for (const ContentInfo* content : current_active_contents) { if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) { @@ -1828,9 +1825,13 @@ void MergeCodecsFromDescription( content->media_description()->as_video(); MergeCodecs(video->codecs(), video_codecs, used_pltypes); } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) { - const DataContentDescription* data = - content->media_description()->as_data(); - MergeCodecs(data->codecs(), data_codecs, used_pltypes); + const RtpDataContentDescription* data = + content->media_description()->as_rtp_data(); + if (data) { + // Only relevant for RTP datachannels + MergeCodecs(data->codecs(), rtp_data_codecs, + used_pltypes); + } } } } @@ -1845,18 +1846,18 @@ void MediaSessionDescriptionFactory::GetCodecsForOffer( const std::vector& current_active_contents, AudioCodecs* audio_codecs, VideoCodecs* video_codecs, - DataCodecs* data_codecs) const { + RtpDataCodecs* rtp_data_codecs) const { // First - get all codecs from the current description if the media type // is used. Add them to |used_pltypes| so the payload type is not reused if a // new media type is added. UsedPayloadTypes used_pltypes; MergeCodecsFromDescription(current_active_contents, audio_codecs, - video_codecs, data_codecs, &used_pltypes); + video_codecs, rtp_data_codecs, &used_pltypes); // Add our codecs that are not in the current description. MergeCodecs(all_audio_codecs_, audio_codecs, &used_pltypes); MergeCodecs(video_codecs_, video_codecs, &used_pltypes); - MergeCodecs(data_codecs_, data_codecs, &used_pltypes); + MergeCodecs(rtp_data_codecs_, rtp_data_codecs, &used_pltypes); } // Getting codecs for an answer involves these steps: @@ -1871,18 +1872,18 @@ void MediaSessionDescriptionFactory::GetCodecsForAnswer( const SessionDescription& remote_offer, AudioCodecs* audio_codecs, VideoCodecs* video_codecs, - DataCodecs* data_codecs) const { + RtpDataCodecs* rtp_data_codecs) const { // First - get all codecs from the current description if the media type // is used. Add them to |used_pltypes| so the payload type is not reused if a // new media type is added. UsedPayloadTypes used_pltypes; MergeCodecsFromDescription(current_active_contents, audio_codecs, - video_codecs, data_codecs, &used_pltypes); + video_codecs, rtp_data_codecs, &used_pltypes); // Second - filter out codecs that we don't support at all and should ignore. AudioCodecs filtered_offered_audio_codecs; VideoCodecs filtered_offered_video_codecs; - DataCodecs filtered_offered_data_codecs; + RtpDataCodecs filtered_offered_rtp_data_codecs; for (const ContentInfo& content : remote_offer.contents()) { if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) { const AudioContentDescription* audio = @@ -1909,15 +1910,19 @@ void MediaSessionDescriptionFactory::GetCodecsForAnswer( } } } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) { - const DataContentDescription* data = - content.media_description()->as_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); + const RtpDataContentDescription* data = + content.media_description()->as_rtp_data(); + if (data) { + // RTP data. This part is inactive for SCTP data. + for (const RtpDataCodec& offered_rtp_data_codec : data->codecs()) { + if (!FindMatchingCodec( + data->codecs(), filtered_offered_rtp_data_codecs, + offered_rtp_data_codec, nullptr) && + FindMatchingCodec(data->codecs(), rtp_data_codecs_, + offered_rtp_data_codec, + nullptr)) { + filtered_offered_rtp_data_codecs.push_back(offered_rtp_data_codec); + } } } } @@ -1929,7 +1934,7 @@ void MediaSessionDescriptionFactory::GetCodecsForAnswer( &used_pltypes); MergeCodecs(filtered_offered_video_codecs, video_codecs, &used_pltypes); - MergeCodecs(filtered_offered_data_codecs, data_codecs, + MergeCodecs(filtered_offered_rtp_data_codecs, rtp_data_codecs, &used_pltypes); } @@ -2206,18 +2211,101 @@ 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 RtpDataCodecs& rtp_data_codecs, + StreamParamsVec* current_streams, + SessionDescription* desc, + IceCredentialsIterator* ice_credentials) const { + std::unique_ptr data( + new RtpDataContentDescription()); + 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, + rtp_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, const ContentInfo* current_content, const SessionDescription* current_description, - const DataCodecs& data_codecs, + const RtpDataCodecs& rtp_data_codecs, 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. @@ -2226,52 +2314,16 @@ 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) { - // 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); + return AddSctpDataContentForOffer( + media_description_options, session_options, current_content, + current_description, current_streams, desc, ice_credentials); } else { - GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options, - &crypto_suites); + return AddRtpDataContentForOffer(media_description_options, session_options, + current_content, current_description, + rtp_data_codecs, current_streams, desc, + ice_credentials); } - - // 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 @@ -2359,9 +2411,15 @@ 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, - filtered_codecs, sdes_policy, GetCryptos(current_content), + sdes_policy, GetCryptos(current_content), audio_rtp_header_extensions(), ssrc_generator_, enable_encrypted_rtp_header_extensions_, current_streams, bundle_enabled, audio_answer.get())) { @@ -2454,9 +2512,15 @@ 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, - filtered_codecs, sdes_policy, GetCryptos(current_content), + sdes_policy, GetCryptos(current_content), video_rtp_header_extensions(), ssrc_generator_, enable_encrypted_rtp_header_extensions_, current_streams, bundle_enabled, video_answer.get())) { @@ -2492,7 +2556,7 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer( const ContentInfo* current_content, const SessionDescription* current_description, const TransportInfo* bundle_transport, - const DataCodecs& data_codecs, + const RtpDataCodecs& rtp_data_codecs, StreamParamsVec* current_streams, SessionDescription* answer, IceCredentialsIterator* ice_credentials) const { @@ -2504,28 +2568,51 @@ 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)); - 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. - } + 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(); - // 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); + const RtpDataContentDescription* offer_data_description = + offer_content->media_description()->as_rtp_data(); + RTC_CHECK(offer_data_description); + if (!SetCodecsInAnswer(offer_data_description, rtp_data_codecs, + media_description_options, session_options, + ssrc_generator_, current_streams, + data_answer->as_rtp_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. + } + } bool secure = bundle_transport ? bundle_transport->description.secure() : data_transport->secure(); @@ -2649,20 +2736,35 @@ const MediaContentDescription* GetFirstMediaContentDescription( const AudioContentDescription* GetFirstAudioContentDescription( const SessionDescription* sdesc) { - return static_cast( - GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO)); + auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO); + return desc ? desc->as_audio() : nullptr; } const VideoContentDescription* GetFirstVideoContentDescription( const SessionDescription* sdesc) { - return static_cast( - GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO)); + auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO); + return desc ? desc->as_video() : nullptr; } +const RtpDataContentDescription* GetFirstRtpDataContentDescription( + const SessionDescription* sdesc) { + auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA); + return desc ? desc->as_rtp_data() : nullptr; +} + +const SctpDataContentDescription* GetFirstSctpDataContentDescription( + const SessionDescription* sdesc) { + auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA); + return desc ? desc->as_sctp() : nullptr; +} + +// Returns a shim representing either an SctpDataContentDescription +// or an RtpDataContentDescription, as appropriate. +// TODO(bugs.webrtc.org/10597): Remove together with shim. const DataContentDescription* GetFirstDataContentDescription( const SessionDescription* sdesc) { - return static_cast( - GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA)); + auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA); + return desc ? desc->as_data() : nullptr; } // @@ -2721,20 +2823,33 @@ MediaContentDescription* GetFirstMediaContentDescription( AudioContentDescription* GetFirstAudioContentDescription( SessionDescription* sdesc) { - return static_cast( - GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO)); + auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO); + return desc ? desc->as_audio() : nullptr; } VideoContentDescription* GetFirstVideoContentDescription( SessionDescription* sdesc) { - return static_cast( - GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO)); + auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO); + return desc ? desc->as_video() : nullptr; } +RtpDataContentDescription* GetFirstRtpDataContentDescription( + SessionDescription* sdesc) { + auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA); + return desc ? desc->as_rtp_data() : nullptr; +} + +SctpDataContentDescription* GetFirstSctpDataContentDescription( + SessionDescription* sdesc) { + auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA); + return desc ? desc->as_sctp() : nullptr; +} + +// Returns shim DataContentDescription* GetFirstDataContentDescription( SessionDescription* sdesc) { - return static_cast( - GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA)); + auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA); + return desc ? desc->as_data() : nullptr; } } // namespace cricket diff --git a/pc/media_session.h b/pc/media_session.h index a369756964..dc889b215f 100644 --- a/pc/media_session.h +++ b/pc/media_session.h @@ -24,6 +24,7 @@ #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" @@ -154,8 +155,10 @@ class MediaSessionDescriptionFactory { video_rtp_extensions_ = extensions; } RtpHeaderExtensions video_rtp_header_extensions() const; - const DataCodecs& data_codecs() const { return data_codecs_; } - void set_data_codecs(const DataCodecs& codecs) { data_codecs_ = codecs; } + const RtpDataCodecs& rtp_data_codecs() const { return rtp_data_codecs_; } + void set_rtp_data_codecs(const RtpDataCodecs& codecs) { + rtp_data_codecs_ = codecs; + } SecurePolicy secure() const { return secure_; } void set_secure(SecurePolicy s) { secure_ = s; } @@ -185,13 +188,13 @@ class MediaSessionDescriptionFactory { const std::vector& current_active_contents, AudioCodecs* audio_codecs, VideoCodecs* video_codecs, - DataCodecs* data_codecs) const; + RtpDataCodecs* rtp_data_codecs) const; void GetCodecsForAnswer( const std::vector& current_active_contents, const SessionDescription& remote_offer, AudioCodecs* audio_codecs, VideoCodecs* video_codecs, - DataCodecs* data_codecs) const; + RtpDataCodecs* rtp_data_codecs) const; void GetRtpHdrExtsToOffer( const std::vector& current_active_contents, RtpHeaderExtensions* audio_extensions, @@ -240,12 +243,32 @@ 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 RtpDataCodecs& rtp_data_codecs, + StreamParamsVec* current_streams, + SessionDescription* desc, + IceCredentialsIterator* ice_credentials) const; + // This function calls either AddRtpDataContentForOffer or + // AddSctpDataContentForOffer depending on protocol. + // The codecs argument is ignored for SCTP. bool AddDataContentForOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* current_content, const SessionDescription* current_description, - const DataCodecs& data_codecs, + const RtpDataCodecs& rtp_data_codecs, StreamParamsVec* current_streams, SessionDescription* desc, IceCredentialsIterator* ice_credentials) const; @@ -284,7 +307,7 @@ class MediaSessionDescriptionFactory { const ContentInfo* current_content, const SessionDescription* current_description, const TransportInfo* bundle_transport, - const DataCodecs& data_codecs, + const RtpDataCodecs& rtp_data_codecs, StreamParamsVec* current_streams, SessionDescription* answer, IceCredentialsIterator* ice_credentials) const; @@ -301,7 +324,7 @@ class MediaSessionDescriptionFactory { RtpHeaderExtensions audio_rtp_extensions_; VideoCodecs video_codecs_; RtpHeaderExtensions video_rtp_extensions_; - DataCodecs data_codecs_; + RtpDataCodecs rtp_data_codecs_; // This object is not owned by the channel so it must outlive it. rtc::UniqueRandomIdGenerator* const ssrc_generator_; bool enable_encrypted_rtp_header_extensions_ = false; @@ -330,6 +353,11 @@ const AudioContentDescription* GetFirstAudioContentDescription( const SessionDescription* sdesc); const VideoContentDescription* GetFirstVideoContentDescription( const SessionDescription* sdesc); +const RtpDataContentDescription* GetFirstRtpDataContentDescription( + const SessionDescription* sdesc); +const SctpDataContentDescription* GetFirstSctpDataContentDescription( + const SessionDescription* sdesc); +// Returns shim. Deprecated - ask for the right protocol instead. const DataContentDescription* GetFirstDataContentDescription( const SessionDescription* sdesc); // Non-const versions of the above functions. @@ -347,6 +375,10 @@ AudioContentDescription* GetFirstAudioContentDescription( SessionDescription* sdesc); VideoContentDescription* GetFirstVideoContentDescription( SessionDescription* sdesc); +RtpDataContentDescription* GetFirstRtpDataContentDescription( + SessionDescription* sdesc); +SctpDataContentDescription* GetFirstSctpDataContentDescription( + SessionDescription* sdesc); DataContentDescription* GetFirstDataContentDescription( SessionDescription* sdesc); @@ -370,9 +402,6 @@ 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 11366071ce..b69ded3e1f 100644 --- a/pc/media_session_unittest.cc +++ b/pc/media_session_unittest.cc @@ -42,12 +42,10 @@ using cricket::AudioCodec; using cricket::AudioContentDescription; using cricket::ContentInfo; using cricket::CryptoParamsVec; -using cricket::DataCodec; -using cricket::DataContentDescription; using cricket::GetFirstAudioContent; using cricket::GetFirstAudioContentDescription; using cricket::GetFirstDataContent; -using cricket::GetFirstDataContentDescription; +using cricket::GetFirstRtpDataContentDescription; using cricket::GetFirstVideoContent; using cricket::GetFirstVideoContentDescription; using cricket::kAutoBandwidth; @@ -62,6 +60,9 @@ using cricket::MediaSessionOptions; using cricket::MediaType; using cricket::RidDescription; using cricket::RidDirection; +using cricket::RtpDataCodec; +using cricket::RtpDataContentDescription; +using cricket::SctpDataContentDescription; using cricket::SEC_DISABLED; using cricket::SEC_ENABLED; using cricket::SEC_REQUIRED; @@ -126,14 +127,14 @@ static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"), static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")}; -static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"), - DataCodec(99, "utf8-text")}; +static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"), + RtpDataCodec(99, "utf8-text")}; -static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"), - DataCodec(127, "utf8-text")}; +static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"), + RtpDataCodec(127, "utf8-text")}; -static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"), - DataCodec(99, "utf8-text")}; +static const RtpDataCodec kDataCodecsAnswer[] = { + RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")}; static const RtpExtension kAudioRtpExtension1[] = { RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8), @@ -412,11 +413,11 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1), MAKE_VECTOR(kAudioCodecs1)); f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1)); - f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1)); + f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1)); f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2), MAKE_VECTOR(kAudioCodecs2)); f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2)); - f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2)); + f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2)); tdf1_.set_certificate(rtc::RTCCertificate::Create( std::unique_ptr(new rtc::FakeSSLIdentity("id1")))); tdf2_.set_certificate(rtc::RTCCertificate::Create( @@ -801,7 +802,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) { TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) { const VideoCodec& offered_video_codec = f2_.video_codecs()[0]; const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0]; - const DataCodec& offered_data_codec = f2_.data_codecs()[0]; + const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0]; ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id); ASSERT_EQ(offered_video_codec.id, offered_data_codec.id); @@ -814,8 +815,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) { GetFirstVideoContentDescription(offer.get()); const AudioContentDescription* acd = GetFirstAudioContentDescription(offer.get()); - const DataContentDescription* dcd = - GetFirstDataContentDescription(offer.get()); + const RtpDataContentDescription* dcd = + GetFirstRtpDataContentDescription(offer.get()); ASSERT_TRUE(NULL != vcd); ASSERT_TRUE(NULL != acd); ASSERT_TRUE(NULL != dcd); @@ -858,8 +859,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, GetFirstAudioContentDescription(updated_offer.get()); const VideoContentDescription* vcd = GetFirstVideoContentDescription(updated_offer.get()); - const DataContentDescription* dcd = - GetFirstDataContentDescription(updated_offer.get()); + const RtpDataContentDescription* dcd = + GetFirstRtpDataContentDescription(updated_offer.get()); EXPECT_TRUE(NULL != vcd); EXPECT_TRUE(NULL != acd); EXPECT_TRUE(NULL != dcd); @@ -887,7 +888,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) { EXPECT_EQ(MediaProtocolType::kRtp, ac->type); EXPECT_EQ(MediaProtocolType::kRtp, dc->type); const AudioContentDescription* acd = ac->media_description()->as_audio(); - const DataContentDescription* dcd = dc->media_description()->as_data(); + const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data(); EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type()); EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs()); EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched. @@ -896,7 +897,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) { ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite); EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol()); EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type()); - EXPECT_EQ(f1_.data_codecs(), dcd->codecs()); + EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs()); EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached. EXPECT_EQ(cricket::kDataMaxBandwidth, dcd->bandwidth()); // default bandwidth (auto) @@ -1280,7 +1281,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) { EXPECT_EQ(MediaProtocolType::kRtp, ac->type); EXPECT_EQ(MediaProtocolType::kRtp, dc->type); const AudioContentDescription* acd = ac->media_description()->as_audio(); - const DataContentDescription* dcd = dc->media_description()->as_data(); + const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data(); EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type()); EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer)); EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw @@ -1312,7 +1313,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) { EXPECT_EQ(MediaProtocolType::kRtp, ac->type); EXPECT_EQ(MediaProtocolType::kRtp, dc->type); const AudioContentDescription* acd = ac->media_description()->as_audio(); - const DataContentDescription* dcd = dc->media_description()->as_data(); + const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data(); EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type()); EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer)); EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw @@ -1336,15 +1337,16 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) { ASSERT_TRUE(offer.get() != NULL); ContentInfo* dc_offer = offer->GetContentByName("data"); ASSERT_TRUE(dc_offer != NULL); - DataContentDescription* dcd_offer = dc_offer->media_description()->as_data(); + SctpDataContentDescription* dcd_offer = + dc_offer->media_description()->as_sctp(); 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 DataContentDescription* dcd_answer = - dc_answer->media_description()->as_data(); + const SctpDataContentDescription* dcd_answer = + dc_answer->media_description()->as_sctp(); EXPECT_TRUE(dcd_answer->use_sctpmap()); } @@ -1356,15 +1358,16 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) { ASSERT_TRUE(offer.get() != NULL); ContentInfo* dc_offer = offer->GetContentByName("data"); ASSERT_TRUE(dc_offer != NULL); - DataContentDescription* dcd_offer = dc_offer->media_description()->as_data(); + SctpDataContentDescription* dcd_offer = + dc_offer->media_description()->as_sctp(); 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 DataContentDescription* dcd_answer = - dc_answer->media_description()->as_data(); + const SctpDataContentDescription* dcd_answer = + dc_answer->media_description()->as_sctp(); EXPECT_FALSE(dcd_answer->use_sctpmap()); } @@ -1385,7 +1388,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, ASSERT_TRUE(offer.get() != nullptr); ContentInfo* dc_offer = offer->GetContentByName("data"); ASSERT_TRUE(dc_offer != nullptr); - DataContentDescription* dcd_offer = dc_offer->media_description()->as_data(); + SctpDataContentDescription* dcd_offer = + dc_offer->media_description()->as_sctp(); + ASSERT_TRUE(dcd_offer); std::vector protos = {"DTLS/SCTP", "UDP/DTLS/SCTP", "TCP/DTLS/SCTP"}; @@ -1395,8 +1400,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, f2_.CreateAnswer(offer.get(), opts, nullptr); const ContentInfo* dc_answer = answer->GetContentByName("data"); ASSERT_TRUE(dc_answer != nullptr); - const DataContentDescription* dcd_answer = - dc_answer->media_description()->as_data(); + const SctpDataContentDescription* dcd_answer = + dc_answer->media_description()->as_sctp(); EXPECT_FALSE(dc_answer->rejected); EXPECT_EQ(proto, dcd_answer->protocol()); } @@ -1478,9 +1483,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, std::unique_ptr offer = f1_.CreateOffer(opts, NULL); ContentInfo* dc_offer = offer->GetContentByName("data"); ASSERT_TRUE(dc_offer != NULL); - DataContentDescription* dcd_offer = dc_offer->media_description()->as_data(); + RtpDataContentDescription* dcd_offer = + dc_offer->media_description()->as_rtp_data(); ASSERT_TRUE(dcd_offer != NULL); - std::string protocol = "a weird unknown protocol"; + // Offer must be acceptable as an RTP protocol in order to be set. + std::string protocol = "RTP/a weird unknown protocol"; dcd_offer->set_protocol(protocol); std::unique_ptr answer = @@ -1489,8 +1496,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, const ContentInfo* dc_answer = answer->GetContentByName("data"); ASSERT_TRUE(dc_answer != NULL); EXPECT_TRUE(dc_answer->rejected); - const DataContentDescription* dcd_answer = - dc_answer->media_description()->as_data(); + const RtpDataContentDescription* dcd_answer = + dc_answer->media_description()->as_rtp_data(); ASSERT_TRUE(dcd_answer != NULL); EXPECT_EQ(protocol, dcd_answer->protocol()); } @@ -1688,7 +1695,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, ASSERT_TRUE(vc != NULL); const AudioContentDescription* acd = ac->media_description()->as_audio(); const VideoContentDescription* vcd = vc->media_description()->as_video(); - const DataContentDescription* dcd = dc->media_description()->as_data(); + const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data(); EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams. EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams. @@ -1716,16 +1723,16 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) { answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL); ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get())); ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get())); + ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get())); ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get())); ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get())); - ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get())); + ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get())); EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux()); EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux()); - EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux()); + EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux()); EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux()); EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux()); - EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux()); + EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux()); offer_opts.rtcp_mux_enabled = true; answer_opts.rtcp_mux_enabled = false; @@ -1733,16 +1740,16 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) { answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL); ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get())); ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get())); + ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get())); ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get())); ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get())); - ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get())); + ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get())); EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux()); EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux()); - EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux()); + EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux()); - EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux()); + EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux()); offer_opts.rtcp_mux_enabled = false; answer_opts.rtcp_mux_enabled = true; @@ -1750,16 +1757,16 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) { answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL); ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get())); ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get())); + ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get())); ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get())); ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get())); - ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get())); + ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get())); EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux()); - EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux()); + EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux()); - EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux()); + EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux()); offer_opts.rtcp_mux_enabled = false; answer_opts.rtcp_mux_enabled = false; @@ -1767,16 +1774,16 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) { answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL); ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get())); ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get())); + ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get())); ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get())); ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get())); - ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get())); + ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get())); EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux()); - EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux()); + EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux()); - EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux()); + EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux()); } // Create an audio-only answer to a video offer. @@ -1948,7 +1955,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) { ASSERT_TRUE(dc != NULL); const AudioContentDescription* acd = ac->media_description()->as_audio(); const VideoContentDescription* vcd = vc->media_description()->as_video(); - const DataContentDescription* dcd = dc->media_description()->as_data(); + const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data(); EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type()); EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs()); @@ -1978,7 +1985,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) { EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type()); - EXPECT_EQ(f1_.data_codecs(), dcd->codecs()); + EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs()); ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite); const StreamParamsVec& data_streams = dcd->streams(); @@ -2020,8 +2027,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) { ac->media_description()->as_audio(); const VideoContentDescription* updated_vcd = vc->media_description()->as_video(); - const DataContentDescription* updated_dcd = - dc->media_description()->as_data(); + const RtpDataContentDescription* updated_dcd = + dc->media_description()->as_rtp_data(); EXPECT_EQ(acd->type(), updated_acd->type()); EXPECT_EQ(acd->codecs(), updated_acd->codecs()); @@ -2307,7 +2314,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) { ASSERT_TRUE(dc != NULL); const AudioContentDescription* acd = ac->media_description()->as_audio(); const VideoContentDescription* vcd = vc->media_description()->as_video(); - const DataContentDescription* dcd = dc->media_description()->as_data(); + const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data(); ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite); ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite); ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite); @@ -2375,8 +2382,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) { ac->media_description()->as_audio(); const VideoContentDescription* updated_vcd = vc->media_description()->as_video(); - const DataContentDescription* updated_dcd = - dc->media_description()->as_data(); + const RtpDataContentDescription* updated_dcd = + dc->media_description()->as_rtp_data(); ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite); EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos())); @@ -3536,8 +3543,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) { const VideoContentDescription* video_offer = GetFirstVideoContentDescription(offer.get()); ASSERT_TRUE(video_offer->cryptos().empty()); - const DataContentDescription* data_offer = - GetFirstDataContentDescription(offer.get()); + const RtpDataContentDescription* data_offer = + GetFirstRtpDataContentDescription(offer.get()); ASSERT_TRUE(data_offer->cryptos().empty()); const cricket::TransportDescription* audio_offer_trans_desc = @@ -4068,11 +4075,11 @@ class MediaProtocolTest : public ::testing::TestWithParam { f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1), MAKE_VECTOR(kAudioCodecs1)); f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1)); - f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1)); + f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1)); f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2), MAKE_VECTOR(kAudioCodecs2)); f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2)); - f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2)); + f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2)); f1_.set_secure(SEC_ENABLED); f2_.set_secure(SEC_ENABLED); tdf1_.set_certificate(rtc::RTCCertificate::Create( diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc index 8a6d0e57ac..7cdd9831fb 100644 --- a/pc/peer_connection.cc +++ b/pc/peer_connection.cc @@ -559,24 +559,13 @@ 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::DataContentDescription* data_desc = - GetFirstDataContentDescription(session_description); + const cricket::SctpDataContentDescription* data_desc = + GetFirstSctpDataContentDescription(session_description); RTC_DCHECK(data_desc); if (!data_desc) { return -1; } - 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; + return data_desc->port(); } // Returns true if |new_desc| requests an ICE restart (i.e., new ufrag/pwd). @@ -2423,11 +2412,11 @@ RTCError PeerConnection::ApplyLocalDescription( const cricket::ContentInfo* data_content = GetFirstDataContent(local_description()->description()); if (data_content) { - const cricket::DataContentDescription* data_desc = - data_content->media_description()->as_data(); - if (absl::StartsWith(data_desc->protocol(), - cricket::kMediaProtocolRtpPrefix)) { - UpdateLocalRtpDataChannels(data_desc->streams()); + const cricket::RtpDataContentDescription* rtp_data_desc = + data_content->media_description()->as_rtp_data(); + // rtp_data_desc will be null if this is an SCTP description. + if (rtp_data_desc) { + UpdateLocalRtpDataChannels(rtp_data_desc->streams()); } } @@ -2833,8 +2822,8 @@ RTCError PeerConnection::ApplyRemoteDescription( GetFirstAudioContentDescription(remote_description()->description()); const cricket::VideoContentDescription* video_desc = GetFirstVideoContentDescription(remote_description()->description()); - const cricket::DataContentDescription* data_desc = - GetFirstDataContentDescription(remote_description()->description()); + const cricket::RtpDataContentDescription* rtp_data_desc = + GetFirstRtpDataContentDescription(remote_description()->description()); // Check if the descriptions include streams, just in case the peer supports // MSID, but doesn't indicate so with "a=msid-semantic". @@ -2887,12 +2876,10 @@ RTCError PeerConnection::ApplyRemoteDescription( } } - // Update the DataChannels with the information from the remote peer. - if (data_desc) { - if (absl::StartsWith(data_desc->protocol(), - cricket::kMediaProtocolRtpPrefix)) { - UpdateRemoteRtpDataChannels(GetActiveStreams(data_desc)); - } + // If this is an RTP data transport, update the DataChannels with the + // information from the remote peer. + if (rtp_data_desc) { + UpdateRemoteRtpDataChannels(GetActiveStreams(rtp_data_desc)); } // Iterate new_streams and notify the observer about new MediaStreams. diff --git a/pc/peer_connection_data_channel_unittest.cc b/pc/peer_connection_data_channel_unittest.cc index ad3817e5b5..4080dd98bb 100644 --- a/pc/peer_connection_data_channel_unittest.cc +++ b/pc/peer_connection_data_channel_unittest.cc @@ -193,14 +193,11 @@ 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_data(); - data_desc->set_codecs({sctp_codec}); + auto* data_desc = data_content->media_description()->as_sctp(); + RTC_DCHECK(data_desc); + data_desc->set_port(port); } std::unique_ptr vss_; diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc index 6087f0f4f6..e84ffe0360 100644 --- a/pc/peer_connection_integrationtest.cc +++ b/pc/peer_connection_integrationtest.cc @@ -3450,8 +3450,8 @@ TEST_P(PeerConnectionIntegrationTest, SctpDataChannelToAudioVideoUpgrade) { } static void MakeSpecCompliantSctpOffer(cricket::SessionDescription* desc) { - cricket::DataContentDescription* dcd_offer = - GetFirstDataContentDescription(desc); + cricket::SctpDataContentDescription* dcd_offer = + GetFirstSctpDataContentDescription(desc); ASSERT_TRUE(dcd_offer); dcd_offer->set_use_sctpmap(false); dcd_offer->set_protocol("UDP/DTLS/SCTP"); diff --git a/pc/session_description.cc b/pc/session_description.cc index d4ccb5082e..925acb6819 100644 --- a/pc/session_description.cc +++ b/pc/session_description.cc @@ -15,6 +15,7 @@ #include "absl/algorithm/container.h" #include "absl/memory/memory.h" +#include "pc/media_protocol_names.h" #include "rtc_base/checks.h" namespace cricket { @@ -183,6 +184,24 @@ void SessionDescription::AddContent(const std::string& name, } void SessionDescription::AddContent(ContentInfo* content) { + // Unwrap the as_data shim layer before using. + auto* description = content->media_description(); + bool should_delete = false; + if (description->as_rtp_data()) { + if (description->as_rtp_data() != description) { + content->set_media_description( + description->as_data()->Unshim(&should_delete)); + } + } + if (description->as_sctp()) { + if (description->as_sctp() != description) { + content->set_media_description( + description->as_data()->Unshim(&should_delete)); + } + } + if (should_delete) { + delete description; + } if (extmap_allow_mixed()) { // Mixed support on session level overrides setting on media level. content->description->set_extmap_allow_mixed_enum( @@ -272,4 +291,404 @@ const ContentGroup* SessionDescription::GetGroupByName( return NULL; } +// DataContentDescription shim creation +DataContentDescription* RtpDataContentDescription::as_data() { + if (!shim_) { + shim_.reset(new DataContentDescription(this)); + } + return shim_.get(); +} + +const DataContentDescription* RtpDataContentDescription::as_data() const { + return const_cast(this)->as_data(); +} + +DataContentDescription* SctpDataContentDescription::as_data() { + if (!shim_) { + shim_.reset(new DataContentDescription(this)); + } + return shim_.get(); +} + +const DataContentDescription* SctpDataContentDescription::as_data() const { + return const_cast(this)->as_data(); +} + +DataContentDescription::DataContentDescription() { + // In this case, we will initialize |owned_description_| as soon as + // we are told what protocol to use via set_protocol or another function + // calling CreateShimTarget. +} + +DataContentDescription::DataContentDescription( + SctpDataContentDescription* wrapped) + : real_description_(wrapped) { + // SctpDataContentDescription doesn't contain codecs, but code + // using DataContentDescription expects to see one. + Super::AddCodec( + cricket::DataCodec(kGoogleSctpDataCodecPlType, kGoogleSctpDataCodecName)); +} + +DataContentDescription::DataContentDescription( + RtpDataContentDescription* wrapped) + : real_description_(wrapped) {} + +DataContentDescription::DataContentDescription( + const DataContentDescription* o) { + if (o->real_description_) { + owned_description_ = absl::WrapUnique(o->real_description_->Copy()); + real_description_ = owned_description_.get(); + } +} + +void DataContentDescription::CreateShimTarget(bool is_sctp) { + RTC_LOG(LS_INFO) << "Creating shim target, is_sctp is " << is_sctp; + RTC_CHECK(!owned_description_.get()); + if (is_sctp) { + owned_description_ = absl::make_unique(); + // Copy all information collected so far, except codecs. + owned_description_->MediaContentDescription::operator=(*this); + } else { + owned_description_ = absl::make_unique(); + // Copy all information collected so far, including codecs. + owned_description_->as_rtp_data() + ->MediaContentDescriptionImpl::operator=(*this); + } + real_description_ = owned_description_.get(); +} + +MediaContentDescription* DataContentDescription::Unshim(bool* should_delete) { + if (owned_description_) { + // Pass ownership to caller, and remove myself. + // Since caller can't know if I was owner or owned, tell them. + MediaContentDescription* to_return = owned_description_.release(); + *should_delete = true; + return to_return; + } + // Real object is owner, and presumably referenced from elsewhere. + *should_delete = false; + return real_description_; +} + +void DataContentDescription::set_protocol(const std::string& protocol) { + if (real_description_) { + real_description_->set_protocol(protocol); + } else { + CreateShimTarget(IsSctpProtocol(protocol)); + } +} + +bool DataContentDescription::IsSctp() const { + return (real_description_ && real_description_->as_sctp()); +} + +void DataContentDescription::EnsureIsRtp() { + RTC_CHECK(real_description_); + RTC_CHECK(real_description_->as_rtp_data()); +} + +RtpDataContentDescription* DataContentDescription::as_rtp_data() { + if (real_description_) { + return real_description_->as_rtp_data(); + } + return nullptr; +} + +SctpDataContentDescription* DataContentDescription::as_sctp() { + if (real_description_) { + return real_description_->as_sctp(); + } + return nullptr; +} + +// Override all methods defined in MediaContentDescription. +bool DataContentDescription::has_codecs() const { + if (!real_description_) { + return Super::has_codecs(); + } + return real_description_->has_codecs(); +} +std::string DataContentDescription::protocol() const { + if (!real_description_) { + return Super::protocol(); + } + return real_description_->protocol(); +} + +webrtc::RtpTransceiverDirection DataContentDescription::direction() const { + if (!real_description_) { + return Super::direction(); + } + return real_description_->direction(); +} +void DataContentDescription::set_direction( + webrtc::RtpTransceiverDirection direction) { + if (!real_description_) { + return Super::set_direction(direction); + } + return real_description_->set_direction(direction); +} +bool DataContentDescription::rtcp_mux() const { + if (!real_description_) { + return Super::rtcp_mux(); + } + return real_description_->rtcp_mux(); +} +void DataContentDescription::set_rtcp_mux(bool mux) { + if (!real_description_) { + Super::set_rtcp_mux(mux); + return; + } + real_description_->set_rtcp_mux(mux); +} +bool DataContentDescription::rtcp_reduced_size() const { + if (!real_description_) { + return Super::rtcp_reduced_size(); + } + return real_description_->rtcp_reduced_size(); +} +void DataContentDescription::set_rtcp_reduced_size(bool reduced_size) { + if (!real_description_) { + return Super::set_rtcp_reduced_size(reduced_size); + } + + return real_description_->set_rtcp_reduced_size(reduced_size); +} +int DataContentDescription::bandwidth() const { + if (!real_description_) { + return Super::bandwidth(); + } + + return real_description_->bandwidth(); +} +void DataContentDescription::set_bandwidth(int bandwidth) { + if (!real_description_) { + return Super::set_bandwidth(bandwidth); + } + + return real_description_->set_bandwidth(bandwidth); +} +const std::vector& DataContentDescription::cryptos() const { + if (!real_description_) { + return Super::cryptos(); + } + + return real_description_->cryptos(); +} +void DataContentDescription::AddCrypto(const CryptoParams& params) { + if (!real_description_) { + return Super::AddCrypto(params); + } + + return real_description_->AddCrypto(params); +} +void DataContentDescription::set_cryptos( + const std::vector& cryptos) { + if (!real_description_) { + return Super::set_cryptos(cryptos); + } + + return real_description_->set_cryptos(cryptos); +} +const RtpHeaderExtensions& DataContentDescription::rtp_header_extensions() + const { + if (!real_description_) { + return Super::rtp_header_extensions(); + } + + return real_description_->rtp_header_extensions(); +} +void DataContentDescription::set_rtp_header_extensions( + const RtpHeaderExtensions& extensions) { + if (!real_description_) { + return Super::set_rtp_header_extensions(extensions); + } + + return real_description_->set_rtp_header_extensions(extensions); +} +void DataContentDescription::AddRtpHeaderExtension( + const webrtc::RtpExtension& ext) { + if (!real_description_) { + return Super::AddRtpHeaderExtension(ext); + } + return real_description_->AddRtpHeaderExtension(ext); +} +void DataContentDescription::AddRtpHeaderExtension( + const cricket::RtpHeaderExtension& ext) { + if (!real_description_) { + return Super::AddRtpHeaderExtension(ext); + } + return real_description_->AddRtpHeaderExtension(ext); +} +void DataContentDescription::ClearRtpHeaderExtensions() { + if (!real_description_) { + return Super::ClearRtpHeaderExtensions(); + } + return real_description_->ClearRtpHeaderExtensions(); +} +bool DataContentDescription::rtp_header_extensions_set() const { + if (!real_description_) { + return Super::rtp_header_extensions_set(); + } + return real_description_->rtp_header_extensions_set(); +} +const StreamParamsVec& DataContentDescription::streams() const { + if (!real_description_) { + return Super::streams(); + } + return real_description_->streams(); +} +StreamParamsVec& DataContentDescription::mutable_streams() { + if (!real_description_) { + return Super::mutable_streams(); + } + EnsureIsRtp(); + return real_description_->mutable_streams(); +} +void DataContentDescription::AddStream(const StreamParams& stream) { + if (!real_description_) { + return Super::AddStream(stream); + } + EnsureIsRtp(); + return real_description_->AddStream(stream); +} +void DataContentDescription::SetCnameIfEmpty(const std::string& cname) { + if (!real_description_) { + return Super::SetCnameIfEmpty(cname); + } + return real_description_->SetCnameIfEmpty(cname); +} +uint32_t DataContentDescription::first_ssrc() const { + if (!real_description_) { + return Super::first_ssrc(); + } + return real_description_->first_ssrc(); +} +bool DataContentDescription::has_ssrcs() const { + if (!real_description_) { + return Super::has_ssrcs(); + } + return real_description_->has_ssrcs(); +} +void DataContentDescription::set_conference_mode(bool enable) { + if (!real_description_) { + return Super::set_conference_mode(enable); + } + return real_description_->set_conference_mode(enable); +} +bool DataContentDescription::conference_mode() const { + if (!real_description_) { + return Super::conference_mode(); + } + return real_description_->conference_mode(); +} +void DataContentDescription::set_connection_address( + const rtc::SocketAddress& address) { + if (!real_description_) { + return Super::set_connection_address(address); + } + return real_description_->set_connection_address(address); +} +const rtc::SocketAddress& DataContentDescription::connection_address() const { + if (!real_description_) { + return Super::connection_address(); + } + return real_description_->connection_address(); +} +void DataContentDescription::set_extmap_allow_mixed_enum( + ExtmapAllowMixed mixed) { + if (!real_description_) { + return Super::set_extmap_allow_mixed_enum(mixed); + } + return real_description_->set_extmap_allow_mixed_enum(mixed); +} +MediaContentDescription::ExtmapAllowMixed +DataContentDescription::extmap_allow_mixed_enum() const { + if (!real_description_) { + return Super::extmap_allow_mixed_enum(); + } + return real_description_->extmap_allow_mixed_enum(); +} +bool DataContentDescription::HasSimulcast() const { + if (!real_description_) { + return Super::HasSimulcast(); + } + return real_description_->HasSimulcast(); +} +SimulcastDescription& DataContentDescription::simulcast_description() { + if (!real_description_) { + return Super::simulcast_description(); + } + return real_description_->simulcast_description(); +} +const SimulcastDescription& DataContentDescription::simulcast_description() + const { + if (!real_description_) { + return Super::simulcast_description(); + } + return real_description_->simulcast_description(); +} +void DataContentDescription::set_simulcast_description( + const SimulcastDescription& simulcast) { + if (!real_description_) { + return Super::set_simulcast_description(simulcast); + } + return real_description_->set_simulcast_description(simulcast); +} + +// Methods defined in MediaContentDescriptionImpl. +// For SCTP, we implement codec handling. +// For RTP, we pass the codecs. +// In the cases where type hasn't been decided yet, we return dummies. + +const std::vector& DataContentDescription::codecs() const { + if (IsSctp() || !real_description_) { + return Super::codecs(); + } + return real_description_->as_rtp_data()->codecs(); +} + +void DataContentDescription::set_codecs(const std::vector& codecs) { + if (IsSctp() || !real_description_) { + Super::set_codecs(codecs); + } else { + EnsureIsRtp(); + real_description_->as_rtp_data()->set_codecs(codecs); + } +} + +bool DataContentDescription::HasCodec(int id) { + if (IsSctp() || !real_description_) { + return Super::HasCodec(id); + } + return real_description_->as_rtp_data()->HasCodec(id); +} + +void DataContentDescription::AddCodec(const DataCodec& codec) { + if (IsSctp() || !real_description_) { + Super::AddCodec(codec); + } else { + EnsureIsRtp(); + real_description_->as_rtp_data()->AddCodec(codec); + } +} + +void DataContentDescription::AddOrReplaceCodec(const DataCodec& codec) { + if (IsSctp() || real_description_) { + Super::AddOrReplaceCodec(codec); + } else { + EnsureIsRtp(); + real_description_->as_rtp_data()->AddOrReplaceCodec(codec); + } +} + +void DataContentDescription::AddCodecs(const std::vector& codecs) { + if (IsSctp() || !real_description_) { + Super::AddCodecs(codecs); + } else { + EnsureIsRtp(); + real_description_->as_rtp_data()->AddCodecs(codecs); + } +} + } // namespace cricket diff --git a/pc/session_description.h b/pc/session_description.h index 7b70ddf556..60c3d6b92c 100644 --- a/pc/session_description.h +++ b/pc/session_description.h @@ -18,6 +18,7 @@ #include #include +#include "absl/memory/memory.h" #include "api/crypto_params.h" #include "api/media_types.h" #include "api/rtp_parameters.h" @@ -26,6 +27,7 @@ #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" @@ -33,7 +35,7 @@ namespace cricket { typedef std::vector AudioCodecs; typedef std::vector VideoCodecs; -typedef std::vector DataCodecs; +typedef std::vector RtpDataCodecs; typedef std::vector CryptoParamsVec; typedef std::vector RtpHeaderExtensions; @@ -44,19 +46,15 @@ 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; class AudioContentDescription; -class DataContentDescription; class VideoContentDescription; +class DataContentDescription; +class RtpDataContentDescription; +class SctpDataContentDescription; // Describes a session description media section. There are subclasses for each // media type (audio, video, data) that will have additional information. @@ -77,61 +75,77 @@ class MediaContentDescription { virtual VideoContentDescription* as_video() { return nullptr; } virtual const VideoContentDescription* as_video() const { return nullptr; } - // Try to cast this media description to a DataContentDescription. Returns - // nullptr if the cast fails. + // Backwards compatible shim: Return a shim object that allows + // callers to ignore the distinction between RtpDataContentDescription + // and SctpDataContentDescription objects. virtual DataContentDescription* as_data() { return nullptr; } virtual const DataContentDescription* as_data() const { return nullptr; } + virtual RtpDataContentDescription* as_rtp_data() { return nullptr; } + virtual const RtpDataContentDescription* as_rtp_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; // |protocol| is the expected media transport protocol, such as RTP/AVPF, // RTP/SAVPF or SCTP/DTLS. - std::string protocol() const { return protocol_; } - void set_protocol(const std::string& protocol) { protocol_ = protocol; } + virtual std::string protocol() const { return protocol_; } + virtual void set_protocol(const std::string& protocol) { + protocol_ = protocol; + } - webrtc::RtpTransceiverDirection direction() const { return direction_; } - void set_direction(webrtc::RtpTransceiverDirection direction) { + virtual webrtc::RtpTransceiverDirection direction() const { + return direction_; + } + virtual void set_direction(webrtc::RtpTransceiverDirection direction) { direction_ = direction; } - bool rtcp_mux() const { return rtcp_mux_; } - void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; } + virtual bool rtcp_mux() const { return rtcp_mux_; } + virtual void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; } - bool rtcp_reduced_size() const { return rtcp_reduced_size_; } - void set_rtcp_reduced_size(bool reduced_size) { + virtual bool rtcp_reduced_size() const { return rtcp_reduced_size_; } + virtual void set_rtcp_reduced_size(bool reduced_size) { rtcp_reduced_size_ = reduced_size; } - int bandwidth() const { return bandwidth_; } - void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; } + virtual int bandwidth() const { return bandwidth_; } + virtual void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; } - const std::vector& cryptos() const { return cryptos_; } - void AddCrypto(const CryptoParams& params) { cryptos_.push_back(params); } - void set_cryptos(const std::vector& cryptos) { + virtual const std::vector& cryptos() const { return cryptos_; } + virtual void AddCrypto(const CryptoParams& params) { + cryptos_.push_back(params); + } + virtual void set_cryptos(const std::vector& cryptos) { cryptos_ = cryptos; } - const RtpHeaderExtensions& rtp_header_extensions() const { + virtual const RtpHeaderExtensions& rtp_header_extensions() const { return rtp_header_extensions_; } - void set_rtp_header_extensions(const RtpHeaderExtensions& extensions) { + virtual void set_rtp_header_extensions( + const RtpHeaderExtensions& extensions) { rtp_header_extensions_ = extensions; rtp_header_extensions_set_ = true; } - void AddRtpHeaderExtension(const webrtc::RtpExtension& ext) { + virtual void AddRtpHeaderExtension(const webrtc::RtpExtension& ext) { rtp_header_extensions_.push_back(ext); rtp_header_extensions_set_ = true; } - void AddRtpHeaderExtension(const cricket::RtpHeaderExtension& ext) { + virtual void AddRtpHeaderExtension(const cricket::RtpHeaderExtension& ext) { webrtc::RtpExtension webrtc_extension; webrtc_extension.uri = ext.uri; webrtc_extension.id = ext.id; rtp_header_extensions_.push_back(webrtc_extension); rtp_header_extensions_set_ = true; } - void ClearRtpHeaderExtensions() { + virtual void ClearRtpHeaderExtensions() { rtp_header_extensions_.clear(); rtp_header_extensions_set_ = true; } @@ -140,62 +154,65 @@ class MediaContentDescription { // signal them. For now we assume an empty list means no signaling, but // provide the ClearRtpHeaderExtensions method to allow "no support" to be // clearly indicated (i.e. when derived from other information). - bool rtp_header_extensions_set() const { return rtp_header_extensions_set_; } - const StreamParamsVec& streams() const { return send_streams_; } + virtual bool rtp_header_extensions_set() const { + return rtp_header_extensions_set_; + } + virtual const StreamParamsVec& streams() const { return send_streams_; } // TODO(pthatcher): Remove this by giving mediamessage.cc access // to MediaContentDescription - StreamParamsVec& mutable_streams() { return send_streams_; } - void AddStream(const StreamParams& stream) { + virtual StreamParamsVec& mutable_streams() { return send_streams_; } + virtual void AddStream(const StreamParams& stream) { send_streams_.push_back(stream); } // Legacy streams have an ssrc, but nothing else. void AddLegacyStream(uint32_t ssrc) { - send_streams_.push_back(StreamParams::CreateLegacy(ssrc)); + AddStream(StreamParams::CreateLegacy(ssrc)); } void AddLegacyStream(uint32_t ssrc, uint32_t fid_ssrc) { StreamParams sp = StreamParams::CreateLegacy(ssrc); sp.AddFidSsrc(ssrc, fid_ssrc); - send_streams_.push_back(sp); + AddStream(sp); } // Sets the CNAME of all StreamParams if it have not been set. - void SetCnameIfEmpty(const std::string& cname) { + virtual void SetCnameIfEmpty(const std::string& cname) { for (cricket::StreamParamsVec::iterator it = send_streams_.begin(); it != send_streams_.end(); ++it) { if (it->cname.empty()) it->cname = cname; } } - uint32_t first_ssrc() const { + virtual uint32_t first_ssrc() const { if (send_streams_.empty()) { return 0; } return send_streams_[0].first_ssrc(); } - bool has_ssrcs() const { + virtual bool has_ssrcs() const { if (send_streams_.empty()) { return false; } return send_streams_[0].has_ssrcs(); } - void set_conference_mode(bool enable) { conference_mode_ = enable; } - bool conference_mode() const { return conference_mode_; } + virtual void set_conference_mode(bool enable) { conference_mode_ = enable; } + virtual bool conference_mode() const { return conference_mode_; } // https://tools.ietf.org/html/rfc4566#section-5.7 // May be present at the media or session level of SDP. If present at both // levels, the media-level attribute overwrites the session-level one. - void set_connection_address(const rtc::SocketAddress& address) { + virtual void set_connection_address(const rtc::SocketAddress& address) { connection_address_ = address; } - const rtc::SocketAddress& connection_address() const { + virtual const rtc::SocketAddress& connection_address() const { return connection_address_; } // Determines if it's allowed to mix one- and two-byte rtp header extensions // within the same rtp stream. enum ExtmapAllowMixed { kNo, kSession, kMedia }; - void set_extmap_allow_mixed_enum(ExtmapAllowMixed new_extmap_allow_mixed) { + virtual void set_extmap_allow_mixed_enum( + ExtmapAllowMixed new_extmap_allow_mixed) { if (new_extmap_allow_mixed == kMedia && extmap_allow_mixed_enum_ == kSession) { // Do not downgrade from session level to media level. @@ -203,10 +220,12 @@ class MediaContentDescription { } extmap_allow_mixed_enum_ = new_extmap_allow_mixed; } - ExtmapAllowMixed extmap_allow_mixed_enum() const { + virtual ExtmapAllowMixed extmap_allow_mixed_enum() const { return extmap_allow_mixed_enum_; } - bool extmap_allow_mixed() const { return extmap_allow_mixed_enum_ != kNo; } + virtual bool extmap_allow_mixed() const { + return extmap_allow_mixed_enum_ != kNo; + } // Simulcast functionality. virtual bool HasSimulcast() const { return !simulcast_.empty(); } @@ -247,13 +266,18 @@ 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; } - virtual bool has_codecs() const { return !codecs_.empty(); } - bool HasCodec(int id) { + virtual const std::vector& codecs() const { return codecs_; } + virtual void set_codecs(const std::vector& codecs) { codecs_ = codecs; } + bool has_codecs() const override { return !codecs_.empty(); } + virtual bool HasCodec(int id) { bool found = false; for (typename std::vector::iterator iter = codecs_.begin(); iter != codecs_.end(); ++iter) { @@ -264,8 +288,8 @@ class MediaContentDescriptionImpl : public MediaContentDescription { } return found; } - void AddCodec(const C& codec) { codecs_.push_back(codec); } - void AddOrReplaceCodec(const C& codec) { + virtual void AddCodec(const C& codec) { codecs_.push_back(codec); } + virtual void AddOrReplaceCodec(const C& codec) { for (typename std::vector::iterator iter = codecs_.begin(); iter != codecs_.end(); ++iter) { if (iter->id == codec.id) { @@ -275,7 +299,7 @@ class MediaContentDescriptionImpl : public MediaContentDescription { } AddCodec(codec); } - void AddCodecs(const std::vector& codecs) { + virtual void AddCodecs(const std::vector& codecs) { typename std::vector::const_iterator codec; for (codec = codecs.begin(); codec != codecs.end(); ++codec) { AddCodec(*codec); @@ -308,22 +332,173 @@ class VideoContentDescription : public MediaContentDescriptionImpl { virtual const VideoContentDescription* as_video() const { return this; } }; +// The DataContentDescription is a shim over the RtpDataContentDescription +// and SctpDataContentDescription classes that is used for external callers +// into this internal API. +// It is a templated derivation of MediaContentDescriptionImpl because +// that's what the external caller expects it to be. +// TODO(bugs.webrtc.org/10597): Declare this class obsolete and remove it +// once external callers have been updated. class DataContentDescription : public MediaContentDescriptionImpl { public: - DataContentDescription() {} + DataContentDescription(); + MediaType type() const override { return MEDIA_TYPE_DATA; } + DataContentDescription* as_data() override { return this; } + const DataContentDescription* as_data() const override { return this; } - virtual DataContentDescription* Copy() const { - return new DataContentDescription(*this); + // Override all methods defined in MediaContentDescription. + bool has_codecs() const override; + DataContentDescription* Copy() const override { + return new DataContentDescription(this); + } + std::string protocol() const override; + void set_protocol(const std::string& protocol) override; + webrtc::RtpTransceiverDirection direction() const override; + void set_direction(webrtc::RtpTransceiverDirection direction) override; + bool rtcp_mux() const override; + void set_rtcp_mux(bool mux) override; + bool rtcp_reduced_size() const override; + void set_rtcp_reduced_size(bool) override; + int bandwidth() const override; + void set_bandwidth(int bandwidth) override; + const std::vector& cryptos() const override; + void AddCrypto(const CryptoParams& params) override; + void set_cryptos(const std::vector& cryptos) override; + const RtpHeaderExtensions& rtp_header_extensions() const override; + void set_rtp_header_extensions( + const RtpHeaderExtensions& extensions) override; + void AddRtpHeaderExtension(const webrtc::RtpExtension& ext) override; + void AddRtpHeaderExtension(const cricket::RtpHeaderExtension& ext) override; + void ClearRtpHeaderExtensions() override; + bool rtp_header_extensions_set() const override; + const StreamParamsVec& streams() const override; + StreamParamsVec& mutable_streams() override; + void AddStream(const StreamParams& stream) override; + void SetCnameIfEmpty(const std::string& cname) override; + uint32_t first_ssrc() const override; + bool has_ssrcs() const override; + void set_conference_mode(bool enable) override; + bool conference_mode() const override; + void set_connection_address(const rtc::SocketAddress& address) override; + const rtc::SocketAddress& connection_address() const override; + void set_extmap_allow_mixed_enum(ExtmapAllowMixed) override; + ExtmapAllowMixed extmap_allow_mixed_enum() const override; + bool HasSimulcast() const override; + SimulcastDescription& simulcast_description() override; + const SimulcastDescription& simulcast_description() const override; + void set_simulcast_description( + const SimulcastDescription& simulcast) override; + + // Override all methods defined in MediaContentDescriptionImpl. + const std::vector& codecs() const override; + void set_codecs(const std::vector& codecs) override; + bool HasCodec(int id) override; + void AddCodec(const CodecType& codec) override; + void AddOrReplaceCodec(const CodecType& codec) override; + void AddCodecs(const std::vector& codec) override; + + private: + typedef MediaContentDescriptionImpl Super; + // Friend classes are allowed to create proxies for themselves. + friend class RtpDataContentDescription; // for constructors + friend class SctpDataContentDescription; + friend class SessionDescription; // for Unshim() + // Copy constructor. A copy results in an object that owns its + // real description, which is a copy of the original description + // (whether that was owned or not). + explicit DataContentDescription(const DataContentDescription* o); + + explicit DataContentDescription(RtpDataContentDescription*); + explicit DataContentDescription(SctpDataContentDescription*); + + // Exposed for internal use - new clients should not use this class. + RtpDataContentDescription* as_rtp_data() override; + SctpDataContentDescription* as_sctp() override; + + // Create a shimmed object, owned by the shim. + void CreateShimTarget(bool is_sctp); + + // Return the shimmed object, passing ownership if owned, and set + // |should_delete| to true if it was the owner. If |should_delete| + // is true on return, the caller should immediately delete the + // DataContentDescription object. + MediaContentDescription* Unshim(bool* should_delete); + + // Returns whether SCTP is in use. False when it's not decided. + bool IsSctp() const; + // Check function for use when caller obviously assumes RTP. + void EnsureIsRtp(); + + MediaContentDescription* real_description_ = nullptr; + std::unique_ptr owned_description_; +}; + +class RtpDataContentDescription + : public MediaContentDescriptionImpl { + public: + RtpDataContentDescription() {} + RtpDataContentDescription(const RtpDataContentDescription& o) + : MediaContentDescriptionImpl(o), shim_(nullptr) {} + RtpDataContentDescription& operator=(const RtpDataContentDescription& o) { + this->MediaContentDescriptionImpl::operator=(o); + // Do not copy the shim. + return *this; + } + + RtpDataContentDescription* Copy() const override { + return new RtpDataContentDescription(*this); + } + MediaType type() const override { return MEDIA_TYPE_DATA; } + RtpDataContentDescription* as_rtp_data() override { return this; } + const RtpDataContentDescription* as_rtp_data() const override { return this; } + // Shim support + DataContentDescription* as_data() override; + const DataContentDescription* as_data() const override; + + private: + std::unique_ptr shim_; +}; + +class SctpDataContentDescription : public MediaContentDescription { + public: + SctpDataContentDescription() {} + SctpDataContentDescription(const SctpDataContentDescription& o) + : MediaContentDescription(o), + use_sctpmap_(o.use_sctpmap_), + port_(o.port_), + max_message_size_(o.max_message_size_), + shim_(nullptr) {} + 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; } + // Shim support + DataContentDescription* as_data() override; + const DataContentDescription* as_data() const override; + + bool has_codecs() const override { return false; } + void set_protocol(const std::string& protocol) override { + RTC_DCHECK(IsSctpProtocol(protocol)); + protocol_ = protocol; } - virtual MediaType type() const { return MEDIA_TYPE_DATA; } - virtual DataContentDescription* as_data() { return this; } - virtual const DataContentDescription* as_data() const { return this; } 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; + 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; + std::unique_ptr shim_; }; // Protocol used for encoding media. This is the "top level" protocol that may diff --git a/pc/session_description_unittest.cc b/pc/session_description_unittest.cc index 3b05dca381..9797ed5627 100644 --- a/pc/session_description_unittest.cc +++ b/pc/session_description_unittest.cc @@ -9,6 +9,7 @@ */ #include "pc/session_description.h" +#include "absl/memory/memory.h" #include "test/gtest.h" namespace cricket { @@ -121,11 +122,69 @@ TEST(SessionDescriptionTest, AddContentTransfersExtmapAllowMixedSetting) { video_desc->extmap_allow_mixed_enum()); // Session level setting overrides media level when new content is added. - MediaContentDescription* data_desc = new DataContentDescription; + MediaContentDescription* data_desc = new RtpDataContentDescription; data_desc->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia); session_desc.AddContent("data", MediaProtocolType::kRtp, data_desc); EXPECT_EQ(MediaContentDescription::kSession, data_desc->extmap_allow_mixed_enum()); } +TEST(SessionDescriptionTest, DataContentDescriptionCanAddStream) { + auto description = absl::make_unique(); + // Adding a stream without setting protocol first should work. + description->AddLegacyStream(1234); + EXPECT_EQ(1UL, description->streams().size()); +} + +TEST(SessionDescriptionTest, DataContentDescriptionCopyWorks) { + auto description = absl::make_unique(); + auto shim_description = description->as_data(); + auto shim_copy = shim_description->Copy(); + delete shim_copy; +} + +TEST(SessionDescriptionTest, DataContentDescriptionCodecsCallableOnNull) { + auto shim_description = absl::make_unique(); + auto codec_list = shim_description->codecs(); + EXPECT_EQ(0UL, codec_list.size()); +} + +TEST(SessionDescriptionTest, DataContentDescriptionSctpConferenceMode) { + auto description = absl::make_unique(); + auto shim_description = description->as_data(); + EXPECT_FALSE(shim_description->conference_mode()); + shim_description->set_conference_mode(true); + EXPECT_TRUE(shim_description->conference_mode()); +} + +TEST(SessionDescriptionTest, DataContentDesriptionInSessionIsUnwrapped) { + auto description = absl::make_unique(); + // Create a DTLS object behind the shim. + description->set_protocol(kMediaProtocolUdpDtlsSctp); + SessionDescription session; + session.AddContent("name", MediaProtocolType::kSctp, description.release()); + ContentInfo* content = &(session.contents()[0]); + ASSERT_TRUE(content); + ASSERT_TRUE(content->media_description()->type() == MEDIA_TYPE_DATA); + ASSERT_TRUE(content->media_description()->as_sctp()); +} + +TEST(SessionDescriptionTest, + DataContentDescriptionInfoSurvivesInstantiationAsSctp) { + auto description = absl::make_unique(); + description->set_rtcp_mux(true); + description->set_protocol(kMediaProtocolUdpDtlsSctp); + EXPECT_TRUE(description->rtcp_mux()); +} + +TEST(SessionDescriptionTest, + DataContentDescriptionStreamInfoSurvivesInstantiationAsRtp) { + auto description = absl::make_unique(); + StreamParams stream; + description->AddLegacyStream(1234); + EXPECT_EQ(1UL, description->streams().size()); + description->set_protocol(kMediaProtocolDtlsSavpf); + EXPECT_EQ(1UL, description->streams().size()); +} + } // namespace cricket diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc index 984a1e14a1..d89bd78390 100644 --- a/pc/webrtc_sdp.cc +++ b/pc/webrtc_sdp.cc @@ -54,29 +54,31 @@ using cricket::Candidates; using cricket::ContentInfo; using cricket::CryptoParams; using cricket::DataContentDescription; -using cricket::ICE_CANDIDATE_COMPONENT_RTP; using cricket::ICE_CANDIDATE_COMPONENT_RTCP; +using cricket::ICE_CANDIDATE_COMPONENT_RTP; +using cricket::kCodecParamAssociatedPayloadType; +using cricket::kCodecParamMaxAverageBitrate; 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::kCodecParamUseInbandFec; using cricket::kCodecParamUseDtx; -using cricket::kCodecParamSctpProtocol; -using cricket::kCodecParamSctpStreams; -using cricket::kCodecParamMaxAverageBitrate; -using cricket::kCodecParamMaxPlaybackRate; -using cricket::kCodecParamAssociatedPayloadType; +using cricket::kCodecParamUseInbandFec; using cricket::MediaContentDescription; -using cricket::MediaType; -using cricket::RtpHeaderExtensions; using cricket::MediaProtocolType; +using cricket::MediaType; using cricket::RidDescription; +using cricket::RtpDataContentDescription; +using cricket::RtpHeaderExtensions; +using cricket::SctpDataContentDescription; using cricket::SimulcastDescription; using cricket::SimulcastLayer; using cricket::SimulcastLayerList; @@ -1337,8 +1339,6 @@ 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. @@ -1366,25 +1366,19 @@ 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()) { - 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)); + fmt.append(rtc::ToString(data_desc->port())); } else { fmt.append(kDefaultSctpmapProtocol); } } else { - for (const cricket::DataCodec& codec : data_desc->codecs()) { + const RtpDataContentDescription* data_desc = media_desc->as_rtp_data(); + for (const cricket::RtpDataCodec& codec : data_desc->codecs()) { fmt.append(" "); fmt.append(rtc::ToString(codec.id)); } @@ -1523,9 +1517,10 @@ void BuildMediaDescription(const ContentInfo* content_info, AddLine(os.str(), message); if (IsDtlsSctp(media_desc->protocol())) { - const DataContentDescription* data_desc = media_desc->as_data(); + const cricket::SctpDataContentDescription* data_desc = + media_desc->as_sctp(); bool use_sctpmap = data_desc->use_sctpmap(); - BuildSctpContentAttributes(message, sctp_port, use_sctpmap); + BuildSctpContentAttributes(message, data_desc->port(), use_sctpmap); } else if (IsRtp(media_desc->protocol())) { BuildRtpContentAttributes(media_desc, media_type, msid_signaling, message); } @@ -1834,43 +1829,6 @@ 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; @@ -1960,7 +1918,8 @@ void BuildRtpMap(const MediaContentDescription* media_desc, AddAttributeLine(kCodecParamPTime, ptime, message); } } else if (media_type == cricket::MEDIA_TYPE_DATA) { - for (const cricket::DataCodec& codec : media_desc->as_data()->codecs()) { + for (const cricket::RtpDataCodec& codec : + media_desc->as_rtp_data()->codecs()) { // RFC 4566 // a=rtpmap: / // [/] @@ -2748,24 +2707,36 @@ bool ParseMediaDescription( payload_types, pos, &content_name, &bundle_only, §ion_msid_signaling, &transport, candidates, error); } else if (HasAttribute(line, kMediaTypeData)) { - 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)) { + if (IsDtlsSctp(protocol)) { + // The draft-03 format is: + // m=application DTLS/SCTP ... + // use_sctpmap should be false. + // The draft-26 format is: + // m=application UDP/DTLS/SCTP webrtc-datachannel + // use_sctpmap should be false. + auto data_desc = absl::make_unique(); int p; if (rtc::FromString(fields[3], &p)) { - if (!AddOrModifySctpDataCodecPort(data_desc.get(), p)) { - return false; - } + data_desc->set_port(p); } 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; @@ -3138,13 +3109,15 @@ 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; } - if (!AddOrModifySctpDataCodecPort(media_desc->as_data(), sctp_port)) { - return false; - } + media_desc->as_sctp()->set_port(sctp_port); } else if (IsDtlsSctp(protocol) && HasAttribute(line, kAttributeMaxMessageSize)) { if (media_type != cricket::MEDIA_TYPE_DATA) { @@ -3157,10 +3130,7 @@ bool ParseContent(const std::string& message, if (!ParseSctpMaxMessageSize(line, &max_message_size, error)) { return false; } - if (!AddOrModifySctpDataMaxMessageSize(media_desc->as_data(), - max_message_size)) { - return false; - } + media_desc->as_sctp()->set_max_message_size(max_message_size); } else if (IsRtp(protocol)) { // // RTP specific attrubtes @@ -3621,8 +3591,8 @@ bool ParseRtpmapAttribute(const std::string& line, UpdateCodec(payload_type, encoding_name, clock_rate, 0, channels, audio_desc); } else if (media_type == cricket::MEDIA_TYPE_DATA) { - DataContentDescription* data_desc = media_desc->as_data(); - data_desc->AddCodec(cricket::DataCodec(payload_type, encoding_name)); + RtpDataContentDescription* data_desc = media_desc->as_rtp_data(); + data_desc->AddCodec(cricket::RtpDataCodec(payload_type, encoding_name)); } return true; } diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc index 3de2b602dd..367fac84d7 100644 --- a/pc/webrtc_sdp_unittest.cc +++ b/pc/webrtc_sdp_unittest.cc @@ -56,7 +56,6 @@ using cricket::ContentGroup; using cricket::ContentInfo; using cricket::CryptoParams; using cricket::DataCodec; -using cricket::DataContentDescription; using cricket::ICE_CANDIDATE_COMPONENT_RTCP; using cricket::ICE_CANDIDATE_COMPONENT_RTP; using cricket::kFecSsrcGroupSemantics; @@ -65,6 +64,8 @@ using cricket::MediaProtocolType; using cricket::RELAY_PORT_TYPE; using cricket::RidDescription; using cricket::RidDirection; +using cricket::RtpDataContentDescription; +using cricket::SctpDataContentDescription; using cricket::SessionDescription; using cricket::SimulcastDescription; using cricket::SimulcastLayer; @@ -275,6 +276,7 @@ static const char kSdpRtpDataChannelString[] = "a=ssrc:10 mslabel:data_channel\r\n" "a=ssrc:10 label:data_channeld0\r\n"; +// draft-ietf-mmusic-sctp-sdp-03 static const char kSdpSctpDataChannelString[] = "m=application 9 DTLS/SCTP 5000\r\n" "c=IN IP4 0.0.0.0\r\n" @@ -1443,10 +1445,17 @@ class WebRtcSdpTest : public ::testing::Test { simulcast2.receive_layers().size()); } - void CompareDataContentDescription(const DataContentDescription* dcd1, - const DataContentDescription* dcd2) { + void CompareRtpDataContentDescription(const RtpDataContentDescription* dcd1, + const RtpDataContentDescription* dcd2) { + CompareMediaContentDescription(dcd1, dcd2); + } + + void CompareSctpDataContentDescription( + const SctpDataContentDescription* dcd1, + const SctpDataContentDescription* dcd2) { EXPECT_EQ(dcd1->use_sctpmap(), dcd2->use_sctpmap()); - CompareMediaContentDescription(dcd1, dcd2); + EXPECT_EQ(dcd1->port(), dcd2->port()); + EXPECT_EQ(dcd1->max_message_size(), dcd2->max_message_size()); } void CompareSessionDescription(const SessionDescription& desc1, @@ -1484,10 +1493,21 @@ class WebRtcSdpTest : public ::testing::Test { } ASSERT_EQ(IsDataContent(&c1), IsDataContent(&c2)); - if (IsDataContent(&c1)) { - const DataContentDescription* dcd1 = c1.media_description()->as_data(); - const DataContentDescription* dcd2 = c2.media_description()->as_data(); - CompareDataContentDescription(dcd1, dcd2); + 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 RtpDataContentDescription* dcd1 = + c1.media_description()->as_rtp_data(); + const RtpDataContentDescription* dcd2 = + c2.media_description()->as_rtp_data(); + CompareRtpDataContentDescription(dcd1, dcd2); + } } CompareSimulcastDescription( @@ -1760,14 +1780,12 @@ class WebRtcSdpTest : public ::testing::Test { } void AddSctpDataChannel(bool use_sctpmap) { - 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); + 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); desc_.AddContent(kDataContentName, MediaProtocolType::kSctp, data.release()); desc_.AddTransportInfo(TransportInfo( @@ -1775,7 +1793,8 @@ class WebRtcSdpTest : public ::testing::Test { } void AddRtpDataChannel() { - std::unique_ptr data(new DataContentDescription()); + std::unique_ptr data( + new RtpDataContentDescription()); data_desc_ = data.get(); data_desc_->AddCodec(DataCodec(101, "google-data")); @@ -2043,7 +2062,8 @@ class WebRtcSdpTest : public ::testing::Test { SessionDescription desc_; AudioContentDescription* audio_desc_; VideoContentDescription* video_desc_; - DataContentDescription* data_desc_; + RtpDataContentDescription* data_desc_; + SctpDataContentDescription* sctp_desc_; Candidates candidates_; std::unique_ptr jcandidate_; JsepSessionDescription jdesc_; @@ -2215,21 +2235,26 @@ 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; - cricket::DataCodec codec(cricket::kGoogleSctpDataCodecPlType, - cricket::kGoogleSctpDataCodecName); - codec.SetParam(cricket::kCodecParamPort, kNewPort); - dcdesc->AddOrReplaceCodec(codec); + MutateJsepSctpPort(&jsep_desc, desc_, kNewPort); std::string message = webrtc::SdpSerialize(jsep_desc); @@ -2868,14 +2893,12 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpColonPort) { // Helper function to set the max-message-size parameter in the // SCTP data codec. void MutateJsepSctpMaxMessageSize(const SessionDescription& desc, - const std::string& new_value, + int new_value, JsepSessionDescription* jdesc) { cricket::SessionDescription* mutant = desc.Copy(); - DataContentDescription* dcdesc = - mutant->GetContentDescriptionByName(kDataContentName)->as_data(); - std::vector codecs(dcdesc->codecs()); - codecs[0].SetParam(cricket::kCodecParamMaxMessageSize, new_value); - dcdesc->set_codecs(codecs); + SctpDataContentDescription* dcdesc = + mutant->GetContentDescriptionByName(kDataContentName)->as_sctp(); + dcdesc->set_max_message_size(new_value); jdesc->Initialize(mutant, kSessionId, kSessionVersion); } @@ -2887,7 +2910,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. @@ -2937,29 +2960,13 @@ 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_); + MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort); // Then get the deserialized JsepSessionDescription. std::string sdp_with_data = kSdpString; @@ -2979,7 +2986,7 @@ TEST_F(WebRtcSdpTest, AddSctpDataChannel(use_sctpmap); JsepSessionDescription jdesc(kDummyType); - MutateJsepSctpPort(&jdesc, desc_); + MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort); // We need to test the deserialized JsepSessionDescription from // kSdpSctpDataChannelStringWithSctpPort for @@ -3015,7 +3022,7 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) { bool use_sctpmap = true; AddSctpDataChannel(use_sctpmap); JsepSessionDescription jdesc(kDummyType); - DataContentDescription* dcd = GetFirstDataContentDescription(&desc_); + SctpDataContentDescription* dcd = GetFirstSctpDataContentDescription(&desc_); dcd->set_bandwidth(100 * 1000); ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));