blob: 43ba4ad6b4010575b6601558e7c431f4b35ba774 [file] [log] [blame]
Zhi Huange818b6e2018-02-22 15:26:27 -08001/*
2 * Copyright 2018 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 <map>
12#include <memory>
13
Steve Anton2bed3972019-01-04 17:04:30 -080014#include "absl/memory/memory.h"
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -080015#include "api/media_transport_interface.h"
Anton Sukhanov7940da02018-10-10 10:34:49 -070016#include "api/test/fake_media_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "p2p/base/fake_dtls_transport.h"
18#include "p2p/base/fake_ice_transport.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080019#include "p2p/base/no_op_dtls_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "p2p/base/transport_factory_interface.h"
21#include "p2p/base/transport_info.h"
22#include "pc/jsep_transport_controller.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080023#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/thread.h"
25#include "test/gtest.h"
26
27using cricket::FakeDtlsTransport;
28using cricket::Candidate;
29using cricket::Candidates;
30using webrtc::SdpType;
31
32static const int kTimeout = 100;
33static const char kIceUfrag1[] = "u0001";
34static const char kIcePwd1[] = "TESTICEPWD00000000000001";
35static const char kIceUfrag2[] = "u0002";
36static const char kIcePwd2[] = "TESTICEPWD00000000000002";
37static const char kIceUfrag3[] = "u0003";
38static const char kIcePwd3[] = "TESTICEPWD00000000000003";
39static const char kAudioMid1[] = "audio1";
40static const char kAudioMid2[] = "audio2";
41static const char kVideoMid1[] = "video1";
42static const char kVideoMid2[] = "video2";
43static const char kDataMid1[] = "data1";
44
45namespace webrtc {
46
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070047namespace {
48
49// Media transport factory requires crypto settings to be present in order to
50// create media transport.
51void AddCryptoSettings(cricket::SessionDescription* description) {
52 for (auto& content : description->contents()) {
53 content.media_description()->AddCrypto(cricket::CryptoParams(
54 /*t=*/0, std::string(rtc::CS_AES_CM_128_HMAC_SHA1_80),
55 "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2", ""));
56 }
57}
58
59} // namespace
60
Zhi Huange818b6e2018-02-22 15:26:27 -080061class FakeTransportFactory : public cricket::TransportFactoryInterface {
62 public:
63 std::unique_ptr<cricket::IceTransportInternal> CreateIceTransport(
64 const std::string& transport_name,
65 int component) override {
Karl Wiberg918f50c2018-07-05 11:40:33 +020066 return absl::make_unique<cricket::FakeIceTransport>(transport_name,
67 component);
Zhi Huange818b6e2018-02-22 15:26:27 -080068 }
69
70 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
71 std::unique_ptr<cricket::IceTransportInternal> ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070072 const webrtc::CryptoOptions& crypto_options) override {
Zhi Huange818b6e2018-02-22 15:26:27 -080073 std::unique_ptr<cricket::FakeIceTransport> fake_ice(
74 static_cast<cricket::FakeIceTransport*>(ice.release()));
Karl Wiberg918f50c2018-07-05 11:40:33 +020075 return absl::make_unique<FakeDtlsTransport>(std::move(fake_ice));
Zhi Huange818b6e2018-02-22 15:26:27 -080076 }
77};
78
Zhi Huang365381f2018-04-13 16:44:34 -070079class JsepTransportControllerTest : public JsepTransportController::Observer,
80 public testing::Test,
Zhi Huange818b6e2018-02-22 15:26:27 -080081 public sigslot::has_slots<> {
82 public:
83 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Karl Wiberg918f50c2018-07-05 11:40:33 +020084 fake_transport_factory_ = absl::make_unique<FakeTransportFactory>();
Zhi Huange818b6e2018-02-22 15:26:27 -080085 }
86
87 void CreateJsepTransportController(
88 JsepTransportController::Config config,
89 rtc::Thread* signaling_thread = rtc::Thread::Current(),
90 rtc::Thread* network_thread = rtc::Thread::Current(),
91 cricket::PortAllocator* port_allocator = nullptr) {
Zhi Huang365381f2018-04-13 16:44:34 -070092 config.transport_observer = this;
Zhi Huange818b6e2018-02-22 15:26:27 -080093 // The tests only works with |fake_transport_factory|;
94 config.external_transport_factory = fake_transport_factory_.get();
Zach Steine20867f2018-08-02 13:20:15 -070095 // TODO(zstein): Provide an AsyncResolverFactory once it is required.
Karl Wiberg918f50c2018-07-05 11:40:33 +020096 transport_controller_ = absl::make_unique<JsepTransportController>(
Zach Steine20867f2018-08-02 13:20:15 -070097 signaling_thread, network_thread, port_allocator, nullptr, config);
Zhi Huange818b6e2018-02-22 15:26:27 -080098 ConnectTransportControllerSignals();
99 }
100
101 void ConnectTransportControllerSignals() {
102 transport_controller_->SignalIceConnectionState.connect(
103 this, &JsepTransportControllerTest::OnConnectionState);
Alex Loiko9289eda2018-11-23 16:18:59 +0000104 transport_controller_->SignalStandardizedIceConnectionState.connect(
105 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200106 transport_controller_->SignalConnectionState.connect(
107 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800108 transport_controller_->SignalIceGatheringState.connect(
109 this, &JsepTransportControllerTest::OnGatheringState);
110 transport_controller_->SignalIceCandidatesGathered.connect(
111 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800112 }
113
114 std::unique_ptr<cricket::SessionDescription>
115 CreateSessionDescriptionWithoutBundle() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200116 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800117 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
118 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
119 nullptr);
120 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
121 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
122 nullptr);
123 return description;
124 }
125
126 std::unique_ptr<cricket::SessionDescription>
127 CreateSessionDescriptionWithBundleGroup() {
128 auto description = CreateSessionDescriptionWithoutBundle();
129 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
130 bundle_group.AddContentName(kAudioMid1);
131 bundle_group.AddContentName(kVideoMid1);
132 description->AddGroup(bundle_group);
133
134 return description;
135 }
136
137 void AddAudioSection(cricket::SessionDescription* description,
138 const std::string& mid,
139 const std::string& ufrag,
140 const std::string& pwd,
141 cricket::IceMode ice_mode,
142 cricket::ConnectionRole conn_role,
143 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
144 std::unique_ptr<cricket::AudioContentDescription> audio(
145 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700146 // Set RTCP-mux to be true because the default policy is "mux required".
147 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800148 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
149 /*rejected=*/false, audio.release());
150 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
151 }
152
153 void AddVideoSection(cricket::SessionDescription* description,
154 const std::string& mid,
155 const std::string& ufrag,
156 const std::string& pwd,
157 cricket::IceMode ice_mode,
158 cricket::ConnectionRole conn_role,
159 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
160 std::unique_ptr<cricket::VideoContentDescription> video(
161 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700162 // Set RTCP-mux to be true because the default policy is "mux required".
163 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800164 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
165 /*rejected=*/false, video.release());
166 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
167 }
168
169 void AddDataSection(cricket::SessionDescription* description,
170 const std::string& mid,
171 cricket::MediaProtocolType protocol_type,
172 const std::string& ufrag,
173 const std::string& pwd,
174 cricket::IceMode ice_mode,
175 cricket::ConnectionRole conn_role,
176 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
177 std::unique_ptr<cricket::DataContentDescription> data(
178 new cricket::DataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700179 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800180 description->AddContent(mid, protocol_type,
181 /*rejected=*/false, data.release());
182 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
183 }
184
185 void AddTransportInfo(cricket::SessionDescription* description,
186 const std::string& mid,
187 const std::string& ufrag,
188 const std::string& pwd,
189 cricket::IceMode ice_mode,
190 cricket::ConnectionRole conn_role,
191 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
192 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
193 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700194 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800195 }
196
197 cricket::TransportDescription transport_desc(std::vector<std::string>(),
198 ufrag, pwd, ice_mode,
199 conn_role, fingerprint.get());
200 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
201 }
202
203 cricket::IceConfig CreateIceConfig(
204 int receiving_timeout,
205 cricket::ContinualGatheringPolicy continual_gathering_policy) {
206 cricket::IceConfig config;
207 config.receiving_timeout = receiving_timeout;
208 config.continual_gathering_policy = continual_gathering_policy;
209 return config;
210 }
211
212 Candidate CreateCandidate(const std::string& transport_name, int component) {
213 Candidate c;
214 c.set_transport_name(transport_name);
215 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
216 c.set_component(component);
217 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
218 c.set_priority(1);
219 return c;
220 }
221
222 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
223 if (!network_thread_->IsCurrent()) {
224 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
225 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
226 });
227 return;
228 }
229
230 auto description = CreateSessionDescriptionWithBundleGroup();
231 EXPECT_TRUE(transport_controller_
232 ->SetLocalDescription(SdpType::kOffer, description.get())
233 .ok());
234
235 transport_controller_->MaybeStartGathering();
236 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
237 transport_controller_->GetDtlsTransport(kAudioMid1));
238 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
239 transport_controller_->GetDtlsTransport(kVideoMid1));
240 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
241 fake_audio_dtls->fake_ice_transport(),
242 CreateCandidate(kAudioMid1, /*component=*/1));
243 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
244 fake_video_dtls->fake_ice_transport(),
245 CreateCandidate(kVideoMid1, /*component=*/1));
246 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
247 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
248 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
249 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
250 fake_audio_dtls->SetReceiving(true);
251 fake_video_dtls->SetReceiving(true);
252 fake_audio_dtls->SetWritable(true);
253 fake_video_dtls->SetWritable(true);
254 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
255 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
256 }
257
258 protected:
Alex Loiko9289eda2018-11-23 16:18:59 +0000259 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800260 if (!signaling_thread_->IsCurrent()) {
261 signaled_on_non_signaling_thread_ = true;
262 }
263 connection_state_ = state;
264 ++connection_state_signal_count_;
265 }
266
Alex Loiko9289eda2018-11-23 16:18:59 +0000267 void OnStandardizedIceConnectionState(
268 PeerConnectionInterface::IceConnectionState state) {
269 if (!signaling_thread_->IsCurrent()) {
270 signaled_on_non_signaling_thread_ = true;
271 }
272 ice_connection_state_ = state;
273 ++ice_connection_state_signal_count_;
274 }
275
Jonas Olsson635474e2018-10-18 15:58:17 +0200276 void OnCombinedConnectionState(
277 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100278 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
279 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 15:58:17 +0200280 if (!signaling_thread_->IsCurrent()) {
281 signaled_on_non_signaling_thread_ = true;
282 }
283 combined_connection_state_ = state;
284 ++combined_connection_state_signal_count_;
285 }
286
Zhi Huange818b6e2018-02-22 15:26:27 -0800287 void OnGatheringState(cricket::IceGatheringState state) {
288 if (!signaling_thread_->IsCurrent()) {
289 signaled_on_non_signaling_thread_ = true;
290 }
291 gathering_state_ = state;
292 ++gathering_state_signal_count_;
293 }
294
295 void OnCandidatesGathered(const std::string& transport_name,
296 const Candidates& candidates) {
297 if (!signaling_thread_->IsCurrent()) {
298 signaled_on_non_signaling_thread_ = true;
299 }
300 candidates_[transport_name].insert(candidates_[transport_name].end(),
301 candidates.begin(), candidates.end());
302 ++candidates_signal_count_;
303 }
304
Zhi Huang365381f2018-04-13 16:44:34 -0700305 // JsepTransportController::Observer overrides.
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800306 bool OnTransportChanged(const std::string& mid,
307 RtpTransportInternal* rtp_transport,
308 cricket::DtlsTransportInternal* dtls_transport,
309 MediaTransportInterface* media_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700310 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800311 changed_dtls_transport_by_mid_[mid] = dtls_transport;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800312 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700313 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800314 }
315
316 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000317 cricket::IceConnectionState connection_state_ =
318 cricket::kIceConnectionConnecting;
319 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200320 PeerConnectionInterface::kIceConnectionNew;
321 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
322 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800323 bool receiving_ = false;
324 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
325 // transport_name => candidates
326 std::map<std::string, Candidates> candidates_;
327 // Counts of each signal emitted.
328 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000329 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200330 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800331 int receiving_signal_count_ = 0;
332 int gathering_state_signal_count_ = 0;
333 int candidates_signal_count_ = 0;
334
335 // |network_thread_| should be destroyed after |transport_controller_|
336 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800337 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
338 rtc::Thread* const signaling_thread_ = nullptr;
339 bool signaled_on_non_signaling_thread_ = false;
340 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
341 // signaled correctly.
342 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
343 std::map<std::string, cricket::DtlsTransportInternal*>
344 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800345 std::map<std::string, MediaTransportInterface*>
346 changed_media_transport_by_mid_;
347
348 // Transport controller needs to be destroyed first, because it may issue
349 // callbacks that modify the changed_*_by_mid in the destructor.
350 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800351};
352
353TEST_F(JsepTransportControllerTest, GetRtpTransport) {
354 CreateJsepTransportController(JsepTransportController::Config());
355 auto description = CreateSessionDescriptionWithoutBundle();
356 EXPECT_TRUE(transport_controller_
357 ->SetLocalDescription(SdpType::kOffer, description.get())
358 .ok());
359 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
360 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
361 EXPECT_NE(nullptr, audio_rtp_transport);
362 EXPECT_NE(nullptr, video_rtp_transport);
363 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
364 // Return nullptr for non-existing ones.
365 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
366}
367
368TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
369 JsepTransportController::Config config;
370 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
371 CreateJsepTransportController(config);
372 auto description = CreateSessionDescriptionWithoutBundle();
373 EXPECT_TRUE(transport_controller_
374 ->SetLocalDescription(SdpType::kOffer, description.get())
375 .ok());
376 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
377 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100378 EXPECT_NE(nullptr,
379 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800380 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
381 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100382 EXPECT_NE(nullptr,
383 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
384 // Lookup for all MIDs should return different transports (no bundle)
385 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
386 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800387 // Return nullptr for non-existing ones.
388 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
389 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100390 EXPECT_EQ(nullptr,
391 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100392 // Take a pointer to a transport, shut down the transport controller,
393 // and verify that the resulting container is empty.
394 auto dtls_transport =
395 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
396 webrtc::DtlsTransport* my_transport =
397 static_cast<DtlsTransport*>(dtls_transport.get());
398 EXPECT_NE(nullptr, my_transport->internal());
399 transport_controller_.reset();
400 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800401}
402
Zhi Huange830e682018-03-30 10:48:35 -0700403TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
404 JsepTransportController::Config config;
405 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
406 CreateJsepTransportController(config);
407 auto description = CreateSessionDescriptionWithoutBundle();
408 EXPECT_TRUE(transport_controller_
409 ->SetLocalDescription(SdpType::kOffer, description.get())
410 .ok());
411 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
412 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
413 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
414 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700415 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
416}
417
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800418TEST_F(JsepTransportControllerTest,
419 DtlsIsStillCreatedIfMediaTransportIsOnlyUsedForDataChannels) {
420 FakeMediaTransportFactory fake_media_transport_factory;
421 JsepTransportController::Config config;
422
423 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
424 config.media_transport_factory = &fake_media_transport_factory;
425 config.use_media_transport_for_data_channels = true;
426 CreateJsepTransportController(config);
427 auto description = CreateSessionDescriptionWithBundleGroup();
428 AddCryptoSettings(description.get());
429
430 EXPECT_TRUE(transport_controller_
431 ->SetLocalDescription(SdpType::kOffer, description.get())
432 .ok());
433
434 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
435 transport_controller_->GetMediaTransport(kAudioMid1));
436
437 ASSERT_NE(nullptr, media_transport);
438
439 // After SetLocalDescription, media transport should be created as caller.
440 EXPECT_TRUE(media_transport->is_caller());
441 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
442
443 // Return nullptr for non-existing mids.
444 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
445
446 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
447 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
448 << "Media transport for media was not enabled, and so DTLS transport "
449 "should be created.";
450}
451
Anton Sukhanov7940da02018-10-10 10:34:49 -0700452TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
453 FakeMediaTransportFactory fake_media_transport_factory;
454 JsepTransportController::Config config;
455
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800456 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700457 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800458 config.use_media_transport_for_data_channels = true;
459 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700460 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800461 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700462 AddCryptoSettings(description.get());
463
Anton Sukhanov7940da02018-10-10 10:34:49 -0700464 EXPECT_TRUE(transport_controller_
465 ->SetLocalDescription(SdpType::kOffer, description.get())
466 .ok());
467
468 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
469 transport_controller_->GetMediaTransport(kAudioMid1));
470
471 ASSERT_NE(nullptr, media_transport);
472
473 // After SetLocalDescription, media transport should be created as caller.
474 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700475 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700476
477 // Return nullptr for non-existing mids.
478 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800479
480 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
481 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
482 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700483}
484
485TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
486 FakeMediaTransportFactory fake_media_transport_factory;
487 JsepTransportController::Config config;
488
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800489 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700490 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800491 config.use_media_transport_for_data_channels = true;
492 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700493 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800494 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700495 AddCryptoSettings(description.get());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700496 EXPECT_TRUE(transport_controller_
497 ->SetRemoteDescription(SdpType::kOffer, description.get())
498 .ok());
499
500 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
501 transport_controller_->GetMediaTransport(kAudioMid1));
502
503 ASSERT_NE(nullptr, media_transport);
504
505 // After SetRemoteDescription, media transport should be created as callee.
506 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700507 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700508
509 // Return nullptr for non-existing mids.
510 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800511
512 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
513 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
514 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700515}
516
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700517TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
518 FakeMediaTransportFactory fake_media_transport_factory;
519 JsepTransportController::Config config;
520
521 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
522 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800523 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700524 CreateJsepTransportController(config);
525 auto description = CreateSessionDescriptionWithoutBundle();
526 EXPECT_TRUE(transport_controller_
527 ->SetRemoteDescription(SdpType::kOffer, description.get())
528 .ok());
529
530 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
531
532 // Even if we set local description with crypto now (after the remote offer
533 // was set), media transport won't be provided.
534 auto description2 = CreateSessionDescriptionWithoutBundle();
535 AddCryptoSettings(description2.get());
536 EXPECT_TRUE(transport_controller_
537 ->SetLocalDescription(SdpType::kAnswer, description2.get())
538 .ok());
539
540 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800541 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
542 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
543 << "Because media transport is NOT used (fallback to RTP), expected "
544 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700545}
546
547TEST_F(JsepTransportControllerTest,
548 AfterSettingAnswerTheSameMediaTransportIsReturned) {
549 FakeMediaTransportFactory fake_media_transport_factory;
550 JsepTransportController::Config config;
551
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800552 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700553 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800554 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700555 CreateJsepTransportController(config);
556 auto description = CreateSessionDescriptionWithoutBundle();
557 AddCryptoSettings(description.get());
558 EXPECT_TRUE(transport_controller_
559 ->SetRemoteDescription(SdpType::kOffer, description.get())
560 .ok());
561
562 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
563 transport_controller_->GetMediaTransport(kAudioMid1));
564 EXPECT_NE(nullptr, media_transport);
565 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
566
567 // Even if we set local description with crypto now (after the remote offer
568 // was set), media transport won't be provided.
569 auto description2 = CreateSessionDescriptionWithoutBundle();
570 AddCryptoSettings(description2.get());
571
572 RTCError result = transport_controller_->SetLocalDescription(
573 SdpType::kAnswer, description2.get());
574 EXPECT_TRUE(result.ok()) << result.message();
575
576 // Media transport did not change.
577 EXPECT_EQ(media_transport,
578 transport_controller_->GetMediaTransport(kAudioMid1));
579}
580
Zhi Huange818b6e2018-02-22 15:26:27 -0800581TEST_F(JsepTransportControllerTest, SetIceConfig) {
582 CreateJsepTransportController(JsepTransportController::Config());
583 auto description = CreateSessionDescriptionWithoutBundle();
584 EXPECT_TRUE(transport_controller_
585 ->SetLocalDescription(SdpType::kOffer, description.get())
586 .ok());
587
588 transport_controller_->SetIceConfig(
589 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
590 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
591 transport_controller_->GetDtlsTransport(kAudioMid1));
592 ASSERT_NE(nullptr, fake_audio_dtls);
593 EXPECT_EQ(kTimeout,
594 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
595 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
596
597 // Test that value stored in controller is applied to new transports.
598 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
599 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
600 nullptr);
601
602 EXPECT_TRUE(transport_controller_
603 ->SetLocalDescription(SdpType::kOffer, description.get())
604 .ok());
605 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
606 transport_controller_->GetDtlsTransport(kAudioMid2));
607 ASSERT_NE(nullptr, fake_audio_dtls);
608 EXPECT_EQ(kTimeout,
609 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
610 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
611}
612
613// Tests the getter and setter of the ICE restart flag.
614TEST_F(JsepTransportControllerTest, NeedIceRestart) {
615 CreateJsepTransportController(JsepTransportController::Config());
616 auto description = CreateSessionDescriptionWithoutBundle();
617 EXPECT_TRUE(transport_controller_
618 ->SetLocalDescription(SdpType::kOffer, description.get())
619 .ok());
620 EXPECT_TRUE(transport_controller_
621 ->SetRemoteDescription(SdpType::kAnswer, description.get())
622 .ok());
623
624 // Initially NeedsIceRestart should return false.
625 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
626 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
627 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
628 // true.
629 transport_controller_->SetNeedsIceRestartFlag();
630 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
631 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
632 // For a nonexistent transport, false should be returned.
633 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
634
635 // Reset the ice_ufrag/ice_pwd for audio.
636 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
637 audio_transport_info->description.ice_ufrag = kIceUfrag2;
638 audio_transport_info->description.ice_pwd = kIcePwd2;
639 EXPECT_TRUE(transport_controller_
640 ->SetLocalDescription(SdpType::kOffer, description.get())
641 .ok());
642 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
643 // return false for audio and true for video.
644 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
645 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
646}
647
648TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
649 CreateJsepTransportController(JsepTransportController::Config());
650 auto description = CreateSessionDescriptionWithBundleGroup();
651 EXPECT_TRUE(transport_controller_
652 ->SetLocalDescription(SdpType::kOffer, description.get())
653 .ok());
654 // After setting the local description, we should be able to start gathering
655 // candidates.
656 transport_controller_->MaybeStartGathering();
657 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
658 EXPECT_EQ(1, gathering_state_signal_count_);
659}
660
661TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
662 CreateJsepTransportController(JsepTransportController::Config());
663 auto description = CreateSessionDescriptionWithoutBundle();
664 transport_controller_->SetLocalDescription(SdpType::kOffer,
665 description.get());
666 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
667 description.get());
668 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
669 transport_controller_->GetDtlsTransport(kAudioMid1));
670 ASSERT_NE(nullptr, fake_audio_dtls);
671 Candidates candidates;
672 candidates.push_back(
673 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
674 EXPECT_TRUE(
675 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
676 EXPECT_EQ(1U,
677 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
678
679 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
680 EXPECT_EQ(0U,
681 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
682}
683
684TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
685 CreateJsepTransportController(JsepTransportController::Config());
686
687 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
688 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
689 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
690 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
691
Karl Wiberg918f50c2018-07-05 11:40:33 +0200692 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800693 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
694 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
695 certificate1);
696
697 // Apply the local certificate.
698 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
699 // Apply the local description.
700 EXPECT_TRUE(transport_controller_
701 ->SetLocalDescription(SdpType::kOffer, description.get())
702 .ok());
703 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
704 EXPECT_TRUE(returned_certificate);
705 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
706 returned_certificate->identity()->certificate().ToPEMString());
707
708 // Should fail if called for a nonexistant transport.
709 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
710
711 // Shouldn't be able to change the identity once set.
712 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
713 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
714 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
715 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
716}
717
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800718TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800719 CreateJsepTransportController(JsepTransportController::Config());
720 auto description = CreateSessionDescriptionWithBundleGroup();
721 EXPECT_TRUE(transport_controller_
722 ->SetLocalDescription(SdpType::kOffer, description.get())
723 .ok());
724 rtc::FakeSSLCertificate fake_certificate("fake_data");
725
726 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
727 transport_controller_->GetDtlsTransport(kAudioMid1));
728 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800729 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
730 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
731 ASSERT_TRUE(returned_cert_chain);
732 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800733 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800734 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800735
736 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800737 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800738}
739
740TEST_F(JsepTransportControllerTest, GetDtlsRole) {
741 CreateJsepTransportController(JsepTransportController::Config());
742 auto offer_certificate =
743 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
744 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
745 auto answer_certificate =
746 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
747 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
748 transport_controller_->SetLocalCertificate(offer_certificate);
749
Karl Wiberg918f50c2018-07-05 11:40:33 +0200750 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800751 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
752 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
753 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200754 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800755 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
756 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
757 answer_certificate);
758
759 EXPECT_TRUE(transport_controller_
760 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
761 .ok());
762
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200763 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800764 transport_controller_->GetDtlsRole(kAudioMid1);
765 // The DTLS role is not decided yet.
766 EXPECT_FALSE(role);
767 EXPECT_TRUE(transport_controller_
768 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
769 .ok());
770 role = transport_controller_->GetDtlsRole(kAudioMid1);
771
772 ASSERT_TRUE(role);
773 EXPECT_EQ(rtc::SSL_CLIENT, *role);
774}
775
776TEST_F(JsepTransportControllerTest, GetStats) {
777 CreateJsepTransportController(JsepTransportController::Config());
778 auto description = CreateSessionDescriptionWithBundleGroup();
779 EXPECT_TRUE(transport_controller_
780 ->SetLocalDescription(SdpType::kOffer, description.get())
781 .ok());
782
783 cricket::TransportStats stats;
784 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
785 EXPECT_EQ(kAudioMid1, stats.transport_name);
786 EXPECT_EQ(1u, stats.channel_stats.size());
787 // Return false for non-existing transport.
788 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
789}
790
791TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
792 CreateJsepTransportController(JsepTransportController::Config());
793 auto description = CreateSessionDescriptionWithoutBundle();
794 EXPECT_TRUE(transport_controller_
795 ->SetLocalDescription(SdpType::kOffer, description.get())
796 .ok());
797
798 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
799 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
800 fake_ice->SetCandidatesGatheringComplete();
801 fake_ice->SetConnectionCount(1);
802 // The connection stats will be failed if there is no active connection.
803 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +0000804 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100805 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000806 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
807 ice_connection_state_, kTimeout);
808 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100809 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
810 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200811 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800812}
813
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700814TEST_F(JsepTransportControllerTest,
815 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800816 CreateJsepTransportController(JsepTransportController::Config());
817 auto description = CreateSessionDescriptionWithoutBundle();
818 EXPECT_TRUE(transport_controller_
819 ->SetLocalDescription(SdpType::kOffer, description.get())
820 .ok());
821
822 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
823 transport_controller_->GetDtlsTransport(kAudioMid1));
824 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
825 transport_controller_->GetDtlsTransport(kVideoMid1));
826
827 // First, have one transport connect, and another fail, to ensure that
828 // the first transport connecting didn't trigger a "connected" state signal.
829 // We should only get a signal when all are connected.
830 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
831 fake_audio_dtls->SetWritable(true);
832 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
833 // Decrease the number of the connection to trigger the signal.
834 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
835 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
836 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
837
Alex Loiko9289eda2018-11-23 16:18:59 +0000838 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100839 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000840 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
841 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100842 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100843 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
844 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100845 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800846
Jonas Olsson635474e2018-10-18 15:58:17 +0200847 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
848 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800849 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
850 // the transport state to be STATE_CONNECTING.
851 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
852 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000853 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100854 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000855 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
856 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100857 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100858 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
859 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100860 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800861}
862
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700863TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800864 SignalConnectionStateConnectedWithMediaTransportAndNoDtls) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700865 FakeMediaTransportFactory fake_media_transport_factory;
866 JsepTransportController::Config config;
867 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800868 config.use_media_transport_for_data_channels = true;
869 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700870 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800871
872 // Media Transport is only used with bundle.
873 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700874 AddCryptoSettings(description.get());
875 EXPECT_TRUE(transport_controller_
876 ->SetLocalDescription(SdpType::kOffer, description.get())
877 .ok());
878
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800879 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
880 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
881 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
882 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
883 fake_audio_ice->SetConnectionCount(2);
884 fake_audio_ice->SetConnectionCount(1);
885 fake_video_ice->SetConnectionCount(2);
886 fake_video_ice->SetConnectionCount(1);
887 fake_audio_ice->SetWritable(true);
888 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700889
890 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +0000891 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
892 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700893
894 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
895 transport_controller_->GetMediaTransport(kAudioMid1));
896
897 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Alex Loiko9289eda2018-11-23 16:18:59 +0000898 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
899 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700900
901 // Still waiting for the second media transport.
902 media_transport = static_cast<FakeMediaTransport*>(
903 transport_controller_->GetMediaTransport(kVideoMid1));
904 media_transport->SetState(webrtc::MediaTransportState::kWritable);
905
Alex Loiko9289eda2018-11-23 16:18:59 +0000906 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700907}
908
909TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800910 SignalConnectionStateConnectedWithMediaTransport) {
911 FakeMediaTransportFactory fake_media_transport_factory;
912 JsepTransportController::Config config;
913 config.media_transport_factory = &fake_media_transport_factory;
914 config.use_media_transport_for_media = true;
915 CreateJsepTransportController(config);
916
917 // Media Transport is only used with bundle.
918 auto description = CreateSessionDescriptionWithBundleGroup();
919 AddCryptoSettings(description.get());
920 EXPECT_TRUE(transport_controller_
921 ->SetLocalDescription(SdpType::kOffer, description.get())
922 .ok());
923
924 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
925 transport_controller_->GetDtlsTransport(kAudioMid1));
926 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
927 transport_controller_->GetDtlsTransport(kVideoMid1));
928
929 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
930 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
931 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
932 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
933 fake_audio_ice->SetConnectionCount(2);
934 fake_audio_ice->SetConnectionCount(1);
935 fake_video_ice->SetConnectionCount(2);
936 fake_video_ice->SetConnectionCount(1);
937 fake_audio_ice->SetWritable(true);
938 fake_video_ice->SetWritable(true);
939 fake_audio_dtls->SetWritable(true);
940 fake_video_dtls->SetWritable(true);
941
942 // Still not connected, because we are waiting for media transport.
943 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
944 kTimeout);
945
946 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
947 transport_controller_->GetMediaTransport(kAudioMid1));
948
949 media_transport->SetState(webrtc::MediaTransportState::kWritable);
950 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
951 kTimeout);
952
953 // Still waiting for the second media transport.
954 media_transport = static_cast<FakeMediaTransport*>(
955 transport_controller_->GetMediaTransport(kVideoMid1));
956 media_transport->SetState(webrtc::MediaTransportState::kWritable);
957
958 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
959}
960
961TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700962 SignalConnectionStateFailedWhenMediaTransportClosed) {
963 FakeMediaTransportFactory fake_media_transport_factory;
964 JsepTransportController::Config config;
965 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800966 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700967 CreateJsepTransportController(config);
968 auto description = CreateSessionDescriptionWithoutBundle();
969 AddCryptoSettings(description.get());
970 EXPECT_TRUE(transport_controller_
971 ->SetLocalDescription(SdpType::kOffer, description.get())
972 .ok());
973
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800974 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
975 transport_controller_->GetDtlsTransport(kAudioMid1));
976 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
977 transport_controller_->GetDtlsTransport(kVideoMid1));
978
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800979 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
980 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
981 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
982 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
983 fake_audio_ice->SetWritable(true);
984 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700985 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800986 fake_audio_ice->SetConnectionCount(2);
987 fake_audio_ice->SetConnectionCount(1);
988 fake_video_ice->SetConnectionCount(2);
989 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700990
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800991 fake_audio_dtls->SetWritable(true);
992 fake_video_dtls->SetWritable(true);
993
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700994 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
995 transport_controller_->GetMediaTransport(kAudioMid1));
996
997 media_transport->SetState(webrtc::MediaTransportState::kWritable);
998
999 media_transport = static_cast<FakeMediaTransport*>(
1000 transport_controller_->GetMediaTransport(kVideoMid1));
1001
1002 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1003
Alex Loiko9289eda2018-11-23 16:18:59 +00001004 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001005
1006 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +00001007 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001008}
1009
Zhi Huange818b6e2018-02-22 15:26:27 -08001010TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1011 CreateJsepTransportController(JsepTransportController::Config());
1012 auto description = CreateSessionDescriptionWithoutBundle();
1013 EXPECT_TRUE(transport_controller_
1014 ->SetLocalDescription(SdpType::kOffer, description.get())
1015 .ok());
1016
1017 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1018 transport_controller_->GetDtlsTransport(kAudioMid1));
1019 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1020 transport_controller_->GetDtlsTransport(kVideoMid1));
1021
1022 // First, have one transport connect, and another fail, to ensure that
1023 // the first transport connecting didn't trigger a "connected" state signal.
1024 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001025 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1026 IceTransportState::kCompleted,
1027 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001028 fake_audio_dtls->SetWritable(true);
1029 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001030
1031 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1032 ice_connection_state_, kTimeout);
1033 EXPECT_EQ(1, ice_connection_state_signal_count_);
1034 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1035 combined_connection_state_, kTimeout);
1036 EXPECT_EQ(1, combined_connection_state_signal_count_);
1037
1038 fake_video_dtls->fake_ice_transport()->SetTransportState(
1039 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001040 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1041
Alex Loiko9289eda2018-11-23 16:18:59 +00001042 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001043 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001044 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1045 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001046 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001047 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1048 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001049 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001050
Jonas Olsson635474e2018-10-18 15:58:17 +02001051 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1052 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001053 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1054 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001055 fake_video_dtls->fake_ice_transport()->SetTransportState(
1056 IceTransportState::kCompleted,
1057 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001058 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001059 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +01001060 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001061 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1062 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001063 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001064 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1065 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001066 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001067}
1068
1069TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1070 CreateJsepTransportController(JsepTransportController::Config());
1071 auto description = CreateSessionDescriptionWithoutBundle();
1072 EXPECT_TRUE(transport_controller_
1073 ->SetLocalDescription(SdpType::kOffer, description.get())
1074 .ok());
1075
1076 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1077 transport_controller_->GetDtlsTransport(kAudioMid1));
1078 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1079 // Should be in the gathering state as soon as any transport starts gathering.
1080 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1081 EXPECT_EQ(1, gathering_state_signal_count_);
1082}
1083
1084TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1085 CreateJsepTransportController(JsepTransportController::Config());
1086 auto description = CreateSessionDescriptionWithoutBundle();
1087 EXPECT_TRUE(transport_controller_
1088 ->SetLocalDescription(SdpType::kOffer, description.get())
1089 .ok());
1090
1091 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1092 transport_controller_->GetDtlsTransport(kAudioMid1));
1093 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1094 transport_controller_->GetDtlsTransport(kVideoMid1));
1095
1096 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1097 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1098 EXPECT_EQ(1, gathering_state_signal_count_);
1099
1100 // Have one transport finish gathering, to make sure gathering
1101 // completion wasn't signalled if only one transport finished gathering.
1102 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1103 EXPECT_EQ(1, gathering_state_signal_count_);
1104
1105 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1106 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1107 EXPECT_EQ(1, gathering_state_signal_count_);
1108
1109 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1110 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1111 EXPECT_EQ(2, gathering_state_signal_count_);
1112}
1113
1114// Test that when the last transport that hasn't finished connecting and/or
1115// gathering is destroyed, the aggregate state jumps to "completed". This can
1116// happen if, for example, we have an audio and video transport, the audio
1117// transport completes, then we start bundling video on the audio transport.
1118TEST_F(JsepTransportControllerTest,
1119 SignalingWhenLastIncompleteTransportDestroyed) {
1120 CreateJsepTransportController(JsepTransportController::Config());
1121 auto description = CreateSessionDescriptionWithBundleGroup();
1122 EXPECT_TRUE(transport_controller_
1123 ->SetLocalDescription(SdpType::kOffer, description.get())
1124 .ok());
1125
1126 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1127 transport_controller_->GetDtlsTransport(kAudioMid1));
1128 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1129 transport_controller_->GetDtlsTransport(kVideoMid1));
1130 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1131
1132 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1133 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1134 EXPECT_EQ(1, gathering_state_signal_count_);
1135
1136 // Let the audio transport complete.
1137 fake_audio_dtls->SetWritable(true);
1138 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1139 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001140 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001141 EXPECT_EQ(1, gathering_state_signal_count_);
1142
1143 // Set the remote description and enable the bundle.
1144 EXPECT_TRUE(transport_controller_
1145 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1146 .ok());
1147 // The BUNDLE should be enabled, the incomplete video transport should be
1148 // deleted and the states shoud be updated.
1149 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1150 transport_controller_->GetDtlsTransport(kVideoMid1));
1151 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001152 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1153 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1154 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001155 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1156 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001157 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1158 EXPECT_EQ(2, gathering_state_signal_count_);
1159}
1160
1161TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1162 CreateJsepTransportController(JsepTransportController::Config());
1163 auto description = CreateSessionDescriptionWithBundleGroup();
1164 EXPECT_TRUE(transport_controller_
1165 ->SetLocalDescription(SdpType::kOffer, description.get())
1166 .ok());
1167 transport_controller_->MaybeStartGathering();
1168
1169 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1170 transport_controller_->GetDtlsTransport(kAudioMid1));
1171 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1172 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1173 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1174 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1175}
1176
1177TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1178 network_thread_ = rtc::Thread::CreateWithSocketServer();
1179 network_thread_->Start();
1180 CreateJsepTransportController(JsepTransportController::Config(),
1181 signaling_thread_, network_thread_.get(),
1182 /*PortAllocator=*/nullptr);
1183 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1184
1185 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001186 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001187 EXPECT_EQ(2, connection_state_signal_count_);
1188
1189 // new --> gathering --> complete
1190 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1191 EXPECT_EQ(2, gathering_state_signal_count_);
1192
1193 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1194 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1195 EXPECT_EQ(2, candidates_signal_count_);
1196
1197 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1198}
1199
1200// Older versions of Chrome expect the ICE role to be re-determined when an
1201// ICE restart occurs, and also don't perform conflict resolution correctly,
1202// so for now we can't safely stop doing this.
1203// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1204// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1205// enough population.
1206TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1207 CreateJsepTransportController(JsepTransportController::Config());
1208 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001209 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001210 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1211 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1212 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001213 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001214 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1215 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1216 nullptr);
1217
1218 EXPECT_TRUE(transport_controller_
1219 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1220 .ok());
1221 EXPECT_TRUE(transport_controller_
1222 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1223 .ok());
1224
1225 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1226 transport_controller_->GetDtlsTransport(kAudioMid1));
1227 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1228 fake_dtls->fake_ice_transport()->GetIceRole());
1229
1230 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001231 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001232 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1233 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1234 nullptr);
1235 EXPECT_TRUE(
1236 transport_controller_
1237 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1238 .ok());
1239 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1240 fake_dtls->fake_ice_transport()->GetIceRole());
1241}
1242
1243// Test that if the TransportController was created with the
1244// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1245// redetermined on an ICE restart.
1246TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1247 JsepTransportController::Config config;
1248 config.redetermine_role_on_ice_restart = false;
1249
1250 CreateJsepTransportController(config);
1251 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001252 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001253 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1254 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1255 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001256 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001257 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1258 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1259 nullptr);
1260
1261 EXPECT_TRUE(transport_controller_
1262 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1263 .ok());
1264 EXPECT_TRUE(transport_controller_
1265 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1266 .ok());
1267
1268 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1269 transport_controller_->GetDtlsTransport(kAudioMid1));
1270 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1271 fake_dtls->fake_ice_transport()->GetIceRole());
1272
1273 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001274 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001275 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1276 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1277 nullptr);
1278 EXPECT_TRUE(
1279 transport_controller_
1280 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1281 .ok());
1282 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1283 fake_dtls->fake_ice_transport()->GetIceRole());
1284}
1285
1286// Tests ICE-Lite mode in remote answer.
1287TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1288 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001289 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001290 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1291 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1292 nullptr);
1293 EXPECT_TRUE(transport_controller_
1294 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1295 .ok());
1296 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1297 transport_controller_->GetDtlsTransport(kAudioMid1));
1298 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1299 fake_dtls->fake_ice_transport()->GetIceRole());
1300 EXPECT_EQ(cricket::ICEMODE_FULL,
1301 fake_dtls->fake_ice_transport()->remote_ice_mode());
1302
Karl Wiberg918f50c2018-07-05 11:40:33 +02001303 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001304 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1305 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1306 nullptr);
1307 EXPECT_TRUE(transport_controller_
1308 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1309 .ok());
1310 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1311 fake_dtls->fake_ice_transport()->GetIceRole());
1312 EXPECT_EQ(cricket::ICEMODE_LITE,
1313 fake_dtls->fake_ice_transport()->remote_ice_mode());
1314}
1315
1316// Tests that the ICE role remains "controlling" if a subsequent offer that
1317// does an ICE restart is received from an ICE lite endpoint. Regression test
1318// for: https://crbug.com/710760
1319TEST_F(JsepTransportControllerTest,
1320 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1321 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001322 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001323 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1324 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1325 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001326 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001327 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1328 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1329 nullptr);
1330 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1331 // local side is the controlling.
1332 EXPECT_TRUE(transport_controller_
1333 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1334 .ok());
1335 EXPECT_TRUE(transport_controller_
1336 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1337 .ok());
1338 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1339 transport_controller_->GetDtlsTransport(kAudioMid1));
1340 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1341 fake_dtls->fake_ice_transport()->GetIceRole());
1342
1343 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001344 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001345 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1346 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1347 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001348 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001349 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1350 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1351 nullptr);
1352 EXPECT_TRUE(transport_controller_
1353 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1354 .ok());
1355 EXPECT_TRUE(transport_controller_
1356 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1357 .ok());
1358 fake_dtls = static_cast<FakeDtlsTransport*>(
1359 transport_controller_->GetDtlsTransport(kAudioMid1));
1360 // The local side is still the controlling role since the remote side is using
1361 // ICE-Lite.
1362 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1363 fake_dtls->fake_ice_transport()->GetIceRole());
1364}
1365
1366// Tests that the SDP has more than one audio/video m= sections.
1367TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1368 CreateJsepTransportController(JsepTransportController::Config());
1369 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1370 bundle_group.AddContentName(kAudioMid1);
1371 bundle_group.AddContentName(kAudioMid2);
1372 bundle_group.AddContentName(kVideoMid1);
1373 bundle_group.AddContentName(kDataMid1);
1374
Karl Wiberg918f50c2018-07-05 11:40:33 +02001375 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001376 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1377 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1378 nullptr);
1379 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1380 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1381 nullptr);
1382 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1383 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1384 nullptr);
1385 AddDataSection(local_offer.get(), kDataMid1,
1386 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1387 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1388 nullptr);
1389
Karl Wiberg918f50c2018-07-05 11:40:33 +02001390 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001391 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1392 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1393 nullptr);
1394 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1395 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1396 nullptr);
1397 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1398 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1399 nullptr);
1400 AddDataSection(remote_answer.get(), kDataMid1,
1401 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1402 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1403 nullptr);
1404
1405 local_offer->AddGroup(bundle_group);
1406 remote_answer->AddGroup(bundle_group);
1407
1408 EXPECT_TRUE(transport_controller_
1409 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1410 .ok());
1411 EXPECT_TRUE(transport_controller_
1412 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1413 .ok());
1414 // Verify that all the sections are bundled on kAudio1.
1415 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1416 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1417 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1418 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1419 EXPECT_EQ(transport1, transport2);
1420 EXPECT_EQ(transport1, transport3);
1421 EXPECT_EQ(transport1, transport4);
1422
Harald Alvestrandad88c882018-11-28 16:47:46 +01001423 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1424 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1425
Zhi Huange818b6e2018-02-22 15:26:27 -08001426 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1427 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1428 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1429 EXPECT_EQ(transport1, it->second);
1430 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1431 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1432 EXPECT_EQ(transport1, it->second);
1433 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1434 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1435 EXPECT_EQ(transport1, it->second);
1436 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1437 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1438 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1439 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1440}
1441
1442// Tests that only a subset of all the m= sections are bundled.
1443TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1444 CreateJsepTransportController(JsepTransportController::Config());
1445 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1446 bundle_group.AddContentName(kAudioMid1);
1447 bundle_group.AddContentName(kVideoMid1);
1448
Karl Wiberg918f50c2018-07-05 11:40:33 +02001449 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001450 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1451 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1452 nullptr);
1453 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1454 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1455 nullptr);
1456 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1457 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1458 nullptr);
1459
Karl Wiberg918f50c2018-07-05 11:40:33 +02001460 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001461 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1462 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1463 nullptr);
1464 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1465 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1466 nullptr);
1467 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1468 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1469 nullptr);
1470
1471 local_offer->AddGroup(bundle_group);
1472 remote_answer->AddGroup(bundle_group);
1473 EXPECT_TRUE(transport_controller_
1474 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1475 .ok());
1476 EXPECT_TRUE(transport_controller_
1477 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1478 .ok());
1479
1480 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1481 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1482 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1483 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1484 EXPECT_NE(transport1, transport2);
1485 EXPECT_EQ(transport1, transport3);
1486
1487 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1488 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1489 EXPECT_EQ(transport1, it->second);
1490 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001491 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001492}
1493
1494// Tests that the initial offer/answer only have data section and audio/video
1495// sections are added in the subsequent offer.
1496TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1497 CreateJsepTransportController(JsepTransportController::Config());
1498 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1499 bundle_group.AddContentName(kDataMid1);
1500
Karl Wiberg918f50c2018-07-05 11:40:33 +02001501 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001502 AddDataSection(local_offer.get(), kDataMid1,
1503 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1504 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1505 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001506 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001507 AddDataSection(remote_answer.get(), kDataMid1,
1508 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1509 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1510 nullptr);
1511 local_offer->AddGroup(bundle_group);
1512 remote_answer->AddGroup(bundle_group);
1513
1514 EXPECT_TRUE(transport_controller_
1515 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1516 .ok());
1517 EXPECT_TRUE(transport_controller_
1518 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1519 .ok());
1520 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1521
1522 // Add audio/video sections in subsequent offer.
1523 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1524 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1525 nullptr);
1526 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1527 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1528 nullptr);
1529 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1530 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1531 nullptr);
1532 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1533 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1534 nullptr);
1535
1536 // Reset the bundle group and do another offer/answer exchange.
1537 bundle_group.AddContentName(kAudioMid1);
1538 bundle_group.AddContentName(kVideoMid1);
1539 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1540 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1541 local_offer->AddGroup(bundle_group);
1542 remote_answer->AddGroup(bundle_group);
1543
1544 EXPECT_TRUE(transport_controller_
1545 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1546 .ok());
1547 EXPECT_TRUE(transport_controller_
1548 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1549 .ok());
1550
1551 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1552 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1553 EXPECT_EQ(data_transport, audio_transport);
1554 EXPECT_EQ(data_transport, video_transport);
1555}
1556
1557TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1558 CreateJsepTransportController(JsepTransportController::Config());
1559 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1560 bundle_group.AddContentName(kAudioMid1);
1561 bundle_group.AddContentName(kVideoMid1);
1562 bundle_group.AddContentName(kDataMid1);
1563
Karl Wiberg918f50c2018-07-05 11:40:33 +02001564 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001565 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1566 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1567 nullptr);
1568 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1569 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1570 nullptr);
1571 AddDataSection(local_offer.get(), kDataMid1,
1572 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1573 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1574 nullptr);
1575
Karl Wiberg918f50c2018-07-05 11:40:33 +02001576 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001577 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1578 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1579 nullptr);
1580 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1581 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1582 nullptr);
1583 AddDataSection(remote_answer.get(), kDataMid1,
1584 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1585 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1586 nullptr);
1587 // Reject video and data section.
1588 remote_answer->contents()[1].rejected = true;
1589 remote_answer->contents()[2].rejected = true;
1590
1591 local_offer->AddGroup(bundle_group);
1592 remote_answer->AddGroup(bundle_group);
1593
1594 EXPECT_TRUE(transport_controller_
1595 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1596 .ok());
1597 EXPECT_TRUE(transport_controller_
1598 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1599 .ok());
1600
1601 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1602 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1603 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1604 // Verify the signals are fired correctly.
1605 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1606 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1607 EXPECT_EQ(nullptr, it->second);
1608 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1609 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1610 EXPECT_EQ(nullptr, it2->second);
1611}
1612
1613// Tests that changing the bundled MID in subsequent offer/answer exchange is
1614// not supported.
1615// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1616// fixed
1617TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1618 CreateJsepTransportController(JsepTransportController::Config());
1619 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1620 bundle_group.AddContentName(kAudioMid1);
1621 bundle_group.AddContentName(kVideoMid1);
1622
Karl Wiberg918f50c2018-07-05 11:40:33 +02001623 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001624 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1625 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1626 nullptr);
1627 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1628 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1629 nullptr);
1630
Karl Wiberg918f50c2018-07-05 11:40:33 +02001631 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001632 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1633 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1634 nullptr);
1635 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1636 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1637 nullptr);
1638
1639 local_offer->AddGroup(bundle_group);
1640 remote_answer->AddGroup(bundle_group);
1641 EXPECT_TRUE(transport_controller_
1642 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1643 .ok());
1644 EXPECT_TRUE(transport_controller_
1645 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1646 .ok());
1647 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1648 transport_controller_->GetRtpTransport(kVideoMid1));
1649
1650 // Reorder the bundle group.
1651 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1652 bundle_group.AddContentName(kAudioMid1);
1653 // The answerer uses the new bundle group and now the bundle mid is changed to
1654 // |kVideo1|.
1655 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1656 remote_answer->AddGroup(bundle_group);
1657 EXPECT_TRUE(transport_controller_
1658 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1659 .ok());
1660 EXPECT_FALSE(transport_controller_
1661 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1662 .ok());
1663}
Zhi Huange830e682018-03-30 10:48:35 -07001664// Test that rejecting only the first m= section of a BUNDLE group is treated as
1665// an error, but rejecting all of them works as expected.
1666TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1667 CreateJsepTransportController(JsepTransportController::Config());
1668 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1669 bundle_group.AddContentName(kAudioMid1);
1670 bundle_group.AddContentName(kVideoMid1);
1671 bundle_group.AddContentName(kDataMid1);
1672
Karl Wiberg918f50c2018-07-05 11:40:33 +02001673 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001674 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1675 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1676 nullptr);
1677 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1678 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1679 nullptr);
1680 AddDataSection(local_offer.get(), kDataMid1,
1681 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1682 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1683 nullptr);
1684
Karl Wiberg918f50c2018-07-05 11:40:33 +02001685 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001686 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1687 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1688 nullptr);
1689 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1690 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1691 nullptr);
1692 AddDataSection(remote_answer.get(), kDataMid1,
1693 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1694 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1695 nullptr);
1696 // Reject audio content in answer.
1697 remote_answer->contents()[0].rejected = true;
1698
1699 local_offer->AddGroup(bundle_group);
1700 remote_answer->AddGroup(bundle_group);
1701
1702 EXPECT_TRUE(transport_controller_
1703 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1704 .ok());
1705 EXPECT_FALSE(transport_controller_
1706 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1707 .ok());
1708
1709 // Reject all the contents.
1710 remote_answer->contents()[1].rejected = true;
1711 remote_answer->contents()[2].rejected = true;
1712 EXPECT_TRUE(transport_controller_
1713 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1714 .ok());
1715 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1716 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1717 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1718}
1719
1720// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1721// is used.
1722TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1723 JsepTransportController::Config config;
1724 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1725 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001726 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001727 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1728 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1729 nullptr);
1730
1731 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1732 // Applying a non-RTCP-mux offer is expected to fail.
1733 EXPECT_FALSE(transport_controller_
1734 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1735 .ok());
1736}
1737
1738// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1739// is used.
1740TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1741 JsepTransportController::Config config;
1742 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1743 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001744 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001745 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1746 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1747 nullptr);
1748 EXPECT_TRUE(transport_controller_
1749 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1750 .ok());
1751
Karl Wiberg918f50c2018-07-05 11:40:33 +02001752 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001753 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1754 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1755 nullptr);
1756 // Applying a non-RTCP-mux answer is expected to fail.
1757 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1758 EXPECT_FALSE(transport_controller_
1759 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1760 .ok());
1761}
Zhi Huange818b6e2018-02-22 15:26:27 -08001762
Zhi Huangd2248f82018-04-10 14:41:03 -07001763// This tests that the BUNDLE group in answer should be a subset of the offered
1764// group.
1765TEST_F(JsepTransportControllerTest,
1766 AddContentToBundleGroupInAnswerNotSupported) {
1767 CreateJsepTransportController(JsepTransportController::Config());
1768 auto local_offer = CreateSessionDescriptionWithoutBundle();
1769 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1770
1771 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1772 offer_bundle_group.AddContentName(kAudioMid1);
1773 local_offer->AddGroup(offer_bundle_group);
1774
1775 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1776 answer_bundle_group.AddContentName(kAudioMid1);
1777 answer_bundle_group.AddContentName(kVideoMid1);
1778 remote_answer->AddGroup(answer_bundle_group);
1779 EXPECT_TRUE(transport_controller_
1780 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1781 .ok());
1782 EXPECT_FALSE(transport_controller_
1783 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1784 .ok());
1785}
1786
1787// This tests that the BUNDLE group with non-existing MID should be rejectd.
1788TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1789 CreateJsepTransportController(JsepTransportController::Config());
1790 auto local_offer = CreateSessionDescriptionWithoutBundle();
1791 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1792
1793 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1794 // The BUNDLE group is invalid because there is no data section in the
1795 // description.
1796 invalid_bundle_group.AddContentName(kDataMid1);
1797 local_offer->AddGroup(invalid_bundle_group);
1798 remote_answer->AddGroup(invalid_bundle_group);
1799
1800 EXPECT_FALSE(transport_controller_
1801 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1802 .ok());
1803 EXPECT_FALSE(transport_controller_
1804 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1805 .ok());
1806}
1807
1808// This tests that an answer shouldn't be able to remove an m= section from an
1809// established group without rejecting it.
1810TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1811 CreateJsepTransportController(JsepTransportController::Config());
1812
1813 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1814 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1815 EXPECT_TRUE(transport_controller_
1816 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1817 .ok());
1818 EXPECT_TRUE(transport_controller_
1819 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1820 .ok());
1821
1822 // Do an re-offer/answer.
1823 EXPECT_TRUE(transport_controller_
1824 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1825 .ok());
1826 auto new_answer = CreateSessionDescriptionWithoutBundle();
1827 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1828 // The answer removes video from the BUNDLE group without rejecting it is
1829 // invalid.
1830 new_bundle_group.AddContentName(kAudioMid1);
1831 new_answer->AddGroup(new_bundle_group);
1832
1833 // Applying invalid answer is expected to fail.
1834 EXPECT_FALSE(transport_controller_
1835 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1836 .ok());
1837
1838 // Rejected the video content.
1839 auto video_content = new_answer->GetContentByName(kVideoMid1);
1840 ASSERT_TRUE(video_content);
1841 video_content->rejected = true;
1842 EXPECT_TRUE(transport_controller_
1843 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1844 .ok());
1845}
1846
Steve Anton2bed3972019-01-04 17:04:30 -08001847// Test that the JsepTransportController can process a new local and remote
1848// description that changes the tagged BUNDLE group with the max-bundle policy
1849// specified.
1850// This is a regression test for bugs.webrtc.org/9954
1851TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
1852 CreateJsepTransportController(JsepTransportController::Config());
1853
1854 auto local_offer = absl::make_unique<cricket::SessionDescription>();
1855 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1856 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1857 nullptr);
1858 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1859 bundle_group.AddContentName(kAudioMid1);
1860 local_offer->AddGroup(bundle_group);
1861 EXPECT_TRUE(transport_controller_
1862 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1863 .ok());
1864
1865 std::unique_ptr<cricket::SessionDescription> remote_answer(
1866 local_offer->Copy());
1867 EXPECT_TRUE(transport_controller_
1868 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1869 .ok());
1870
1871 std::unique_ptr<cricket::SessionDescription> local_reoffer(
1872 local_offer->Copy());
1873 local_reoffer->contents()[0].rejected = true;
1874 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
1875 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1876 nullptr);
1877 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1878 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1879 new_bundle_group.AddContentName(kVideoMid1);
1880 local_reoffer->AddGroup(new_bundle_group);
1881
1882 EXPECT_TRUE(transport_controller_
1883 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
1884 .ok());
1885
1886 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
1887 local_reoffer->Copy());
1888 EXPECT_TRUE(
1889 transport_controller_
1890 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
1891 .ok());
1892}
1893
Zhi Huange818b6e2018-02-22 15:26:27 -08001894} // namespace webrtc