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