diff options
Diffstat (limited to 'third_party/libwebrtc/pc/peer_connection_header_extension_unittest.cc')
-rw-r--r-- | third_party/libwebrtc/pc/peer_connection_header_extension_unittest.cc | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/third_party/libwebrtc/pc/peer_connection_header_extension_unittest.cc b/third_party/libwebrtc/pc/peer_connection_header_extension_unittest.cc new file mode 100644 index 0000000000..b1c6c3cfb5 --- /dev/null +++ b/third_party/libwebrtc/pc/peer_connection_header_extension_unittest.cc @@ -0,0 +1,589 @@ +/* + * Copyright 2020 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 <memory> +#include <string> +#include <tuple> +#include <utility> +#include <vector> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/call/call_factory_interface.h" +#include "api/jsep.h" +#include "api/media_types.h" +#include "api/peer_connection_interface.h" +#include "api/rtc_error.h" +#include "api/rtc_event_log/rtc_event_log_factory.h" +#include "api/rtc_event_log/rtc_event_log_factory_interface.h" +#include "api/rtp_parameters.h" +#include "api/rtp_transceiver_direction.h" +#include "api/rtp_transceiver_interface.h" +#include "api/scoped_refptr.h" +#include "api/task_queue/default_task_queue_factory.h" +#include "api/task_queue/task_queue_factory.h" +#include "media/base/fake_media_engine.h" +#include "media/base/media_engine.h" +#include "p2p/base/fake_port_allocator.h" +#include "p2p/base/port_allocator.h" +#include "pc/peer_connection_wrapper.h" +#include "pc/session_description.h" +#include "pc/test/mock_peer_connection_observers.h" +#include "rtc_base/internal/default_socket_server.h" +#include "rtc_base/rtc_certificate_generator.h" +#include "rtc_base/strings/string_builder.h" +#include "rtc_base/thread.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/scoped_key_value_config.h" + +namespace webrtc { + +using ::testing::Combine; +using ::testing::ElementsAre; +using ::testing::Field; +using ::testing::Return; +using ::testing::Values; + +class PeerConnectionHeaderExtensionTest + : public ::testing::TestWithParam< + std::tuple<cricket::MediaType, SdpSemantics>> { + protected: + PeerConnectionHeaderExtensionTest() + : socket_server_(rtc::CreateDefaultSocketServer()), + main_thread_(socket_server_.get()), + extensions_( + {RtpHeaderExtensionCapability("uri1", + 1, + RtpTransceiverDirection::kStopped), + RtpHeaderExtensionCapability("uri2", + 2, + RtpTransceiverDirection::kSendOnly), + RtpHeaderExtensionCapability("uri3", + 3, + RtpTransceiverDirection::kRecvOnly), + RtpHeaderExtensionCapability( + "uri4", + 4, + RtpTransceiverDirection::kSendRecv)}) {} + + std::unique_ptr<PeerConnectionWrapper> CreatePeerConnection( + cricket::MediaType media_type, + absl::optional<SdpSemantics> semantics) { + auto voice = std::make_unique<cricket::FakeVoiceEngine>(); + auto video = std::make_unique<cricket::FakeVideoEngine>(); + if (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO) + voice->SetRtpHeaderExtensions(extensions_); + else + video->SetRtpHeaderExtensions(extensions_); + auto media_engine = std::make_unique<cricket::CompositeMediaEngine>( + std::move(voice), std::move(video)); + PeerConnectionFactoryDependencies factory_dependencies; + factory_dependencies.network_thread = rtc::Thread::Current(); + factory_dependencies.worker_thread = rtc::Thread::Current(); + factory_dependencies.signaling_thread = rtc::Thread::Current(); + factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory(); + factory_dependencies.media_engine = std::move(media_engine); + factory_dependencies.call_factory = CreateCallFactory(); + factory_dependencies.event_log_factory = + std::make_unique<RtcEventLogFactory>( + factory_dependencies.task_queue_factory.get()); + + auto pc_factory = + CreateModularPeerConnectionFactory(std::move(factory_dependencies)); + + auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>( + rtc::Thread::Current(), + std::make_unique<rtc::BasicPacketSocketFactory>(socket_server_.get()), + &field_trials_); + auto observer = std::make_unique<MockPeerConnectionObserver>(); + PeerConnectionInterface::RTCConfiguration config; + if (semantics) + config.sdp_semantics = *semantics; + PeerConnectionDependencies pc_dependencies(observer.get()); + pc_dependencies.allocator = std::move(fake_port_allocator); + auto result = pc_factory->CreatePeerConnectionOrError( + config, std::move(pc_dependencies)); + EXPECT_TRUE(result.ok()); + observer->SetPeerConnectionInterface(result.value().get()); + return std::make_unique<PeerConnectionWrapper>( + pc_factory, result.MoveValue(), std::move(observer)); + } + + webrtc::test::ScopedKeyValueConfig field_trials_; + std::unique_ptr<rtc::SocketServer> socket_server_; + rtc::AutoSocketServerThread main_thread_; + std::vector<RtpHeaderExtensionCapability> extensions_; +}; + +TEST_P(PeerConnectionHeaderExtensionTest, TransceiverOffersHeaderExtensions) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> wrapper = + CreatePeerConnection(media_type, semantics); + auto transceiver = wrapper->AddTransceiver(media_type); + EXPECT_EQ(transceiver->GetHeaderExtensionsToNegotiate(), extensions_); +} + +TEST_P(PeerConnectionHeaderExtensionTest, + SenderReceiverCapabilitiesReturnNotStoppedExtensions) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + std::unique_ptr<PeerConnectionWrapper> wrapper = + CreatePeerConnection(media_type, semantics); + EXPECT_THAT(wrapper->pc_factory() + ->GetRtpSenderCapabilities(media_type) + .header_extensions, + ElementsAre(Field(&RtpHeaderExtensionCapability::uri, "uri2"), + Field(&RtpHeaderExtensionCapability::uri, "uri3"), + Field(&RtpHeaderExtensionCapability::uri, "uri4"))); + EXPECT_EQ(wrapper->pc_factory() + ->GetRtpReceiverCapabilities(media_type) + .header_extensions, + wrapper->pc_factory() + ->GetRtpSenderCapabilities(media_type) + .header_extensions); +} + +TEST_P(PeerConnectionHeaderExtensionTest, OffersUnstoppedDefaultExtensions) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> wrapper = + CreatePeerConnection(media_type, semantics); + auto transceiver = wrapper->AddTransceiver(media_type); + auto session_description = wrapper->CreateOffer(); + EXPECT_THAT(session_description->description() + ->contents()[0] + .media_description() + ->rtp_header_extensions(), + ElementsAre(Field(&RtpExtension::uri, "uri2"), + Field(&RtpExtension::uri, "uri3"), + Field(&RtpExtension::uri, "uri4"))); +} + +TEST_P(PeerConnectionHeaderExtensionTest, OffersUnstoppedModifiedExtensions) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> wrapper = + CreatePeerConnection(media_type, semantics); + auto transceiver = wrapper->AddTransceiver(media_type); + auto modified_extensions = transceiver->GetHeaderExtensionsToNegotiate(); + modified_extensions[0].direction = RtpTransceiverDirection::kSendRecv; + modified_extensions[3].direction = RtpTransceiverDirection::kStopped; + EXPECT_TRUE( + transceiver->SetHeaderExtensionsToNegotiate(modified_extensions).ok()); + auto session_description = wrapper->CreateOffer(); + EXPECT_THAT(session_description->description() + ->contents()[0] + .media_description() + ->rtp_header_extensions(), + ElementsAre(Field(&RtpExtension::uri, "uri1"), + Field(&RtpExtension::uri, "uri2"), + Field(&RtpExtension::uri, "uri3"))); +} + +TEST_P(PeerConnectionHeaderExtensionTest, AnswersUnstoppedModifiedExtensions) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> pc1 = + CreatePeerConnection(media_type, semantics); + std::unique_ptr<PeerConnectionWrapper> pc2 = + CreatePeerConnection(media_type, semantics); + auto transceiver1 = pc1->AddTransceiver(media_type); + + auto offer = pc1->CreateOfferAndSetAsLocal( + PeerConnectionInterface::RTCOfferAnswerOptions()); + pc2->SetRemoteDescription(std::move(offer)); + + ASSERT_EQ(pc2->pc()->GetTransceivers().size(), 1u); + auto transceiver2 = pc2->pc()->GetTransceivers()[0]; + auto modified_extensions = transceiver2->GetHeaderExtensionsToNegotiate(); + // Don't offer uri4. + modified_extensions[3].direction = RtpTransceiverDirection::kStopped; + transceiver2->SetHeaderExtensionsToNegotiate(modified_extensions); + + auto answer = pc2->CreateAnswerAndSetAsLocal( + PeerConnectionInterface::RTCOfferAnswerOptions()); + EXPECT_THAT(answer->description() + ->contents()[0] + .media_description() + ->rtp_header_extensions(), + ElementsAre(Field(&RtpExtension::uri, "uri2"), + Field(&RtpExtension::uri, "uri3"))); +} + +TEST_P(PeerConnectionHeaderExtensionTest, NegotiatedExtensionsAreAccessible) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> pc1 = + CreatePeerConnection(media_type, semantics); + auto transceiver1 = pc1->AddTransceiver(media_type); + auto modified_extensions = transceiver1->GetHeaderExtensionsToNegotiate(); + modified_extensions[3].direction = RtpTransceiverDirection::kStopped; + transceiver1->SetHeaderExtensionsToNegotiate(modified_extensions); + auto offer = pc1->CreateOfferAndSetAsLocal( + PeerConnectionInterface::RTCOfferAnswerOptions()); + + std::unique_ptr<PeerConnectionWrapper> pc2 = + CreatePeerConnection(media_type, semantics); + auto transceiver2 = pc2->AddTransceiver(media_type); + pc2->SetRemoteDescription(std::move(offer)); + auto answer = pc2->CreateAnswerAndSetAsLocal( + PeerConnectionInterface::RTCOfferAnswerOptions()); + pc1->SetRemoteDescription(std::move(answer)); + + // PC1 has exts 2-4 unstopped and PC2 has exts 1-3 unstopped -> ext 2, 3 + // survives. + EXPECT_THAT(transceiver1->GetNegotiatedHeaderExtensions(), + ElementsAre(Field(&RtpHeaderExtensionCapability::direction, + RtpTransceiverDirection::kStopped), + Field(&RtpHeaderExtensionCapability::direction, + RtpTransceiverDirection::kSendRecv), + Field(&RtpHeaderExtensionCapability::direction, + RtpTransceiverDirection::kSendRecv), + Field(&RtpHeaderExtensionCapability::direction, + RtpTransceiverDirection::kStopped))); +} + +TEST_P(PeerConnectionHeaderExtensionTest, OfferedExtensionsArePerTransceiver) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> pc1 = + CreatePeerConnection(media_type, semantics); + auto transceiver1 = pc1->AddTransceiver(media_type); + auto modified_extensions = transceiver1->GetHeaderExtensionsToNegotiate(); + modified_extensions[3].direction = RtpTransceiverDirection::kStopped; + transceiver1->SetHeaderExtensionsToNegotiate(modified_extensions); + auto transceiver2 = pc1->AddTransceiver(media_type); + + auto session_description = pc1->CreateOffer(); + EXPECT_THAT(session_description->description() + ->contents()[0] + .media_description() + ->rtp_header_extensions(), + ElementsAre(Field(&RtpExtension::uri, "uri2"), + Field(&RtpExtension::uri, "uri3"))); + EXPECT_THAT(session_description->description() + ->contents()[1] + .media_description() + ->rtp_header_extensions(), + ElementsAre(Field(&RtpExtension::uri, "uri2"), + Field(&RtpExtension::uri, "uri3"), + Field(&RtpExtension::uri, "uri4"))); +} + +TEST_P(PeerConnectionHeaderExtensionTest, RemovalAfterRenegotiation) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> pc1 = + CreatePeerConnection(media_type, semantics); + std::unique_ptr<PeerConnectionWrapper> pc2 = + CreatePeerConnection(media_type, semantics); + auto transceiver1 = pc1->AddTransceiver(media_type); + + auto offer = pc1->CreateOfferAndSetAsLocal( + PeerConnectionInterface::RTCOfferAnswerOptions()); + pc2->SetRemoteDescription(std::move(offer)); + auto answer = pc2->CreateAnswerAndSetAsLocal( + PeerConnectionInterface::RTCOfferAnswerOptions()); + pc1->SetRemoteDescription(std::move(answer)); + + auto modified_extensions = transceiver1->GetHeaderExtensionsToNegotiate(); + modified_extensions[3].direction = RtpTransceiverDirection::kStopped; + transceiver1->SetHeaderExtensionsToNegotiate(modified_extensions); + auto session_description = pc1->CreateOffer(); + EXPECT_THAT(session_description->description() + ->contents()[0] + .media_description() + ->rtp_header_extensions(), + ElementsAre(Field(&RtpExtension::uri, "uri2"), + Field(&RtpExtension::uri, "uri3"))); +} + +TEST_P(PeerConnectionHeaderExtensionTest, + StoppedByDefaultExtensionCanBeActivatedByRemoteSdp) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> pc1 = + CreatePeerConnection(media_type, semantics); + std::unique_ptr<PeerConnectionWrapper> pc2 = + CreatePeerConnection(media_type, semantics); + auto transceiver1 = pc1->AddTransceiver(media_type); + + auto offer = pc1->CreateOfferAndSetAsLocal( + PeerConnectionInterface::RTCOfferAnswerOptions()); + pc2->SetRemoteDescription(std::move(offer)); + auto answer = pc2->CreateAnswerAndSetAsLocal( + PeerConnectionInterface::RTCOfferAnswerOptions()); + std::string sdp; + ASSERT_TRUE(answer->ToString(&sdp)); + // We support uri1 but it is stopped by default. Let the remote reactivate it. + sdp += "a=extmap:15 uri1\r\n"; + auto modified_answer = CreateSessionDescription(SdpType::kAnswer, sdp); + pc1->SetRemoteDescription(std::move(modified_answer)); + EXPECT_THAT(transceiver1->GetNegotiatedHeaderExtensions(), + ElementsAre(Field(&RtpHeaderExtensionCapability::direction, + RtpTransceiverDirection::kSendRecv), + Field(&RtpHeaderExtensionCapability::direction, + RtpTransceiverDirection::kSendRecv), + Field(&RtpHeaderExtensionCapability::direction, + RtpTransceiverDirection::kSendRecv), + Field(&RtpHeaderExtensionCapability::direction, + RtpTransceiverDirection::kSendRecv))); +} + +TEST_P(PeerConnectionHeaderExtensionTest, + UnknownExtensionInRemoteOfferDoesNotShowUp) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> pc = + CreatePeerConnection(media_type, semantics); + std::string sdp = + "v=0\r\n" + "o=- 0 3 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=fingerprint:sha-256 " + "A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:" + "AD:7E:77:43:2A:29:EC:93\r\n" + "a=ice-ufrag:6HHHdzzeIhkE0CKj\r\n" + "a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew\r\n"; + if (media_type == cricket::MEDIA_TYPE_AUDIO) { + sdp += + "m=audio 9 RTP/AVPF 111\r\n" + "a=rtpmap:111 fake_audio_codec/8000\r\n"; + } else { + sdp += + "m=video 9 RTP/AVPF 111\r\n" + "a=rtpmap:111 fake_video_codec/90000\r\n"; + } + sdp += + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp-mux\r\n" + "a=sendonly\r\n" + "a=mid:audio\r\n" + "a=setup:actpass\r\n" + "a=extmap:1 urn:bogus\r\n"; + auto offer = CreateSessionDescription(SdpType::kOffer, sdp); + pc->SetRemoteDescription(std::move(offer)); + pc->CreateAnswerAndSetAsLocal( + PeerConnectionInterface::RTCOfferAnswerOptions()); + ASSERT_GT(pc->pc()->GetTransceivers().size(), 0u); + auto transceiver = pc->pc()->GetTransceivers()[0]; + auto negotiated = transceiver->GetNegotiatedHeaderExtensions(); + EXPECT_EQ(negotiated.size(), + transceiver->GetHeaderExtensionsToNegotiate().size()); + // All extensions are stopped, the "bogus" one does not show up. + for (const auto& extension : negotiated) { + EXPECT_EQ(extension.direction, RtpTransceiverDirection::kStopped); + EXPECT_NE(extension.uri, "urn:bogus"); + } +} + +// These tests are regression tests for behavior that the API +// enables in a proper way. It conflicts with the behavior +// of the API to only offer non-stopped extensions. +TEST_P(PeerConnectionHeaderExtensionTest, + SdpMungingAnswerWithoutApiUsageEnablesExtensions) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> pc = + CreatePeerConnection(media_type, semantics); + std::string sdp = + "v=0\r\n" + "o=- 0 3 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=fingerprint:sha-256 " + "A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:" + "AD:7E:77:43:2A:29:EC:93\r\n" + "a=ice-ufrag:6HHHdzzeIhkE0CKj\r\n" + "a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew\r\n"; + if (media_type == cricket::MEDIA_TYPE_AUDIO) { + sdp += + "m=audio 9 RTP/AVPF 111\r\n" + "a=rtpmap:111 fake_audio_codec/8000\r\n"; + } else { + sdp += + "m=video 9 RTP/AVPF 111\r\n" + "a=rtpmap:111 fake_video_codec/90000\r\n"; + } + sdp += + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp-mux\r\n" + "a=sendrecv\r\n" + "a=mid:audio\r\n" + "a=setup:actpass\r\n" + "a=extmap:1 uri1\r\n"; + auto offer = CreateSessionDescription(SdpType::kOffer, sdp); + pc->SetRemoteDescription(std::move(offer)); + auto answer = + pc->CreateAnswer(PeerConnectionInterface::RTCOfferAnswerOptions()); + std::string modified_sdp; + ASSERT_TRUE(answer->ToString(&modified_sdp)); + modified_sdp += "a=extmap:1 uri1\r\n"; + auto modified_answer = + CreateSessionDescription(SdpType::kAnswer, modified_sdp); + ASSERT_TRUE(pc->SetLocalDescription(std::move(modified_answer))); + + auto session_description = pc->CreateOffer(); + EXPECT_THAT(session_description->description() + ->contents()[0] + .media_description() + ->rtp_header_extensions(), + ElementsAre(Field(&RtpExtension::uri, "uri1"), + Field(&RtpExtension::uri, "uri2"), + Field(&RtpExtension::uri, "uri3"), + Field(&RtpExtension::uri, "uri4"))); +} + +TEST_P(PeerConnectionHeaderExtensionTest, + SdpMungingOfferWithoutApiUsageEnablesExtensions) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> pc = + CreatePeerConnection(media_type, semantics); + pc->AddTransceiver(media_type); + + auto offer = + pc->CreateOffer(PeerConnectionInterface::RTCOfferAnswerOptions()); + std::string modified_sdp; + ASSERT_TRUE(offer->ToString(&modified_sdp)); + modified_sdp += "a=extmap:1 uri1\r\n"; + auto modified_offer = CreateSessionDescription(SdpType::kOffer, modified_sdp); + ASSERT_TRUE(pc->SetLocalDescription(std::move(modified_offer))); + + auto offer2 = + pc->CreateOffer(PeerConnectionInterface::RTCOfferAnswerOptions()); + EXPECT_THAT(offer2->description() + ->contents()[0] + .media_description() + ->rtp_header_extensions(), + ElementsAre(Field(&RtpExtension::uri, "uri2"), + Field(&RtpExtension::uri, "uri3"), + Field(&RtpExtension::uri, "uri4"), + Field(&RtpExtension::uri, "uri1"))); +} + +TEST_P(PeerConnectionHeaderExtensionTest, EnablingExtensionsAfterRemoteOffer) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = GetParam(); + if (semantics != SdpSemantics::kUnifiedPlan) + return; + std::unique_ptr<PeerConnectionWrapper> pc = + CreatePeerConnection(media_type, semantics); + std::string sdp = + "v=0\r\n" + "o=- 0 3 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=fingerprint:sha-256 " + "A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:" + "AD:7E:77:43:2A:29:EC:93\r\n" + "a=ice-ufrag:6HHHdzzeIhkE0CKj\r\n" + "a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew\r\n"; + if (media_type == cricket::MEDIA_TYPE_AUDIO) { + sdp += + "m=audio 9 RTP/AVPF 111\r\n" + "a=rtpmap:111 fake_audio_codec/8000\r\n"; + } else { + sdp += + "m=video 9 RTP/AVPF 111\r\n" + "a=rtpmap:111 fake_video_codec/90000\r\n"; + } + sdp += + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp-mux\r\n" + "a=sendrecv\r\n" + "a=mid:audio\r\n" + "a=setup:actpass\r\n" + "a=extmap:5 uri1\r\n"; + auto offer = CreateSessionDescription(SdpType::kOffer, sdp); + pc->SetRemoteDescription(std::move(offer)); + + ASSERT_GT(pc->pc()->GetTransceivers().size(), 0u); + auto transceiver = pc->pc()->GetTransceivers()[0]; + auto modified_extensions = transceiver->GetHeaderExtensionsToNegotiate(); + modified_extensions[0].direction = RtpTransceiverDirection::kSendRecv; + transceiver->SetHeaderExtensionsToNegotiate(modified_extensions); + + pc->CreateAnswerAndSetAsLocal( + PeerConnectionInterface::RTCOfferAnswerOptions()); + + auto session_description = pc->CreateOffer(); + auto extensions = session_description->description() + ->contents()[0] + .media_description() + ->rtp_header_extensions(); + EXPECT_THAT(extensions, ElementsAre(Field(&RtpExtension::uri, "uri1"), + Field(&RtpExtension::uri, "uri2"), + Field(&RtpExtension::uri, "uri3"), + Field(&RtpExtension::uri, "uri4"))); + // Check uri1's id still matches the remote id. + EXPECT_EQ(extensions[0].id, 5); +} + +INSTANTIATE_TEST_SUITE_P( + , + PeerConnectionHeaderExtensionTest, + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), + Values(cricket::MediaType::MEDIA_TYPE_AUDIO, + cricket::MediaType::MEDIA_TYPE_VIDEO)), + [](const testing::TestParamInfo< + PeerConnectionHeaderExtensionTest::ParamType>& info) { + cricket::MediaType media_type; + SdpSemantics semantics; + std::tie(media_type, semantics) = info.param; + return (rtc::StringBuilder("With") + << (semantics == SdpSemantics::kPlanB_DEPRECATED ? "PlanB" + : "UnifiedPlan") + << "And" + << (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO ? "Voice" + : "Video") + << "Engine") + .str(); + }); + +} // namespace webrtc |