diff --git a/webrtc/pc/mediasession.cc b/webrtc/pc/mediasession.cc index a9d1b95c22..382cdbc44f 100644 --- a/webrtc/pc/mediasession.cc +++ b/webrtc/pc/mediasession.cc @@ -57,6 +57,13 @@ const char kMediaProtocolAvpf[] = "RTP/AVPF"; // RFC5124 const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF"; +// The accepted pattern for media protocol (JSEP Section 5.1.3) +const std::vector kMediaProtocols = {"RTP/SAVPF", "RTP/SAVP", + "RTP/AVPF", "RTP/AVP"}; +const std::vector kMediaProtocolsDtls = { + "UDP/TLS/RTP/SAVPF", "UDP/TLS/RTP/SAVP", "TCP/TLS/RTP/SAVPF", + "TCP/TLS/RTP/SAVP"}; + // We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP, // but we tolerate "RTP/SAVPF" in offers we receive, for compatibility. const char kMediaProtocolSavpf[] = "RTP/SAVPF"; @@ -1105,6 +1112,12 @@ static bool CreateMediaContentAnswer( return true; } +static bool IsProtocolFound(const std::vector protocols, + const std::string& protocol) { + return std::find(protocols.begin(), protocols.end(), protocol) != + protocols.end(); +} + static bool IsMediaProtocolSupported(MediaType type, const std::string& protocol, bool secure_transport) { @@ -1117,9 +1130,8 @@ static bool IsMediaProtocolSupported(MediaType type, // Since not all applications serialize and deserialize the media protocol, // we will have to accept |protocol| to be empty. - return protocol == kMediaProtocolAvpf || protocol.empty() || - protocol == kMediaProtocolSavpf || - (protocol == kMediaProtocolDtlsSavpf && secure_transport); + return protocol.empty() || IsProtocolFound(kMediaProtocols, protocol) || + (IsProtocolFound(kMediaProtocolsDtls, protocol) && secure_transport); } static void SetMediaProtocol(bool secure_transport, diff --git a/webrtc/pc/mediasession_unittest.cc b/webrtc/pc/mediasession_unittest.cc index 6ea7aeb8ab..1b2aa4eb3b 100644 --- a/webrtc/pc/mediasession_unittest.cc +++ b/webrtc/pc/mediasession_unittest.cc @@ -180,6 +180,12 @@ static const char kDataTrack1[] = "data_1"; static const char kDataTrack2[] = "data_2"; static const char kDataTrack3[] = "data_3"; +static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF", + "RTP/SAVPF"}; +static const char* kMediaProtocolsDtls[] = { + "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF", + "UDP/TLS/RTP/SAVP"}; + static bool IsMediaContentOfType(const ContentInfo* content, MediaType media_type) { const MediaContentDescription* mdesc = @@ -2391,3 +2397,62 @@ TEST_F(MediaSessionDescriptionFactoryTest, EXPECT_EQ("video_modified", video_content->name); EXPECT_EQ("data_modified", data_content->name); } + +class MediaProtocolTest : public ::testing::TestWithParam { + public: + MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) { + f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1)); + f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1)); + f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1)); + f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2)); + f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2)); + f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2)); + f1_.set_secure(SEC_ENABLED); + f2_.set_secure(SEC_ENABLED); + tdf1_.set_certificate(rtc::RTCCertificate::Create( + rtc::scoped_ptr(new rtc::FakeSSLIdentity("id1")))); + tdf2_.set_certificate(rtc::RTCCertificate::Create( + rtc::scoped_ptr(new rtc::FakeSSLIdentity("id2")))); + tdf1_.set_secure(SEC_ENABLED); + tdf2_.set_secure(SEC_ENABLED); + } + + protected: + MediaSessionDescriptionFactory f1_; + MediaSessionDescriptionFactory f2_; + TransportDescriptionFactory tdf1_; + TransportDescriptionFactory tdf2_; +}; + +TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) { + MediaSessionOptions opts; + opts.recv_video = true; + std::unique_ptr offer(f1_.CreateOffer(opts, nullptr)); + ASSERT_TRUE(offer.get() != nullptr); + // Set the protocol for all the contents. + for (auto content : offer.get()->contents()) { + static_cast(content.description) + ->set_protocol(GetParam()); + } + std::unique_ptr answer( + f2_.CreateAnswer(offer.get(), opts, nullptr)); + const ContentInfo* ac = answer->GetContentByName("audio"); + const ContentInfo* vc = answer->GetContentByName("video"); + ASSERT_TRUE(ac != nullptr); + ASSERT_TRUE(vc != nullptr); + EXPECT_FALSE(ac->rejected); // the offer is accepted + EXPECT_FALSE(vc->rejected); + const AudioContentDescription* acd = + static_cast(ac->description); + const VideoContentDescription* vcd = + static_cast(vc->description); + EXPECT_EQ(GetParam(), acd->protocol()); + EXPECT_EQ(GetParam(), vcd->protocol()); +} + +INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest, + MediaProtocolTest, + ::testing::ValuesIn(kMediaProtocols)); +INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest, + MediaProtocolTest, + ::testing::ValuesIn(kMediaProtocolsDtls));