blob: ca3a3f11ca42c67899251277104ebfac79d2b7ad [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);
Steve Antonb1c1de12017-12-21 15:14:30 -0800150 auto* data_desc = data_content->media_description()->as_data();
Steve Antonda6c0952017-10-23 11:41:54 -0700151 data_desc->set_codecs({sctp_codec});
152 }
153
154 std::unique_ptr<rtc::VirtualSocketServer> vss_;
155 rtc::AutoSocketServerThread main_;
156};
157
158TEST_F(PeerConnectionDataChannelTest,
159 NoSctpTransportCreatedIfRtpDataChannelEnabled) {
160 RTCConfiguration config;
161 config.enable_rtp_data_channel = true;
162 auto caller = CreatePeerConnectionWithDataChannel(config);
163
164 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
165 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
166}
167
168TEST_F(PeerConnectionDataChannelTest,
169 RtpDataChannelCreatedEvenIfSctpAvailable) {
170 RTCConfiguration config;
171 config.enable_rtp_data_channel = true;
172 PeerConnectionFactoryInterface::Options options;
173 options.disable_sctp_data_channels = false;
174 auto caller = CreatePeerConnectionWithDataChannel(config, options);
175
176 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
177 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
178}
179
180// Test that sctp_content_name/sctp_transport_name (used for stats) are correct
181// before and after BUNDLE is negotiated.
182TEST_F(PeerConnectionDataChannelTest, SctpContentAndTransportNameSetCorrectly) {
183 auto caller = CreatePeerConnection();
184 auto callee = CreatePeerConnection();
185
186 // Initially these fields should be empty.
187 EXPECT_FALSE(caller->sctp_content_name());
188 EXPECT_FALSE(caller->sctp_transport_name());
189
190 // Create offer with audio/video/data.
191 // Default bundle policy is "balanced", so data should be using its own
192 // transport.
193 caller->AddAudioTrack("a");
194 caller->AddVideoTrack("v");
195 caller->pc()->CreateDataChannel("dc", nullptr);
196 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
197
198 ASSERT_TRUE(caller->sctp_content_name());
199 EXPECT_EQ(cricket::CN_DATA, *caller->sctp_content_name());
200 ASSERT_TRUE(caller->sctp_transport_name());
201 EXPECT_EQ(cricket::CN_DATA, *caller->sctp_transport_name());
202
203 // Create answer that finishes BUNDLE negotiation, which means everything
204 // should be bundled on the first transport (audio).
205 RTCOfferAnswerOptions options;
206 options.use_rtp_mux = true;
207 ASSERT_TRUE(
208 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
209
210 ASSERT_TRUE(caller->sctp_content_name());
211 EXPECT_EQ(cricket::CN_DATA, *caller->sctp_content_name());
212 ASSERT_TRUE(caller->sctp_transport_name());
213 EXPECT_EQ(cricket::CN_AUDIO, *caller->sctp_transport_name());
214}
215
216TEST_F(PeerConnectionDataChannelTest,
217 CreateOfferWithNoDataChannelsGivesNoDataSection) {
218 auto caller = CreatePeerConnection();
219 auto offer = caller->CreateOffer();
220
221 EXPECT_FALSE(offer->description()->GetContentByName(cricket::CN_DATA));
222 EXPECT_FALSE(offer->description()->GetTransportInfoByName(cricket::CN_DATA));
223}
224
225TEST_F(PeerConnectionDataChannelTest,
226 CreateAnswerWithRemoteSctpDataChannelIncludesDataSection) {
227 auto caller = CreatePeerConnectionWithDataChannel();
228 auto callee = CreatePeerConnection();
229
230 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
231
232 auto answer = callee->CreateAnswer();
233 ASSERT_TRUE(answer);
234 auto* data_content =
235 answer->description()->GetContentByName(cricket::CN_DATA);
236 ASSERT_TRUE(data_content);
237 EXPECT_FALSE(data_content->rejected);
238 EXPECT_TRUE(answer->description()->GetTransportInfoByName(cricket::CN_DATA));
239}
240
241TEST_F(PeerConnectionDataChannelTest,
242 CreateDataChannelWithDtlsDisabledSucceeds) {
243 RTCConfiguration config;
244 config.enable_dtls_srtp.emplace(false);
245 auto caller = CreatePeerConnection();
246
247 EXPECT_TRUE(caller->pc()->CreateDataChannel("dc", nullptr));
248}
249
250TEST_F(PeerConnectionDataChannelTest, CreateDataChannelWithSctpDisabledFails) {
251 PeerConnectionFactoryInterface::Options options;
252 options.disable_sctp_data_channels = true;
253 auto caller = CreatePeerConnection(RTCConfiguration(), options);
254
255 EXPECT_FALSE(caller->pc()->CreateDataChannel("dc", nullptr));
256}
257
258// Test that if a callee has SCTP disabled and receives an offer with an SCTP
259// data channel, the data section is rejected and no SCTP transport is created
260// on the callee.
261TEST_F(PeerConnectionDataChannelTest,
262 DataSectionRejectedIfCalleeHasSctpDisabled) {
263 auto caller = CreatePeerConnectionWithDataChannel();
264 PeerConnectionFactoryInterface::Options options;
265 options.disable_sctp_data_channels = true;
266 auto callee = CreatePeerConnection(RTCConfiguration(), options);
267
268 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
269
270 EXPECT_FALSE(callee->sctp_transport_factory()->last_fake_sctp_transport());
271
272 auto answer = callee->CreateAnswer();
273 auto* data_content =
274 answer->description()->GetContentByName(cricket::CN_DATA);
275 ASSERT_TRUE(data_content);
276 EXPECT_TRUE(data_content->rejected);
277}
278
279TEST_F(PeerConnectionDataChannelTest, SctpPortPropagatedFromSdpToTransport) {
280 constexpr int kNewSendPort = 9998;
281 constexpr int kNewRecvPort = 7775;
282
283 auto caller = CreatePeerConnectionWithDataChannel();
284 auto callee = CreatePeerConnectionWithDataChannel();
285
286 auto offer = caller->CreateOffer();
287 ChangeSctpPortOnDescription(offer->description(), kNewSendPort);
288 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
289
290 auto answer = callee->CreateAnswer();
291 ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
292 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
293
294 auto* callee_transport =
295 callee->sctp_transport_factory()->last_fake_sctp_transport();
296 ASSERT_TRUE(callee_transport);
297 EXPECT_EQ(kNewSendPort, callee_transport->remote_port());
298 EXPECT_EQ(kNewRecvPort, callee_transport->local_port());
299}
300
301} // namespace webrtc