Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2020 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | #include <memory> |
Harald Alvestrand | c24a218 | 2022-02-23 13:44:59 +0000 | [diff] [blame] | 12 | #include <string> |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 13 | #include <tuple> |
Harald Alvestrand | c24a218 | 2022-02-23 13:44:59 +0000 | [diff] [blame] | 14 | #include <utility> |
| 15 | #include <vector> |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 16 | |
Harald Alvestrand | c24a218 | 2022-02-23 13:44:59 +0000 | [diff] [blame] | 17 | #include "absl/strings/string_view.h" |
| 18 | #include "absl/types/optional.h" |
| 19 | #include "api/call/call_factory_interface.h" |
| 20 | #include "api/jsep.h" |
| 21 | #include "api/media_types.h" |
| 22 | #include "api/peer_connection_interface.h" |
| 23 | #include "api/rtc_error.h" |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 24 | #include "api/rtc_event_log/rtc_event_log_factory.h" |
Harald Alvestrand | c24a218 | 2022-02-23 13:44:59 +0000 | [diff] [blame] | 25 | #include "api/rtc_event_log/rtc_event_log_factory_interface.h" |
| 26 | #include "api/rtp_parameters.h" |
| 27 | #include "api/rtp_transceiver_direction.h" |
| 28 | #include "api/rtp_transceiver_interface.h" |
| 29 | #include "api/scoped_refptr.h" |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 30 | #include "api/task_queue/default_task_queue_factory.h" |
Harald Alvestrand | c24a218 | 2022-02-23 13:44:59 +0000 | [diff] [blame] | 31 | #include "api/task_queue/task_queue_factory.h" |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 32 | #include "media/base/fake_media_engine.h" |
Harald Alvestrand | c24a218 | 2022-02-23 13:44:59 +0000 | [diff] [blame] | 33 | #include "media/base/media_engine.h" |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 34 | #include "p2p/base/fake_port_allocator.h" |
Harald Alvestrand | c24a218 | 2022-02-23 13:44:59 +0000 | [diff] [blame] | 35 | #include "p2p/base/port_allocator.h" |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 36 | #include "pc/peer_connection_wrapper.h" |
Harald Alvestrand | c24a218 | 2022-02-23 13:44:59 +0000 | [diff] [blame] | 37 | #include "pc/session_description.h" |
| 38 | #include "pc/test/mock_peer_connection_observers.h" |
| 39 | #include "rtc_base/rtc_certificate_generator.h" |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 40 | #include "rtc_base/strings/string_builder.h" |
Harald Alvestrand | c24a218 | 2022-02-23 13:44:59 +0000 | [diff] [blame] | 41 | #include "rtc_base/thread.h" |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 42 | #include "test/gmock.h" |
Harald Alvestrand | c24a218 | 2022-02-23 13:44:59 +0000 | [diff] [blame] | 43 | #include "test/gtest.h" |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 44 | |
| 45 | namespace webrtc { |
| 46 | |
| 47 | using ::testing::Combine; |
| 48 | using ::testing::ElementsAre; |
| 49 | using ::testing::Field; |
| 50 | using ::testing::Return; |
| 51 | using ::testing::Values; |
| 52 | |
| 53 | class PeerConnectionHeaderExtensionTest |
| 54 | : public ::testing::TestWithParam< |
| 55 | std::tuple<cricket::MediaType, SdpSemantics>> { |
| 56 | protected: |
Markus Handell | 755c65d | 2020-06-24 01:06:10 +0200 | [diff] [blame] | 57 | PeerConnectionHeaderExtensionTest() |
| 58 | : extensions_( |
| 59 | {RtpHeaderExtensionCapability("uri1", |
| 60 | 1, |
| 61 | RtpTransceiverDirection::kStopped), |
| 62 | RtpHeaderExtensionCapability("uri2", |
| 63 | 2, |
| 64 | RtpTransceiverDirection::kSendOnly), |
| 65 | RtpHeaderExtensionCapability("uri3", |
| 66 | 3, |
| 67 | RtpTransceiverDirection::kRecvOnly), |
| 68 | RtpHeaderExtensionCapability( |
| 69 | "uri4", |
| 70 | 4, |
| 71 | RtpTransceiverDirection::kSendRecv)}) {} |
| 72 | |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 73 | std::unique_ptr<PeerConnectionWrapper> CreatePeerConnection( |
| 74 | cricket::MediaType media_type, |
Markus Handell | 755c65d | 2020-06-24 01:06:10 +0200 | [diff] [blame] | 75 | absl::optional<SdpSemantics> semantics) { |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 76 | auto voice = std::make_unique<cricket::FakeVoiceEngine>(); |
| 77 | auto video = std::make_unique<cricket::FakeVideoEngine>(); |
| 78 | if (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO) |
Markus Handell | 755c65d | 2020-06-24 01:06:10 +0200 | [diff] [blame] | 79 | voice->SetRtpHeaderExtensions(extensions_); |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 80 | else |
Markus Handell | 755c65d | 2020-06-24 01:06:10 +0200 | [diff] [blame] | 81 | video->SetRtpHeaderExtensions(extensions_); |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 82 | auto media_engine = std::make_unique<cricket::CompositeMediaEngine>( |
| 83 | std::move(voice), std::move(video)); |
| 84 | PeerConnectionFactoryDependencies factory_dependencies; |
| 85 | factory_dependencies.network_thread = rtc::Thread::Current(); |
| 86 | factory_dependencies.worker_thread = rtc::Thread::Current(); |
| 87 | factory_dependencies.signaling_thread = rtc::Thread::Current(); |
| 88 | factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory(); |
| 89 | factory_dependencies.media_engine = std::move(media_engine); |
| 90 | factory_dependencies.call_factory = CreateCallFactory(); |
| 91 | factory_dependencies.event_log_factory = |
| 92 | std::make_unique<RtcEventLogFactory>( |
| 93 | factory_dependencies.task_queue_factory.get()); |
| 94 | |
| 95 | auto pc_factory = |
| 96 | CreateModularPeerConnectionFactory(std::move(factory_dependencies)); |
| 97 | |
| 98 | auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>( |
| 99 | rtc::Thread::Current(), nullptr); |
| 100 | auto observer = std::make_unique<MockPeerConnectionObserver>(); |
| 101 | PeerConnectionInterface::RTCConfiguration config; |
| 102 | if (semantics) |
| 103 | config.sdp_semantics = *semantics; |
Florent Castelli | 7242440 | 2022-04-06 03:45:10 +0200 | [diff] [blame] | 104 | PeerConnectionDependencies pc_dependencies(observer.get()); |
| 105 | pc_dependencies.allocator = std::move(fake_port_allocator); |
| 106 | auto result = pc_factory->CreatePeerConnectionOrError( |
| 107 | config, std::move(pc_dependencies)); |
| 108 | EXPECT_TRUE(result.ok()); |
Niels Möller | afb246b | 2022-04-20 14:26:50 +0200 | [diff] [blame] | 109 | observer->SetPeerConnectionInterface(result.value().get()); |
Florent Castelli | 7242440 | 2022-04-06 03:45:10 +0200 | [diff] [blame] | 110 | return std::make_unique<PeerConnectionWrapper>( |
| 111 | pc_factory, result.MoveValue(), std::move(observer)); |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 112 | } |
Markus Handell | 755c65d | 2020-06-24 01:06:10 +0200 | [diff] [blame] | 113 | |
| 114 | std::vector<RtpHeaderExtensionCapability> extensions_; |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 115 | }; |
| 116 | |
| 117 | TEST_P(PeerConnectionHeaderExtensionTest, TransceiverOffersHeaderExtensions) { |
| 118 | cricket::MediaType media_type; |
| 119 | SdpSemantics semantics; |
| 120 | std::tie(media_type, semantics) = GetParam(); |
| 121 | if (semantics != SdpSemantics::kUnifiedPlan) |
| 122 | return; |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 123 | std::unique_ptr<PeerConnectionWrapper> wrapper = |
Markus Handell | 755c65d | 2020-06-24 01:06:10 +0200 | [diff] [blame] | 124 | CreatePeerConnection(media_type, semantics); |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 125 | auto transceiver = wrapper->AddTransceiver(media_type); |
Markus Handell | 755c65d | 2020-06-24 01:06:10 +0200 | [diff] [blame] | 126 | EXPECT_EQ(transceiver->HeaderExtensionsToOffer(), extensions_); |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 127 | } |
| 128 | |
| 129 | TEST_P(PeerConnectionHeaderExtensionTest, |
| 130 | SenderReceiverCapabilitiesReturnNotStoppedExtensions) { |
| 131 | cricket::MediaType media_type; |
| 132 | SdpSemantics semantics; |
| 133 | std::tie(media_type, semantics) = GetParam(); |
Markus Handell | 755c65d | 2020-06-24 01:06:10 +0200 | [diff] [blame] | 134 | std::unique_ptr<PeerConnectionWrapper> wrapper = |
| 135 | CreatePeerConnection(media_type, semantics); |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 136 | EXPECT_THAT(wrapper->pc_factory() |
| 137 | ->GetRtpSenderCapabilities(media_type) |
| 138 | .header_extensions, |
Markus Handell | 755c65d | 2020-06-24 01:06:10 +0200 | [diff] [blame] | 139 | ElementsAre(Field(&RtpHeaderExtensionCapability::uri, "uri2"), |
| 140 | Field(&RtpHeaderExtensionCapability::uri, "uri3"), |
| 141 | Field(&RtpHeaderExtensionCapability::uri, "uri4"))); |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 142 | EXPECT_EQ(wrapper->pc_factory() |
| 143 | ->GetRtpReceiverCapabilities(media_type) |
| 144 | .header_extensions, |
| 145 | wrapper->pc_factory() |
| 146 | ->GetRtpSenderCapabilities(media_type) |
| 147 | .header_extensions); |
| 148 | } |
| 149 | |
Markus Handell | 755c65d | 2020-06-24 01:06:10 +0200 | [diff] [blame] | 150 | TEST_P(PeerConnectionHeaderExtensionTest, OffersUnstoppedDefaultExtensions) { |
| 151 | cricket::MediaType media_type; |
| 152 | SdpSemantics semantics; |
| 153 | std::tie(media_type, semantics) = GetParam(); |
| 154 | if (semantics != SdpSemantics::kUnifiedPlan) |
| 155 | return; |
| 156 | std::unique_ptr<PeerConnectionWrapper> wrapper = |
| 157 | CreatePeerConnection(media_type, semantics); |
| 158 | auto transceiver = wrapper->AddTransceiver(media_type); |
| 159 | auto session_description = wrapper->CreateOffer(); |
| 160 | EXPECT_THAT(session_description->description() |
| 161 | ->contents()[0] |
| 162 | .media_description() |
| 163 | ->rtp_header_extensions(), |
| 164 | ElementsAre(Field(&RtpExtension::uri, "uri2"), |
| 165 | Field(&RtpExtension::uri, "uri3"), |
| 166 | Field(&RtpExtension::uri, "uri4"))); |
| 167 | } |
| 168 | |
| 169 | TEST_P(PeerConnectionHeaderExtensionTest, OffersUnstoppedModifiedExtensions) { |
| 170 | cricket::MediaType media_type; |
| 171 | SdpSemantics semantics; |
| 172 | std::tie(media_type, semantics) = GetParam(); |
| 173 | if (semantics != SdpSemantics::kUnifiedPlan) |
| 174 | return; |
| 175 | std::unique_ptr<PeerConnectionWrapper> wrapper = |
| 176 | CreatePeerConnection(media_type, semantics); |
| 177 | auto transceiver = wrapper->AddTransceiver(media_type); |
| 178 | auto modified_extensions = transceiver->HeaderExtensionsToOffer(); |
| 179 | modified_extensions[0].direction = RtpTransceiverDirection::kSendRecv; |
| 180 | modified_extensions[3].direction = RtpTransceiverDirection::kStopped; |
| 181 | EXPECT_TRUE( |
| 182 | transceiver->SetOfferedRtpHeaderExtensions(modified_extensions).ok()); |
| 183 | auto session_description = wrapper->CreateOffer(); |
| 184 | EXPECT_THAT(session_description->description() |
| 185 | ->contents()[0] |
| 186 | .media_description() |
| 187 | ->rtp_header_extensions(), |
| 188 | ElementsAre(Field(&RtpExtension::uri, "uri1"), |
| 189 | Field(&RtpExtension::uri, "uri2"), |
| 190 | Field(&RtpExtension::uri, "uri3"))); |
| 191 | } |
| 192 | |
Markus Handell | 5932fe1 | 2020-12-17 22:19:40 +0100 | [diff] [blame] | 193 | TEST_P(PeerConnectionHeaderExtensionTest, NegotiatedExtensionsAreAccessible) { |
| 194 | cricket::MediaType media_type; |
| 195 | SdpSemantics semantics; |
| 196 | std::tie(media_type, semantics) = GetParam(); |
| 197 | if (semantics != SdpSemantics::kUnifiedPlan) |
| 198 | return; |
| 199 | std::unique_ptr<PeerConnectionWrapper> pc1 = |
| 200 | CreatePeerConnection(media_type, semantics); |
| 201 | auto transceiver1 = pc1->AddTransceiver(media_type); |
| 202 | auto modified_extensions = transceiver1->HeaderExtensionsToOffer(); |
| 203 | modified_extensions[3].direction = RtpTransceiverDirection::kStopped; |
| 204 | transceiver1->SetOfferedRtpHeaderExtensions(modified_extensions); |
| 205 | auto offer = pc1->CreateOfferAndSetAsLocal( |
| 206 | PeerConnectionInterface::RTCOfferAnswerOptions()); |
| 207 | |
| 208 | std::unique_ptr<PeerConnectionWrapper> pc2 = |
| 209 | CreatePeerConnection(media_type, semantics); |
| 210 | auto transceiver2 = pc2->AddTransceiver(media_type); |
| 211 | pc2->SetRemoteDescription(std::move(offer)); |
| 212 | auto answer = pc2->CreateAnswerAndSetAsLocal( |
| 213 | PeerConnectionInterface::RTCOfferAnswerOptions()); |
| 214 | pc1->SetRemoteDescription(std::move(answer)); |
| 215 | |
| 216 | // PC1 has exts 2-4 unstopped and PC2 has exts 1-3 unstopped -> ext 2, 3 |
| 217 | // survives. |
| 218 | EXPECT_THAT(transceiver1->HeaderExtensionsNegotiated(), |
| 219 | ElementsAre(Field(&RtpHeaderExtensionCapability::uri, "uri2"), |
| 220 | Field(&RtpHeaderExtensionCapability::uri, "uri3"))); |
| 221 | } |
| 222 | |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 223 | INSTANTIATE_TEST_SUITE_P( |
| 224 | , |
| 225 | PeerConnectionHeaderExtensionTest, |
Florent Castelli | 15a38de | 2022-04-06 00:38:21 +0200 | [diff] [blame] | 226 | Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), |
Björn Terelius | 99261af | 2021-05-12 17:06:49 +0000 | [diff] [blame] | 227 | Values(cricket::MediaType::MEDIA_TYPE_AUDIO, |
| 228 | cricket::MediaType::MEDIA_TYPE_VIDEO)), |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 229 | [](const testing::TestParamInfo< |
| 230 | PeerConnectionHeaderExtensionTest::ParamType>& info) { |
| 231 | cricket::MediaType media_type; |
| 232 | SdpSemantics semantics; |
| 233 | std::tie(media_type, semantics) = info.param; |
| 234 | return (rtc::StringBuilder("With") |
Florent Castelli | 15a38de | 2022-04-06 00:38:21 +0200 | [diff] [blame] | 235 | << (semantics == SdpSemantics::kPlanB_DEPRECATED ? "PlanB" |
| 236 | : "UnifiedPlan") |
Markus Handell | 0357b3e | 2020-03-16 13:40:51 +0100 | [diff] [blame] | 237 | << "And" |
| 238 | << (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO ? "Voice" |
| 239 | : "Video") |
| 240 | << "Engine") |
| 241 | .str(); |
| 242 | }); |
| 243 | |
| 244 | } // namespace webrtc |