blob: d796b236d3e8686d5a7ab5f6525bf7978af264e0 [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"
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -080017#include "api/test/loopback_media_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "p2p/base/fake_dtls_transport.h"
19#include "p2p/base/fake_ice_transport.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080020#include "p2p/base/no_op_dtls_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "p2p/base/transport_factory_interface.h"
22#include "p2p/base/transport_info.h"
23#include "pc/jsep_transport_controller.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080025#include "rtc_base/thread.h"
26#include "test/gtest.h"
27
28using cricket::FakeDtlsTransport;
29using cricket::Candidate;
30using cricket::Candidates;
31using webrtc::SdpType;
32
33static const int kTimeout = 100;
34static const char kIceUfrag1[] = "u0001";
35static const char kIcePwd1[] = "TESTICEPWD00000000000001";
36static const char kIceUfrag2[] = "u0002";
37static const char kIcePwd2[] = "TESTICEPWD00000000000002";
38static const char kIceUfrag3[] = "u0003";
39static const char kIcePwd3[] = "TESTICEPWD00000000000003";
40static const char kAudioMid1[] = "audio1";
41static const char kAudioMid2[] = "audio2";
42static const char kVideoMid1[] = "video1";
43static const char kVideoMid2[] = "video2";
44static const char kDataMid1[] = "data1";
45
46namespace webrtc {
47
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070048namespace {
49
50// Media transport factory requires crypto settings to be present in order to
51// create media transport.
52void AddCryptoSettings(cricket::SessionDescription* description) {
53 for (auto& content : description->contents()) {
54 content.media_description()->AddCrypto(cricket::CryptoParams(
55 /*t=*/0, std::string(rtc::CS_AES_CM_128_HMAC_SHA1_80),
56 "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2", ""));
57 }
58}
59
60} // namespace
61
Zhi Huange818b6e2018-02-22 15:26:27 -080062class FakeTransportFactory : public cricket::TransportFactoryInterface {
63 public:
64 std::unique_ptr<cricket::IceTransportInternal> CreateIceTransport(
65 const std::string& transport_name,
66 int component) override {
Karl Wiberg918f50c2018-07-05 11:40:33 +020067 return absl::make_unique<cricket::FakeIceTransport>(transport_name,
68 component);
Zhi Huange818b6e2018-02-22 15:26:27 -080069 }
70
71 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070072 cricket::IceTransportInternal* ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070073 const webrtc::CryptoOptions& crypto_options) override {
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070074 return absl::make_unique<FakeDtlsTransport>(
75 static_cast<cricket::FakeIceTransport*>(ice));
Zhi Huange818b6e2018-02-22 15:26:27 -080076 }
77};
78
Zhi Huang365381f2018-04-13 16:44:34 -070079class JsepTransportControllerTest : public JsepTransportController::Observer,
Mirko Bonadei6a489f22019-04-09 15:11:12 +020080 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) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200177 RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp);
178 std::unique_ptr<cricket::SctpDataContentDescription> data(
179 new cricket::SctpDataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700180 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800181 description->AddContent(mid, protocol_type,
182 /*rejected=*/false, data.release());
183 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
184 }
185
186 void AddTransportInfo(cricket::SessionDescription* description,
187 const std::string& mid,
188 const std::string& ufrag,
189 const std::string& pwd,
190 cricket::IceMode ice_mode,
191 cricket::ConnectionRole conn_role,
192 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
193 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
194 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700195 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800196 }
197
198 cricket::TransportDescription transport_desc(std::vector<std::string>(),
199 ufrag, pwd, ice_mode,
200 conn_role, fingerprint.get());
201 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
202 }
203
204 cricket::IceConfig CreateIceConfig(
205 int receiving_timeout,
206 cricket::ContinualGatheringPolicy continual_gathering_policy) {
207 cricket::IceConfig config;
208 config.receiving_timeout = receiving_timeout;
209 config.continual_gathering_policy = continual_gathering_policy;
210 return config;
211 }
212
213 Candidate CreateCandidate(const std::string& transport_name, int component) {
214 Candidate c;
215 c.set_transport_name(transport_name);
216 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
217 c.set_component(component);
218 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
219 c.set_priority(1);
220 return c;
221 }
222
223 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
224 if (!network_thread_->IsCurrent()) {
225 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
226 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
227 });
228 return;
229 }
230
231 auto description = CreateSessionDescriptionWithBundleGroup();
232 EXPECT_TRUE(transport_controller_
233 ->SetLocalDescription(SdpType::kOffer, description.get())
234 .ok());
235
236 transport_controller_->MaybeStartGathering();
237 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
238 transport_controller_->GetDtlsTransport(kAudioMid1));
239 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
240 transport_controller_->GetDtlsTransport(kVideoMid1));
241 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
242 fake_audio_dtls->fake_ice_transport(),
243 CreateCandidate(kAudioMid1, /*component=*/1));
244 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
245 fake_video_dtls->fake_ice_transport(),
246 CreateCandidate(kVideoMid1, /*component=*/1));
247 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
248 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
249 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
250 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
251 fake_audio_dtls->SetReceiving(true);
252 fake_video_dtls->SetReceiving(true);
253 fake_audio_dtls->SetWritable(true);
254 fake_video_dtls->SetWritable(true);
255 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
256 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
257 }
258
259 protected:
Alex Loiko9289eda2018-11-23 16:18:59 +0000260 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800261 if (!signaling_thread_->IsCurrent()) {
262 signaled_on_non_signaling_thread_ = true;
263 }
264 connection_state_ = state;
265 ++connection_state_signal_count_;
266 }
267
Alex Loiko9289eda2018-11-23 16:18:59 +0000268 void OnStandardizedIceConnectionState(
269 PeerConnectionInterface::IceConnectionState state) {
270 if (!signaling_thread_->IsCurrent()) {
271 signaled_on_non_signaling_thread_ = true;
272 }
273 ice_connection_state_ = state;
274 ++ice_connection_state_signal_count_;
275 }
276
Jonas Olsson635474e2018-10-18 15:58:17 +0200277 void OnCombinedConnectionState(
278 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100279 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
280 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 15:58:17 +0200281 if (!signaling_thread_->IsCurrent()) {
282 signaled_on_non_signaling_thread_ = true;
283 }
284 combined_connection_state_ = state;
285 ++combined_connection_state_signal_count_;
286 }
287
Zhi Huange818b6e2018-02-22 15:26:27 -0800288 void OnGatheringState(cricket::IceGatheringState state) {
289 if (!signaling_thread_->IsCurrent()) {
290 signaled_on_non_signaling_thread_ = true;
291 }
292 gathering_state_ = state;
293 ++gathering_state_signal_count_;
294 }
295
296 void OnCandidatesGathered(const std::string& transport_name,
297 const Candidates& candidates) {
298 if (!signaling_thread_->IsCurrent()) {
299 signaled_on_non_signaling_thread_ = true;
300 }
301 candidates_[transport_name].insert(candidates_[transport_name].end(),
302 candidates.begin(), candidates.end());
303 ++candidates_signal_count_;
304 }
305
Zhi Huang365381f2018-04-13 16:44:34 -0700306 // JsepTransportController::Observer overrides.
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800307 bool OnTransportChanged(const std::string& mid,
308 RtpTransportInternal* rtp_transport,
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100309 rtc::scoped_refptr<DtlsTransport> dtls_transport,
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800310 MediaTransportInterface* media_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700311 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100312 if (dtls_transport) {
313 changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
314 } else {
315 changed_dtls_transport_by_mid_[mid] = nullptr;
316 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800317 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700318 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800319 }
320
321 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000322 cricket::IceConnectionState connection_state_ =
323 cricket::kIceConnectionConnecting;
324 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200325 PeerConnectionInterface::kIceConnectionNew;
326 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
327 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800328 bool receiving_ = false;
329 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
330 // transport_name => candidates
331 std::map<std::string, Candidates> candidates_;
332 // Counts of each signal emitted.
333 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000334 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200335 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800336 int receiving_signal_count_ = 0;
337 int gathering_state_signal_count_ = 0;
338 int candidates_signal_count_ = 0;
339
340 // |network_thread_| should be destroyed after |transport_controller_|
341 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800342 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
343 rtc::Thread* const signaling_thread_ = nullptr;
344 bool signaled_on_non_signaling_thread_ = false;
345 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
346 // signaled correctly.
347 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
348 std::map<std::string, cricket::DtlsTransportInternal*>
349 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800350 std::map<std::string, MediaTransportInterface*>
351 changed_media_transport_by_mid_;
352
353 // Transport controller needs to be destroyed first, because it may issue
354 // callbacks that modify the changed_*_by_mid in the destructor.
355 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800356};
357
358TEST_F(JsepTransportControllerTest, GetRtpTransport) {
359 CreateJsepTransportController(JsepTransportController::Config());
360 auto description = CreateSessionDescriptionWithoutBundle();
361 EXPECT_TRUE(transport_controller_
362 ->SetLocalDescription(SdpType::kOffer, description.get())
363 .ok());
364 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
365 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
366 EXPECT_NE(nullptr, audio_rtp_transport);
367 EXPECT_NE(nullptr, video_rtp_transport);
368 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
369 // Return nullptr for non-existing ones.
370 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
371}
372
373TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
374 JsepTransportController::Config config;
375 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
376 CreateJsepTransportController(config);
377 auto description = CreateSessionDescriptionWithoutBundle();
378 EXPECT_TRUE(transport_controller_
379 ->SetLocalDescription(SdpType::kOffer, description.get())
380 .ok());
381 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
382 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100383 EXPECT_NE(nullptr,
384 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800385 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
386 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100387 EXPECT_NE(nullptr,
388 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
389 // Lookup for all MIDs should return different transports (no bundle)
390 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
391 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800392 // Return nullptr for non-existing ones.
393 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
394 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100395 EXPECT_EQ(nullptr,
396 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100397 // Take a pointer to a transport, shut down the transport controller,
398 // and verify that the resulting container is empty.
399 auto dtls_transport =
400 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
401 webrtc::DtlsTransport* my_transport =
402 static_cast<DtlsTransport*>(dtls_transport.get());
403 EXPECT_NE(nullptr, my_transport->internal());
404 transport_controller_.reset();
405 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800406}
407
Zhi Huange830e682018-03-30 10:48:35 -0700408TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
409 JsepTransportController::Config config;
410 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
411 CreateJsepTransportController(config);
412 auto description = CreateSessionDescriptionWithoutBundle();
413 EXPECT_TRUE(transport_controller_
414 ->SetLocalDescription(SdpType::kOffer, description.get())
415 .ok());
416 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
417 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
418 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
419 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700420 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
421}
422
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800423TEST_F(JsepTransportControllerTest,
424 DtlsIsStillCreatedIfMediaTransportIsOnlyUsedForDataChannels) {
425 FakeMediaTransportFactory fake_media_transport_factory;
426 JsepTransportController::Config config;
427
428 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800429 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800430 config.media_transport_factory = &fake_media_transport_factory;
431 config.use_media_transport_for_data_channels = true;
432 CreateJsepTransportController(config);
433 auto description = CreateSessionDescriptionWithBundleGroup();
434 AddCryptoSettings(description.get());
435
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800436 EXPECT_NE(absl::nullopt,
437 transport_controller_->GenerateOrGetLastMediaTransportOffer());
438
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800439 EXPECT_TRUE(transport_controller_
440 ->SetLocalDescription(SdpType::kOffer, description.get())
441 .ok());
442
443 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700444 transport_controller_->GetMediaTransportForDataChannel(kAudioMid1));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800445
446 ASSERT_NE(nullptr, media_transport);
447
448 // After SetLocalDescription, media transport should be created as caller.
449 EXPECT_TRUE(media_transport->is_caller());
450 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
451
452 // Return nullptr for non-existing mids.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700453 EXPECT_EQ(nullptr,
454 transport_controller_->GetMediaTransportForDataChannel(kVideoMid2));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800455
456 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
457 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
458 << "Media transport for media was not enabled, and so DTLS transport "
459 "should be created.";
460}
461
Anton Sukhanov7940da02018-10-10 10:34:49 -0700462TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
463 FakeMediaTransportFactory fake_media_transport_factory;
464 JsepTransportController::Config config;
465
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800466 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800467 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700468 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800469 config.use_media_transport_for_data_channels = true;
470 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700471 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800472 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700473 AddCryptoSettings(description.get());
474
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800475 EXPECT_NE(absl::nullopt,
476 transport_controller_->GenerateOrGetLastMediaTransportOffer());
477
Anton Sukhanov7940da02018-10-10 10:34:49 -0700478 EXPECT_TRUE(transport_controller_
479 ->SetLocalDescription(SdpType::kOffer, description.get())
480 .ok());
481
482 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
483 transport_controller_->GetMediaTransport(kAudioMid1));
484
485 ASSERT_NE(nullptr, media_transport);
486
487 // After SetLocalDescription, media transport should be created as caller.
488 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800489 // We set the pre-shared key on the caller.
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700490 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800491 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700492
493 // Return nullptr for non-existing mids.
494 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800495
496 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
497 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
498 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700499}
500
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800501TEST_F(JsepTransportControllerTest,
502 GetMediaTransportOfferInTheConfigOnSubsequentCalls) {
503 FakeMediaTransportFactory fake_media_transport_factory;
504 WrapperMediaTransportFactory wrapping_factory(&fake_media_transport_factory);
505 JsepTransportController::Config config;
506
507 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
508 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
509 config.media_transport_factory = &wrapping_factory;
510 config.use_media_transport_for_data_channels = true;
511 config.use_media_transport_for_media = true;
512 CreateJsepTransportController(config);
513 auto description = CreateSessionDescriptionWithBundleGroup();
514 AddCryptoSettings(description.get());
515
516 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
517 transport_controller_->GenerateOrGetLastMediaTransportOffer();
518 ASSERT_NE(absl::nullopt, settings);
519
520 EXPECT_TRUE(transport_controller_
521 ->SetLocalDescription(SdpType::kOffer, description.get())
522 .ok());
523
524 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
525 transport_controller_->GetMediaTransport(kAudioMid1));
526
527 ASSERT_NE(nullptr, media_transport);
528
529 absl::optional<cricket::SessionDescription::MediaTransportSetting>
530 new_settings =
531 transport_controller_->GenerateOrGetLastMediaTransportOffer();
532 ASSERT_NE(absl::nullopt, new_settings);
533 EXPECT_EQ(settings->transport_name, new_settings->transport_name);
534 EXPECT_EQ(settings->transport_setting, new_settings->transport_setting);
535 EXPECT_EQ(1, wrapping_factory.created_transport_count());
536}
537
Anton Sukhanov7940da02018-10-10 10:34:49 -0700538TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
539 FakeMediaTransportFactory fake_media_transport_factory;
540 JsepTransportController::Config config;
541
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800542 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700543 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800544 config.use_media_transport_for_data_channels = true;
545 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700546 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800547 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700548 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800549 description->AddMediaTransportSetting("fake", "fake-remote-settings");
Anton Sukhanov7940da02018-10-10 10:34:49 -0700550 EXPECT_TRUE(transport_controller_
551 ->SetRemoteDescription(SdpType::kOffer, description.get())
552 .ok());
553
554 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
555 transport_controller_->GetMediaTransport(kAudioMid1));
556
557 ASSERT_NE(nullptr, media_transport);
558
559 // After SetRemoteDescription, media transport should be created as callee.
560 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800561 // We do not set pre-shared key on the callee, it comes in media transport
562 // settings.
563 EXPECT_EQ(absl::nullopt, media_transport->settings().pre_shared_key);
564 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700565
566 // Return nullptr for non-existing mids.
567 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800568
569 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
570 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
571 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700572}
573
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800574TEST_F(JsepTransportControllerTest, GetMediaTransportInCalleePassesSdp) {
575 FakeMediaTransportFactory fake_media_transport_factory;
576 JsepTransportController::Config config;
577
578 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
579 config.media_transport_factory = &fake_media_transport_factory;
580 config.use_media_transport_for_data_channels = true;
581 config.use_media_transport_for_media = true;
582 CreateJsepTransportController(config);
583 auto description = CreateSessionDescriptionWithBundleGroup();
584 AddCryptoSettings(description.get());
585 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
586 EXPECT_TRUE(transport_controller_
587 ->SetRemoteDescription(SdpType::kOffer, description.get())
588 .ok());
589
590 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
591 transport_controller_->GetMediaTransport(kAudioMid1));
592
593 ASSERT_NE(nullptr, media_transport);
594
595 EXPECT_EQ("this-is-a-test-setting",
596 media_transport->settings().remote_transport_parameters);
597}
598
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800599// Caller generates the offer if media transport returns empty offer (no
600// parameters).
601TEST_F(JsepTransportControllerTest, MediaTransportGeneratesSessionDescription) {
602 FakeMediaTransportFactory fake_media_transport_factory(
603 /*transport_offer=*/"");
604 JsepTransportController::Config config;
605
606 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
607 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
608 config.media_transport_factory = &fake_media_transport_factory;
609 config.use_media_transport_for_data_channels = true;
610 config.use_media_transport_for_media = true;
611 CreateJsepTransportController(config);
612 auto description = CreateSessionDescriptionWithBundleGroup();
613 AddCryptoSettings(description.get());
614 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
615 transport_controller_->GenerateOrGetLastMediaTransportOffer();
616
617 ASSERT_TRUE(settings.has_value());
618 EXPECT_EQ("fake", settings->transport_name);
619 // Fake media transport returns empty settings (but not nullopt settings!)
620 EXPECT_EQ("", settings->transport_setting);
621}
622
623// Caller generates the offer if media transport returns offer with parameters.
624TEST_F(JsepTransportControllerTest,
625 MediaTransportGeneratesSessionDescriptionWithOfferParams) {
626 FakeMediaTransportFactory fake_media_transport_factory(
627 /*transport_offer=*/"offer-params");
628 JsepTransportController::Config config;
629
630 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
631 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
632 config.media_transport_factory = &fake_media_transport_factory;
633 config.use_media_transport_for_data_channels = true;
634 config.use_media_transport_for_media = true;
635 CreateJsepTransportController(config);
636 auto description = CreateSessionDescriptionWithBundleGroup();
637 AddCryptoSettings(description.get());
638 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
639 transport_controller_->GenerateOrGetLastMediaTransportOffer();
640
641 ASSERT_TRUE(settings.has_value());
642 EXPECT_EQ("fake", settings->transport_name);
643 EXPECT_EQ("offer-params", settings->transport_setting);
644}
645
646// Caller skips the offer if media transport requests it.
647TEST_F(JsepTransportControllerTest,
648 MediaTransportGeneratesSkipsSessionDescription) {
649 FakeMediaTransportFactory fake_media_transport_factory(
650 /*transport_offer=*/absl::nullopt);
651 JsepTransportController::Config config;
652
653 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
654 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
655 config.media_transport_factory = &fake_media_transport_factory;
656 config.use_media_transport_for_data_channels = true;
657 config.use_media_transport_for_media = true;
658 CreateJsepTransportController(config);
659 auto description = CreateSessionDescriptionWithBundleGroup();
660 AddCryptoSettings(description.get());
661 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
662 transport_controller_->GenerateOrGetLastMediaTransportOffer();
663
664 // Fake media transport returns nullopt settings
665 ASSERT_EQ(absl::nullopt, settings);
666}
667
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800668// Caller ignores its own outgoing parameters.
669TEST_F(JsepTransportControllerTest,
670 GetMediaTransportInCallerIgnoresXmtSection) {
671 FakeMediaTransportFactory fake_media_transport_factory;
672 JsepTransportController::Config config;
673
674 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800675 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800676 config.media_transport_factory = &fake_media_transport_factory;
677 config.use_media_transport_for_data_channels = true;
678 config.use_media_transport_for_media = true;
679 CreateJsepTransportController(config);
680 auto description = CreateSessionDescriptionWithBundleGroup();
681 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800682 EXPECT_NE(absl::nullopt,
683 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800684 EXPECT_TRUE(transport_controller_
685 ->SetLocalDescription(SdpType::kOffer, description.get())
686 .ok());
687
688 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
689 transport_controller_->GetMediaTransport(kAudioMid1));
690
691 ASSERT_NE(nullptr, media_transport);
692
693 // Remote parameters are nullopt, because we are the offerer (we don't)
694 // have the remote transport parameters, only ours.
695 EXPECT_EQ(absl::nullopt,
696 media_transport->settings().remote_transport_parameters);
697}
698
699TEST_F(JsepTransportControllerTest,
700 GetMediaTransportInCalleeIgnoresDifferentTransport) {
701 FakeMediaTransportFactory fake_media_transport_factory;
702 JsepTransportController::Config config;
703
704 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800705 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800706 config.media_transport_factory = &fake_media_transport_factory;
707 config.use_media_transport_for_data_channels = true;
708 config.use_media_transport_for_media = true;
709 CreateJsepTransportController(config);
710 auto description = CreateSessionDescriptionWithBundleGroup();
711 AddCryptoSettings(description.get());
712 description->AddMediaTransportSetting("not-a-fake-transport",
713 "this-is-a-test-setting");
714 EXPECT_TRUE(transport_controller_
715 ->SetRemoteDescription(SdpType::kOffer, description.get())
716 .ok());
717
718 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
719 transport_controller_->GetMediaTransport(kAudioMid1));
720
721 ASSERT_NE(nullptr, media_transport);
722
723 EXPECT_EQ(absl::nullopt,
724 media_transport->settings().remote_transport_parameters);
725}
726
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700727TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
728 FakeMediaTransportFactory fake_media_transport_factory;
729 JsepTransportController::Config config;
730
731 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800732 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700733 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800734 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700735 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800736 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700737 EXPECT_TRUE(transport_controller_
738 ->SetRemoteDescription(SdpType::kOffer, description.get())
739 .ok());
740
741 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
742
743 // Even if we set local description with crypto now (after the remote offer
744 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800745 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700746 AddCryptoSettings(description2.get());
747 EXPECT_TRUE(transport_controller_
748 ->SetLocalDescription(SdpType::kAnswer, description2.get())
749 .ok());
750
751 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800752 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
753 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
754 << "Because media transport is NOT used (fallback to RTP), expected "
755 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700756}
757
758TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800759 AfterSettingAnswerTheSameMediaTransportIsReturnedCallee) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700760 FakeMediaTransportFactory fake_media_transport_factory;
761 JsepTransportController::Config config;
762
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800763 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800764 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700765 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800766 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700767 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800768 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700769 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800770 description->AddMediaTransportSetting("fake", "fake-settings");
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700771 EXPECT_TRUE(transport_controller_
772 ->SetRemoteDescription(SdpType::kOffer, description.get())
773 .ok());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700774 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
775 transport_controller_->GetMediaTransport(kAudioMid1));
776 EXPECT_NE(nullptr, media_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800777 EXPECT_FALSE(media_transport->pre_shared_key().has_value())
778 << "On the callee, preshared key is passed through the media-transport "
779 "settings (x-mt)";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700780
781 // Even if we set local description with crypto now (after the remote offer
782 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800783 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700784 AddCryptoSettings(description2.get());
785
786 RTCError result = transport_controller_->SetLocalDescription(
787 SdpType::kAnswer, description2.get());
788 EXPECT_TRUE(result.ok()) << result.message();
789
790 // Media transport did not change.
791 EXPECT_EQ(media_transport,
792 transport_controller_->GetMediaTransport(kAudioMid1));
793}
794
Zhi Huange818b6e2018-02-22 15:26:27 -0800795TEST_F(JsepTransportControllerTest, SetIceConfig) {
796 CreateJsepTransportController(JsepTransportController::Config());
797 auto description = CreateSessionDescriptionWithoutBundle();
798 EXPECT_TRUE(transport_controller_
799 ->SetLocalDescription(SdpType::kOffer, description.get())
800 .ok());
801
802 transport_controller_->SetIceConfig(
803 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
804 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
805 transport_controller_->GetDtlsTransport(kAudioMid1));
806 ASSERT_NE(nullptr, fake_audio_dtls);
807 EXPECT_EQ(kTimeout,
808 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
809 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
810
811 // Test that value stored in controller is applied to new transports.
812 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
813 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
814 nullptr);
815
816 EXPECT_TRUE(transport_controller_
817 ->SetLocalDescription(SdpType::kOffer, description.get())
818 .ok());
819 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
820 transport_controller_->GetDtlsTransport(kAudioMid2));
821 ASSERT_NE(nullptr, fake_audio_dtls);
822 EXPECT_EQ(kTimeout,
823 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
824 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
825}
826
827// Tests the getter and setter of the ICE restart flag.
828TEST_F(JsepTransportControllerTest, NeedIceRestart) {
829 CreateJsepTransportController(JsepTransportController::Config());
830 auto description = CreateSessionDescriptionWithoutBundle();
831 EXPECT_TRUE(transport_controller_
832 ->SetLocalDescription(SdpType::kOffer, description.get())
833 .ok());
834 EXPECT_TRUE(transport_controller_
835 ->SetRemoteDescription(SdpType::kAnswer, description.get())
836 .ok());
837
838 // Initially NeedsIceRestart should return false.
839 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
840 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
841 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
842 // true.
843 transport_controller_->SetNeedsIceRestartFlag();
844 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
845 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
846 // For a nonexistent transport, false should be returned.
847 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
848
849 // Reset the ice_ufrag/ice_pwd for audio.
850 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
851 audio_transport_info->description.ice_ufrag = kIceUfrag2;
852 audio_transport_info->description.ice_pwd = kIcePwd2;
853 EXPECT_TRUE(transport_controller_
854 ->SetLocalDescription(SdpType::kOffer, description.get())
855 .ok());
856 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
857 // return false for audio and true for video.
858 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
859 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
860}
861
862TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
863 CreateJsepTransportController(JsepTransportController::Config());
864 auto description = CreateSessionDescriptionWithBundleGroup();
865 EXPECT_TRUE(transport_controller_
866 ->SetLocalDescription(SdpType::kOffer, description.get())
867 .ok());
868 // After setting the local description, we should be able to start gathering
869 // candidates.
870 transport_controller_->MaybeStartGathering();
871 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
872 EXPECT_EQ(1, gathering_state_signal_count_);
873}
874
875TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
876 CreateJsepTransportController(JsepTransportController::Config());
877 auto description = CreateSessionDescriptionWithoutBundle();
878 transport_controller_->SetLocalDescription(SdpType::kOffer,
879 description.get());
880 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
881 description.get());
882 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
883 transport_controller_->GetDtlsTransport(kAudioMid1));
884 ASSERT_NE(nullptr, fake_audio_dtls);
885 Candidates candidates;
886 candidates.push_back(
887 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
888 EXPECT_TRUE(
889 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
890 EXPECT_EQ(1U,
891 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
892
893 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
894 EXPECT_EQ(0U,
895 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
896}
897
898TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
899 CreateJsepTransportController(JsepTransportController::Config());
900
901 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
902 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
903 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
904 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
905
Karl Wiberg918f50c2018-07-05 11:40:33 +0200906 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800907 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
908 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
909 certificate1);
910
911 // Apply the local certificate.
912 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
913 // Apply the local description.
914 EXPECT_TRUE(transport_controller_
915 ->SetLocalDescription(SdpType::kOffer, description.get())
916 .ok());
917 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
918 EXPECT_TRUE(returned_certificate);
919 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
920 returned_certificate->identity()->certificate().ToPEMString());
921
922 // Should fail if called for a nonexistant transport.
923 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
924
925 // Shouldn't be able to change the identity once set.
926 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
927 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
928 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
929 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
930}
931
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800932TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800933 CreateJsepTransportController(JsepTransportController::Config());
934 auto description = CreateSessionDescriptionWithBundleGroup();
935 EXPECT_TRUE(transport_controller_
936 ->SetLocalDescription(SdpType::kOffer, description.get())
937 .ok());
938 rtc::FakeSSLCertificate fake_certificate("fake_data");
939
940 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
941 transport_controller_->GetDtlsTransport(kAudioMid1));
942 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800943 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
944 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
945 ASSERT_TRUE(returned_cert_chain);
946 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800947 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800948 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800949
950 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800951 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800952}
953
954TEST_F(JsepTransportControllerTest, GetDtlsRole) {
955 CreateJsepTransportController(JsepTransportController::Config());
956 auto offer_certificate =
957 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
958 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
959 auto answer_certificate =
960 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
961 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
962 transport_controller_->SetLocalCertificate(offer_certificate);
963
Karl Wiberg918f50c2018-07-05 11:40:33 +0200964 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800965 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
966 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
967 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200968 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800969 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
970 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
971 answer_certificate);
972
973 EXPECT_TRUE(transport_controller_
974 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
975 .ok());
976
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200977 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800978 transport_controller_->GetDtlsRole(kAudioMid1);
979 // The DTLS role is not decided yet.
980 EXPECT_FALSE(role);
981 EXPECT_TRUE(transport_controller_
982 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
983 .ok());
984 role = transport_controller_->GetDtlsRole(kAudioMid1);
985
986 ASSERT_TRUE(role);
987 EXPECT_EQ(rtc::SSL_CLIENT, *role);
988}
989
990TEST_F(JsepTransportControllerTest, GetStats) {
991 CreateJsepTransportController(JsepTransportController::Config());
992 auto description = CreateSessionDescriptionWithBundleGroup();
993 EXPECT_TRUE(transport_controller_
994 ->SetLocalDescription(SdpType::kOffer, description.get())
995 .ok());
996
997 cricket::TransportStats stats;
998 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
999 EXPECT_EQ(kAudioMid1, stats.transport_name);
1000 EXPECT_EQ(1u, stats.channel_stats.size());
1001 // Return false for non-existing transport.
1002 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
1003}
1004
1005TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
1006 CreateJsepTransportController(JsepTransportController::Config());
1007 auto description = CreateSessionDescriptionWithoutBundle();
1008 EXPECT_TRUE(transport_controller_
1009 ->SetLocalDescription(SdpType::kOffer, description.get())
1010 .ok());
1011
1012 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
1013 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1014 fake_ice->SetCandidatesGatheringComplete();
1015 fake_ice->SetConnectionCount(1);
1016 // The connection stats will be failed if there is no active connection.
1017 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +00001018 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001019 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001020 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1021 ice_connection_state_, kTimeout);
1022 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001023 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1024 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +02001025 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001026}
1027
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001028TEST_F(JsepTransportControllerTest,
1029 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001030 CreateJsepTransportController(JsepTransportController::Config());
1031 auto description = CreateSessionDescriptionWithoutBundle();
1032 EXPECT_TRUE(transport_controller_
1033 ->SetLocalDescription(SdpType::kOffer, description.get())
1034 .ok());
1035
1036 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1037 transport_controller_->GetDtlsTransport(kAudioMid1));
1038 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1039 transport_controller_->GetDtlsTransport(kVideoMid1));
1040
1041 // First, have one transport connect, and another fail, to ensure that
1042 // the first transport connecting didn't trigger a "connected" state signal.
1043 // We should only get a signal when all are connected.
1044 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
1045 fake_audio_dtls->SetWritable(true);
1046 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1047 // Decrease the number of the connection to trigger the signal.
1048 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
1049 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
1050 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1051
Alex Loiko9289eda2018-11-23 16:18:59 +00001052 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001053 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001054 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1055 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001056 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001057 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1058 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001059 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001060
Jonas Olsson635474e2018-10-18 15:58:17 +02001061 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1062 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001063 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
1064 // the transport state to be STATE_CONNECTING.
1065 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
1066 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001067 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001068 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001069 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
1070 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001071 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001072 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1073 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001074 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001075}
1076
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001077TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001078 SignalConnectionStateConnectedWithMediaTransportAndNoDtlsCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001079 FakeMediaTransportFactory fake_media_transport_factory;
1080 JsepTransportController::Config config;
1081 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001082 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1083 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001084 config.use_media_transport_for_data_channels = true;
1085 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001086 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001087
1088 // Media Transport is only used with bundle.
1089 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001090 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001091 EXPECT_NE(absl::nullopt,
1092 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001093 EXPECT_TRUE(transport_controller_
1094 ->SetLocalDescription(SdpType::kOffer, description.get())
1095 .ok());
1096
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001097 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1098 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1099 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1100 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001101 EXPECT_EQ(fake_audio_ice, fake_video_ice);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001102 fake_audio_ice->SetConnectionCount(2);
1103 fake_audio_ice->SetConnectionCount(1);
1104 fake_video_ice->SetConnectionCount(2);
1105 fake_video_ice->SetConnectionCount(1);
1106 fake_audio_ice->SetWritable(true);
1107 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001108
1109 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001110 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1111 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001112
1113 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1114 transport_controller_->GetMediaTransport(kAudioMid1));
1115
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001116 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001117
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001118 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001119 // Only one media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001120 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001121}
1122
1123TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001124 SignalConnectionStateConnectedWithMediaTransportCaller) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001125 FakeMediaTransportFactory fake_media_transport_factory;
1126 JsepTransportController::Config config;
1127 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001128 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1129 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001130 config.use_media_transport_for_media = true;
1131 CreateJsepTransportController(config);
1132
1133 // Media Transport is only used with bundle.
1134 auto description = CreateSessionDescriptionWithBundleGroup();
1135 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001136 EXPECT_NE(absl::nullopt,
1137 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001138 EXPECT_TRUE(transport_controller_
1139 ->SetLocalDescription(SdpType::kOffer, description.get())
1140 .ok());
1141
1142 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1143 transport_controller_->GetDtlsTransport(kAudioMid1));
1144 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1145 transport_controller_->GetDtlsTransport(kVideoMid1));
1146
1147 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1148 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1149 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1150 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1151 fake_audio_ice->SetConnectionCount(2);
1152 fake_audio_ice->SetConnectionCount(1);
1153 fake_video_ice->SetConnectionCount(2);
1154 fake_video_ice->SetConnectionCount(1);
1155 fake_audio_ice->SetWritable(true);
1156 fake_video_ice->SetWritable(true);
1157 fake_audio_dtls->SetWritable(true);
1158 fake_video_dtls->SetWritable(true);
1159
1160 // Still not connected, because we are waiting for media transport.
1161 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1162 kTimeout);
1163
1164 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1165 transport_controller_->GetMediaTransport(kAudioMid1));
1166
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001167 ASSERT_NE(nullptr, media_transport);
1168
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001169 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1170 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1171 kTimeout);
1172
1173 // Still waiting for the second media transport.
1174 media_transport = static_cast<FakeMediaTransport*>(
1175 transport_controller_->GetMediaTransport(kVideoMid1));
1176 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1177
1178 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
1179}
1180
1181TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001182 SignalConnectionStateFailedWhenMediaTransportClosedCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001183 FakeMediaTransportFactory fake_media_transport_factory;
1184 JsepTransportController::Config config;
1185 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001186 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1187 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001188 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001189 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001190 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001191 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001192 EXPECT_NE(absl::nullopt,
1193 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001194 EXPECT_TRUE(transport_controller_
1195 ->SetLocalDescription(SdpType::kOffer, description.get())
1196 .ok());
1197
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001198 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1199 transport_controller_->GetDtlsTransport(kAudioMid1));
1200 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1201 transport_controller_->GetDtlsTransport(kVideoMid1));
1202
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001203 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1204 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1205 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1206 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1207 fake_audio_ice->SetWritable(true);
1208 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001209 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001210 fake_audio_ice->SetConnectionCount(2);
1211 fake_audio_ice->SetConnectionCount(1);
1212 fake_video_ice->SetConnectionCount(2);
1213 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001214
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001215 fake_audio_dtls->SetWritable(true);
1216 fake_video_dtls->SetWritable(true);
1217
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001218 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1219 transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001220 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001221 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1222
1223 media_transport = static_cast<FakeMediaTransport*>(
1224 transport_controller_->GetMediaTransport(kVideoMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001225 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001226
1227 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1228
Alex Loiko9289eda2018-11-23 16:18:59 +00001229 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001230
1231 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +00001232 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001233}
1234
Zhi Huange818b6e2018-02-22 15:26:27 -08001235TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1236 CreateJsepTransportController(JsepTransportController::Config());
1237 auto description = CreateSessionDescriptionWithoutBundle();
1238 EXPECT_TRUE(transport_controller_
1239 ->SetLocalDescription(SdpType::kOffer, description.get())
1240 .ok());
1241
1242 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1243 transport_controller_->GetDtlsTransport(kAudioMid1));
1244 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1245 transport_controller_->GetDtlsTransport(kVideoMid1));
1246
1247 // First, have one transport connect, and another fail, to ensure that
1248 // the first transport connecting didn't trigger a "connected" state signal.
1249 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001250 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1251 IceTransportState::kCompleted,
1252 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001253 fake_audio_dtls->SetWritable(true);
1254 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001255
1256 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1257 ice_connection_state_, kTimeout);
1258 EXPECT_EQ(1, ice_connection_state_signal_count_);
1259 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1260 combined_connection_state_, kTimeout);
1261 EXPECT_EQ(1, combined_connection_state_signal_count_);
1262
1263 fake_video_dtls->fake_ice_transport()->SetTransportState(
1264 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001265 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1266
Alex Loiko9289eda2018-11-23 16:18:59 +00001267 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001268 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001269 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1270 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001271 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001272 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1273 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001274 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001275
Jonas Olsson635474e2018-10-18 15:58:17 +02001276 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1277 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001278 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1279 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001280 fake_video_dtls->fake_ice_transport()->SetTransportState(
1281 IceTransportState::kCompleted,
1282 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001283 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001284 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +01001285 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001286 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1287 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001288 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001289 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1290 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001291 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001292}
1293
1294TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1295 CreateJsepTransportController(JsepTransportController::Config());
1296 auto description = CreateSessionDescriptionWithoutBundle();
1297 EXPECT_TRUE(transport_controller_
1298 ->SetLocalDescription(SdpType::kOffer, description.get())
1299 .ok());
1300
1301 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1302 transport_controller_->GetDtlsTransport(kAudioMid1));
1303 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1304 // Should be in the gathering state as soon as any transport starts gathering.
1305 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1306 EXPECT_EQ(1, gathering_state_signal_count_);
1307}
1308
1309TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1310 CreateJsepTransportController(JsepTransportController::Config());
1311 auto description = CreateSessionDescriptionWithoutBundle();
1312 EXPECT_TRUE(transport_controller_
1313 ->SetLocalDescription(SdpType::kOffer, description.get())
1314 .ok());
1315
1316 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1317 transport_controller_->GetDtlsTransport(kAudioMid1));
1318 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1319 transport_controller_->GetDtlsTransport(kVideoMid1));
1320
1321 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1322 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1323 EXPECT_EQ(1, gathering_state_signal_count_);
1324
1325 // Have one transport finish gathering, to make sure gathering
1326 // completion wasn't signalled if only one transport finished gathering.
1327 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1328 EXPECT_EQ(1, gathering_state_signal_count_);
1329
1330 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1331 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1332 EXPECT_EQ(1, gathering_state_signal_count_);
1333
1334 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1335 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1336 EXPECT_EQ(2, gathering_state_signal_count_);
1337}
1338
1339// Test that when the last transport that hasn't finished connecting and/or
1340// gathering is destroyed, the aggregate state jumps to "completed". This can
1341// happen if, for example, we have an audio and video transport, the audio
1342// transport completes, then we start bundling video on the audio transport.
1343TEST_F(JsepTransportControllerTest,
1344 SignalingWhenLastIncompleteTransportDestroyed) {
1345 CreateJsepTransportController(JsepTransportController::Config());
1346 auto description = CreateSessionDescriptionWithBundleGroup();
1347 EXPECT_TRUE(transport_controller_
1348 ->SetLocalDescription(SdpType::kOffer, description.get())
1349 .ok());
1350
1351 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1352 transport_controller_->GetDtlsTransport(kAudioMid1));
1353 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1354 transport_controller_->GetDtlsTransport(kVideoMid1));
1355 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1356
1357 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1358 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1359 EXPECT_EQ(1, gathering_state_signal_count_);
1360
1361 // Let the audio transport complete.
1362 fake_audio_dtls->SetWritable(true);
1363 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1364 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001365 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001366 EXPECT_EQ(1, gathering_state_signal_count_);
1367
1368 // Set the remote description and enable the bundle.
1369 EXPECT_TRUE(transport_controller_
1370 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1371 .ok());
1372 // The BUNDLE should be enabled, the incomplete video transport should be
1373 // deleted and the states shoud be updated.
1374 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1375 transport_controller_->GetDtlsTransport(kVideoMid1));
1376 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001377 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1378 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1379 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001380 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1381 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001382 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1383 EXPECT_EQ(2, gathering_state_signal_count_);
1384}
1385
1386TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1387 CreateJsepTransportController(JsepTransportController::Config());
1388 auto description = CreateSessionDescriptionWithBundleGroup();
1389 EXPECT_TRUE(transport_controller_
1390 ->SetLocalDescription(SdpType::kOffer, description.get())
1391 .ok());
1392 transport_controller_->MaybeStartGathering();
1393
1394 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1395 transport_controller_->GetDtlsTransport(kAudioMid1));
1396 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1397 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1398 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1399 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1400}
1401
1402TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1403 network_thread_ = rtc::Thread::CreateWithSocketServer();
1404 network_thread_->Start();
1405 CreateJsepTransportController(JsepTransportController::Config(),
1406 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 14:57:52 +01001407 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 15:26:27 -08001408 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1409
1410 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001411 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001412 EXPECT_EQ(2, connection_state_signal_count_);
1413
1414 // new --> gathering --> complete
1415 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1416 EXPECT_EQ(2, gathering_state_signal_count_);
1417
1418 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1419 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1420 EXPECT_EQ(2, candidates_signal_count_);
1421
1422 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1423}
1424
1425// Older versions of Chrome expect the ICE role to be re-determined when an
1426// ICE restart occurs, and also don't perform conflict resolution correctly,
1427// so for now we can't safely stop doing this.
1428// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1429// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1430// enough population.
1431TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1432 CreateJsepTransportController(JsepTransportController::Config());
1433 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001434 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001435 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1436 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1437 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001438 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001439 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1440 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1441 nullptr);
1442
1443 EXPECT_TRUE(transport_controller_
1444 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1445 .ok());
1446 EXPECT_TRUE(transport_controller_
1447 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1448 .ok());
1449
1450 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1451 transport_controller_->GetDtlsTransport(kAudioMid1));
1452 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1453 fake_dtls->fake_ice_transport()->GetIceRole());
1454
1455 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001456 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001457 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1458 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1459 nullptr);
1460 EXPECT_TRUE(
1461 transport_controller_
1462 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1463 .ok());
1464 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1465 fake_dtls->fake_ice_transport()->GetIceRole());
1466}
1467
1468// Test that if the TransportController was created with the
1469// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1470// redetermined on an ICE restart.
1471TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1472 JsepTransportController::Config config;
1473 config.redetermine_role_on_ice_restart = false;
1474
1475 CreateJsepTransportController(config);
1476 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001477 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001478 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1479 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1480 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001481 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001482 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1483 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1484 nullptr);
1485
1486 EXPECT_TRUE(transport_controller_
1487 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1488 .ok());
1489 EXPECT_TRUE(transport_controller_
1490 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1491 .ok());
1492
1493 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1494 transport_controller_->GetDtlsTransport(kAudioMid1));
1495 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1496 fake_dtls->fake_ice_transport()->GetIceRole());
1497
1498 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001499 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001500 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1501 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1502 nullptr);
1503 EXPECT_TRUE(
1504 transport_controller_
1505 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1506 .ok());
1507 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1508 fake_dtls->fake_ice_transport()->GetIceRole());
1509}
1510
1511// Tests ICE-Lite mode in remote answer.
1512TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1513 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001514 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001515 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1516 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1517 nullptr);
1518 EXPECT_TRUE(transport_controller_
1519 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1520 .ok());
1521 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1522 transport_controller_->GetDtlsTransport(kAudioMid1));
1523 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1524 fake_dtls->fake_ice_transport()->GetIceRole());
1525 EXPECT_EQ(cricket::ICEMODE_FULL,
1526 fake_dtls->fake_ice_transport()->remote_ice_mode());
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, kIceUfrag2, kIcePwd2,
1530 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1531 nullptr);
1532 EXPECT_TRUE(transport_controller_
1533 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1534 .ok());
1535 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1536 fake_dtls->fake_ice_transport()->GetIceRole());
1537 EXPECT_EQ(cricket::ICEMODE_LITE,
1538 fake_dtls->fake_ice_transport()->remote_ice_mode());
1539}
1540
1541// Tests that the ICE role remains "controlling" if a subsequent offer that
1542// does an ICE restart is received from an ICE lite endpoint. Regression test
1543// for: https://crbug.com/710760
1544TEST_F(JsepTransportControllerTest,
1545 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1546 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001547 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001548 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1549 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1550 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001551 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001552 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1553 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1554 nullptr);
1555 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1556 // local side is the controlling.
1557 EXPECT_TRUE(transport_controller_
1558 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1559 .ok());
1560 EXPECT_TRUE(transport_controller_
1561 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1562 .ok());
1563 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1564 transport_controller_->GetDtlsTransport(kAudioMid1));
1565 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1566 fake_dtls->fake_ice_transport()->GetIceRole());
1567
1568 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001569 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001570 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1571 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1572 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001573 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001574 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1575 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1576 nullptr);
1577 EXPECT_TRUE(transport_controller_
1578 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1579 .ok());
1580 EXPECT_TRUE(transport_controller_
1581 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1582 .ok());
1583 fake_dtls = static_cast<FakeDtlsTransport*>(
1584 transport_controller_->GetDtlsTransport(kAudioMid1));
1585 // The local side is still the controlling role since the remote side is using
1586 // ICE-Lite.
1587 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1588 fake_dtls->fake_ice_transport()->GetIceRole());
1589}
1590
1591// Tests that the SDP has more than one audio/video m= sections.
1592TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1593 CreateJsepTransportController(JsepTransportController::Config());
1594 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1595 bundle_group.AddContentName(kAudioMid1);
1596 bundle_group.AddContentName(kAudioMid2);
1597 bundle_group.AddContentName(kVideoMid1);
1598 bundle_group.AddContentName(kDataMid1);
1599
Karl Wiberg918f50c2018-07-05 11:40:33 +02001600 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001601 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1602 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1603 nullptr);
1604 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1605 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1606 nullptr);
1607 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1608 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1609 nullptr);
1610 AddDataSection(local_offer.get(), kDataMid1,
1611 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1612 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1613 nullptr);
1614
Karl Wiberg918f50c2018-07-05 11:40:33 +02001615 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001616 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1617 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1618 nullptr);
1619 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1620 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1621 nullptr);
1622 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1623 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1624 nullptr);
1625 AddDataSection(remote_answer.get(), kDataMid1,
1626 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1627 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1628 nullptr);
1629
1630 local_offer->AddGroup(bundle_group);
1631 remote_answer->AddGroup(bundle_group);
1632
1633 EXPECT_TRUE(transport_controller_
1634 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1635 .ok());
1636 EXPECT_TRUE(transport_controller_
1637 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1638 .ok());
1639 // Verify that all the sections are bundled on kAudio1.
1640 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1641 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1642 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1643 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1644 EXPECT_EQ(transport1, transport2);
1645 EXPECT_EQ(transport1, transport3);
1646 EXPECT_EQ(transport1, transport4);
1647
Harald Alvestrandad88c882018-11-28 16:47:46 +01001648 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1649 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1650
Zhi Huange818b6e2018-02-22 15:26:27 -08001651 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1652 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1653 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1654 EXPECT_EQ(transport1, it->second);
1655 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1656 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1657 EXPECT_EQ(transport1, it->second);
1658 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1659 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1660 EXPECT_EQ(transport1, it->second);
1661 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1662 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1663 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
Zhi Huange818b6e2018-02-22 15:26:27 -08001664}
1665
1666// Tests that only a subset of all the m= sections are bundled.
1667TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1668 CreateJsepTransportController(JsepTransportController::Config());
1669 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1670 bundle_group.AddContentName(kAudioMid1);
1671 bundle_group.AddContentName(kVideoMid1);
1672
Karl Wiberg918f50c2018-07-05 11:40:33 +02001673 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001674 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1675 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1676 nullptr);
1677 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1678 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1679 nullptr);
1680 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1681 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1682 nullptr);
1683
Karl Wiberg918f50c2018-07-05 11:40:33 +02001684 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001685 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1686 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1687 nullptr);
1688 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1689 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1690 nullptr);
1691 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1692 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1693 nullptr);
1694
1695 local_offer->AddGroup(bundle_group);
1696 remote_answer->AddGroup(bundle_group);
1697 EXPECT_TRUE(transport_controller_
1698 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1699 .ok());
1700 EXPECT_TRUE(transport_controller_
1701 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1702 .ok());
1703
1704 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1705 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1706 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1707 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1708 EXPECT_NE(transport1, transport2);
1709 EXPECT_EQ(transport1, transport3);
1710
1711 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1712 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1713 EXPECT_EQ(transport1, it->second);
1714 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001715 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001716}
1717
1718// Tests that the initial offer/answer only have data section and audio/video
1719// sections are added in the subsequent offer.
1720TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1721 CreateJsepTransportController(JsepTransportController::Config());
1722 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1723 bundle_group.AddContentName(kDataMid1);
1724
Karl Wiberg918f50c2018-07-05 11:40:33 +02001725 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001726 AddDataSection(local_offer.get(), kDataMid1,
1727 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1728 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1729 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001730 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001731 AddDataSection(remote_answer.get(), kDataMid1,
1732 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1733 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1734 nullptr);
1735 local_offer->AddGroup(bundle_group);
1736 remote_answer->AddGroup(bundle_group);
1737
1738 EXPECT_TRUE(transport_controller_
1739 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1740 .ok());
1741 EXPECT_TRUE(transport_controller_
1742 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1743 .ok());
1744 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1745
1746 // Add audio/video sections in subsequent offer.
1747 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1748 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1749 nullptr);
1750 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1751 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1752 nullptr);
1753 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1754 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1755 nullptr);
1756 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1757 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1758 nullptr);
1759
1760 // Reset the bundle group and do another offer/answer exchange.
1761 bundle_group.AddContentName(kAudioMid1);
1762 bundle_group.AddContentName(kVideoMid1);
1763 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1764 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1765 local_offer->AddGroup(bundle_group);
1766 remote_answer->AddGroup(bundle_group);
1767
1768 EXPECT_TRUE(transport_controller_
1769 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1770 .ok());
1771 EXPECT_TRUE(transport_controller_
1772 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1773 .ok());
1774
1775 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1776 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1777 EXPECT_EQ(data_transport, audio_transport);
1778 EXPECT_EQ(data_transport, video_transport);
1779}
1780
1781TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1782 CreateJsepTransportController(JsepTransportController::Config());
1783 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1784 bundle_group.AddContentName(kAudioMid1);
1785 bundle_group.AddContentName(kVideoMid1);
1786 bundle_group.AddContentName(kDataMid1);
1787
Karl Wiberg918f50c2018-07-05 11:40:33 +02001788 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001789 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1790 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1791 nullptr);
1792 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1793 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1794 nullptr);
1795 AddDataSection(local_offer.get(), kDataMid1,
1796 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1797 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1798 nullptr);
1799
Karl Wiberg918f50c2018-07-05 11:40:33 +02001800 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001801 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1802 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1803 nullptr);
1804 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1805 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1806 nullptr);
1807 AddDataSection(remote_answer.get(), kDataMid1,
1808 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1809 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1810 nullptr);
1811 // Reject video and data section.
1812 remote_answer->contents()[1].rejected = true;
1813 remote_answer->contents()[2].rejected = true;
1814
1815 local_offer->AddGroup(bundle_group);
1816 remote_answer->AddGroup(bundle_group);
1817
1818 EXPECT_TRUE(transport_controller_
1819 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1820 .ok());
1821 EXPECT_TRUE(transport_controller_
1822 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1823 .ok());
1824
1825 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1826 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1827 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1828 // Verify the signals are fired correctly.
1829 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1830 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1831 EXPECT_EQ(nullptr, it->second);
1832 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1833 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1834 EXPECT_EQ(nullptr, it2->second);
1835}
1836
1837// Tests that changing the bundled MID in subsequent offer/answer exchange is
1838// not supported.
1839// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1840// fixed
1841TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1842 CreateJsepTransportController(JsepTransportController::Config());
1843 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1844 bundle_group.AddContentName(kAudioMid1);
1845 bundle_group.AddContentName(kVideoMid1);
1846
Karl Wiberg918f50c2018-07-05 11:40:33 +02001847 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001848 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1849 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1850 nullptr);
1851 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1852 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1853 nullptr);
1854
Karl Wiberg918f50c2018-07-05 11:40:33 +02001855 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001856 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1857 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1858 nullptr);
1859 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1860 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1861 nullptr);
1862
1863 local_offer->AddGroup(bundle_group);
1864 remote_answer->AddGroup(bundle_group);
1865 EXPECT_TRUE(transport_controller_
1866 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1867 .ok());
1868 EXPECT_TRUE(transport_controller_
1869 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1870 .ok());
1871 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1872 transport_controller_->GetRtpTransport(kVideoMid1));
1873
1874 // Reorder the bundle group.
1875 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1876 bundle_group.AddContentName(kAudioMid1);
1877 // The answerer uses the new bundle group and now the bundle mid is changed to
1878 // |kVideo1|.
1879 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1880 remote_answer->AddGroup(bundle_group);
1881 EXPECT_TRUE(transport_controller_
1882 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1883 .ok());
1884 EXPECT_FALSE(transport_controller_
1885 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1886 .ok());
1887}
Zhi Huange830e682018-03-30 10:48:35 -07001888// Test that rejecting only the first m= section of a BUNDLE group is treated as
1889// an error, but rejecting all of them works as expected.
1890TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1891 CreateJsepTransportController(JsepTransportController::Config());
1892 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1893 bundle_group.AddContentName(kAudioMid1);
1894 bundle_group.AddContentName(kVideoMid1);
1895 bundle_group.AddContentName(kDataMid1);
1896
Karl Wiberg918f50c2018-07-05 11:40:33 +02001897 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001898 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1899 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1900 nullptr);
1901 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1902 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1903 nullptr);
1904 AddDataSection(local_offer.get(), kDataMid1,
1905 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1906 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1907 nullptr);
1908
Karl Wiberg918f50c2018-07-05 11:40:33 +02001909 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001910 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1911 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1912 nullptr);
1913 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1914 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1915 nullptr);
1916 AddDataSection(remote_answer.get(), kDataMid1,
1917 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1918 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1919 nullptr);
1920 // Reject audio content in answer.
1921 remote_answer->contents()[0].rejected = true;
1922
1923 local_offer->AddGroup(bundle_group);
1924 remote_answer->AddGroup(bundle_group);
1925
1926 EXPECT_TRUE(transport_controller_
1927 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1928 .ok());
1929 EXPECT_FALSE(transport_controller_
1930 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1931 .ok());
1932
1933 // Reject all the contents.
1934 remote_answer->contents()[1].rejected = true;
1935 remote_answer->contents()[2].rejected = true;
1936 EXPECT_TRUE(transport_controller_
1937 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1938 .ok());
1939 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1940 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1941 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1942}
1943
1944// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1945// is used.
1946TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1947 JsepTransportController::Config config;
1948 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1949 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001950 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001951 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1952 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1953 nullptr);
1954
1955 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1956 // Applying a non-RTCP-mux offer is expected to fail.
1957 EXPECT_FALSE(transport_controller_
1958 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1959 .ok());
1960}
1961
1962// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1963// is used.
1964TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1965 JsepTransportController::Config config;
1966 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1967 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001968 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001969 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1970 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1971 nullptr);
1972 EXPECT_TRUE(transport_controller_
1973 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1974 .ok());
1975
Karl Wiberg918f50c2018-07-05 11:40:33 +02001976 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001977 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1978 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1979 nullptr);
1980 // Applying a non-RTCP-mux answer is expected to fail.
1981 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1982 EXPECT_FALSE(transport_controller_
1983 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1984 .ok());
1985}
Zhi Huange818b6e2018-02-22 15:26:27 -08001986
Zhi Huangd2248f82018-04-10 14:41:03 -07001987// This tests that the BUNDLE group in answer should be a subset of the offered
1988// group.
1989TEST_F(JsepTransportControllerTest,
1990 AddContentToBundleGroupInAnswerNotSupported) {
1991 CreateJsepTransportController(JsepTransportController::Config());
1992 auto local_offer = CreateSessionDescriptionWithoutBundle();
1993 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1994
1995 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1996 offer_bundle_group.AddContentName(kAudioMid1);
1997 local_offer->AddGroup(offer_bundle_group);
1998
1999 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2000 answer_bundle_group.AddContentName(kAudioMid1);
2001 answer_bundle_group.AddContentName(kVideoMid1);
2002 remote_answer->AddGroup(answer_bundle_group);
2003 EXPECT_TRUE(transport_controller_
2004 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2005 .ok());
2006 EXPECT_FALSE(transport_controller_
2007 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2008 .ok());
2009}
2010
2011// This tests that the BUNDLE group with non-existing MID should be rejectd.
2012TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
2013 CreateJsepTransportController(JsepTransportController::Config());
2014 auto local_offer = CreateSessionDescriptionWithoutBundle();
2015 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2016
2017 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2018 // The BUNDLE group is invalid because there is no data section in the
2019 // description.
2020 invalid_bundle_group.AddContentName(kDataMid1);
2021 local_offer->AddGroup(invalid_bundle_group);
2022 remote_answer->AddGroup(invalid_bundle_group);
2023
2024 EXPECT_FALSE(transport_controller_
2025 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2026 .ok());
2027 EXPECT_FALSE(transport_controller_
2028 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2029 .ok());
2030}
2031
2032// This tests that an answer shouldn't be able to remove an m= section from an
2033// established group without rejecting it.
2034TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
2035 CreateJsepTransportController(JsepTransportController::Config());
2036
2037 auto local_offer = CreateSessionDescriptionWithBundleGroup();
2038 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
2039 EXPECT_TRUE(transport_controller_
2040 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2041 .ok());
2042 EXPECT_TRUE(transport_controller_
2043 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2044 .ok());
2045
2046 // Do an re-offer/answer.
2047 EXPECT_TRUE(transport_controller_
2048 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2049 .ok());
2050 auto new_answer = CreateSessionDescriptionWithoutBundle();
2051 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2052 // The answer removes video from the BUNDLE group without rejecting it is
2053 // invalid.
2054 new_bundle_group.AddContentName(kAudioMid1);
2055 new_answer->AddGroup(new_bundle_group);
2056
2057 // Applying invalid answer is expected to fail.
2058 EXPECT_FALSE(transport_controller_
2059 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2060 .ok());
2061
2062 // Rejected the video content.
2063 auto video_content = new_answer->GetContentByName(kVideoMid1);
2064 ASSERT_TRUE(video_content);
2065 video_content->rejected = true;
2066 EXPECT_TRUE(transport_controller_
2067 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2068 .ok());
2069}
2070
Steve Anton2bed3972019-01-04 17:04:30 -08002071// Test that the JsepTransportController can process a new local and remote
2072// description that changes the tagged BUNDLE group with the max-bundle policy
2073// specified.
2074// This is a regression test for bugs.webrtc.org/9954
2075TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
2076 CreateJsepTransportController(JsepTransportController::Config());
2077
2078 auto local_offer = absl::make_unique<cricket::SessionDescription>();
2079 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2080 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2081 nullptr);
2082 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
2083 bundle_group.AddContentName(kAudioMid1);
2084 local_offer->AddGroup(bundle_group);
2085 EXPECT_TRUE(transport_controller_
2086 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2087 .ok());
2088
2089 std::unique_ptr<cricket::SessionDescription> remote_answer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002090 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002091 EXPECT_TRUE(transport_controller_
2092 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2093 .ok());
2094
2095 std::unique_ptr<cricket::SessionDescription> local_reoffer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002096 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002097 local_reoffer->contents()[0].rejected = true;
2098 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
2099 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2100 nullptr);
2101 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
2102 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2103 new_bundle_group.AddContentName(kVideoMid1);
2104 local_reoffer->AddGroup(new_bundle_group);
2105
2106 EXPECT_TRUE(transport_controller_
2107 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
2108 .ok());
2109
2110 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002111 local_reoffer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002112 EXPECT_TRUE(
2113 transport_controller_
2114 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
2115 .ok());
2116}
2117
Zhi Huange818b6e2018-02-22 15:26:27 -08002118} // namespace webrtc