blob: d6a31c81b75afed801b3582adb16f68bea88d354 [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
418TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
419 FakeMediaTransportFactory fake_media_transport_factory;
420 JsepTransportController::Config config;
421
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800422 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700423 config.media_transport_factory = &fake_media_transport_factory;
424 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800425 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700426 AddCryptoSettings(description.get());
427
Anton Sukhanov7940da02018-10-10 10:34:49 -0700428 EXPECT_TRUE(transport_controller_
429 ->SetLocalDescription(SdpType::kOffer, description.get())
430 .ok());
431
432 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
433 transport_controller_->GetMediaTransport(kAudioMid1));
434
435 ASSERT_NE(nullptr, media_transport);
436
437 // After SetLocalDescription, media transport should be created as caller.
438 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700439 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700440
441 // Return nullptr for non-existing mids.
442 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800443
444 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
445 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
446 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700447}
448
449TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
450 FakeMediaTransportFactory fake_media_transport_factory;
451 JsepTransportController::Config config;
452
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800453 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700454 config.media_transport_factory = &fake_media_transport_factory;
455 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800456 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700457 AddCryptoSettings(description.get());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700458 EXPECT_TRUE(transport_controller_
459 ->SetRemoteDescription(SdpType::kOffer, description.get())
460 .ok());
461
462 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
463 transport_controller_->GetMediaTransport(kAudioMid1));
464
465 ASSERT_NE(nullptr, media_transport);
466
467 // After SetRemoteDescription, media transport should be created as callee.
468 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700469 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700470
471 // Return nullptr for non-existing mids.
472 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800473
474 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
475 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
476 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700477}
478
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700479TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
480 FakeMediaTransportFactory fake_media_transport_factory;
481 JsepTransportController::Config config;
482
483 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
484 config.media_transport_factory = &fake_media_transport_factory;
485 CreateJsepTransportController(config);
486 auto description = CreateSessionDescriptionWithoutBundle();
487 EXPECT_TRUE(transport_controller_
488 ->SetRemoteDescription(SdpType::kOffer, description.get())
489 .ok());
490
491 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
492
493 // Even if we set local description with crypto now (after the remote offer
494 // was set), media transport won't be provided.
495 auto description2 = CreateSessionDescriptionWithoutBundle();
496 AddCryptoSettings(description2.get());
497 EXPECT_TRUE(transport_controller_
498 ->SetLocalDescription(SdpType::kAnswer, description2.get())
499 .ok());
500
501 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800502 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
503 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
504 << "Because media transport is NOT used (fallback to RTP), expected "
505 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700506}
507
508TEST_F(JsepTransportControllerTest,
509 AfterSettingAnswerTheSameMediaTransportIsReturned) {
510 FakeMediaTransportFactory fake_media_transport_factory;
511 JsepTransportController::Config config;
512
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800513 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700514 config.media_transport_factory = &fake_media_transport_factory;
515 CreateJsepTransportController(config);
516 auto description = CreateSessionDescriptionWithoutBundle();
517 AddCryptoSettings(description.get());
518 EXPECT_TRUE(transport_controller_
519 ->SetRemoteDescription(SdpType::kOffer, description.get())
520 .ok());
521
522 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
523 transport_controller_->GetMediaTransport(kAudioMid1));
524 EXPECT_NE(nullptr, media_transport);
525 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
526
527 // Even if we set local description with crypto now (after the remote offer
528 // was set), media transport won't be provided.
529 auto description2 = CreateSessionDescriptionWithoutBundle();
530 AddCryptoSettings(description2.get());
531
532 RTCError result = transport_controller_->SetLocalDescription(
533 SdpType::kAnswer, description2.get());
534 EXPECT_TRUE(result.ok()) << result.message();
535
536 // Media transport did not change.
537 EXPECT_EQ(media_transport,
538 transport_controller_->GetMediaTransport(kAudioMid1));
539}
540
Zhi Huange818b6e2018-02-22 15:26:27 -0800541TEST_F(JsepTransportControllerTest, SetIceConfig) {
542 CreateJsepTransportController(JsepTransportController::Config());
543 auto description = CreateSessionDescriptionWithoutBundle();
544 EXPECT_TRUE(transport_controller_
545 ->SetLocalDescription(SdpType::kOffer, description.get())
546 .ok());
547
548 transport_controller_->SetIceConfig(
549 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
550 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
551 transport_controller_->GetDtlsTransport(kAudioMid1));
552 ASSERT_NE(nullptr, fake_audio_dtls);
553 EXPECT_EQ(kTimeout,
554 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
555 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
556
557 // Test that value stored in controller is applied to new transports.
558 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
559 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
560 nullptr);
561
562 EXPECT_TRUE(transport_controller_
563 ->SetLocalDescription(SdpType::kOffer, description.get())
564 .ok());
565 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
566 transport_controller_->GetDtlsTransport(kAudioMid2));
567 ASSERT_NE(nullptr, fake_audio_dtls);
568 EXPECT_EQ(kTimeout,
569 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
570 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
571}
572
573// Tests the getter and setter of the ICE restart flag.
574TEST_F(JsepTransportControllerTest, NeedIceRestart) {
575 CreateJsepTransportController(JsepTransportController::Config());
576 auto description = CreateSessionDescriptionWithoutBundle();
577 EXPECT_TRUE(transport_controller_
578 ->SetLocalDescription(SdpType::kOffer, description.get())
579 .ok());
580 EXPECT_TRUE(transport_controller_
581 ->SetRemoteDescription(SdpType::kAnswer, description.get())
582 .ok());
583
584 // Initially NeedsIceRestart should return false.
585 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
586 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
587 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
588 // true.
589 transport_controller_->SetNeedsIceRestartFlag();
590 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
591 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
592 // For a nonexistent transport, false should be returned.
593 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
594
595 // Reset the ice_ufrag/ice_pwd for audio.
596 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
597 audio_transport_info->description.ice_ufrag = kIceUfrag2;
598 audio_transport_info->description.ice_pwd = kIcePwd2;
599 EXPECT_TRUE(transport_controller_
600 ->SetLocalDescription(SdpType::kOffer, description.get())
601 .ok());
602 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
603 // return false for audio and true for video.
604 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
605 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
606}
607
608TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
609 CreateJsepTransportController(JsepTransportController::Config());
610 auto description = CreateSessionDescriptionWithBundleGroup();
611 EXPECT_TRUE(transport_controller_
612 ->SetLocalDescription(SdpType::kOffer, description.get())
613 .ok());
614 // After setting the local description, we should be able to start gathering
615 // candidates.
616 transport_controller_->MaybeStartGathering();
617 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
618 EXPECT_EQ(1, gathering_state_signal_count_);
619}
620
621TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
622 CreateJsepTransportController(JsepTransportController::Config());
623 auto description = CreateSessionDescriptionWithoutBundle();
624 transport_controller_->SetLocalDescription(SdpType::kOffer,
625 description.get());
626 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
627 description.get());
628 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
629 transport_controller_->GetDtlsTransport(kAudioMid1));
630 ASSERT_NE(nullptr, fake_audio_dtls);
631 Candidates candidates;
632 candidates.push_back(
633 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
634 EXPECT_TRUE(
635 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
636 EXPECT_EQ(1U,
637 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
638
639 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
640 EXPECT_EQ(0U,
641 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
642}
643
644TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
645 CreateJsepTransportController(JsepTransportController::Config());
646
647 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
648 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
649 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
650 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
651
Karl Wiberg918f50c2018-07-05 11:40:33 +0200652 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800653 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
654 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
655 certificate1);
656
657 // Apply the local certificate.
658 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
659 // Apply the local description.
660 EXPECT_TRUE(transport_controller_
661 ->SetLocalDescription(SdpType::kOffer, description.get())
662 .ok());
663 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
664 EXPECT_TRUE(returned_certificate);
665 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
666 returned_certificate->identity()->certificate().ToPEMString());
667
668 // Should fail if called for a nonexistant transport.
669 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
670
671 // Shouldn't be able to change the identity once set.
672 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
673 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
674 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
675 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
676}
677
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800678TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800679 CreateJsepTransportController(JsepTransportController::Config());
680 auto description = CreateSessionDescriptionWithBundleGroup();
681 EXPECT_TRUE(transport_controller_
682 ->SetLocalDescription(SdpType::kOffer, description.get())
683 .ok());
684 rtc::FakeSSLCertificate fake_certificate("fake_data");
685
686 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
687 transport_controller_->GetDtlsTransport(kAudioMid1));
688 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800689 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
690 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
691 ASSERT_TRUE(returned_cert_chain);
692 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800693 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800694 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800695
696 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800697 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800698}
699
700TEST_F(JsepTransportControllerTest, GetDtlsRole) {
701 CreateJsepTransportController(JsepTransportController::Config());
702 auto offer_certificate =
703 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
704 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
705 auto answer_certificate =
706 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
707 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
708 transport_controller_->SetLocalCertificate(offer_certificate);
709
Karl Wiberg918f50c2018-07-05 11:40:33 +0200710 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800711 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
712 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
713 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200714 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800715 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
716 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
717 answer_certificate);
718
719 EXPECT_TRUE(transport_controller_
720 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
721 .ok());
722
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200723 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800724 transport_controller_->GetDtlsRole(kAudioMid1);
725 // The DTLS role is not decided yet.
726 EXPECT_FALSE(role);
727 EXPECT_TRUE(transport_controller_
728 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
729 .ok());
730 role = transport_controller_->GetDtlsRole(kAudioMid1);
731
732 ASSERT_TRUE(role);
733 EXPECT_EQ(rtc::SSL_CLIENT, *role);
734}
735
736TEST_F(JsepTransportControllerTest, GetStats) {
737 CreateJsepTransportController(JsepTransportController::Config());
738 auto description = CreateSessionDescriptionWithBundleGroup();
739 EXPECT_TRUE(transport_controller_
740 ->SetLocalDescription(SdpType::kOffer, description.get())
741 .ok());
742
743 cricket::TransportStats stats;
744 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
745 EXPECT_EQ(kAudioMid1, stats.transport_name);
746 EXPECT_EQ(1u, stats.channel_stats.size());
747 // Return false for non-existing transport.
748 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
749}
750
751TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
752 CreateJsepTransportController(JsepTransportController::Config());
753 auto description = CreateSessionDescriptionWithoutBundle();
754 EXPECT_TRUE(transport_controller_
755 ->SetLocalDescription(SdpType::kOffer, description.get())
756 .ok());
757
758 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
759 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
760 fake_ice->SetCandidatesGatheringComplete();
761 fake_ice->SetConnectionCount(1);
762 // The connection stats will be failed if there is no active connection.
763 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +0000764 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100765 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000766 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
767 ice_connection_state_, kTimeout);
768 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100769 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
770 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200771 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800772}
773
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700774TEST_F(JsepTransportControllerTest,
775 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800776 CreateJsepTransportController(JsepTransportController::Config());
777 auto description = CreateSessionDescriptionWithoutBundle();
778 EXPECT_TRUE(transport_controller_
779 ->SetLocalDescription(SdpType::kOffer, description.get())
780 .ok());
781
782 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
783 transport_controller_->GetDtlsTransport(kAudioMid1));
784 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
785 transport_controller_->GetDtlsTransport(kVideoMid1));
786
787 // First, have one transport connect, and another fail, to ensure that
788 // the first transport connecting didn't trigger a "connected" state signal.
789 // We should only get a signal when all are connected.
790 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
791 fake_audio_dtls->SetWritable(true);
792 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
793 // Decrease the number of the connection to trigger the signal.
794 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
795 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
796 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
797
Alex Loiko9289eda2018-11-23 16:18:59 +0000798 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100799 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000800 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
801 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100802 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100803 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
804 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100805 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800806
Jonas Olsson635474e2018-10-18 15:58:17 +0200807 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
808 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800809 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
810 // the transport state to be STATE_CONNECTING.
811 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
812 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000813 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100814 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000815 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
816 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100817 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100818 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
819 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100820 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800821}
822
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700823TEST_F(JsepTransportControllerTest,
824 SignalConnectionStateConnectedWithMediaTransport) {
825 FakeMediaTransportFactory fake_media_transport_factory;
826 JsepTransportController::Config config;
827 config.media_transport_factory = &fake_media_transport_factory;
828 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800829
830 // Media Transport is only used with bundle.
831 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700832 AddCryptoSettings(description.get());
833 EXPECT_TRUE(transport_controller_
834 ->SetLocalDescription(SdpType::kOffer, description.get())
835 .ok());
836
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800837 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
838 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
839 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
840 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
841 fake_audio_ice->SetConnectionCount(2);
842 fake_audio_ice->SetConnectionCount(1);
843 fake_video_ice->SetConnectionCount(2);
844 fake_video_ice->SetConnectionCount(1);
845 fake_audio_ice->SetWritable(true);
846 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700847
848 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +0000849 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
850 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700851
852 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
853 transport_controller_->GetMediaTransport(kAudioMid1));
854
855 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Alex Loiko9289eda2018-11-23 16:18:59 +0000856 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
857 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700858
859 // Still waiting for the second media transport.
860 media_transport = static_cast<FakeMediaTransport*>(
861 transport_controller_->GetMediaTransport(kVideoMid1));
862 media_transport->SetState(webrtc::MediaTransportState::kWritable);
863
Alex Loiko9289eda2018-11-23 16:18:59 +0000864 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700865}
866
867TEST_F(JsepTransportControllerTest,
868 SignalConnectionStateFailedWhenMediaTransportClosed) {
869 FakeMediaTransportFactory fake_media_transport_factory;
870 JsepTransportController::Config config;
871 config.media_transport_factory = &fake_media_transport_factory;
872 CreateJsepTransportController(config);
873 auto description = CreateSessionDescriptionWithoutBundle();
874 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->SetWritable(true);
884 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700885 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800886 fake_audio_ice->SetConnectionCount(2);
887 fake_audio_ice->SetConnectionCount(1);
888 fake_video_ice->SetConnectionCount(2);
889 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700890
891 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
892 transport_controller_->GetMediaTransport(kAudioMid1));
893
894 media_transport->SetState(webrtc::MediaTransportState::kWritable);
895
896 media_transport = static_cast<FakeMediaTransport*>(
897 transport_controller_->GetMediaTransport(kVideoMid1));
898
899 media_transport->SetState(webrtc::MediaTransportState::kWritable);
900
Alex Loiko9289eda2018-11-23 16:18:59 +0000901 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700902
903 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +0000904 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700905}
906
Zhi Huange818b6e2018-02-22 15:26:27 -0800907TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
908 CreateJsepTransportController(JsepTransportController::Config());
909 auto description = CreateSessionDescriptionWithoutBundle();
910 EXPECT_TRUE(transport_controller_
911 ->SetLocalDescription(SdpType::kOffer, description.get())
912 .ok());
913
914 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
915 transport_controller_->GetDtlsTransport(kAudioMid1));
916 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
917 transport_controller_->GetDtlsTransport(kVideoMid1));
918
919 // First, have one transport connect, and another fail, to ensure that
920 // the first transport connecting didn't trigger a "connected" state signal.
921 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100922 fake_audio_dtls->fake_ice_transport()->SetTransportState(
923 IceTransportState::kCompleted,
924 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800925 fake_audio_dtls->SetWritable(true);
926 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100927
928 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
929 ice_connection_state_, kTimeout);
930 EXPECT_EQ(1, ice_connection_state_signal_count_);
931 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
932 combined_connection_state_, kTimeout);
933 EXPECT_EQ(1, combined_connection_state_signal_count_);
934
935 fake_video_dtls->fake_ice_transport()->SetTransportState(
936 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800937 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
938
Alex Loiko9289eda2018-11-23 16:18:59 +0000939 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100940 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000941 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
942 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100943 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100944 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
945 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100946 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800947
Jonas Olsson635474e2018-10-18 15:58:17 +0200948 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
949 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800950 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
951 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100952 fake_video_dtls->fake_ice_transport()->SetTransportState(
953 IceTransportState::kCompleted,
954 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800955 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000956 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +0100957 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000958 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
959 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100960 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100961 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
962 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100963 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800964}
965
966TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
967 CreateJsepTransportController(JsepTransportController::Config());
968 auto description = CreateSessionDescriptionWithoutBundle();
969 EXPECT_TRUE(transport_controller_
970 ->SetLocalDescription(SdpType::kOffer, description.get())
971 .ok());
972
973 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
974 transport_controller_->GetDtlsTransport(kAudioMid1));
975 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
976 // Should be in the gathering state as soon as any transport starts gathering.
977 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
978 EXPECT_EQ(1, gathering_state_signal_count_);
979}
980
981TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
982 CreateJsepTransportController(JsepTransportController::Config());
983 auto description = CreateSessionDescriptionWithoutBundle();
984 EXPECT_TRUE(transport_controller_
985 ->SetLocalDescription(SdpType::kOffer, description.get())
986 .ok());
987
988 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
989 transport_controller_->GetDtlsTransport(kAudioMid1));
990 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
991 transport_controller_->GetDtlsTransport(kVideoMid1));
992
993 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
994 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
995 EXPECT_EQ(1, gathering_state_signal_count_);
996
997 // Have one transport finish gathering, to make sure gathering
998 // completion wasn't signalled if only one transport finished gathering.
999 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1000 EXPECT_EQ(1, gathering_state_signal_count_);
1001
1002 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1003 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1004 EXPECT_EQ(1, gathering_state_signal_count_);
1005
1006 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1007 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1008 EXPECT_EQ(2, gathering_state_signal_count_);
1009}
1010
1011// Test that when the last transport that hasn't finished connecting and/or
1012// gathering is destroyed, the aggregate state jumps to "completed". This can
1013// happen if, for example, we have an audio and video transport, the audio
1014// transport completes, then we start bundling video on the audio transport.
1015TEST_F(JsepTransportControllerTest,
1016 SignalingWhenLastIncompleteTransportDestroyed) {
1017 CreateJsepTransportController(JsepTransportController::Config());
1018 auto description = CreateSessionDescriptionWithBundleGroup();
1019 EXPECT_TRUE(transport_controller_
1020 ->SetLocalDescription(SdpType::kOffer, description.get())
1021 .ok());
1022
1023 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1024 transport_controller_->GetDtlsTransport(kAudioMid1));
1025 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1026 transport_controller_->GetDtlsTransport(kVideoMid1));
1027 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1028
1029 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1030 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1031 EXPECT_EQ(1, gathering_state_signal_count_);
1032
1033 // Let the audio transport complete.
1034 fake_audio_dtls->SetWritable(true);
1035 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1036 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001037 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001038 EXPECT_EQ(1, gathering_state_signal_count_);
1039
1040 // Set the remote description and enable the bundle.
1041 EXPECT_TRUE(transport_controller_
1042 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1043 .ok());
1044 // The BUNDLE should be enabled, the incomplete video transport should be
1045 // deleted and the states shoud be updated.
1046 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1047 transport_controller_->GetDtlsTransport(kVideoMid1));
1048 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001049 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1050 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1051 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001052 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1053 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001054 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1055 EXPECT_EQ(2, gathering_state_signal_count_);
1056}
1057
1058TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1059 CreateJsepTransportController(JsepTransportController::Config());
1060 auto description = CreateSessionDescriptionWithBundleGroup();
1061 EXPECT_TRUE(transport_controller_
1062 ->SetLocalDescription(SdpType::kOffer, description.get())
1063 .ok());
1064 transport_controller_->MaybeStartGathering();
1065
1066 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1067 transport_controller_->GetDtlsTransport(kAudioMid1));
1068 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1069 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1070 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1071 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1072}
1073
1074TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1075 network_thread_ = rtc::Thread::CreateWithSocketServer();
1076 network_thread_->Start();
1077 CreateJsepTransportController(JsepTransportController::Config(),
1078 signaling_thread_, network_thread_.get(),
1079 /*PortAllocator=*/nullptr);
1080 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1081
1082 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001083 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001084 EXPECT_EQ(2, connection_state_signal_count_);
1085
1086 // new --> gathering --> complete
1087 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1088 EXPECT_EQ(2, gathering_state_signal_count_);
1089
1090 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1091 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1092 EXPECT_EQ(2, candidates_signal_count_);
1093
1094 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1095}
1096
1097// Older versions of Chrome expect the ICE role to be re-determined when an
1098// ICE restart occurs, and also don't perform conflict resolution correctly,
1099// so for now we can't safely stop doing this.
1100// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1101// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1102// enough population.
1103TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1104 CreateJsepTransportController(JsepTransportController::Config());
1105 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001106 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001107 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1108 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1109 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001110 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001111 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1112 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1113 nullptr);
1114
1115 EXPECT_TRUE(transport_controller_
1116 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1117 .ok());
1118 EXPECT_TRUE(transport_controller_
1119 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1120 .ok());
1121
1122 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1123 transport_controller_->GetDtlsTransport(kAudioMid1));
1124 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1125 fake_dtls->fake_ice_transport()->GetIceRole());
1126
1127 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001128 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001129 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1130 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1131 nullptr);
1132 EXPECT_TRUE(
1133 transport_controller_
1134 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1135 .ok());
1136 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1137 fake_dtls->fake_ice_transport()->GetIceRole());
1138}
1139
1140// Test that if the TransportController was created with the
1141// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1142// redetermined on an ICE restart.
1143TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1144 JsepTransportController::Config config;
1145 config.redetermine_role_on_ice_restart = false;
1146
1147 CreateJsepTransportController(config);
1148 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001149 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001150 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1151 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1152 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001153 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001154 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1155 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1156 nullptr);
1157
1158 EXPECT_TRUE(transport_controller_
1159 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1160 .ok());
1161 EXPECT_TRUE(transport_controller_
1162 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1163 .ok());
1164
1165 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1166 transport_controller_->GetDtlsTransport(kAudioMid1));
1167 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1168 fake_dtls->fake_ice_transport()->GetIceRole());
1169
1170 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001171 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001172 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1173 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1174 nullptr);
1175 EXPECT_TRUE(
1176 transport_controller_
1177 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1178 .ok());
1179 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1180 fake_dtls->fake_ice_transport()->GetIceRole());
1181}
1182
1183// Tests ICE-Lite mode in remote answer.
1184TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1185 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001186 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001187 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1188 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1189 nullptr);
1190 EXPECT_TRUE(transport_controller_
1191 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1192 .ok());
1193 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1194 transport_controller_->GetDtlsTransport(kAudioMid1));
1195 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1196 fake_dtls->fake_ice_transport()->GetIceRole());
1197 EXPECT_EQ(cricket::ICEMODE_FULL,
1198 fake_dtls->fake_ice_transport()->remote_ice_mode());
1199
Karl Wiberg918f50c2018-07-05 11:40:33 +02001200 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001201 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1202 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1203 nullptr);
1204 EXPECT_TRUE(transport_controller_
1205 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1206 .ok());
1207 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1208 fake_dtls->fake_ice_transport()->GetIceRole());
1209 EXPECT_EQ(cricket::ICEMODE_LITE,
1210 fake_dtls->fake_ice_transport()->remote_ice_mode());
1211}
1212
1213// Tests that the ICE role remains "controlling" if a subsequent offer that
1214// does an ICE restart is received from an ICE lite endpoint. Regression test
1215// for: https://crbug.com/710760
1216TEST_F(JsepTransportControllerTest,
1217 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1218 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001219 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001220 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1221 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1222 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001223 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001224 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1225 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1226 nullptr);
1227 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1228 // local side is the controlling.
1229 EXPECT_TRUE(transport_controller_
1230 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1231 .ok());
1232 EXPECT_TRUE(transport_controller_
1233 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1234 .ok());
1235 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1236 transport_controller_->GetDtlsTransport(kAudioMid1));
1237 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1238 fake_dtls->fake_ice_transport()->GetIceRole());
1239
1240 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001241 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001242 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1243 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1244 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001245 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001246 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1247 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1248 nullptr);
1249 EXPECT_TRUE(transport_controller_
1250 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1251 .ok());
1252 EXPECT_TRUE(transport_controller_
1253 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1254 .ok());
1255 fake_dtls = static_cast<FakeDtlsTransport*>(
1256 transport_controller_->GetDtlsTransport(kAudioMid1));
1257 // The local side is still the controlling role since the remote side is using
1258 // ICE-Lite.
1259 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1260 fake_dtls->fake_ice_transport()->GetIceRole());
1261}
1262
1263// Tests that the SDP has more than one audio/video m= sections.
1264TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1265 CreateJsepTransportController(JsepTransportController::Config());
1266 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1267 bundle_group.AddContentName(kAudioMid1);
1268 bundle_group.AddContentName(kAudioMid2);
1269 bundle_group.AddContentName(kVideoMid1);
1270 bundle_group.AddContentName(kDataMid1);
1271
Karl Wiberg918f50c2018-07-05 11:40:33 +02001272 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001273 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1274 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1275 nullptr);
1276 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1277 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1278 nullptr);
1279 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1280 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1281 nullptr);
1282 AddDataSection(local_offer.get(), kDataMid1,
1283 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1284 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1285 nullptr);
1286
Karl Wiberg918f50c2018-07-05 11:40:33 +02001287 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001288 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1289 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1290 nullptr);
1291 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1292 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1293 nullptr);
1294 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1295 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1296 nullptr);
1297 AddDataSection(remote_answer.get(), kDataMid1,
1298 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1299 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1300 nullptr);
1301
1302 local_offer->AddGroup(bundle_group);
1303 remote_answer->AddGroup(bundle_group);
1304
1305 EXPECT_TRUE(transport_controller_
1306 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1307 .ok());
1308 EXPECT_TRUE(transport_controller_
1309 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1310 .ok());
1311 // Verify that all the sections are bundled on kAudio1.
1312 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1313 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1314 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1315 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1316 EXPECT_EQ(transport1, transport2);
1317 EXPECT_EQ(transport1, transport3);
1318 EXPECT_EQ(transport1, transport4);
1319
Harald Alvestrandad88c882018-11-28 16:47:46 +01001320 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1321 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1322
Zhi Huange818b6e2018-02-22 15:26:27 -08001323 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1324 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1325 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1326 EXPECT_EQ(transport1, it->second);
1327 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1328 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1329 EXPECT_EQ(transport1, it->second);
1330 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1331 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1332 EXPECT_EQ(transport1, it->second);
1333 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1334 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1335 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1336 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1337}
1338
1339// Tests that only a subset of all the m= sections are bundled.
1340TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1341 CreateJsepTransportController(JsepTransportController::Config());
1342 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1343 bundle_group.AddContentName(kAudioMid1);
1344 bundle_group.AddContentName(kVideoMid1);
1345
Karl Wiberg918f50c2018-07-05 11:40:33 +02001346 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001347 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1348 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1349 nullptr);
1350 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1351 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1352 nullptr);
1353 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1354 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1355 nullptr);
1356
Karl Wiberg918f50c2018-07-05 11:40:33 +02001357 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001358 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1359 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1360 nullptr);
1361 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1362 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1363 nullptr);
1364 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1365 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1366 nullptr);
1367
1368 local_offer->AddGroup(bundle_group);
1369 remote_answer->AddGroup(bundle_group);
1370 EXPECT_TRUE(transport_controller_
1371 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1372 .ok());
1373 EXPECT_TRUE(transport_controller_
1374 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1375 .ok());
1376
1377 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1378 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1379 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1380 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1381 EXPECT_NE(transport1, transport2);
1382 EXPECT_EQ(transport1, transport3);
1383
1384 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1385 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1386 EXPECT_EQ(transport1, it->second);
1387 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001388 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001389}
1390
1391// Tests that the initial offer/answer only have data section and audio/video
1392// sections are added in the subsequent offer.
1393TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1394 CreateJsepTransportController(JsepTransportController::Config());
1395 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1396 bundle_group.AddContentName(kDataMid1);
1397
Karl Wiberg918f50c2018-07-05 11:40:33 +02001398 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001399 AddDataSection(local_offer.get(), kDataMid1,
1400 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1401 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1402 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001403 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001404 AddDataSection(remote_answer.get(), kDataMid1,
1405 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1406 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1407 nullptr);
1408 local_offer->AddGroup(bundle_group);
1409 remote_answer->AddGroup(bundle_group);
1410
1411 EXPECT_TRUE(transport_controller_
1412 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1413 .ok());
1414 EXPECT_TRUE(transport_controller_
1415 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1416 .ok());
1417 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1418
1419 // Add audio/video sections in subsequent offer.
1420 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1421 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1422 nullptr);
1423 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1424 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1425 nullptr);
1426 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1427 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1428 nullptr);
1429 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1430 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1431 nullptr);
1432
1433 // Reset the bundle group and do another offer/answer exchange.
1434 bundle_group.AddContentName(kAudioMid1);
1435 bundle_group.AddContentName(kVideoMid1);
1436 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1437 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1438 local_offer->AddGroup(bundle_group);
1439 remote_answer->AddGroup(bundle_group);
1440
1441 EXPECT_TRUE(transport_controller_
1442 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1443 .ok());
1444 EXPECT_TRUE(transport_controller_
1445 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1446 .ok());
1447
1448 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1449 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1450 EXPECT_EQ(data_transport, audio_transport);
1451 EXPECT_EQ(data_transport, video_transport);
1452}
1453
1454TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1455 CreateJsepTransportController(JsepTransportController::Config());
1456 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1457 bundle_group.AddContentName(kAudioMid1);
1458 bundle_group.AddContentName(kVideoMid1);
1459 bundle_group.AddContentName(kDataMid1);
1460
Karl Wiberg918f50c2018-07-05 11:40:33 +02001461 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001462 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1463 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1464 nullptr);
1465 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1466 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1467 nullptr);
1468 AddDataSection(local_offer.get(), kDataMid1,
1469 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1470 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1471 nullptr);
1472
Karl Wiberg918f50c2018-07-05 11:40:33 +02001473 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001474 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1475 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1476 nullptr);
1477 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1478 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1479 nullptr);
1480 AddDataSection(remote_answer.get(), kDataMid1,
1481 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1482 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1483 nullptr);
1484 // Reject video and data section.
1485 remote_answer->contents()[1].rejected = true;
1486 remote_answer->contents()[2].rejected = true;
1487
1488 local_offer->AddGroup(bundle_group);
1489 remote_answer->AddGroup(bundle_group);
1490
1491 EXPECT_TRUE(transport_controller_
1492 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1493 .ok());
1494 EXPECT_TRUE(transport_controller_
1495 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1496 .ok());
1497
1498 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1499 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1500 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1501 // Verify the signals are fired correctly.
1502 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1503 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1504 EXPECT_EQ(nullptr, it->second);
1505 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1506 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1507 EXPECT_EQ(nullptr, it2->second);
1508}
1509
1510// Tests that changing the bundled MID in subsequent offer/answer exchange is
1511// not supported.
1512// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1513// fixed
1514TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1515 CreateJsepTransportController(JsepTransportController::Config());
1516 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1517 bundle_group.AddContentName(kAudioMid1);
1518 bundle_group.AddContentName(kVideoMid1);
1519
Karl Wiberg918f50c2018-07-05 11:40:33 +02001520 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001521 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1522 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1523 nullptr);
1524 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1525 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1526 nullptr);
1527
Karl Wiberg918f50c2018-07-05 11:40:33 +02001528 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001529 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1530 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1531 nullptr);
1532 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1533 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1534 nullptr);
1535
1536 local_offer->AddGroup(bundle_group);
1537 remote_answer->AddGroup(bundle_group);
1538 EXPECT_TRUE(transport_controller_
1539 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1540 .ok());
1541 EXPECT_TRUE(transport_controller_
1542 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1543 .ok());
1544 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1545 transport_controller_->GetRtpTransport(kVideoMid1));
1546
1547 // Reorder the bundle group.
1548 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1549 bundle_group.AddContentName(kAudioMid1);
1550 // The answerer uses the new bundle group and now the bundle mid is changed to
1551 // |kVideo1|.
1552 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1553 remote_answer->AddGroup(bundle_group);
1554 EXPECT_TRUE(transport_controller_
1555 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1556 .ok());
1557 EXPECT_FALSE(transport_controller_
1558 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1559 .ok());
1560}
Zhi Huange830e682018-03-30 10:48:35 -07001561// Test that rejecting only the first m= section of a BUNDLE group is treated as
1562// an error, but rejecting all of them works as expected.
1563TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1564 CreateJsepTransportController(JsepTransportController::Config());
1565 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1566 bundle_group.AddContentName(kAudioMid1);
1567 bundle_group.AddContentName(kVideoMid1);
1568 bundle_group.AddContentName(kDataMid1);
1569
Karl Wiberg918f50c2018-07-05 11:40:33 +02001570 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001571 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1572 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1573 nullptr);
1574 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1575 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1576 nullptr);
1577 AddDataSection(local_offer.get(), kDataMid1,
1578 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1579 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1580 nullptr);
1581
Karl Wiberg918f50c2018-07-05 11:40:33 +02001582 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001583 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1584 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1585 nullptr);
1586 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1587 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1588 nullptr);
1589 AddDataSection(remote_answer.get(), kDataMid1,
1590 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1591 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1592 nullptr);
1593 // Reject audio content in answer.
1594 remote_answer->contents()[0].rejected = true;
1595
1596 local_offer->AddGroup(bundle_group);
1597 remote_answer->AddGroup(bundle_group);
1598
1599 EXPECT_TRUE(transport_controller_
1600 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1601 .ok());
1602 EXPECT_FALSE(transport_controller_
1603 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1604 .ok());
1605
1606 // Reject all the contents.
1607 remote_answer->contents()[1].rejected = true;
1608 remote_answer->contents()[2].rejected = true;
1609 EXPECT_TRUE(transport_controller_
1610 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1611 .ok());
1612 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1613 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1614 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1615}
1616
1617// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1618// is used.
1619TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1620 JsepTransportController::Config config;
1621 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1622 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001623 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001624 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1625 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1626 nullptr);
1627
1628 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1629 // Applying a non-RTCP-mux offer is expected to fail.
1630 EXPECT_FALSE(transport_controller_
1631 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1632 .ok());
1633}
1634
1635// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1636// is used.
1637TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1638 JsepTransportController::Config config;
1639 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1640 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001641 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001642 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1643 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1644 nullptr);
1645 EXPECT_TRUE(transport_controller_
1646 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1647 .ok());
1648
Karl Wiberg918f50c2018-07-05 11:40:33 +02001649 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001650 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1651 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1652 nullptr);
1653 // Applying a non-RTCP-mux answer is expected to fail.
1654 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1655 EXPECT_FALSE(transport_controller_
1656 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1657 .ok());
1658}
Zhi Huange818b6e2018-02-22 15:26:27 -08001659
Zhi Huangd2248f82018-04-10 14:41:03 -07001660// This tests that the BUNDLE group in answer should be a subset of the offered
1661// group.
1662TEST_F(JsepTransportControllerTest,
1663 AddContentToBundleGroupInAnswerNotSupported) {
1664 CreateJsepTransportController(JsepTransportController::Config());
1665 auto local_offer = CreateSessionDescriptionWithoutBundle();
1666 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1667
1668 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1669 offer_bundle_group.AddContentName(kAudioMid1);
1670 local_offer->AddGroup(offer_bundle_group);
1671
1672 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1673 answer_bundle_group.AddContentName(kAudioMid1);
1674 answer_bundle_group.AddContentName(kVideoMid1);
1675 remote_answer->AddGroup(answer_bundle_group);
1676 EXPECT_TRUE(transport_controller_
1677 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1678 .ok());
1679 EXPECT_FALSE(transport_controller_
1680 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1681 .ok());
1682}
1683
1684// This tests that the BUNDLE group with non-existing MID should be rejectd.
1685TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1686 CreateJsepTransportController(JsepTransportController::Config());
1687 auto local_offer = CreateSessionDescriptionWithoutBundle();
1688 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1689
1690 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1691 // The BUNDLE group is invalid because there is no data section in the
1692 // description.
1693 invalid_bundle_group.AddContentName(kDataMid1);
1694 local_offer->AddGroup(invalid_bundle_group);
1695 remote_answer->AddGroup(invalid_bundle_group);
1696
1697 EXPECT_FALSE(transport_controller_
1698 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1699 .ok());
1700 EXPECT_FALSE(transport_controller_
1701 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1702 .ok());
1703}
1704
1705// This tests that an answer shouldn't be able to remove an m= section from an
1706// established group without rejecting it.
1707TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1708 CreateJsepTransportController(JsepTransportController::Config());
1709
1710 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1711 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1712 EXPECT_TRUE(transport_controller_
1713 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1714 .ok());
1715 EXPECT_TRUE(transport_controller_
1716 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1717 .ok());
1718
1719 // Do an re-offer/answer.
1720 EXPECT_TRUE(transport_controller_
1721 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1722 .ok());
1723 auto new_answer = CreateSessionDescriptionWithoutBundle();
1724 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1725 // The answer removes video from the BUNDLE group without rejecting it is
1726 // invalid.
1727 new_bundle_group.AddContentName(kAudioMid1);
1728 new_answer->AddGroup(new_bundle_group);
1729
1730 // Applying invalid answer is expected to fail.
1731 EXPECT_FALSE(transport_controller_
1732 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1733 .ok());
1734
1735 // Rejected the video content.
1736 auto video_content = new_answer->GetContentByName(kVideoMid1);
1737 ASSERT_TRUE(video_content);
1738 video_content->rejected = true;
1739 EXPECT_TRUE(transport_controller_
1740 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1741 .ok());
1742}
1743
Steve Anton2bed3972019-01-04 17:04:30 -08001744// Test that the JsepTransportController can process a new local and remote
1745// description that changes the tagged BUNDLE group with the max-bundle policy
1746// specified.
1747// This is a regression test for bugs.webrtc.org/9954
1748TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
1749 CreateJsepTransportController(JsepTransportController::Config());
1750
1751 auto local_offer = absl::make_unique<cricket::SessionDescription>();
1752 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1753 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1754 nullptr);
1755 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1756 bundle_group.AddContentName(kAudioMid1);
1757 local_offer->AddGroup(bundle_group);
1758 EXPECT_TRUE(transport_controller_
1759 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1760 .ok());
1761
1762 std::unique_ptr<cricket::SessionDescription> remote_answer(
1763 local_offer->Copy());
1764 EXPECT_TRUE(transport_controller_
1765 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1766 .ok());
1767
1768 std::unique_ptr<cricket::SessionDescription> local_reoffer(
1769 local_offer->Copy());
1770 local_reoffer->contents()[0].rejected = true;
1771 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
1772 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1773 nullptr);
1774 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1775 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1776 new_bundle_group.AddContentName(kVideoMid1);
1777 local_reoffer->AddGroup(new_bundle_group);
1778
1779 EXPECT_TRUE(transport_controller_
1780 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
1781 .ok());
1782
1783 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
1784 local_reoffer->Copy());
1785 EXPECT_TRUE(
1786 transport_controller_
1787 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
1788 .ok());
1789}
1790
Zhi Huange818b6e2018-02-22 15:26:27 -08001791} // namespace webrtc