blob: b18f85a5ba1c6d3c4d51d049bd4535c138874ed1 [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(
72 std::unique_ptr<cricket::IceTransportInternal> ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070073 const webrtc::CryptoOptions& crypto_options) override {
Zhi Huange818b6e2018-02-22 15:26:27 -080074 std::unique_ptr<cricket::FakeIceTransport> fake_ice(
75 static_cast<cricket::FakeIceTransport*>(ice.release()));
Karl Wiberg918f50c2018-07-05 11:40:33 +020076 return absl::make_unique<FakeDtlsTransport>(std::move(fake_ice));
Zhi Huange818b6e2018-02-22 15:26:27 -080077 }
78};
79
Zhi Huang365381f2018-04-13 16:44:34 -070080class JsepTransportControllerTest : public JsepTransportController::Observer,
Mirko Bonadei6a489f22019-04-09 15:11:12 +020081 public ::testing::Test,
Zhi Huange818b6e2018-02-22 15:26:27 -080082 public sigslot::has_slots<> {
83 public:
84 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Karl Wiberg918f50c2018-07-05 11:40:33 +020085 fake_transport_factory_ = absl::make_unique<FakeTransportFactory>();
Zhi Huange818b6e2018-02-22 15:26:27 -080086 }
87
88 void CreateJsepTransportController(
89 JsepTransportController::Config config,
90 rtc::Thread* signaling_thread = rtc::Thread::Current(),
91 rtc::Thread* network_thread = rtc::Thread::Current(),
92 cricket::PortAllocator* port_allocator = nullptr) {
Zhi Huang365381f2018-04-13 16:44:34 -070093 config.transport_observer = this;
Zhi Huange818b6e2018-02-22 15:26:27 -080094 // The tests only works with |fake_transport_factory|;
95 config.external_transport_factory = fake_transport_factory_.get();
Zach Steine20867f2018-08-02 13:20:15 -070096 // TODO(zstein): Provide an AsyncResolverFactory once it is required.
Karl Wiberg918f50c2018-07-05 11:40:33 +020097 transport_controller_ = absl::make_unique<JsepTransportController>(
Zach Steine20867f2018-08-02 13:20:15 -070098 signaling_thread, network_thread, port_allocator, nullptr, config);
Zhi Huange818b6e2018-02-22 15:26:27 -080099 ConnectTransportControllerSignals();
100 }
101
102 void ConnectTransportControllerSignals() {
103 transport_controller_->SignalIceConnectionState.connect(
104 this, &JsepTransportControllerTest::OnConnectionState);
Alex Loiko9289eda2018-11-23 16:18:59 +0000105 transport_controller_->SignalStandardizedIceConnectionState.connect(
106 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200107 transport_controller_->SignalConnectionState.connect(
108 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800109 transport_controller_->SignalIceGatheringState.connect(
110 this, &JsepTransportControllerTest::OnGatheringState);
111 transport_controller_->SignalIceCandidatesGathered.connect(
112 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800113 }
114
115 std::unique_ptr<cricket::SessionDescription>
116 CreateSessionDescriptionWithoutBundle() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200117 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800118 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
119 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
120 nullptr);
121 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
122 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
123 nullptr);
124 return description;
125 }
126
127 std::unique_ptr<cricket::SessionDescription>
128 CreateSessionDescriptionWithBundleGroup() {
129 auto description = CreateSessionDescriptionWithoutBundle();
130 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
131 bundle_group.AddContentName(kAudioMid1);
132 bundle_group.AddContentName(kVideoMid1);
133 description->AddGroup(bundle_group);
134
135 return description;
136 }
137
138 void AddAudioSection(cricket::SessionDescription* description,
139 const std::string& mid,
140 const std::string& ufrag,
141 const std::string& pwd,
142 cricket::IceMode ice_mode,
143 cricket::ConnectionRole conn_role,
144 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
145 std::unique_ptr<cricket::AudioContentDescription> audio(
146 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700147 // Set RTCP-mux to be true because the default policy is "mux required".
148 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800149 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
150 /*rejected=*/false, audio.release());
151 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
152 }
153
154 void AddVideoSection(cricket::SessionDescription* description,
155 const std::string& mid,
156 const std::string& ufrag,
157 const std::string& pwd,
158 cricket::IceMode ice_mode,
159 cricket::ConnectionRole conn_role,
160 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
161 std::unique_ptr<cricket::VideoContentDescription> video(
162 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700163 // Set RTCP-mux to be true because the default policy is "mux required".
164 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800165 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
166 /*rejected=*/false, video.release());
167 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
168 }
169
170 void AddDataSection(cricket::SessionDescription* description,
171 const std::string& mid,
172 cricket::MediaProtocolType protocol_type,
173 const std::string& ufrag,
174 const std::string& pwd,
175 cricket::IceMode ice_mode,
176 cricket::ConnectionRole conn_role,
177 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
178 std::unique_ptr<cricket::DataContentDescription> data(
179 new cricket::DataContentDescription());
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*>(
444 transport_controller_->GetMediaTransport(kAudioMid1));
445
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.
453 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
454
455 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
456 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
457 << "Media transport for media was not enabled, and so DTLS transport "
458 "should be created.";
459}
460
Anton Sukhanov7940da02018-10-10 10:34:49 -0700461TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
462 FakeMediaTransportFactory fake_media_transport_factory;
463 JsepTransportController::Config config;
464
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800465 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800466 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700467 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800468 config.use_media_transport_for_data_channels = true;
469 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700470 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800471 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700472 AddCryptoSettings(description.get());
473
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800474 EXPECT_NE(absl::nullopt,
475 transport_controller_->GenerateOrGetLastMediaTransportOffer());
476
Anton Sukhanov7940da02018-10-10 10:34:49 -0700477 EXPECT_TRUE(transport_controller_
478 ->SetLocalDescription(SdpType::kOffer, description.get())
479 .ok());
480
481 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
482 transport_controller_->GetMediaTransport(kAudioMid1));
483
484 ASSERT_NE(nullptr, media_transport);
485
486 // After SetLocalDescription, media transport should be created as caller.
487 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800488 // We set the pre-shared key on the caller.
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700489 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800490 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700491
492 // Return nullptr for non-existing mids.
493 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800494
495 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
496 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
497 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700498}
499
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800500TEST_F(JsepTransportControllerTest,
501 GetMediaTransportOfferInTheConfigOnSubsequentCalls) {
502 FakeMediaTransportFactory fake_media_transport_factory;
503 WrapperMediaTransportFactory wrapping_factory(&fake_media_transport_factory);
504 JsepTransportController::Config config;
505
506 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
507 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
508 config.media_transport_factory = &wrapping_factory;
509 config.use_media_transport_for_data_channels = true;
510 config.use_media_transport_for_media = true;
511 CreateJsepTransportController(config);
512 auto description = CreateSessionDescriptionWithBundleGroup();
513 AddCryptoSettings(description.get());
514
515 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
516 transport_controller_->GenerateOrGetLastMediaTransportOffer();
517 ASSERT_NE(absl::nullopt, settings);
518
519 EXPECT_TRUE(transport_controller_
520 ->SetLocalDescription(SdpType::kOffer, description.get())
521 .ok());
522
523 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
524 transport_controller_->GetMediaTransport(kAudioMid1));
525
526 ASSERT_NE(nullptr, media_transport);
527
528 absl::optional<cricket::SessionDescription::MediaTransportSetting>
529 new_settings =
530 transport_controller_->GenerateOrGetLastMediaTransportOffer();
531 ASSERT_NE(absl::nullopt, new_settings);
532 EXPECT_EQ(settings->transport_name, new_settings->transport_name);
533 EXPECT_EQ(settings->transport_setting, new_settings->transport_setting);
534 EXPECT_EQ(1, wrapping_factory.created_transport_count());
535}
536
Anton Sukhanov7940da02018-10-10 10:34:49 -0700537TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
538 FakeMediaTransportFactory fake_media_transport_factory;
539 JsepTransportController::Config config;
540
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800541 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700542 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800543 config.use_media_transport_for_data_channels = true;
544 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700545 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800546 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700547 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800548 description->AddMediaTransportSetting("fake", "fake-remote-settings");
Anton Sukhanov7940da02018-10-10 10:34:49 -0700549 EXPECT_TRUE(transport_controller_
550 ->SetRemoteDescription(SdpType::kOffer, description.get())
551 .ok());
552
553 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
554 transport_controller_->GetMediaTransport(kAudioMid1));
555
556 ASSERT_NE(nullptr, media_transport);
557
558 // After SetRemoteDescription, media transport should be created as callee.
559 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800560 // We do not set pre-shared key on the callee, it comes in media transport
561 // settings.
562 EXPECT_EQ(absl::nullopt, media_transport->settings().pre_shared_key);
563 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700564
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800565 EXPECT_EQ("fake-remote-settings",
566 media_transport->remote_transport_parameters());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700567 // Return nullptr for non-existing mids.
568 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800569
570 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
571 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
572 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700573}
574
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800575TEST_F(JsepTransportControllerTest, GetMediaTransportInCalleePassesSdp) {
576 FakeMediaTransportFactory fake_media_transport_factory;
577 JsepTransportController::Config config;
578
579 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
580 config.media_transport_factory = &fake_media_transport_factory;
581 config.use_media_transport_for_data_channels = true;
582 config.use_media_transport_for_media = true;
583 CreateJsepTransportController(config);
584 auto description = CreateSessionDescriptionWithBundleGroup();
585 AddCryptoSettings(description.get());
586 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
587 EXPECT_TRUE(transport_controller_
588 ->SetRemoteDescription(SdpType::kOffer, description.get())
589 .ok());
590
591 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
592 transport_controller_->GetMediaTransport(kAudioMid1));
593
594 ASSERT_NE(nullptr, media_transport);
595
596 EXPECT_EQ("this-is-a-test-setting",
597 media_transport->settings().remote_transport_parameters);
598}
599
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800600// Caller generates the offer if media transport returns empty offer (no
601// parameters).
602TEST_F(JsepTransportControllerTest, MediaTransportGeneratesSessionDescription) {
603 FakeMediaTransportFactory fake_media_transport_factory(
604 /*transport_offer=*/"");
605 JsepTransportController::Config config;
606
607 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
608 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
609 config.media_transport_factory = &fake_media_transport_factory;
610 config.use_media_transport_for_data_channels = true;
611 config.use_media_transport_for_media = true;
612 CreateJsepTransportController(config);
613 auto description = CreateSessionDescriptionWithBundleGroup();
614 AddCryptoSettings(description.get());
615 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
616 transport_controller_->GenerateOrGetLastMediaTransportOffer();
617
618 ASSERT_TRUE(settings.has_value());
619 EXPECT_EQ("fake", settings->transport_name);
620 // Fake media transport returns empty settings (but not nullopt settings!)
621 EXPECT_EQ("", settings->transport_setting);
622}
623
624// Caller generates the offer if media transport returns offer with parameters.
625TEST_F(JsepTransportControllerTest,
626 MediaTransportGeneratesSessionDescriptionWithOfferParams) {
627 FakeMediaTransportFactory fake_media_transport_factory(
628 /*transport_offer=*/"offer-params");
629 JsepTransportController::Config config;
630
631 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
632 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
633 config.media_transport_factory = &fake_media_transport_factory;
634 config.use_media_transport_for_data_channels = true;
635 config.use_media_transport_for_media = true;
636 CreateJsepTransportController(config);
637 auto description = CreateSessionDescriptionWithBundleGroup();
638 AddCryptoSettings(description.get());
639 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
640 transport_controller_->GenerateOrGetLastMediaTransportOffer();
641
642 ASSERT_TRUE(settings.has_value());
643 EXPECT_EQ("fake", settings->transport_name);
644 EXPECT_EQ("offer-params", settings->transport_setting);
645}
646
647// Caller skips the offer if media transport requests it.
648TEST_F(JsepTransportControllerTest,
649 MediaTransportGeneratesSkipsSessionDescription) {
650 FakeMediaTransportFactory fake_media_transport_factory(
651 /*transport_offer=*/absl::nullopt);
652 JsepTransportController::Config config;
653
654 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
655 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
656 config.media_transport_factory = &fake_media_transport_factory;
657 config.use_media_transport_for_data_channels = true;
658 config.use_media_transport_for_media = true;
659 CreateJsepTransportController(config);
660 auto description = CreateSessionDescriptionWithBundleGroup();
661 AddCryptoSettings(description.get());
662 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
663 transport_controller_->GenerateOrGetLastMediaTransportOffer();
664
665 // Fake media transport returns nullopt settings
666 ASSERT_EQ(absl::nullopt, settings);
667}
668
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800669// Caller ignores its own outgoing parameters.
670TEST_F(JsepTransportControllerTest,
671 GetMediaTransportInCallerIgnoresXmtSection) {
672 FakeMediaTransportFactory fake_media_transport_factory;
673 JsepTransportController::Config config;
674
675 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800676 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800677 config.media_transport_factory = &fake_media_transport_factory;
678 config.use_media_transport_for_data_channels = true;
679 config.use_media_transport_for_media = true;
680 CreateJsepTransportController(config);
681 auto description = CreateSessionDescriptionWithBundleGroup();
682 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800683 EXPECT_NE(absl::nullopt,
684 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800685 EXPECT_TRUE(transport_controller_
686 ->SetLocalDescription(SdpType::kOffer, description.get())
687 .ok());
688
689 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
690 transport_controller_->GetMediaTransport(kAudioMid1));
691
692 ASSERT_NE(nullptr, media_transport);
693
694 // Remote parameters are nullopt, because we are the offerer (we don't)
695 // have the remote transport parameters, only ours.
696 EXPECT_EQ(absl::nullopt,
697 media_transport->settings().remote_transport_parameters);
698}
699
700TEST_F(JsepTransportControllerTest,
701 GetMediaTransportInCalleeIgnoresDifferentTransport) {
702 FakeMediaTransportFactory fake_media_transport_factory;
703 JsepTransportController::Config config;
704
705 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800706 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800707 config.media_transport_factory = &fake_media_transport_factory;
708 config.use_media_transport_for_data_channels = true;
709 config.use_media_transport_for_media = true;
710 CreateJsepTransportController(config);
711 auto description = CreateSessionDescriptionWithBundleGroup();
712 AddCryptoSettings(description.get());
713 description->AddMediaTransportSetting("not-a-fake-transport",
714 "this-is-a-test-setting");
715 EXPECT_TRUE(transport_controller_
716 ->SetRemoteDescription(SdpType::kOffer, description.get())
717 .ok());
718
719 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
720 transport_controller_->GetMediaTransport(kAudioMid1));
721
722 ASSERT_NE(nullptr, media_transport);
723
724 EXPECT_EQ(absl::nullopt,
725 media_transport->settings().remote_transport_parameters);
726}
727
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700728TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
729 FakeMediaTransportFactory fake_media_transport_factory;
730 JsepTransportController::Config config;
731
732 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800733 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700734 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800735 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700736 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800737 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700738 EXPECT_TRUE(transport_controller_
739 ->SetRemoteDescription(SdpType::kOffer, description.get())
740 .ok());
741
742 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
743
744 // Even if we set local description with crypto now (after the remote offer
745 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800746 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700747 AddCryptoSettings(description2.get());
748 EXPECT_TRUE(transport_controller_
749 ->SetLocalDescription(SdpType::kAnswer, description2.get())
750 .ok());
751
752 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800753 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
754 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
755 << "Because media transport is NOT used (fallback to RTP), expected "
756 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700757}
758
759TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800760 AfterSettingAnswerTheSameMediaTransportIsReturnedCallee) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700761 FakeMediaTransportFactory fake_media_transport_factory;
762 JsepTransportController::Config config;
763
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800764 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800765 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700766 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800767 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700768 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800769 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700770 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800771 description->AddMediaTransportSetting("fake", "fake-settings");
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700772 EXPECT_TRUE(transport_controller_
773 ->SetRemoteDescription(SdpType::kOffer, description.get())
774 .ok());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700775 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
776 transport_controller_->GetMediaTransport(kAudioMid1));
777 EXPECT_NE(nullptr, media_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800778 EXPECT_FALSE(media_transport->pre_shared_key().has_value())
779 << "On the callee, preshared key is passed through the media-transport "
780 "settings (x-mt)";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700781
782 // Even if we set local description with crypto now (after the remote offer
783 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800784 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700785 AddCryptoSettings(description2.get());
786
787 RTCError result = transport_controller_->SetLocalDescription(
788 SdpType::kAnswer, description2.get());
789 EXPECT_TRUE(result.ok()) << result.message();
790
791 // Media transport did not change.
792 EXPECT_EQ(media_transport,
793 transport_controller_->GetMediaTransport(kAudioMid1));
794}
795
Zhi Huange818b6e2018-02-22 15:26:27 -0800796TEST_F(JsepTransportControllerTest, SetIceConfig) {
797 CreateJsepTransportController(JsepTransportController::Config());
798 auto description = CreateSessionDescriptionWithoutBundle();
799 EXPECT_TRUE(transport_controller_
800 ->SetLocalDescription(SdpType::kOffer, description.get())
801 .ok());
802
803 transport_controller_->SetIceConfig(
804 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
805 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
806 transport_controller_->GetDtlsTransport(kAudioMid1));
807 ASSERT_NE(nullptr, fake_audio_dtls);
808 EXPECT_EQ(kTimeout,
809 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
810 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
811
812 // Test that value stored in controller is applied to new transports.
813 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
814 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
815 nullptr);
816
817 EXPECT_TRUE(transport_controller_
818 ->SetLocalDescription(SdpType::kOffer, description.get())
819 .ok());
820 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
821 transport_controller_->GetDtlsTransport(kAudioMid2));
822 ASSERT_NE(nullptr, fake_audio_dtls);
823 EXPECT_EQ(kTimeout,
824 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
825 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
826}
827
828// Tests the getter and setter of the ICE restart flag.
829TEST_F(JsepTransportControllerTest, NeedIceRestart) {
830 CreateJsepTransportController(JsepTransportController::Config());
831 auto description = CreateSessionDescriptionWithoutBundle();
832 EXPECT_TRUE(transport_controller_
833 ->SetLocalDescription(SdpType::kOffer, description.get())
834 .ok());
835 EXPECT_TRUE(transport_controller_
836 ->SetRemoteDescription(SdpType::kAnswer, description.get())
837 .ok());
838
839 // Initially NeedsIceRestart should return false.
840 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
841 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
842 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
843 // true.
844 transport_controller_->SetNeedsIceRestartFlag();
845 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
846 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
847 // For a nonexistent transport, false should be returned.
848 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
849
850 // Reset the ice_ufrag/ice_pwd for audio.
851 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
852 audio_transport_info->description.ice_ufrag = kIceUfrag2;
853 audio_transport_info->description.ice_pwd = kIcePwd2;
854 EXPECT_TRUE(transport_controller_
855 ->SetLocalDescription(SdpType::kOffer, description.get())
856 .ok());
857 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
858 // return false for audio and true for video.
859 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
860 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
861}
862
863TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
864 CreateJsepTransportController(JsepTransportController::Config());
865 auto description = CreateSessionDescriptionWithBundleGroup();
866 EXPECT_TRUE(transport_controller_
867 ->SetLocalDescription(SdpType::kOffer, description.get())
868 .ok());
869 // After setting the local description, we should be able to start gathering
870 // candidates.
871 transport_controller_->MaybeStartGathering();
872 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
873 EXPECT_EQ(1, gathering_state_signal_count_);
874}
875
876TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
877 CreateJsepTransportController(JsepTransportController::Config());
878 auto description = CreateSessionDescriptionWithoutBundle();
879 transport_controller_->SetLocalDescription(SdpType::kOffer,
880 description.get());
881 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
882 description.get());
883 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
884 transport_controller_->GetDtlsTransport(kAudioMid1));
885 ASSERT_NE(nullptr, fake_audio_dtls);
886 Candidates candidates;
887 candidates.push_back(
888 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
889 EXPECT_TRUE(
890 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
891 EXPECT_EQ(1U,
892 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
893
894 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
895 EXPECT_EQ(0U,
896 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
897}
898
899TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
900 CreateJsepTransportController(JsepTransportController::Config());
901
902 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
903 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
904 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
905 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
906
Karl Wiberg918f50c2018-07-05 11:40:33 +0200907 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800908 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
909 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
910 certificate1);
911
912 // Apply the local certificate.
913 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
914 // Apply the local description.
915 EXPECT_TRUE(transport_controller_
916 ->SetLocalDescription(SdpType::kOffer, description.get())
917 .ok());
918 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
919 EXPECT_TRUE(returned_certificate);
920 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
921 returned_certificate->identity()->certificate().ToPEMString());
922
923 // Should fail if called for a nonexistant transport.
924 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
925
926 // Shouldn't be able to change the identity once set.
927 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
928 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
929 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
930 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
931}
932
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800933TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800934 CreateJsepTransportController(JsepTransportController::Config());
935 auto description = CreateSessionDescriptionWithBundleGroup();
936 EXPECT_TRUE(transport_controller_
937 ->SetLocalDescription(SdpType::kOffer, description.get())
938 .ok());
939 rtc::FakeSSLCertificate fake_certificate("fake_data");
940
941 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
942 transport_controller_->GetDtlsTransport(kAudioMid1));
943 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800944 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
945 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
946 ASSERT_TRUE(returned_cert_chain);
947 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800948 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800949 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800950
951 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800952 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800953}
954
955TEST_F(JsepTransportControllerTest, GetDtlsRole) {
956 CreateJsepTransportController(JsepTransportController::Config());
957 auto offer_certificate =
958 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
959 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
960 auto answer_certificate =
961 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
962 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
963 transport_controller_->SetLocalCertificate(offer_certificate);
964
Karl Wiberg918f50c2018-07-05 11:40:33 +0200965 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800966 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
967 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
968 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200969 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800970 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
971 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
972 answer_certificate);
973
974 EXPECT_TRUE(transport_controller_
975 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
976 .ok());
977
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200978 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800979 transport_controller_->GetDtlsRole(kAudioMid1);
980 // The DTLS role is not decided yet.
981 EXPECT_FALSE(role);
982 EXPECT_TRUE(transport_controller_
983 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
984 .ok());
985 role = transport_controller_->GetDtlsRole(kAudioMid1);
986
987 ASSERT_TRUE(role);
988 EXPECT_EQ(rtc::SSL_CLIENT, *role);
989}
990
991TEST_F(JsepTransportControllerTest, GetStats) {
992 CreateJsepTransportController(JsepTransportController::Config());
993 auto description = CreateSessionDescriptionWithBundleGroup();
994 EXPECT_TRUE(transport_controller_
995 ->SetLocalDescription(SdpType::kOffer, description.get())
996 .ok());
997
998 cricket::TransportStats stats;
999 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
1000 EXPECT_EQ(kAudioMid1, stats.transport_name);
1001 EXPECT_EQ(1u, stats.channel_stats.size());
1002 // Return false for non-existing transport.
1003 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
1004}
1005
1006TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
1007 CreateJsepTransportController(JsepTransportController::Config());
1008 auto description = CreateSessionDescriptionWithoutBundle();
1009 EXPECT_TRUE(transport_controller_
1010 ->SetLocalDescription(SdpType::kOffer, description.get())
1011 .ok());
1012
1013 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
1014 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1015 fake_ice->SetCandidatesGatheringComplete();
1016 fake_ice->SetConnectionCount(1);
1017 // The connection stats will be failed if there is no active connection.
1018 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +00001019 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001020 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001021 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1022 ice_connection_state_, kTimeout);
1023 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001024 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1025 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +02001026 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001027}
1028
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001029TEST_F(JsepTransportControllerTest,
1030 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001031 CreateJsepTransportController(JsepTransportController::Config());
1032 auto description = CreateSessionDescriptionWithoutBundle();
1033 EXPECT_TRUE(transport_controller_
1034 ->SetLocalDescription(SdpType::kOffer, description.get())
1035 .ok());
1036
1037 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1038 transport_controller_->GetDtlsTransport(kAudioMid1));
1039 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1040 transport_controller_->GetDtlsTransport(kVideoMid1));
1041
1042 // First, have one transport connect, and another fail, to ensure that
1043 // the first transport connecting didn't trigger a "connected" state signal.
1044 // We should only get a signal when all are connected.
1045 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
1046 fake_audio_dtls->SetWritable(true);
1047 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1048 // Decrease the number of the connection to trigger the signal.
1049 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
1050 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
1051 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1052
Alex Loiko9289eda2018-11-23 16:18:59 +00001053 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001054 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001055 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1056 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001057 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001058 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1059 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001060 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001061
Jonas Olsson635474e2018-10-18 15:58:17 +02001062 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1063 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001064 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
1065 // the transport state to be STATE_CONNECTING.
1066 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
1067 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001068 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001069 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001070 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
1071 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001072 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001073 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1074 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001075 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001076}
1077
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001078TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001079 SignalConnectionStateConnectedWithMediaTransportAndNoDtlsCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001080 FakeMediaTransportFactory fake_media_transport_factory;
1081 JsepTransportController::Config config;
1082 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001083 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1084 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001085 config.use_media_transport_for_data_channels = true;
1086 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001087 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001088
1089 // Media Transport is only used with bundle.
1090 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001091 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001092 EXPECT_NE(absl::nullopt,
1093 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001094 EXPECT_TRUE(transport_controller_
1095 ->SetLocalDescription(SdpType::kOffer, description.get())
1096 .ok());
1097
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001098 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1099 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1100 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1101 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001102 EXPECT_EQ(fake_audio_ice, fake_video_ice);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001103 fake_audio_ice->SetConnectionCount(2);
1104 fake_audio_ice->SetConnectionCount(1);
1105 fake_video_ice->SetConnectionCount(2);
1106 fake_video_ice->SetConnectionCount(1);
1107 fake_audio_ice->SetWritable(true);
1108 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001109
1110 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001111 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1112 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001113
1114 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1115 transport_controller_->GetMediaTransport(kAudioMid1));
1116
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001117 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001118
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001119 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001120 // Only one media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001121 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001122}
1123
1124TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001125 SignalConnectionStateConnectedWithMediaTransportCaller) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001126 FakeMediaTransportFactory fake_media_transport_factory;
1127 JsepTransportController::Config config;
1128 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001129 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1130 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001131 config.use_media_transport_for_media = true;
1132 CreateJsepTransportController(config);
1133
1134 // Media Transport is only used with bundle.
1135 auto description = CreateSessionDescriptionWithBundleGroup();
1136 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001137 EXPECT_NE(absl::nullopt,
1138 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001139 EXPECT_TRUE(transport_controller_
1140 ->SetLocalDescription(SdpType::kOffer, description.get())
1141 .ok());
1142
1143 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1144 transport_controller_->GetDtlsTransport(kAudioMid1));
1145 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1146 transport_controller_->GetDtlsTransport(kVideoMid1));
1147
1148 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1149 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1150 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1151 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1152 fake_audio_ice->SetConnectionCount(2);
1153 fake_audio_ice->SetConnectionCount(1);
1154 fake_video_ice->SetConnectionCount(2);
1155 fake_video_ice->SetConnectionCount(1);
1156 fake_audio_ice->SetWritable(true);
1157 fake_video_ice->SetWritable(true);
1158 fake_audio_dtls->SetWritable(true);
1159 fake_video_dtls->SetWritable(true);
1160
1161 // Still not connected, because we are waiting for media transport.
1162 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1163 kTimeout);
1164
1165 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1166 transport_controller_->GetMediaTransport(kAudioMid1));
1167
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001168 ASSERT_NE(nullptr, media_transport);
1169
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001170 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1171 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1172 kTimeout);
1173
1174 // Still waiting for the second media transport.
1175 media_transport = static_cast<FakeMediaTransport*>(
1176 transport_controller_->GetMediaTransport(kVideoMid1));
1177 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1178
1179 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
1180}
1181
1182TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001183 SignalConnectionStateFailedWhenMediaTransportClosedCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001184 FakeMediaTransportFactory fake_media_transport_factory;
1185 JsepTransportController::Config config;
1186 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001187 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1188 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001189 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001190 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001191 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001192 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001193 EXPECT_NE(absl::nullopt,
1194 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001195 EXPECT_TRUE(transport_controller_
1196 ->SetLocalDescription(SdpType::kOffer, description.get())
1197 .ok());
1198
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001199 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1200 transport_controller_->GetDtlsTransport(kAudioMid1));
1201 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1202 transport_controller_->GetDtlsTransport(kVideoMid1));
1203
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001204 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1205 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1206 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1207 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1208 fake_audio_ice->SetWritable(true);
1209 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001210 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001211 fake_audio_ice->SetConnectionCount(2);
1212 fake_audio_ice->SetConnectionCount(1);
1213 fake_video_ice->SetConnectionCount(2);
1214 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001215
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001216 fake_audio_dtls->SetWritable(true);
1217 fake_video_dtls->SetWritable(true);
1218
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001219 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1220 transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001221 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001222 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1223
1224 media_transport = static_cast<FakeMediaTransport*>(
1225 transport_controller_->GetMediaTransport(kVideoMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001226 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001227
1228 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1229
Alex Loiko9289eda2018-11-23 16:18:59 +00001230 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001231
1232 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +00001233 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001234}
1235
Zhi Huange818b6e2018-02-22 15:26:27 -08001236TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1237 CreateJsepTransportController(JsepTransportController::Config());
1238 auto description = CreateSessionDescriptionWithoutBundle();
1239 EXPECT_TRUE(transport_controller_
1240 ->SetLocalDescription(SdpType::kOffer, description.get())
1241 .ok());
1242
1243 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1244 transport_controller_->GetDtlsTransport(kAudioMid1));
1245 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1246 transport_controller_->GetDtlsTransport(kVideoMid1));
1247
1248 // First, have one transport connect, and another fail, to ensure that
1249 // the first transport connecting didn't trigger a "connected" state signal.
1250 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001251 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1252 IceTransportState::kCompleted,
1253 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001254 fake_audio_dtls->SetWritable(true);
1255 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001256
1257 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1258 ice_connection_state_, kTimeout);
1259 EXPECT_EQ(1, ice_connection_state_signal_count_);
1260 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1261 combined_connection_state_, kTimeout);
1262 EXPECT_EQ(1, combined_connection_state_signal_count_);
1263
1264 fake_video_dtls->fake_ice_transport()->SetTransportState(
1265 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001266 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1267
Alex Loiko9289eda2018-11-23 16:18:59 +00001268 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001269 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001270 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1271 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001272 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001273 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1274 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001275 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001276
Jonas Olsson635474e2018-10-18 15:58:17 +02001277 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1278 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001279 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1280 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001281 fake_video_dtls->fake_ice_transport()->SetTransportState(
1282 IceTransportState::kCompleted,
1283 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001284 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001285 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +01001286 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001287 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1288 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001289 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001290 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1291 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001292 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001293}
1294
1295TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1296 CreateJsepTransportController(JsepTransportController::Config());
1297 auto description = CreateSessionDescriptionWithoutBundle();
1298 EXPECT_TRUE(transport_controller_
1299 ->SetLocalDescription(SdpType::kOffer, description.get())
1300 .ok());
1301
1302 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1303 transport_controller_->GetDtlsTransport(kAudioMid1));
1304 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1305 // Should be in the gathering state as soon as any transport starts gathering.
1306 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1307 EXPECT_EQ(1, gathering_state_signal_count_);
1308}
1309
1310TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1311 CreateJsepTransportController(JsepTransportController::Config());
1312 auto description = CreateSessionDescriptionWithoutBundle();
1313 EXPECT_TRUE(transport_controller_
1314 ->SetLocalDescription(SdpType::kOffer, description.get())
1315 .ok());
1316
1317 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1318 transport_controller_->GetDtlsTransport(kAudioMid1));
1319 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1320 transport_controller_->GetDtlsTransport(kVideoMid1));
1321
1322 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1323 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1324 EXPECT_EQ(1, gathering_state_signal_count_);
1325
1326 // Have one transport finish gathering, to make sure gathering
1327 // completion wasn't signalled if only one transport finished gathering.
1328 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1329 EXPECT_EQ(1, gathering_state_signal_count_);
1330
1331 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1332 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1333 EXPECT_EQ(1, gathering_state_signal_count_);
1334
1335 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1336 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1337 EXPECT_EQ(2, gathering_state_signal_count_);
1338}
1339
1340// Test that when the last transport that hasn't finished connecting and/or
1341// gathering is destroyed, the aggregate state jumps to "completed". This can
1342// happen if, for example, we have an audio and video transport, the audio
1343// transport completes, then we start bundling video on the audio transport.
1344TEST_F(JsepTransportControllerTest,
1345 SignalingWhenLastIncompleteTransportDestroyed) {
1346 CreateJsepTransportController(JsepTransportController::Config());
1347 auto description = CreateSessionDescriptionWithBundleGroup();
1348 EXPECT_TRUE(transport_controller_
1349 ->SetLocalDescription(SdpType::kOffer, description.get())
1350 .ok());
1351
1352 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1353 transport_controller_->GetDtlsTransport(kAudioMid1));
1354 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1355 transport_controller_->GetDtlsTransport(kVideoMid1));
1356 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1357
1358 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1359 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1360 EXPECT_EQ(1, gathering_state_signal_count_);
1361
1362 // Let the audio transport complete.
1363 fake_audio_dtls->SetWritable(true);
1364 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1365 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001366 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001367 EXPECT_EQ(1, gathering_state_signal_count_);
1368
1369 // Set the remote description and enable the bundle.
1370 EXPECT_TRUE(transport_controller_
1371 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1372 .ok());
1373 // The BUNDLE should be enabled, the incomplete video transport should be
1374 // deleted and the states shoud be updated.
1375 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1376 transport_controller_->GetDtlsTransport(kVideoMid1));
1377 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001378 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1379 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1380 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001381 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1382 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001383 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1384 EXPECT_EQ(2, gathering_state_signal_count_);
1385}
1386
1387TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1388 CreateJsepTransportController(JsepTransportController::Config());
1389 auto description = CreateSessionDescriptionWithBundleGroup();
1390 EXPECT_TRUE(transport_controller_
1391 ->SetLocalDescription(SdpType::kOffer, description.get())
1392 .ok());
1393 transport_controller_->MaybeStartGathering();
1394
1395 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1396 transport_controller_->GetDtlsTransport(kAudioMid1));
1397 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1398 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1399 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1400 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1401}
1402
1403TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1404 network_thread_ = rtc::Thread::CreateWithSocketServer();
1405 network_thread_->Start();
1406 CreateJsepTransportController(JsepTransportController::Config(),
1407 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 14:57:52 +01001408 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 15:26:27 -08001409 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1410
1411 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001412 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001413 EXPECT_EQ(2, connection_state_signal_count_);
1414
1415 // new --> gathering --> complete
1416 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1417 EXPECT_EQ(2, gathering_state_signal_count_);
1418
1419 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1420 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1421 EXPECT_EQ(2, candidates_signal_count_);
1422
1423 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1424}
1425
1426// Older versions of Chrome expect the ICE role to be re-determined when an
1427// ICE restart occurs, and also don't perform conflict resolution correctly,
1428// so for now we can't safely stop doing this.
1429// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1430// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1431// enough population.
1432TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1433 CreateJsepTransportController(JsepTransportController::Config());
1434 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001435 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001436 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1437 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1438 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001439 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001440 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1441 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1442 nullptr);
1443
1444 EXPECT_TRUE(transport_controller_
1445 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1446 .ok());
1447 EXPECT_TRUE(transport_controller_
1448 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1449 .ok());
1450
1451 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1452 transport_controller_->GetDtlsTransport(kAudioMid1));
1453 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1454 fake_dtls->fake_ice_transport()->GetIceRole());
1455
1456 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001457 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001458 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1459 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1460 nullptr);
1461 EXPECT_TRUE(
1462 transport_controller_
1463 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1464 .ok());
1465 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1466 fake_dtls->fake_ice_transport()->GetIceRole());
1467}
1468
1469// Test that if the TransportController was created with the
1470// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1471// redetermined on an ICE restart.
1472TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1473 JsepTransportController::Config config;
1474 config.redetermine_role_on_ice_restart = false;
1475
1476 CreateJsepTransportController(config);
1477 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001478 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001479 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1480 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1481 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001482 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001483 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1484 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1485 nullptr);
1486
1487 EXPECT_TRUE(transport_controller_
1488 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1489 .ok());
1490 EXPECT_TRUE(transport_controller_
1491 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1492 .ok());
1493
1494 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1495 transport_controller_->GetDtlsTransport(kAudioMid1));
1496 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1497 fake_dtls->fake_ice_transport()->GetIceRole());
1498
1499 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001500 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001501 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1502 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1503 nullptr);
1504 EXPECT_TRUE(
1505 transport_controller_
1506 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1507 .ok());
1508 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1509 fake_dtls->fake_ice_transport()->GetIceRole());
1510}
1511
1512// Tests ICE-Lite mode in remote answer.
1513TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1514 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001515 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001516 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1517 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1518 nullptr);
1519 EXPECT_TRUE(transport_controller_
1520 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1521 .ok());
1522 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1523 transport_controller_->GetDtlsTransport(kAudioMid1));
1524 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1525 fake_dtls->fake_ice_transport()->GetIceRole());
1526 EXPECT_EQ(cricket::ICEMODE_FULL,
1527 fake_dtls->fake_ice_transport()->remote_ice_mode());
1528
Karl Wiberg918f50c2018-07-05 11:40:33 +02001529 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001530 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1531 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1532 nullptr);
1533 EXPECT_TRUE(transport_controller_
1534 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1535 .ok());
1536 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1537 fake_dtls->fake_ice_transport()->GetIceRole());
1538 EXPECT_EQ(cricket::ICEMODE_LITE,
1539 fake_dtls->fake_ice_transport()->remote_ice_mode());
1540}
1541
1542// Tests that the ICE role remains "controlling" if a subsequent offer that
1543// does an ICE restart is received from an ICE lite endpoint. Regression test
1544// for: https://crbug.com/710760
1545TEST_F(JsepTransportControllerTest,
1546 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1547 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001548 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001549 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1550 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1551 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001552 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001553 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1554 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1555 nullptr);
1556 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1557 // local side is the controlling.
1558 EXPECT_TRUE(transport_controller_
1559 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1560 .ok());
1561 EXPECT_TRUE(transport_controller_
1562 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1563 .ok());
1564 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1565 transport_controller_->GetDtlsTransport(kAudioMid1));
1566 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1567 fake_dtls->fake_ice_transport()->GetIceRole());
1568
1569 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001570 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001571 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1572 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1573 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001574 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001575 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1576 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1577 nullptr);
1578 EXPECT_TRUE(transport_controller_
1579 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1580 .ok());
1581 EXPECT_TRUE(transport_controller_
1582 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1583 .ok());
1584 fake_dtls = static_cast<FakeDtlsTransport*>(
1585 transport_controller_->GetDtlsTransport(kAudioMid1));
1586 // The local side is still the controlling role since the remote side is using
1587 // ICE-Lite.
1588 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1589 fake_dtls->fake_ice_transport()->GetIceRole());
1590}
1591
1592// Tests that the SDP has more than one audio/video m= sections.
1593TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1594 CreateJsepTransportController(JsepTransportController::Config());
1595 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1596 bundle_group.AddContentName(kAudioMid1);
1597 bundle_group.AddContentName(kAudioMid2);
1598 bundle_group.AddContentName(kVideoMid1);
1599 bundle_group.AddContentName(kDataMid1);
1600
Karl Wiberg918f50c2018-07-05 11:40:33 +02001601 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001602 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1603 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1604 nullptr);
1605 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1606 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1607 nullptr);
1608 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1609 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1610 nullptr);
1611 AddDataSection(local_offer.get(), kDataMid1,
1612 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1613 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1614 nullptr);
1615
Karl Wiberg918f50c2018-07-05 11:40:33 +02001616 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001617 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1618 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1619 nullptr);
1620 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1621 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1622 nullptr);
1623 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1624 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1625 nullptr);
1626 AddDataSection(remote_answer.get(), kDataMid1,
1627 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1628 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1629 nullptr);
1630
1631 local_offer->AddGroup(bundle_group);
1632 remote_answer->AddGroup(bundle_group);
1633
1634 EXPECT_TRUE(transport_controller_
1635 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1636 .ok());
1637 EXPECT_TRUE(transport_controller_
1638 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1639 .ok());
1640 // Verify that all the sections are bundled on kAudio1.
1641 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1642 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1643 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1644 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1645 EXPECT_EQ(transport1, transport2);
1646 EXPECT_EQ(transport1, transport3);
1647 EXPECT_EQ(transport1, transport4);
1648
Harald Alvestrandad88c882018-11-28 16:47:46 +01001649 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1650 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1651
Zhi Huange818b6e2018-02-22 15:26:27 -08001652 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1653 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1654 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1655 EXPECT_EQ(transport1, it->second);
1656 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1657 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1658 EXPECT_EQ(transport1, it->second);
1659 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1660 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1661 EXPECT_EQ(transport1, it->second);
1662 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1663 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1664 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1665 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1666}
1667
1668// Tests that only a subset of all the m= sections are bundled.
1669TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1670 CreateJsepTransportController(JsepTransportController::Config());
1671 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1672 bundle_group.AddContentName(kAudioMid1);
1673 bundle_group.AddContentName(kVideoMid1);
1674
Karl Wiberg918f50c2018-07-05 11:40:33 +02001675 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001676 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1677 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1678 nullptr);
1679 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1680 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1681 nullptr);
1682 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1683 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1684 nullptr);
1685
Karl Wiberg918f50c2018-07-05 11:40:33 +02001686 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001687 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1688 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1689 nullptr);
1690 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1691 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1692 nullptr);
1693 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1694 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1695 nullptr);
1696
1697 local_offer->AddGroup(bundle_group);
1698 remote_answer->AddGroup(bundle_group);
1699 EXPECT_TRUE(transport_controller_
1700 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1701 .ok());
1702 EXPECT_TRUE(transport_controller_
1703 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1704 .ok());
1705
1706 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1707 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1708 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1709 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1710 EXPECT_NE(transport1, transport2);
1711 EXPECT_EQ(transport1, transport3);
1712
1713 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1714 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1715 EXPECT_EQ(transport1, it->second);
1716 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001717 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001718}
1719
1720// Tests that the initial offer/answer only have data section and audio/video
1721// sections are added in the subsequent offer.
1722TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1723 CreateJsepTransportController(JsepTransportController::Config());
1724 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1725 bundle_group.AddContentName(kDataMid1);
1726
Karl Wiberg918f50c2018-07-05 11:40:33 +02001727 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001728 AddDataSection(local_offer.get(), kDataMid1,
1729 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1730 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1731 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001732 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001733 AddDataSection(remote_answer.get(), kDataMid1,
1734 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1735 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1736 nullptr);
1737 local_offer->AddGroup(bundle_group);
1738 remote_answer->AddGroup(bundle_group);
1739
1740 EXPECT_TRUE(transport_controller_
1741 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1742 .ok());
1743 EXPECT_TRUE(transport_controller_
1744 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1745 .ok());
1746 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1747
1748 // Add audio/video sections in subsequent offer.
1749 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1750 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1751 nullptr);
1752 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1753 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1754 nullptr);
1755 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1756 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1757 nullptr);
1758 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1759 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1760 nullptr);
1761
1762 // Reset the bundle group and do another offer/answer exchange.
1763 bundle_group.AddContentName(kAudioMid1);
1764 bundle_group.AddContentName(kVideoMid1);
1765 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1766 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1767 local_offer->AddGroup(bundle_group);
1768 remote_answer->AddGroup(bundle_group);
1769
1770 EXPECT_TRUE(transport_controller_
1771 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1772 .ok());
1773 EXPECT_TRUE(transport_controller_
1774 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1775 .ok());
1776
1777 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1778 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1779 EXPECT_EQ(data_transport, audio_transport);
1780 EXPECT_EQ(data_transport, video_transport);
1781}
1782
1783TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1784 CreateJsepTransportController(JsepTransportController::Config());
1785 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1786 bundle_group.AddContentName(kAudioMid1);
1787 bundle_group.AddContentName(kVideoMid1);
1788 bundle_group.AddContentName(kDataMid1);
1789
Karl Wiberg918f50c2018-07-05 11:40:33 +02001790 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001791 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1792 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1793 nullptr);
1794 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1795 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1796 nullptr);
1797 AddDataSection(local_offer.get(), kDataMid1,
1798 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1799 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1800 nullptr);
1801
Karl Wiberg918f50c2018-07-05 11:40:33 +02001802 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001803 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1804 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1805 nullptr);
1806 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1807 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1808 nullptr);
1809 AddDataSection(remote_answer.get(), kDataMid1,
1810 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1811 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1812 nullptr);
1813 // Reject video and data section.
1814 remote_answer->contents()[1].rejected = true;
1815 remote_answer->contents()[2].rejected = true;
1816
1817 local_offer->AddGroup(bundle_group);
1818 remote_answer->AddGroup(bundle_group);
1819
1820 EXPECT_TRUE(transport_controller_
1821 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1822 .ok());
1823 EXPECT_TRUE(transport_controller_
1824 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1825 .ok());
1826
1827 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1828 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1829 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1830 // Verify the signals are fired correctly.
1831 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1832 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1833 EXPECT_EQ(nullptr, it->second);
1834 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1835 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1836 EXPECT_EQ(nullptr, it2->second);
1837}
1838
1839// Tests that changing the bundled MID in subsequent offer/answer exchange is
1840// not supported.
1841// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1842// fixed
1843TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1844 CreateJsepTransportController(JsepTransportController::Config());
1845 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1846 bundle_group.AddContentName(kAudioMid1);
1847 bundle_group.AddContentName(kVideoMid1);
1848
Karl Wiberg918f50c2018-07-05 11:40:33 +02001849 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001850 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1851 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1852 nullptr);
1853 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1854 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1855 nullptr);
1856
Karl Wiberg918f50c2018-07-05 11:40:33 +02001857 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001858 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1859 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1860 nullptr);
1861 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1862 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1863 nullptr);
1864
1865 local_offer->AddGroup(bundle_group);
1866 remote_answer->AddGroup(bundle_group);
1867 EXPECT_TRUE(transport_controller_
1868 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1869 .ok());
1870 EXPECT_TRUE(transport_controller_
1871 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1872 .ok());
1873 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1874 transport_controller_->GetRtpTransport(kVideoMid1));
1875
1876 // Reorder the bundle group.
1877 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1878 bundle_group.AddContentName(kAudioMid1);
1879 // The answerer uses the new bundle group and now the bundle mid is changed to
1880 // |kVideo1|.
1881 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1882 remote_answer->AddGroup(bundle_group);
1883 EXPECT_TRUE(transport_controller_
1884 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1885 .ok());
1886 EXPECT_FALSE(transport_controller_
1887 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1888 .ok());
1889}
Zhi Huange830e682018-03-30 10:48:35 -07001890// Test that rejecting only the first m= section of a BUNDLE group is treated as
1891// an error, but rejecting all of them works as expected.
1892TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1893 CreateJsepTransportController(JsepTransportController::Config());
1894 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1895 bundle_group.AddContentName(kAudioMid1);
1896 bundle_group.AddContentName(kVideoMid1);
1897 bundle_group.AddContentName(kDataMid1);
1898
Karl Wiberg918f50c2018-07-05 11:40:33 +02001899 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001900 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1901 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1902 nullptr);
1903 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1904 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1905 nullptr);
1906 AddDataSection(local_offer.get(), kDataMid1,
1907 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1908 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1909 nullptr);
1910
Karl Wiberg918f50c2018-07-05 11:40:33 +02001911 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001912 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1913 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1914 nullptr);
1915 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1916 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1917 nullptr);
1918 AddDataSection(remote_answer.get(), kDataMid1,
1919 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1920 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1921 nullptr);
1922 // Reject audio content in answer.
1923 remote_answer->contents()[0].rejected = true;
1924
1925 local_offer->AddGroup(bundle_group);
1926 remote_answer->AddGroup(bundle_group);
1927
1928 EXPECT_TRUE(transport_controller_
1929 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1930 .ok());
1931 EXPECT_FALSE(transport_controller_
1932 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1933 .ok());
1934
1935 // Reject all the contents.
1936 remote_answer->contents()[1].rejected = true;
1937 remote_answer->contents()[2].rejected = true;
1938 EXPECT_TRUE(transport_controller_
1939 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1940 .ok());
1941 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1942 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1943 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1944}
1945
1946// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1947// is used.
1948TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1949 JsepTransportController::Config config;
1950 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1951 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001952 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001953 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1954 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1955 nullptr);
1956
1957 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1958 // Applying a non-RTCP-mux offer is expected to fail.
1959 EXPECT_FALSE(transport_controller_
1960 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1961 .ok());
1962}
1963
1964// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1965// is used.
1966TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1967 JsepTransportController::Config config;
1968 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1969 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001970 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001971 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1972 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1973 nullptr);
1974 EXPECT_TRUE(transport_controller_
1975 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1976 .ok());
1977
Karl Wiberg918f50c2018-07-05 11:40:33 +02001978 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001979 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1980 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1981 nullptr);
1982 // Applying a non-RTCP-mux answer is expected to fail.
1983 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1984 EXPECT_FALSE(transport_controller_
1985 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1986 .ok());
1987}
Zhi Huange818b6e2018-02-22 15:26:27 -08001988
Zhi Huangd2248f82018-04-10 14:41:03 -07001989// This tests that the BUNDLE group in answer should be a subset of the offered
1990// group.
1991TEST_F(JsepTransportControllerTest,
1992 AddContentToBundleGroupInAnswerNotSupported) {
1993 CreateJsepTransportController(JsepTransportController::Config());
1994 auto local_offer = CreateSessionDescriptionWithoutBundle();
1995 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1996
1997 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1998 offer_bundle_group.AddContentName(kAudioMid1);
1999 local_offer->AddGroup(offer_bundle_group);
2000
2001 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2002 answer_bundle_group.AddContentName(kAudioMid1);
2003 answer_bundle_group.AddContentName(kVideoMid1);
2004 remote_answer->AddGroup(answer_bundle_group);
2005 EXPECT_TRUE(transport_controller_
2006 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2007 .ok());
2008 EXPECT_FALSE(transport_controller_
2009 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2010 .ok());
2011}
2012
2013// This tests that the BUNDLE group with non-existing MID should be rejectd.
2014TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
2015 CreateJsepTransportController(JsepTransportController::Config());
2016 auto local_offer = CreateSessionDescriptionWithoutBundle();
2017 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2018
2019 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2020 // The BUNDLE group is invalid because there is no data section in the
2021 // description.
2022 invalid_bundle_group.AddContentName(kDataMid1);
2023 local_offer->AddGroup(invalid_bundle_group);
2024 remote_answer->AddGroup(invalid_bundle_group);
2025
2026 EXPECT_FALSE(transport_controller_
2027 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2028 .ok());
2029 EXPECT_FALSE(transport_controller_
2030 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2031 .ok());
2032}
2033
2034// This tests that an answer shouldn't be able to remove an m= section from an
2035// established group without rejecting it.
2036TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
2037 CreateJsepTransportController(JsepTransportController::Config());
2038
2039 auto local_offer = CreateSessionDescriptionWithBundleGroup();
2040 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
2041 EXPECT_TRUE(transport_controller_
2042 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2043 .ok());
2044 EXPECT_TRUE(transport_controller_
2045 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2046 .ok());
2047
2048 // Do an re-offer/answer.
2049 EXPECT_TRUE(transport_controller_
2050 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2051 .ok());
2052 auto new_answer = CreateSessionDescriptionWithoutBundle();
2053 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2054 // The answer removes video from the BUNDLE group without rejecting it is
2055 // invalid.
2056 new_bundle_group.AddContentName(kAudioMid1);
2057 new_answer->AddGroup(new_bundle_group);
2058
2059 // Applying invalid answer is expected to fail.
2060 EXPECT_FALSE(transport_controller_
2061 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2062 .ok());
2063
2064 // Rejected the video content.
2065 auto video_content = new_answer->GetContentByName(kVideoMid1);
2066 ASSERT_TRUE(video_content);
2067 video_content->rejected = true;
2068 EXPECT_TRUE(transport_controller_
2069 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2070 .ok());
2071}
2072
Steve Anton2bed3972019-01-04 17:04:30 -08002073// Test that the JsepTransportController can process a new local and remote
2074// description that changes the tagged BUNDLE group with the max-bundle policy
2075// specified.
2076// This is a regression test for bugs.webrtc.org/9954
2077TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
2078 CreateJsepTransportController(JsepTransportController::Config());
2079
2080 auto local_offer = absl::make_unique<cricket::SessionDescription>();
2081 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2082 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2083 nullptr);
2084 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
2085 bundle_group.AddContentName(kAudioMid1);
2086 local_offer->AddGroup(bundle_group);
2087 EXPECT_TRUE(transport_controller_
2088 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2089 .ok());
2090
2091 std::unique_ptr<cricket::SessionDescription> remote_answer(
2092 local_offer->Copy());
2093 EXPECT_TRUE(transport_controller_
2094 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2095 .ok());
2096
2097 std::unique_ptr<cricket::SessionDescription> local_reoffer(
2098 local_offer->Copy());
2099 local_reoffer->contents()[0].rejected = true;
2100 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
2101 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2102 nullptr);
2103 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
2104 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2105 new_bundle_group.AddContentName(kVideoMid1);
2106 local_reoffer->AddGroup(new_bundle_group);
2107
2108 EXPECT_TRUE(transport_controller_
2109 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
2110 .ok());
2111
2112 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
2113 local_reoffer->Copy());
2114 EXPECT_TRUE(
2115 transport_controller_
2116 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
2117 .ok());
2118}
2119
Zhi Huange818b6e2018-02-22 15:26:27 -08002120} // namespace webrtc