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