blob: 02bac685b412eb3d568b763bf76c3d755dad4c88 [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"
14#include "media/base/fakemediaengine.h"
15#include "pc/mediasession.h"
16#include "pc/peerconnection.h"
17#include "pc/peerconnectionfactory.h"
18#include "pc/peerconnectionwrapper.h"
19#ifdef WEBRTC_ANDROID
20#include "pc/test/androidtestinitializer.h"
21#endif
22#include "pc/test/fakesctptransport.h"
23#include "rtc_base/gunit.h"
24#include "rtc_base/ptr_util.h"
25#include "rtc_base/virtualsocketserver.h"
26
27namespace webrtc {
28
29using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
30using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
31using ::testing::Values;
32
33class PeerConnectionFactoryForDataChannelTest
34 : public rtc::RefCountedObject<PeerConnectionFactory> {
35 public:
36 PeerConnectionFactoryForDataChannelTest()
37 : rtc::RefCountedObject<PeerConnectionFactory>(
38 rtc::Thread::Current(),
39 rtc::Thread::Current(),
40 rtc::Thread::Current(),
41 rtc::MakeUnique<cricket::FakeMediaEngine>(),
42 CreateCallFactory(),
43 nullptr) {}
44
45 std::unique_ptr<cricket::SctpTransportInternalFactory>
46 CreateSctpTransportInternalFactory() {
47 auto factory = rtc::MakeUnique<FakeSctpTransportFactory>();
48 last_fake_sctp_transport_factory_ = factory.get();
49 return factory;
50 }
51
52 FakeSctpTransportFactory* last_fake_sctp_transport_factory_ = nullptr;
53};
54
55class PeerConnectionWrapperForDataChannelTest : public PeerConnectionWrapper {
56 public:
57 using PeerConnectionWrapper::PeerConnectionWrapper;
58
59 FakeSctpTransportFactory* sctp_transport_factory() {
60 return sctp_transport_factory_;
61 }
62
63 void set_sctp_transport_factory(
64 FakeSctpTransportFactory* sctp_transport_factory) {
65 sctp_transport_factory_ = sctp_transport_factory;
66 }
67
68 rtc::Optional<std::string> sctp_content_name() {
69 return GetInternalPeerConnection()->sctp_content_name();
70 }
71
72 rtc::Optional<std::string> sctp_transport_name() {
73 return GetInternalPeerConnection()->sctp_transport_name();
74 }
75
76 PeerConnection* GetInternalPeerConnection() {
Mirko Bonadeie97de912017-12-13 11:29:34 +010077 auto* pci =
78 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
79 pc());
80 return static_cast<PeerConnection*>(pci->internal());
Steve Antonda6c0952017-10-23 11:41:54 -070081 }
82
83 private:
84 FakeSctpTransportFactory* sctp_transport_factory_ = nullptr;
85};
86
87class PeerConnectionDataChannelTest : public ::testing::Test {
88 protected:
89 typedef std::unique_ptr<PeerConnectionWrapperForDataChannelTest> WrapperPtr;
90
91 PeerConnectionDataChannelTest()
92 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
93#ifdef WEBRTC_ANDROID
94 InitializeAndroidObjects();
95#endif
96 }
97
98 WrapperPtr CreatePeerConnection() {
99 return CreatePeerConnection(RTCConfiguration());
100 }
101
102 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
103 return CreatePeerConnection(config,
104 PeerConnectionFactoryInterface::Options());
105 }
106
107 WrapperPtr CreatePeerConnection(
108 const RTCConfiguration& config,
109 const PeerConnectionFactoryInterface::Options factory_options) {
110 rtc::scoped_refptr<PeerConnectionFactoryForDataChannelTest> pc_factory(
111 new PeerConnectionFactoryForDataChannelTest());
112 pc_factory->SetOptions(factory_options);
113 RTC_CHECK(pc_factory->Initialize());
114 auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
115 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
116 observer.get());
117 if (!pc) {
118 return nullptr;
119 }
120
121 auto wrapper = rtc::MakeUnique<PeerConnectionWrapperForDataChannelTest>(
122 pc_factory, pc, std::move(observer));
123 RTC_DCHECK(pc_factory->last_fake_sctp_transport_factory_);
124 wrapper->set_sctp_transport_factory(
125 pc_factory->last_fake_sctp_transport_factory_);
126 return wrapper;
127 }
128
129 // Accepts the same arguments as CreatePeerConnection and adds a default data
130 // channel.
131 template <typename... Args>
132 WrapperPtr CreatePeerConnectionWithDataChannel(Args&&... args) {
133 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
134 if (!wrapper) {
135 return nullptr;
136 }
137 EXPECT_TRUE(wrapper->pc()->CreateDataChannel("dc", nullptr));
138 return wrapper;
139 }
140
141 // Changes the SCTP data channel port on the given session description.
142 void ChangeSctpPortOnDescription(cricket::SessionDescription* desc,
143 int port) {
144 cricket::DataCodec sctp_codec(cricket::kGoogleSctpDataCodecPlType,
145 cricket::kGoogleSctpDataCodecName);
146 sctp_codec.SetParam(cricket::kCodecParamPort, port);
147
148 auto* data_content = cricket::GetFirstDataContent(desc);
149 RTC_DCHECK(data_content);
150 auto* data_desc = static_cast<cricket::DataContentDescription*>(
151 data_content->description);
152 data_desc->set_codecs({sctp_codec});
153 }
154
155 std::unique_ptr<rtc::VirtualSocketServer> vss_;
156 rtc::AutoSocketServerThread main_;
157};
158
159TEST_F(PeerConnectionDataChannelTest,
160 NoSctpTransportCreatedIfRtpDataChannelEnabled) {
161 RTCConfiguration config;
162 config.enable_rtp_data_channel = true;
163 auto caller = CreatePeerConnectionWithDataChannel(config);
164
165 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
166 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
167}
168
169TEST_F(PeerConnectionDataChannelTest,
170 RtpDataChannelCreatedEvenIfSctpAvailable) {
171 RTCConfiguration config;
172 config.enable_rtp_data_channel = true;
173 PeerConnectionFactoryInterface::Options options;
174 options.disable_sctp_data_channels = false;
175 auto caller = CreatePeerConnectionWithDataChannel(config, options);
176
177 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
178 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
179}
180
181// Test that sctp_content_name/sctp_transport_name (used for stats) are correct
182// before and after BUNDLE is negotiated.
183TEST_F(PeerConnectionDataChannelTest, SctpContentAndTransportNameSetCorrectly) {
184 auto caller = CreatePeerConnection();
185 auto callee = CreatePeerConnection();
186
187 // Initially these fields should be empty.
188 EXPECT_FALSE(caller->sctp_content_name());
189 EXPECT_FALSE(caller->sctp_transport_name());
190
191 // Create offer with audio/video/data.
192 // Default bundle policy is "balanced", so data should be using its own
193 // transport.
194 caller->AddAudioTrack("a");
195 caller->AddVideoTrack("v");
196 caller->pc()->CreateDataChannel("dc", nullptr);
197 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
198
199 ASSERT_TRUE(caller->sctp_content_name());
200 EXPECT_EQ(cricket::CN_DATA, *caller->sctp_content_name());
201 ASSERT_TRUE(caller->sctp_transport_name());
202 EXPECT_EQ(cricket::CN_DATA, *caller->sctp_transport_name());
203
204 // Create answer that finishes BUNDLE negotiation, which means everything
205 // should be bundled on the first transport (audio).
206 RTCOfferAnswerOptions options;
207 options.use_rtp_mux = true;
208 ASSERT_TRUE(
209 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
210
211 ASSERT_TRUE(caller->sctp_content_name());
212 EXPECT_EQ(cricket::CN_DATA, *caller->sctp_content_name());
213 ASSERT_TRUE(caller->sctp_transport_name());
214 EXPECT_EQ(cricket::CN_AUDIO, *caller->sctp_transport_name());
215}
216
217TEST_F(PeerConnectionDataChannelTest,
218 CreateOfferWithNoDataChannelsGivesNoDataSection) {
219 auto caller = CreatePeerConnection();
220 auto offer = caller->CreateOffer();
221
222 EXPECT_FALSE(offer->description()->GetContentByName(cricket::CN_DATA));
223 EXPECT_FALSE(offer->description()->GetTransportInfoByName(cricket::CN_DATA));
224}
225
226TEST_F(PeerConnectionDataChannelTest,
227 CreateAnswerWithRemoteSctpDataChannelIncludesDataSection) {
228 auto caller = CreatePeerConnectionWithDataChannel();
229 auto callee = CreatePeerConnection();
230
231 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
232
233 auto answer = callee->CreateAnswer();
234 ASSERT_TRUE(answer);
235 auto* data_content =
236 answer->description()->GetContentByName(cricket::CN_DATA);
237 ASSERT_TRUE(data_content);
238 EXPECT_FALSE(data_content->rejected);
239 EXPECT_TRUE(answer->description()->GetTransportInfoByName(cricket::CN_DATA));
240}
241
242TEST_F(PeerConnectionDataChannelTest,
243 CreateDataChannelWithDtlsDisabledSucceeds) {
244 RTCConfiguration config;
245 config.enable_dtls_srtp.emplace(false);
246 auto caller = CreatePeerConnection();
247
248 EXPECT_TRUE(caller->pc()->CreateDataChannel("dc", nullptr));
249}
250
251TEST_F(PeerConnectionDataChannelTest, CreateDataChannelWithSctpDisabledFails) {
252 PeerConnectionFactoryInterface::Options options;
253 options.disable_sctp_data_channels = true;
254 auto caller = CreatePeerConnection(RTCConfiguration(), options);
255
256 EXPECT_FALSE(caller->pc()->CreateDataChannel("dc", nullptr));
257}
258
259// Test that if a callee has SCTP disabled and receives an offer with an SCTP
260// data channel, the data section is rejected and no SCTP transport is created
261// on the callee.
262TEST_F(PeerConnectionDataChannelTest,
263 DataSectionRejectedIfCalleeHasSctpDisabled) {
264 auto caller = CreatePeerConnectionWithDataChannel();
265 PeerConnectionFactoryInterface::Options options;
266 options.disable_sctp_data_channels = true;
267 auto callee = CreatePeerConnection(RTCConfiguration(), options);
268
269 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
270
271 EXPECT_FALSE(callee->sctp_transport_factory()->last_fake_sctp_transport());
272
273 auto answer = callee->CreateAnswer();
274 auto* data_content =
275 answer->description()->GetContentByName(cricket::CN_DATA);
276 ASSERT_TRUE(data_content);
277 EXPECT_TRUE(data_content->rejected);
278}
279
280TEST_F(PeerConnectionDataChannelTest, SctpPortPropagatedFromSdpToTransport) {
281 constexpr int kNewSendPort = 9998;
282 constexpr int kNewRecvPort = 7775;
283
284 auto caller = CreatePeerConnectionWithDataChannel();
285 auto callee = CreatePeerConnectionWithDataChannel();
286
287 auto offer = caller->CreateOffer();
288 ChangeSctpPortOnDescription(offer->description(), kNewSendPort);
289 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
290
291 auto answer = callee->CreateAnswer();
292 ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
293 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
294
295 auto* callee_transport =
296 callee->sctp_transport_factory()->last_fake_sctp_transport();
297 ASSERT_TRUE(callee_transport);
298 EXPECT_EQ(kNewSendPort, callee_transport->remote_port());
299 EXPECT_EQ(kNewRecvPort, callee_transport->local_port());
300}
301
302} // namespace webrtc