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>
12 #include <string>
13 #include <tuple>
14 #include <utility>
15 #include <vector>
16
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"
24 #include "api/rtc_event_log/rtc_event_log_factory.h"
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"
30 #include "api/task_queue/default_task_queue_factory.h"
31 #include "api/task_queue/task_queue_factory.h"
32 #include "media/base/fake_media_engine.h"
33 #include "media/base/media_engine.h"
34 #include "p2p/base/fake_port_allocator.h"
35 #include "p2p/base/port_allocator.h"
36 #include "pc/peer_connection_wrapper.h"
37 #include "pc/session_description.h"
38 #include "pc/test/mock_peer_connection_observers.h"
39 #include "rtc_base/internal/default_socket_server.h"
40 #include "rtc_base/rtc_certificate_generator.h"
41 #include "rtc_base/strings/string_builder.h"
42 #include "rtc_base/thread.h"
43 #include "test/gmock.h"
44 #include "test/gtest.h"
45
46 namespace webrtc {
47
48 using ::testing::Combine;
49 using ::testing::ElementsAre;
50 using ::testing::Field;
51 using ::testing::Return;
52 using ::testing::Values;
53
54 class PeerConnectionHeaderExtensionTest
55 : public ::testing::TestWithParam<
56 std::tuple<cricket::MediaType, SdpSemantics>> {
57 protected:
PeerConnectionHeaderExtensionTest()58 PeerConnectionHeaderExtensionTest()
59 : socket_server_(rtc::CreateDefaultSocketServer()),
60 main_thread_(socket_server_.get()),
61 extensions_(
62 {RtpHeaderExtensionCapability("uri1",
63 1,
64 RtpTransceiverDirection::kStopped),
65 RtpHeaderExtensionCapability("uri2",
66 2,
67 RtpTransceiverDirection::kSendOnly),
68 RtpHeaderExtensionCapability("uri3",
69 3,
70 RtpTransceiverDirection::kRecvOnly),
71 RtpHeaderExtensionCapability(
72 "uri4",
73 4,
74 RtpTransceiverDirection::kSendRecv)}) {}
75
CreatePeerConnection(cricket::MediaType media_type,absl::optional<SdpSemantics> semantics)76 std::unique_ptr<PeerConnectionWrapper> CreatePeerConnection(
77 cricket::MediaType media_type,
78 absl::optional<SdpSemantics> semantics) {
79 auto voice = std::make_unique<cricket::FakeVoiceEngine>();
80 auto video = std::make_unique<cricket::FakeVideoEngine>();
81 if (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO)
82 voice->SetRtpHeaderExtensions(extensions_);
83 else
84 video->SetRtpHeaderExtensions(extensions_);
85 auto media_engine = std::make_unique<cricket::CompositeMediaEngine>(
86 std::move(voice), std::move(video));
87 PeerConnectionFactoryDependencies factory_dependencies;
88 factory_dependencies.network_thread = rtc::Thread::Current();
89 factory_dependencies.worker_thread = rtc::Thread::Current();
90 factory_dependencies.signaling_thread = rtc::Thread::Current();
91 factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
92 factory_dependencies.media_engine = std::move(media_engine);
93 factory_dependencies.call_factory = CreateCallFactory();
94 factory_dependencies.event_log_factory =
95 std::make_unique<RtcEventLogFactory>(
96 factory_dependencies.task_queue_factory.get());
97
98 auto pc_factory =
99 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
100
101 auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
102 rtc::Thread::Current(),
103 std::make_unique<rtc::BasicPacketSocketFactory>(socket_server_.get()));
104 auto observer = std::make_unique<MockPeerConnectionObserver>();
105 PeerConnectionInterface::RTCConfiguration config;
106 if (semantics)
107 config.sdp_semantics = *semantics;
108 PeerConnectionDependencies pc_dependencies(observer.get());
109 pc_dependencies.allocator = std::move(fake_port_allocator);
110 auto result = pc_factory->CreatePeerConnectionOrError(
111 config, std::move(pc_dependencies));
112 EXPECT_TRUE(result.ok());
113 observer->SetPeerConnectionInterface(result.value().get());
114 return std::make_unique<PeerConnectionWrapper>(
115 pc_factory, result.MoveValue(), std::move(observer));
116 }
117
118 std::unique_ptr<rtc::SocketServer> socket_server_;
119 rtc::AutoSocketServerThread main_thread_;
120 std::vector<RtpHeaderExtensionCapability> extensions_;
121 };
122
TEST_P(PeerConnectionHeaderExtensionTest,TransceiverOffersHeaderExtensions)123 TEST_P(PeerConnectionHeaderExtensionTest, TransceiverOffersHeaderExtensions) {
124 cricket::MediaType media_type;
125 SdpSemantics semantics;
126 std::tie(media_type, semantics) = GetParam();
127 if (semantics != SdpSemantics::kUnifiedPlan)
128 return;
129 std::unique_ptr<PeerConnectionWrapper> wrapper =
130 CreatePeerConnection(media_type, semantics);
131 auto transceiver = wrapper->AddTransceiver(media_type);
132 EXPECT_EQ(transceiver->HeaderExtensionsToOffer(), extensions_);
133 }
134
TEST_P(PeerConnectionHeaderExtensionTest,SenderReceiverCapabilitiesReturnNotStoppedExtensions)135 TEST_P(PeerConnectionHeaderExtensionTest,
136 SenderReceiverCapabilitiesReturnNotStoppedExtensions) {
137 cricket::MediaType media_type;
138 SdpSemantics semantics;
139 std::tie(media_type, semantics) = GetParam();
140 std::unique_ptr<PeerConnectionWrapper> wrapper =
141 CreatePeerConnection(media_type, semantics);
142 EXPECT_THAT(wrapper->pc_factory()
143 ->GetRtpSenderCapabilities(media_type)
144 .header_extensions,
145 ElementsAre(Field(&RtpHeaderExtensionCapability::uri, "uri2"),
146 Field(&RtpHeaderExtensionCapability::uri, "uri3"),
147 Field(&RtpHeaderExtensionCapability::uri, "uri4")));
148 EXPECT_EQ(wrapper->pc_factory()
149 ->GetRtpReceiverCapabilities(media_type)
150 .header_extensions,
151 wrapper->pc_factory()
152 ->GetRtpSenderCapabilities(media_type)
153 .header_extensions);
154 }
155
TEST_P(PeerConnectionHeaderExtensionTest,OffersUnstoppedDefaultExtensions)156 TEST_P(PeerConnectionHeaderExtensionTest, OffersUnstoppedDefaultExtensions) {
157 cricket::MediaType media_type;
158 SdpSemantics semantics;
159 std::tie(media_type, semantics) = GetParam();
160 if (semantics != SdpSemantics::kUnifiedPlan)
161 return;
162 std::unique_ptr<PeerConnectionWrapper> wrapper =
163 CreatePeerConnection(media_type, semantics);
164 auto transceiver = wrapper->AddTransceiver(media_type);
165 auto session_description = wrapper->CreateOffer();
166 EXPECT_THAT(session_description->description()
167 ->contents()[0]
168 .media_description()
169 ->rtp_header_extensions(),
170 ElementsAre(Field(&RtpExtension::uri, "uri2"),
171 Field(&RtpExtension::uri, "uri3"),
172 Field(&RtpExtension::uri, "uri4")));
173 }
174
TEST_P(PeerConnectionHeaderExtensionTest,OffersUnstoppedModifiedExtensions)175 TEST_P(PeerConnectionHeaderExtensionTest, OffersUnstoppedModifiedExtensions) {
176 cricket::MediaType media_type;
177 SdpSemantics semantics;
178 std::tie(media_type, semantics) = GetParam();
179 if (semantics != SdpSemantics::kUnifiedPlan)
180 return;
181 std::unique_ptr<PeerConnectionWrapper> wrapper =
182 CreatePeerConnection(media_type, semantics);
183 auto transceiver = wrapper->AddTransceiver(media_type);
184 auto modified_extensions = transceiver->HeaderExtensionsToOffer();
185 modified_extensions[0].direction = RtpTransceiverDirection::kSendRecv;
186 modified_extensions[3].direction = RtpTransceiverDirection::kStopped;
187 EXPECT_TRUE(
188 transceiver->SetOfferedRtpHeaderExtensions(modified_extensions).ok());
189 auto session_description = wrapper->CreateOffer();
190 EXPECT_THAT(session_description->description()
191 ->contents()[0]
192 .media_description()
193 ->rtp_header_extensions(),
194 ElementsAre(Field(&RtpExtension::uri, "uri1"),
195 Field(&RtpExtension::uri, "uri2"),
196 Field(&RtpExtension::uri, "uri3")));
197 }
198
TEST_P(PeerConnectionHeaderExtensionTest,NegotiatedExtensionsAreAccessible)199 TEST_P(PeerConnectionHeaderExtensionTest, NegotiatedExtensionsAreAccessible) {
200 cricket::MediaType media_type;
201 SdpSemantics semantics;
202 std::tie(media_type, semantics) = GetParam();
203 if (semantics != SdpSemantics::kUnifiedPlan)
204 return;
205 std::unique_ptr<PeerConnectionWrapper> pc1 =
206 CreatePeerConnection(media_type, semantics);
207 auto transceiver1 = pc1->AddTransceiver(media_type);
208 auto modified_extensions = transceiver1->HeaderExtensionsToOffer();
209 modified_extensions[3].direction = RtpTransceiverDirection::kStopped;
210 transceiver1->SetOfferedRtpHeaderExtensions(modified_extensions);
211 auto offer = pc1->CreateOfferAndSetAsLocal(
212 PeerConnectionInterface::RTCOfferAnswerOptions());
213
214 std::unique_ptr<PeerConnectionWrapper> pc2 =
215 CreatePeerConnection(media_type, semantics);
216 auto transceiver2 = pc2->AddTransceiver(media_type);
217 pc2->SetRemoteDescription(std::move(offer));
218 auto answer = pc2->CreateAnswerAndSetAsLocal(
219 PeerConnectionInterface::RTCOfferAnswerOptions());
220 pc1->SetRemoteDescription(std::move(answer));
221
222 // PC1 has exts 2-4 unstopped and PC2 has exts 1-3 unstopped -> ext 2, 3
223 // survives.
224 EXPECT_THAT(transceiver1->HeaderExtensionsNegotiated(),
225 ElementsAre(Field(&RtpHeaderExtensionCapability::uri, "uri2"),
226 Field(&RtpHeaderExtensionCapability::uri, "uri3")));
227 }
228
229 INSTANTIATE_TEST_SUITE_P(
230 ,
231 PeerConnectionHeaderExtensionTest,
232 Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
233 Values(cricket::MediaType::MEDIA_TYPE_AUDIO,
234 cricket::MediaType::MEDIA_TYPE_VIDEO)),
235 [](const testing::TestParamInfo<
__anonb8353a710102(const testing::TestParamInfo< PeerConnectionHeaderExtensionTest::ParamType>& info) 236 PeerConnectionHeaderExtensionTest::ParamType>& info) {
237 cricket::MediaType media_type;
238 SdpSemantics semantics;
239 std::tie(media_type, semantics) = info.param;
240 return (rtc::StringBuilder("With")
241 << (semantics == SdpSemantics::kPlanB_DEPRECATED ? "PlanB"
242 : "UnifiedPlan")
243 << "And"
244 << (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO ? "Voice"
245 : "Video")
246 << "Engine")
247 .str();
248 });
249
250 } // namespace webrtc
251