blob: cfb5dde22af3cbe0487d46e9cf9c932351c04879 [file] [log] [blame]
Steve Antonda6c0952017-10-23 11:41:54 -07001/*
2 * Copyright 2017 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 <tuple>
12
13#include "api/peerconnectionproxy.h"
Bjorn Mellem175aa2e2018-11-08 11:23:22 -080014#include "api/test/fake_media_transport.h"
Steve Antonda6c0952017-10-23 11:41:54 -070015#include "media/base/fakemediaengine.h"
16#include "pc/mediasession.h"
17#include "pc/peerconnection.h"
18#include "pc/peerconnectionfactory.h"
19#include "pc/peerconnectionwrapper.h"
Steve Antondbf9d032018-01-19 15:23:40 -080020#include "pc/sdputils.h"
Steve Antonda6c0952017-10-23 11:41:54 -070021#ifdef WEBRTC_ANDROID
22#include "pc/test/androidtestinitializer.h"
23#endif
Karl Wiberg918f50c2018-07-05 11:40:33 +020024#include "absl/memory/memory.h"
Steve Antonda6c0952017-10-23 11:41:54 -070025#include "pc/test/fakesctptransport.h"
26#include "rtc_base/gunit.h"
Steve Antonda6c0952017-10-23 11:41:54 -070027#include "rtc_base/virtualsocketserver.h"
28
29namespace webrtc {
30
31using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
32using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
33using ::testing::Values;
34
Bjorn Mellem175aa2e2018-11-08 11:23:22 -080035namespace {
36
37PeerConnectionFactoryDependencies CreatePeerConnectionFactoryDependencies(
38 rtc::Thread* network_thread,
39 rtc::Thread* worker_thread,
40 rtc::Thread* signaling_thread,
41 std::unique_ptr<cricket::MediaEngineInterface> media_engine,
42 std::unique_ptr<CallFactoryInterface> call_factory,
43 std::unique_ptr<MediaTransportFactory> media_transport_factory) {
44 PeerConnectionFactoryDependencies deps;
45 deps.network_thread = network_thread;
46 deps.worker_thread = worker_thread;
47 deps.signaling_thread = signaling_thread;
48 deps.media_engine = std::move(media_engine);
49 deps.call_factory = std::move(call_factory);
50 deps.media_transport_factory = std::move(media_transport_factory);
51 return deps;
52}
53
54} // namespace
55
Steve Antonda6c0952017-10-23 11:41:54 -070056class PeerConnectionFactoryForDataChannelTest
57 : public rtc::RefCountedObject<PeerConnectionFactory> {
58 public:
59 PeerConnectionFactoryForDataChannelTest()
60 : rtc::RefCountedObject<PeerConnectionFactory>(
Bjorn Mellem175aa2e2018-11-08 11:23:22 -080061 CreatePeerConnectionFactoryDependencies(
62 rtc::Thread::Current(),
63 rtc::Thread::Current(),
64 rtc::Thread::Current(),
65 absl::make_unique<cricket::FakeMediaEngine>(),
66 CreateCallFactory(),
67 absl::make_unique<FakeMediaTransportFactory>())) {}
Steve Antonda6c0952017-10-23 11:41:54 -070068
69 std::unique_ptr<cricket::SctpTransportInternalFactory>
70 CreateSctpTransportInternalFactory() {
Karl Wiberg918f50c2018-07-05 11:40:33 +020071 auto factory = absl::make_unique<FakeSctpTransportFactory>();
Steve Antonda6c0952017-10-23 11:41:54 -070072 last_fake_sctp_transport_factory_ = factory.get();
73 return factory;
74 }
75
76 FakeSctpTransportFactory* last_fake_sctp_transport_factory_ = nullptr;
77};
78
79class PeerConnectionWrapperForDataChannelTest : public PeerConnectionWrapper {
80 public:
81 using PeerConnectionWrapper::PeerConnectionWrapper;
82
83 FakeSctpTransportFactory* sctp_transport_factory() {
84 return sctp_transport_factory_;
85 }
86
87 void set_sctp_transport_factory(
88 FakeSctpTransportFactory* sctp_transport_factory) {
89 sctp_transport_factory_ = sctp_transport_factory;
90 }
91
Danil Chapovalov66cadcc2018-06-19 16:47:43 +020092 absl::optional<std::string> sctp_content_name() {
Steve Antonda6c0952017-10-23 11:41:54 -070093 return GetInternalPeerConnection()->sctp_content_name();
94 }
95
Danil Chapovalov66cadcc2018-06-19 16:47:43 +020096 absl::optional<std::string> sctp_transport_name() {
Steve Antonda6c0952017-10-23 11:41:54 -070097 return GetInternalPeerConnection()->sctp_transport_name();
98 }
99
100 PeerConnection* GetInternalPeerConnection() {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100101 auto* pci =
102 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
103 pc());
104 return static_cast<PeerConnection*>(pci->internal());
Steve Antonda6c0952017-10-23 11:41:54 -0700105 }
106
107 private:
108 FakeSctpTransportFactory* sctp_transport_factory_ = nullptr;
109};
110
Steve Antondbf9d032018-01-19 15:23:40 -0800111class PeerConnectionDataChannelBaseTest : public ::testing::Test {
Steve Antonda6c0952017-10-23 11:41:54 -0700112 protected:
113 typedef std::unique_ptr<PeerConnectionWrapperForDataChannelTest> WrapperPtr;
114
Steve Antondbf9d032018-01-19 15:23:40 -0800115 explicit PeerConnectionDataChannelBaseTest(SdpSemantics sdp_semantics)
116 : vss_(new rtc::VirtualSocketServer()),
117 main_(vss_.get()),
118 sdp_semantics_(sdp_semantics) {
Steve Antonda6c0952017-10-23 11:41:54 -0700119#ifdef WEBRTC_ANDROID
120 InitializeAndroidObjects();
121#endif
122 }
123
124 WrapperPtr CreatePeerConnection() {
125 return CreatePeerConnection(RTCConfiguration());
126 }
127
128 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
129 return CreatePeerConnection(config,
130 PeerConnectionFactoryInterface::Options());
131 }
132
133 WrapperPtr CreatePeerConnection(
134 const RTCConfiguration& config,
135 const PeerConnectionFactoryInterface::Options factory_options) {
136 rtc::scoped_refptr<PeerConnectionFactoryForDataChannelTest> pc_factory(
137 new PeerConnectionFactoryForDataChannelTest());
138 pc_factory->SetOptions(factory_options);
139 RTC_CHECK(pc_factory->Initialize());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200140 auto observer = absl::make_unique<MockPeerConnectionObserver>();
Steve Antondbf9d032018-01-19 15:23:40 -0800141 RTCConfiguration modified_config = config;
142 modified_config.sdp_semantics = sdp_semantics_;
143 auto pc = pc_factory->CreatePeerConnection(modified_config, nullptr,
144 nullptr, observer.get());
Steve Antonda6c0952017-10-23 11:41:54 -0700145 if (!pc) {
146 return nullptr;
147 }
148
Yves Gerey4e933292018-10-31 15:36:05 +0100149 observer->SetPeerConnectionInterface(pc.get());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200150 auto wrapper = absl::make_unique<PeerConnectionWrapperForDataChannelTest>(
Steve Antonda6c0952017-10-23 11:41:54 -0700151 pc_factory, pc, std::move(observer));
152 RTC_DCHECK(pc_factory->last_fake_sctp_transport_factory_);
153 wrapper->set_sctp_transport_factory(
154 pc_factory->last_fake_sctp_transport_factory_);
155 return wrapper;
156 }
157
158 // Accepts the same arguments as CreatePeerConnection and adds a default data
159 // channel.
160 template <typename... Args>
161 WrapperPtr CreatePeerConnectionWithDataChannel(Args&&... args) {
162 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
163 if (!wrapper) {
164 return nullptr;
165 }
166 EXPECT_TRUE(wrapper->pc()->CreateDataChannel("dc", nullptr));
167 return wrapper;
168 }
169
170 // Changes the SCTP data channel port on the given session description.
171 void ChangeSctpPortOnDescription(cricket::SessionDescription* desc,
172 int port) {
173 cricket::DataCodec sctp_codec(cricket::kGoogleSctpDataCodecPlType,
174 cricket::kGoogleSctpDataCodecName);
175 sctp_codec.SetParam(cricket::kCodecParamPort, port);
176
177 auto* data_content = cricket::GetFirstDataContent(desc);
178 RTC_DCHECK(data_content);
Steve Antonb1c1de12017-12-21 15:14:30 -0800179 auto* data_desc = data_content->media_description()->as_data();
Steve Antonda6c0952017-10-23 11:41:54 -0700180 data_desc->set_codecs({sctp_codec});
181 }
182
183 std::unique_ptr<rtc::VirtualSocketServer> vss_;
184 rtc::AutoSocketServerThread main_;
Steve Antondbf9d032018-01-19 15:23:40 -0800185 const SdpSemantics sdp_semantics_;
Steve Antonda6c0952017-10-23 11:41:54 -0700186};
187
Steve Antondbf9d032018-01-19 15:23:40 -0800188class PeerConnectionDataChannelTest
189 : public PeerConnectionDataChannelBaseTest,
190 public ::testing::WithParamInterface<SdpSemantics> {
191 protected:
192 PeerConnectionDataChannelTest()
193 : PeerConnectionDataChannelBaseTest(GetParam()) {}
194};
195
196TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700197 NoSctpTransportCreatedIfRtpDataChannelEnabled) {
198 RTCConfiguration config;
199 config.enable_rtp_data_channel = true;
200 auto caller = CreatePeerConnectionWithDataChannel(config);
201
202 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
203 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
204}
205
Steve Antondbf9d032018-01-19 15:23:40 -0800206TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700207 RtpDataChannelCreatedEvenIfSctpAvailable) {
208 RTCConfiguration config;
209 config.enable_rtp_data_channel = true;
210 PeerConnectionFactoryInterface::Options options;
211 options.disable_sctp_data_channels = false;
212 auto caller = CreatePeerConnectionWithDataChannel(config, options);
213
214 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
215 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
216}
217
218// Test that sctp_content_name/sctp_transport_name (used for stats) are correct
219// before and after BUNDLE is negotiated.
Steve Antondbf9d032018-01-19 15:23:40 -0800220TEST_P(PeerConnectionDataChannelTest, SctpContentAndTransportNameSetCorrectly) {
Steve Antonda6c0952017-10-23 11:41:54 -0700221 auto caller = CreatePeerConnection();
222 auto callee = CreatePeerConnection();
223
224 // Initially these fields should be empty.
225 EXPECT_FALSE(caller->sctp_content_name());
226 EXPECT_FALSE(caller->sctp_transport_name());
227
228 // Create offer with audio/video/data.
229 // Default bundle policy is "balanced", so data should be using its own
230 // transport.
231 caller->AddAudioTrack("a");
232 caller->AddVideoTrack("v");
233 caller->pc()->CreateDataChannel("dc", nullptr);
Steve Antondbf9d032018-01-19 15:23:40 -0800234
235 auto offer = caller->CreateOffer();
236 const auto& offer_contents = offer->description()->contents();
237 ASSERT_EQ(cricket::MEDIA_TYPE_AUDIO,
238 offer_contents[0].media_description()->type());
239 std::string audio_mid = offer_contents[0].name;
240 ASSERT_EQ(cricket::MEDIA_TYPE_DATA,
241 offer_contents[2].media_description()->type());
242 std::string data_mid = offer_contents[2].name;
243
244 ASSERT_TRUE(
245 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
246 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antonda6c0952017-10-23 11:41:54 -0700247
248 ASSERT_TRUE(caller->sctp_content_name());
Steve Antondbf9d032018-01-19 15:23:40 -0800249 EXPECT_EQ(data_mid, *caller->sctp_content_name());
Steve Antonda6c0952017-10-23 11:41:54 -0700250 ASSERT_TRUE(caller->sctp_transport_name());
Steve Antondbf9d032018-01-19 15:23:40 -0800251 EXPECT_EQ(data_mid, *caller->sctp_transport_name());
Steve Antonda6c0952017-10-23 11:41:54 -0700252
253 // Create answer that finishes BUNDLE negotiation, which means everything
254 // should be bundled on the first transport (audio).
255 RTCOfferAnswerOptions options;
256 options.use_rtp_mux = true;
257 ASSERT_TRUE(
258 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
259
260 ASSERT_TRUE(caller->sctp_content_name());
Steve Antondbf9d032018-01-19 15:23:40 -0800261 EXPECT_EQ(data_mid, *caller->sctp_content_name());
Steve Antonda6c0952017-10-23 11:41:54 -0700262 ASSERT_TRUE(caller->sctp_transport_name());
Steve Antondbf9d032018-01-19 15:23:40 -0800263 EXPECT_EQ(audio_mid, *caller->sctp_transport_name());
Steve Antonda6c0952017-10-23 11:41:54 -0700264}
265
Steve Antondbf9d032018-01-19 15:23:40 -0800266TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700267 CreateOfferWithNoDataChannelsGivesNoDataSection) {
268 auto caller = CreatePeerConnection();
269 auto offer = caller->CreateOffer();
270
271 EXPECT_FALSE(offer->description()->GetContentByName(cricket::CN_DATA));
272 EXPECT_FALSE(offer->description()->GetTransportInfoByName(cricket::CN_DATA));
273}
274
Steve Antondbf9d032018-01-19 15:23:40 -0800275TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700276 CreateAnswerWithRemoteSctpDataChannelIncludesDataSection) {
277 auto caller = CreatePeerConnectionWithDataChannel();
278 auto callee = CreatePeerConnection();
279
280 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
281
282 auto answer = callee->CreateAnswer();
283 ASSERT_TRUE(answer);
Steve Antondbf9d032018-01-19 15:23:40 -0800284 auto* data_content = cricket::GetFirstDataContent(answer->description());
Steve Antonda6c0952017-10-23 11:41:54 -0700285 ASSERT_TRUE(data_content);
286 EXPECT_FALSE(data_content->rejected);
Steve Antondbf9d032018-01-19 15:23:40 -0800287 EXPECT_TRUE(
288 answer->description()->GetTransportInfoByName(data_content->name));
Steve Antonda6c0952017-10-23 11:41:54 -0700289}
290
Steve Antondbf9d032018-01-19 15:23:40 -0800291TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700292 CreateDataChannelWithDtlsDisabledSucceeds) {
293 RTCConfiguration config;
294 config.enable_dtls_srtp.emplace(false);
295 auto caller = CreatePeerConnection();
296
297 EXPECT_TRUE(caller->pc()->CreateDataChannel("dc", nullptr));
298}
299
Steve Antondbf9d032018-01-19 15:23:40 -0800300TEST_P(PeerConnectionDataChannelTest, CreateDataChannelWithSctpDisabledFails) {
Steve Antonda6c0952017-10-23 11:41:54 -0700301 PeerConnectionFactoryInterface::Options options;
302 options.disable_sctp_data_channels = true;
303 auto caller = CreatePeerConnection(RTCConfiguration(), options);
304
305 EXPECT_FALSE(caller->pc()->CreateDataChannel("dc", nullptr));
306}
307
308// Test that if a callee has SCTP disabled and receives an offer with an SCTP
309// data channel, the data section is rejected and no SCTP transport is created
310// on the callee.
Steve Antondbf9d032018-01-19 15:23:40 -0800311TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700312 DataSectionRejectedIfCalleeHasSctpDisabled) {
313 auto caller = CreatePeerConnectionWithDataChannel();
314 PeerConnectionFactoryInterface::Options options;
315 options.disable_sctp_data_channels = true;
316 auto callee = CreatePeerConnection(RTCConfiguration(), options);
317
318 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
319
320 EXPECT_FALSE(callee->sctp_transport_factory()->last_fake_sctp_transport());
321
322 auto answer = callee->CreateAnswer();
Steve Antondbf9d032018-01-19 15:23:40 -0800323 auto* data_content = cricket::GetFirstDataContent(answer->description());
Steve Antonda6c0952017-10-23 11:41:54 -0700324 ASSERT_TRUE(data_content);
325 EXPECT_TRUE(data_content->rejected);
326}
327
Steve Antondbf9d032018-01-19 15:23:40 -0800328TEST_P(PeerConnectionDataChannelTest, SctpPortPropagatedFromSdpToTransport) {
Steve Antonda6c0952017-10-23 11:41:54 -0700329 constexpr int kNewSendPort = 9998;
330 constexpr int kNewRecvPort = 7775;
331
332 auto caller = CreatePeerConnectionWithDataChannel();
333 auto callee = CreatePeerConnectionWithDataChannel();
334
335 auto offer = caller->CreateOffer();
336 ChangeSctpPortOnDescription(offer->description(), kNewSendPort);
337 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
338
339 auto answer = callee->CreateAnswer();
340 ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
341 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
342
343 auto* callee_transport =
344 callee->sctp_transport_factory()->last_fake_sctp_transport();
345 ASSERT_TRUE(callee_transport);
346 EXPECT_EQ(kNewSendPort, callee_transport->remote_port());
347 EXPECT_EQ(kNewRecvPort, callee_transport->local_port());
348}
349
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800350TEST_P(PeerConnectionDataChannelTest,
351 NoSctpTransportCreatedIfMediaTransportDataChannelsEnabled) {
352 RTCConfiguration config;
353 config.use_media_transport_for_data_channels = true;
354 config.enable_dtls_srtp = false; // SDES is required to use media transport.
355 auto caller = CreatePeerConnectionWithDataChannel(config);
356
357 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
358 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
359}
360
361TEST_P(PeerConnectionDataChannelTest,
362 MediaTransportDataChannelCreatedEvenIfSctpAvailable) {
363 RTCConfiguration config;
364 config.use_media_transport_for_data_channels = true;
365 config.enable_dtls_srtp = false; // SDES is required to use media transport.
366 PeerConnectionFactoryInterface::Options options;
367 options.disable_sctp_data_channels = false;
368 auto caller = CreatePeerConnectionWithDataChannel(config, options);
369
370 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
371 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
372}
373
374TEST_P(PeerConnectionDataChannelTest,
375 CannotEnableBothMediaTransportAndRtpDataChannels) {
376 RTCConfiguration config;
377 config.enable_rtp_data_channel = true;
378 config.use_media_transport_for_data_channels = true;
379 config.enable_dtls_srtp = false; // SDES is required to use media transport.
380 EXPECT_EQ(CreatePeerConnection(config), nullptr);
381}
382
383TEST_P(PeerConnectionDataChannelTest,
384 MediaTransportDataChannelFailsWithoutSdes) {
385 RTCConfiguration config;
386 config.use_media_transport_for_data_channels = true;
387 config.enable_dtls_srtp = true; // Disables SDES for data sections.
388 auto caller = CreatePeerConnectionWithDataChannel(config);
389
390 std::string error;
391 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
392 EXPECT_EQ(error,
393 "Failed to set local offer sdp: Failed to create data channel.");
394}
395
Steve Antondbf9d032018-01-19 15:23:40 -0800396INSTANTIATE_TEST_CASE_P(PeerConnectionDataChannelTest,
397 PeerConnectionDataChannelTest,
398 Values(SdpSemantics::kPlanB,
399 SdpSemantics::kUnifiedPlan));
400
Steve Antonda6c0952017-10-23 11:41:54 -0700401} // namespace webrtc