blob: c0927b9db46b8e04fd39eaadcb7a05734b3f691d [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) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200178 RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp);
179 std::unique_ptr<cricket::SctpDataContentDescription> data(
180 new cricket::SctpDataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700181 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800182 description->AddContent(mid, protocol_type,
183 /*rejected=*/false, data.release());
184 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
185 }
186
187 void AddTransportInfo(cricket::SessionDescription* description,
188 const std::string& mid,
189 const std::string& ufrag,
190 const std::string& pwd,
191 cricket::IceMode ice_mode,
192 cricket::ConnectionRole conn_role,
193 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
194 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
195 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700196 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800197 }
198
199 cricket::TransportDescription transport_desc(std::vector<std::string>(),
200 ufrag, pwd, ice_mode,
201 conn_role, fingerprint.get());
202 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
203 }
204
205 cricket::IceConfig CreateIceConfig(
206 int receiving_timeout,
207 cricket::ContinualGatheringPolicy continual_gathering_policy) {
208 cricket::IceConfig config;
209 config.receiving_timeout = receiving_timeout;
210 config.continual_gathering_policy = continual_gathering_policy;
211 return config;
212 }
213
214 Candidate CreateCandidate(const std::string& transport_name, int component) {
215 Candidate c;
216 c.set_transport_name(transport_name);
217 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
218 c.set_component(component);
219 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
220 c.set_priority(1);
221 return c;
222 }
223
224 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
225 if (!network_thread_->IsCurrent()) {
226 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
227 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
228 });
229 return;
230 }
231
232 auto description = CreateSessionDescriptionWithBundleGroup();
233 EXPECT_TRUE(transport_controller_
234 ->SetLocalDescription(SdpType::kOffer, description.get())
235 .ok());
236
237 transport_controller_->MaybeStartGathering();
238 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
239 transport_controller_->GetDtlsTransport(kAudioMid1));
240 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
241 transport_controller_->GetDtlsTransport(kVideoMid1));
242 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
243 fake_audio_dtls->fake_ice_transport(),
244 CreateCandidate(kAudioMid1, /*component=*/1));
245 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
246 fake_video_dtls->fake_ice_transport(),
247 CreateCandidate(kVideoMid1, /*component=*/1));
248 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
249 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
250 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
251 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
252 fake_audio_dtls->SetReceiving(true);
253 fake_video_dtls->SetReceiving(true);
254 fake_audio_dtls->SetWritable(true);
255 fake_video_dtls->SetWritable(true);
256 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
257 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
258 }
259
260 protected:
Alex Loiko9289eda2018-11-23 16:18:59 +0000261 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800262 if (!signaling_thread_->IsCurrent()) {
263 signaled_on_non_signaling_thread_ = true;
264 }
265 connection_state_ = state;
266 ++connection_state_signal_count_;
267 }
268
Alex Loiko9289eda2018-11-23 16:18:59 +0000269 void OnStandardizedIceConnectionState(
270 PeerConnectionInterface::IceConnectionState state) {
271 if (!signaling_thread_->IsCurrent()) {
272 signaled_on_non_signaling_thread_ = true;
273 }
274 ice_connection_state_ = state;
275 ++ice_connection_state_signal_count_;
276 }
277
Jonas Olsson635474e2018-10-18 15:58:17 +0200278 void OnCombinedConnectionState(
279 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100280 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
281 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 15:58:17 +0200282 if (!signaling_thread_->IsCurrent()) {
283 signaled_on_non_signaling_thread_ = true;
284 }
285 combined_connection_state_ = state;
286 ++combined_connection_state_signal_count_;
287 }
288
Zhi Huange818b6e2018-02-22 15:26:27 -0800289 void OnGatheringState(cricket::IceGatheringState state) {
290 if (!signaling_thread_->IsCurrent()) {
291 signaled_on_non_signaling_thread_ = true;
292 }
293 gathering_state_ = state;
294 ++gathering_state_signal_count_;
295 }
296
297 void OnCandidatesGathered(const std::string& transport_name,
298 const Candidates& candidates) {
299 if (!signaling_thread_->IsCurrent()) {
300 signaled_on_non_signaling_thread_ = true;
301 }
302 candidates_[transport_name].insert(candidates_[transport_name].end(),
303 candidates.begin(), candidates.end());
304 ++candidates_signal_count_;
305 }
306
Zhi Huang365381f2018-04-13 16:44:34 -0700307 // JsepTransportController::Observer overrides.
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800308 bool OnTransportChanged(const std::string& mid,
309 RtpTransportInternal* rtp_transport,
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100310 rtc::scoped_refptr<DtlsTransport> dtls_transport,
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800311 MediaTransportInterface* media_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700312 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100313 if (dtls_transport) {
314 changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
315 } else {
316 changed_dtls_transport_by_mid_[mid] = nullptr;
317 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800318 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700319 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800320 }
321
322 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000323 cricket::IceConnectionState connection_state_ =
324 cricket::kIceConnectionConnecting;
325 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200326 PeerConnectionInterface::kIceConnectionNew;
327 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
328 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800329 bool receiving_ = false;
330 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
331 // transport_name => candidates
332 std::map<std::string, Candidates> candidates_;
333 // Counts of each signal emitted.
334 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000335 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200336 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800337 int receiving_signal_count_ = 0;
338 int gathering_state_signal_count_ = 0;
339 int candidates_signal_count_ = 0;
340
341 // |network_thread_| should be destroyed after |transport_controller_|
342 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800343 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
344 rtc::Thread* const signaling_thread_ = nullptr;
345 bool signaled_on_non_signaling_thread_ = false;
346 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
347 // signaled correctly.
348 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
349 std::map<std::string, cricket::DtlsTransportInternal*>
350 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800351 std::map<std::string, MediaTransportInterface*>
352 changed_media_transport_by_mid_;
353
354 // Transport controller needs to be destroyed first, because it may issue
355 // callbacks that modify the changed_*_by_mid in the destructor.
356 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800357};
358
359TEST_F(JsepTransportControllerTest, GetRtpTransport) {
360 CreateJsepTransportController(JsepTransportController::Config());
361 auto description = CreateSessionDescriptionWithoutBundle();
362 EXPECT_TRUE(transport_controller_
363 ->SetLocalDescription(SdpType::kOffer, description.get())
364 .ok());
365 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
366 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
367 EXPECT_NE(nullptr, audio_rtp_transport);
368 EXPECT_NE(nullptr, video_rtp_transport);
369 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
370 // Return nullptr for non-existing ones.
371 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
372}
373
374TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
375 JsepTransportController::Config config;
376 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
377 CreateJsepTransportController(config);
378 auto description = CreateSessionDescriptionWithoutBundle();
379 EXPECT_TRUE(transport_controller_
380 ->SetLocalDescription(SdpType::kOffer, description.get())
381 .ok());
382 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
383 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100384 EXPECT_NE(nullptr,
385 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800386 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
387 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100388 EXPECT_NE(nullptr,
389 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
390 // Lookup for all MIDs should return different transports (no bundle)
391 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
392 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800393 // Return nullptr for non-existing ones.
394 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
395 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100396 EXPECT_EQ(nullptr,
397 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100398 // Take a pointer to a transport, shut down the transport controller,
399 // and verify that the resulting container is empty.
400 auto dtls_transport =
401 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
402 webrtc::DtlsTransport* my_transport =
403 static_cast<DtlsTransport*>(dtls_transport.get());
404 EXPECT_NE(nullptr, my_transport->internal());
405 transport_controller_.reset();
406 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800407}
408
Zhi Huange830e682018-03-30 10:48:35 -0700409TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
410 JsepTransportController::Config config;
411 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
412 CreateJsepTransportController(config);
413 auto description = CreateSessionDescriptionWithoutBundle();
414 EXPECT_TRUE(transport_controller_
415 ->SetLocalDescription(SdpType::kOffer, description.get())
416 .ok());
417 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
418 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
419 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
420 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700421 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
422}
423
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800424TEST_F(JsepTransportControllerTest,
425 DtlsIsStillCreatedIfMediaTransportIsOnlyUsedForDataChannels) {
426 FakeMediaTransportFactory fake_media_transport_factory;
427 JsepTransportController::Config config;
428
429 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800430 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800431 config.media_transport_factory = &fake_media_transport_factory;
432 config.use_media_transport_for_data_channels = true;
433 CreateJsepTransportController(config);
434 auto description = CreateSessionDescriptionWithBundleGroup();
435 AddCryptoSettings(description.get());
436
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800437 EXPECT_NE(absl::nullopt,
438 transport_controller_->GenerateOrGetLastMediaTransportOffer());
439
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800440 EXPECT_TRUE(transport_controller_
441 ->SetLocalDescription(SdpType::kOffer, description.get())
442 .ok());
443
444 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
445 transport_controller_->GetMediaTransport(kAudioMid1));
446
447 ASSERT_NE(nullptr, media_transport);
448
449 // After SetLocalDescription, media transport should be created as caller.
450 EXPECT_TRUE(media_transport->is_caller());
451 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
452
453 // Return nullptr for non-existing mids.
454 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
455
456 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
457 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
458 << "Media transport for media was not enabled, and so DTLS transport "
459 "should be created.";
460}
461
Anton Sukhanov7940da02018-10-10 10:34:49 -0700462TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
463 FakeMediaTransportFactory fake_media_transport_factory;
464 JsepTransportController::Config config;
465
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800466 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800467 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700468 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800469 config.use_media_transport_for_data_channels = true;
470 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700471 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800472 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700473 AddCryptoSettings(description.get());
474
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800475 EXPECT_NE(absl::nullopt,
476 transport_controller_->GenerateOrGetLastMediaTransportOffer());
477
Anton Sukhanov7940da02018-10-10 10:34:49 -0700478 EXPECT_TRUE(transport_controller_
479 ->SetLocalDescription(SdpType::kOffer, description.get())
480 .ok());
481
482 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
483 transport_controller_->GetMediaTransport(kAudioMid1));
484
485 ASSERT_NE(nullptr, media_transport);
486
487 // After SetLocalDescription, media transport should be created as caller.
488 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800489 // We set the pre-shared key on the caller.
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700490 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800491 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700492
493 // Return nullptr for non-existing mids.
494 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800495
496 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
497 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
498 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700499}
500
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800501TEST_F(JsepTransportControllerTest,
502 GetMediaTransportOfferInTheConfigOnSubsequentCalls) {
503 FakeMediaTransportFactory fake_media_transport_factory;
504 WrapperMediaTransportFactory wrapping_factory(&fake_media_transport_factory);
505 JsepTransportController::Config config;
506
507 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
508 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
509 config.media_transport_factory = &wrapping_factory;
510 config.use_media_transport_for_data_channels = true;
511 config.use_media_transport_for_media = true;
512 CreateJsepTransportController(config);
513 auto description = CreateSessionDescriptionWithBundleGroup();
514 AddCryptoSettings(description.get());
515
516 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
517 transport_controller_->GenerateOrGetLastMediaTransportOffer();
518 ASSERT_NE(absl::nullopt, settings);
519
520 EXPECT_TRUE(transport_controller_
521 ->SetLocalDescription(SdpType::kOffer, description.get())
522 .ok());
523
524 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
525 transport_controller_->GetMediaTransport(kAudioMid1));
526
527 ASSERT_NE(nullptr, media_transport);
528
529 absl::optional<cricket::SessionDescription::MediaTransportSetting>
530 new_settings =
531 transport_controller_->GenerateOrGetLastMediaTransportOffer();
532 ASSERT_NE(absl::nullopt, new_settings);
533 EXPECT_EQ(settings->transport_name, new_settings->transport_name);
534 EXPECT_EQ(settings->transport_setting, new_settings->transport_setting);
535 EXPECT_EQ(1, wrapping_factory.created_transport_count());
536}
537
Anton Sukhanov7940da02018-10-10 10:34:49 -0700538TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
539 FakeMediaTransportFactory fake_media_transport_factory;
540 JsepTransportController::Config config;
541
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800542 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700543 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800544 config.use_media_transport_for_data_channels = true;
545 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700546 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800547 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700548 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800549 description->AddMediaTransportSetting("fake", "fake-remote-settings");
Anton Sukhanov7940da02018-10-10 10:34:49 -0700550 EXPECT_TRUE(transport_controller_
551 ->SetRemoteDescription(SdpType::kOffer, description.get())
552 .ok());
553
554 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
555 transport_controller_->GetMediaTransport(kAudioMid1));
556
557 ASSERT_NE(nullptr, media_transport);
558
559 // After SetRemoteDescription, media transport should be created as callee.
560 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800561 // We do not set pre-shared key on the callee, it comes in media transport
562 // settings.
563 EXPECT_EQ(absl::nullopt, media_transport->settings().pre_shared_key);
564 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700565
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800566 EXPECT_EQ("fake-remote-settings",
567 media_transport->remote_transport_parameters());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700568 // Return nullptr for non-existing mids.
569 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800570
571 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
572 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
573 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700574}
575
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800576TEST_F(JsepTransportControllerTest, GetMediaTransportInCalleePassesSdp) {
577 FakeMediaTransportFactory fake_media_transport_factory;
578 JsepTransportController::Config config;
579
580 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
581 config.media_transport_factory = &fake_media_transport_factory;
582 config.use_media_transport_for_data_channels = true;
583 config.use_media_transport_for_media = true;
584 CreateJsepTransportController(config);
585 auto description = CreateSessionDescriptionWithBundleGroup();
586 AddCryptoSettings(description.get());
587 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
588 EXPECT_TRUE(transport_controller_
589 ->SetRemoteDescription(SdpType::kOffer, description.get())
590 .ok());
591
592 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
593 transport_controller_->GetMediaTransport(kAudioMid1));
594
595 ASSERT_NE(nullptr, media_transport);
596
597 EXPECT_EQ("this-is-a-test-setting",
598 media_transport->settings().remote_transport_parameters);
599}
600
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800601// Caller generates the offer if media transport returns empty offer (no
602// parameters).
603TEST_F(JsepTransportControllerTest, MediaTransportGeneratesSessionDescription) {
604 FakeMediaTransportFactory fake_media_transport_factory(
605 /*transport_offer=*/"");
606 JsepTransportController::Config config;
607
608 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
609 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
610 config.media_transport_factory = &fake_media_transport_factory;
611 config.use_media_transport_for_data_channels = true;
612 config.use_media_transport_for_media = true;
613 CreateJsepTransportController(config);
614 auto description = CreateSessionDescriptionWithBundleGroup();
615 AddCryptoSettings(description.get());
616 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
617 transport_controller_->GenerateOrGetLastMediaTransportOffer();
618
619 ASSERT_TRUE(settings.has_value());
620 EXPECT_EQ("fake", settings->transport_name);
621 // Fake media transport returns empty settings (but not nullopt settings!)
622 EXPECT_EQ("", settings->transport_setting);
623}
624
625// Caller generates the offer if media transport returns offer with parameters.
626TEST_F(JsepTransportControllerTest,
627 MediaTransportGeneratesSessionDescriptionWithOfferParams) {
628 FakeMediaTransportFactory fake_media_transport_factory(
629 /*transport_offer=*/"offer-params");
630 JsepTransportController::Config config;
631
632 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
633 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
634 config.media_transport_factory = &fake_media_transport_factory;
635 config.use_media_transport_for_data_channels = true;
636 config.use_media_transport_for_media = true;
637 CreateJsepTransportController(config);
638 auto description = CreateSessionDescriptionWithBundleGroup();
639 AddCryptoSettings(description.get());
640 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
641 transport_controller_->GenerateOrGetLastMediaTransportOffer();
642
643 ASSERT_TRUE(settings.has_value());
644 EXPECT_EQ("fake", settings->transport_name);
645 EXPECT_EQ("offer-params", settings->transport_setting);
646}
647
648// Caller skips the offer if media transport requests it.
649TEST_F(JsepTransportControllerTest,
650 MediaTransportGeneratesSkipsSessionDescription) {
651 FakeMediaTransportFactory fake_media_transport_factory(
652 /*transport_offer=*/absl::nullopt);
653 JsepTransportController::Config config;
654
655 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
656 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
657 config.media_transport_factory = &fake_media_transport_factory;
658 config.use_media_transport_for_data_channels = true;
659 config.use_media_transport_for_media = true;
660 CreateJsepTransportController(config);
661 auto description = CreateSessionDescriptionWithBundleGroup();
662 AddCryptoSettings(description.get());
663 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
664 transport_controller_->GenerateOrGetLastMediaTransportOffer();
665
666 // Fake media transport returns nullopt settings
667 ASSERT_EQ(absl::nullopt, settings);
668}
669
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800670// Caller ignores its own outgoing parameters.
671TEST_F(JsepTransportControllerTest,
672 GetMediaTransportInCallerIgnoresXmtSection) {
673 FakeMediaTransportFactory fake_media_transport_factory;
674 JsepTransportController::Config config;
675
676 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800677 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800678 config.media_transport_factory = &fake_media_transport_factory;
679 config.use_media_transport_for_data_channels = true;
680 config.use_media_transport_for_media = true;
681 CreateJsepTransportController(config);
682 auto description = CreateSessionDescriptionWithBundleGroup();
683 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800684 EXPECT_NE(absl::nullopt,
685 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800686 EXPECT_TRUE(transport_controller_
687 ->SetLocalDescription(SdpType::kOffer, description.get())
688 .ok());
689
690 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
691 transport_controller_->GetMediaTransport(kAudioMid1));
692
693 ASSERT_NE(nullptr, media_transport);
694
695 // Remote parameters are nullopt, because we are the offerer (we don't)
696 // have the remote transport parameters, only ours.
697 EXPECT_EQ(absl::nullopt,
698 media_transport->settings().remote_transport_parameters);
699}
700
701TEST_F(JsepTransportControllerTest,
702 GetMediaTransportInCalleeIgnoresDifferentTransport) {
703 FakeMediaTransportFactory fake_media_transport_factory;
704 JsepTransportController::Config config;
705
706 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800707 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800708 config.media_transport_factory = &fake_media_transport_factory;
709 config.use_media_transport_for_data_channels = true;
710 config.use_media_transport_for_media = true;
711 CreateJsepTransportController(config);
712 auto description = CreateSessionDescriptionWithBundleGroup();
713 AddCryptoSettings(description.get());
714 description->AddMediaTransportSetting("not-a-fake-transport",
715 "this-is-a-test-setting");
716 EXPECT_TRUE(transport_controller_
717 ->SetRemoteDescription(SdpType::kOffer, description.get())
718 .ok());
719
720 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
721 transport_controller_->GetMediaTransport(kAudioMid1));
722
723 ASSERT_NE(nullptr, media_transport);
724
725 EXPECT_EQ(absl::nullopt,
726 media_transport->settings().remote_transport_parameters);
727}
728
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700729TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
730 FakeMediaTransportFactory fake_media_transport_factory;
731 JsepTransportController::Config config;
732
733 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800734 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700735 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800736 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700737 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800738 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700739 EXPECT_TRUE(transport_controller_
740 ->SetRemoteDescription(SdpType::kOffer, description.get())
741 .ok());
742
743 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
744
745 // Even if we set local description with crypto now (after the remote offer
746 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800747 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700748 AddCryptoSettings(description2.get());
749 EXPECT_TRUE(transport_controller_
750 ->SetLocalDescription(SdpType::kAnswer, description2.get())
751 .ok());
752
753 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800754 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
755 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
756 << "Because media transport is NOT used (fallback to RTP), expected "
757 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700758}
759
760TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800761 AfterSettingAnswerTheSameMediaTransportIsReturnedCallee) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700762 FakeMediaTransportFactory fake_media_transport_factory;
763 JsepTransportController::Config config;
764
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800765 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800766 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700767 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800768 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700769 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800770 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700771 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800772 description->AddMediaTransportSetting("fake", "fake-settings");
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700773 EXPECT_TRUE(transport_controller_
774 ->SetRemoteDescription(SdpType::kOffer, description.get())
775 .ok());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700776 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
777 transport_controller_->GetMediaTransport(kAudioMid1));
778 EXPECT_NE(nullptr, media_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800779 EXPECT_FALSE(media_transport->pre_shared_key().has_value())
780 << "On the callee, preshared key is passed through the media-transport "
781 "settings (x-mt)";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700782
783 // Even if we set local description with crypto now (after the remote offer
784 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800785 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700786 AddCryptoSettings(description2.get());
787
788 RTCError result = transport_controller_->SetLocalDescription(
789 SdpType::kAnswer, description2.get());
790 EXPECT_TRUE(result.ok()) << result.message();
791
792 // Media transport did not change.
793 EXPECT_EQ(media_transport,
794 transport_controller_->GetMediaTransport(kAudioMid1));
795}
796
Zhi Huange818b6e2018-02-22 15:26:27 -0800797TEST_F(JsepTransportControllerTest, SetIceConfig) {
798 CreateJsepTransportController(JsepTransportController::Config());
799 auto description = CreateSessionDescriptionWithoutBundle();
800 EXPECT_TRUE(transport_controller_
801 ->SetLocalDescription(SdpType::kOffer, description.get())
802 .ok());
803
804 transport_controller_->SetIceConfig(
805 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
806 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
807 transport_controller_->GetDtlsTransport(kAudioMid1));
808 ASSERT_NE(nullptr, fake_audio_dtls);
809 EXPECT_EQ(kTimeout,
810 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
811 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
812
813 // Test that value stored in controller is applied to new transports.
814 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
815 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
816 nullptr);
817
818 EXPECT_TRUE(transport_controller_
819 ->SetLocalDescription(SdpType::kOffer, description.get())
820 .ok());
821 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
822 transport_controller_->GetDtlsTransport(kAudioMid2));
823 ASSERT_NE(nullptr, fake_audio_dtls);
824 EXPECT_EQ(kTimeout,
825 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
826 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
827}
828
829// Tests the getter and setter of the ICE restart flag.
830TEST_F(JsepTransportControllerTest, NeedIceRestart) {
831 CreateJsepTransportController(JsepTransportController::Config());
832 auto description = CreateSessionDescriptionWithoutBundle();
833 EXPECT_TRUE(transport_controller_
834 ->SetLocalDescription(SdpType::kOffer, description.get())
835 .ok());
836 EXPECT_TRUE(transport_controller_
837 ->SetRemoteDescription(SdpType::kAnswer, description.get())
838 .ok());
839
840 // Initially NeedsIceRestart should return false.
841 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
842 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
843 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
844 // true.
845 transport_controller_->SetNeedsIceRestartFlag();
846 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
847 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
848 // For a nonexistent transport, false should be returned.
849 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
850
851 // Reset the ice_ufrag/ice_pwd for audio.
852 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
853 audio_transport_info->description.ice_ufrag = kIceUfrag2;
854 audio_transport_info->description.ice_pwd = kIcePwd2;
855 EXPECT_TRUE(transport_controller_
856 ->SetLocalDescription(SdpType::kOffer, description.get())
857 .ok());
858 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
859 // return false for audio and true for video.
860 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
861 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
862}
863
864TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
865 CreateJsepTransportController(JsepTransportController::Config());
866 auto description = CreateSessionDescriptionWithBundleGroup();
867 EXPECT_TRUE(transport_controller_
868 ->SetLocalDescription(SdpType::kOffer, description.get())
869 .ok());
870 // After setting the local description, we should be able to start gathering
871 // candidates.
872 transport_controller_->MaybeStartGathering();
873 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
874 EXPECT_EQ(1, gathering_state_signal_count_);
875}
876
877TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
878 CreateJsepTransportController(JsepTransportController::Config());
879 auto description = CreateSessionDescriptionWithoutBundle();
880 transport_controller_->SetLocalDescription(SdpType::kOffer,
881 description.get());
882 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
883 description.get());
884 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
885 transport_controller_->GetDtlsTransport(kAudioMid1));
886 ASSERT_NE(nullptr, fake_audio_dtls);
887 Candidates candidates;
888 candidates.push_back(
889 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
890 EXPECT_TRUE(
891 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
892 EXPECT_EQ(1U,
893 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
894
895 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
896 EXPECT_EQ(0U,
897 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
898}
899
900TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
901 CreateJsepTransportController(JsepTransportController::Config());
902
903 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
904 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
905 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
906 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
907
Karl Wiberg918f50c2018-07-05 11:40:33 +0200908 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800909 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
910 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
911 certificate1);
912
913 // Apply the local certificate.
914 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
915 // Apply the local description.
916 EXPECT_TRUE(transport_controller_
917 ->SetLocalDescription(SdpType::kOffer, description.get())
918 .ok());
919 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
920 EXPECT_TRUE(returned_certificate);
921 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
922 returned_certificate->identity()->certificate().ToPEMString());
923
924 // Should fail if called for a nonexistant transport.
925 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
926
927 // Shouldn't be able to change the identity once set.
928 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
929 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
930 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
931 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
932}
933
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800934TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800935 CreateJsepTransportController(JsepTransportController::Config());
936 auto description = CreateSessionDescriptionWithBundleGroup();
937 EXPECT_TRUE(transport_controller_
938 ->SetLocalDescription(SdpType::kOffer, description.get())
939 .ok());
940 rtc::FakeSSLCertificate fake_certificate("fake_data");
941
942 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
943 transport_controller_->GetDtlsTransport(kAudioMid1));
944 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800945 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
946 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
947 ASSERT_TRUE(returned_cert_chain);
948 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800949 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800950 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800951
952 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800953 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800954}
955
956TEST_F(JsepTransportControllerTest, GetDtlsRole) {
957 CreateJsepTransportController(JsepTransportController::Config());
958 auto offer_certificate =
959 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
960 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
961 auto answer_certificate =
962 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
963 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
964 transport_controller_->SetLocalCertificate(offer_certificate);
965
Karl Wiberg918f50c2018-07-05 11:40:33 +0200966 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800967 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
968 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
969 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200970 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800971 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
972 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
973 answer_certificate);
974
975 EXPECT_TRUE(transport_controller_
976 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
977 .ok());
978
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200979 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800980 transport_controller_->GetDtlsRole(kAudioMid1);
981 // The DTLS role is not decided yet.
982 EXPECT_FALSE(role);
983 EXPECT_TRUE(transport_controller_
984 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
985 .ok());
986 role = transport_controller_->GetDtlsRole(kAudioMid1);
987
988 ASSERT_TRUE(role);
989 EXPECT_EQ(rtc::SSL_CLIENT, *role);
990}
991
992TEST_F(JsepTransportControllerTest, GetStats) {
993 CreateJsepTransportController(JsepTransportController::Config());
994 auto description = CreateSessionDescriptionWithBundleGroup();
995 EXPECT_TRUE(transport_controller_
996 ->SetLocalDescription(SdpType::kOffer, description.get())
997 .ok());
998
999 cricket::TransportStats stats;
1000 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
1001 EXPECT_EQ(kAudioMid1, stats.transport_name);
1002 EXPECT_EQ(1u, stats.channel_stats.size());
1003 // Return false for non-existing transport.
1004 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
1005}
1006
1007TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
1008 CreateJsepTransportController(JsepTransportController::Config());
1009 auto description = CreateSessionDescriptionWithoutBundle();
1010 EXPECT_TRUE(transport_controller_
1011 ->SetLocalDescription(SdpType::kOffer, description.get())
1012 .ok());
1013
1014 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
1015 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1016 fake_ice->SetCandidatesGatheringComplete();
1017 fake_ice->SetConnectionCount(1);
1018 // The connection stats will be failed if there is no active connection.
1019 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +00001020 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001021 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001022 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1023 ice_connection_state_, kTimeout);
1024 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001025 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1026 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +02001027 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001028}
1029
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001030TEST_F(JsepTransportControllerTest,
1031 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001032 CreateJsepTransportController(JsepTransportController::Config());
1033 auto description = CreateSessionDescriptionWithoutBundle();
1034 EXPECT_TRUE(transport_controller_
1035 ->SetLocalDescription(SdpType::kOffer, description.get())
1036 .ok());
1037
1038 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1039 transport_controller_->GetDtlsTransport(kAudioMid1));
1040 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1041 transport_controller_->GetDtlsTransport(kVideoMid1));
1042
1043 // First, have one transport connect, and another fail, to ensure that
1044 // the first transport connecting didn't trigger a "connected" state signal.
1045 // We should only get a signal when all are connected.
1046 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
1047 fake_audio_dtls->SetWritable(true);
1048 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1049 // Decrease the number of the connection to trigger the signal.
1050 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
1051 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
1052 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1053
Alex Loiko9289eda2018-11-23 16:18:59 +00001054 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001055 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001056 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1057 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001058 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001059 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1060 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001061 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001062
Jonas Olsson635474e2018-10-18 15:58:17 +02001063 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1064 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001065 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
1066 // the transport state to be STATE_CONNECTING.
1067 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
1068 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001069 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001070 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001071 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
1072 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001073 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001074 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1075 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001076 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001077}
1078
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001079TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001080 SignalConnectionStateConnectedWithMediaTransportAndNoDtlsCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001081 FakeMediaTransportFactory fake_media_transport_factory;
1082 JsepTransportController::Config config;
1083 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001084 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1085 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001086 config.use_media_transport_for_data_channels = true;
1087 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001088 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001089
1090 // Media Transport is only used with bundle.
1091 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001092 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001093 EXPECT_NE(absl::nullopt,
1094 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001095 EXPECT_TRUE(transport_controller_
1096 ->SetLocalDescription(SdpType::kOffer, description.get())
1097 .ok());
1098
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001099 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1100 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1101 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1102 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001103 EXPECT_EQ(fake_audio_ice, fake_video_ice);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001104 fake_audio_ice->SetConnectionCount(2);
1105 fake_audio_ice->SetConnectionCount(1);
1106 fake_video_ice->SetConnectionCount(2);
1107 fake_video_ice->SetConnectionCount(1);
1108 fake_audio_ice->SetWritable(true);
1109 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001110
1111 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001112 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1113 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001114
1115 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1116 transport_controller_->GetMediaTransport(kAudioMid1));
1117
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001118 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001119
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001120 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001121 // Only one media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001122 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001123}
1124
1125TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001126 SignalConnectionStateConnectedWithMediaTransportCaller) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001127 FakeMediaTransportFactory fake_media_transport_factory;
1128 JsepTransportController::Config config;
1129 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001130 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1131 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001132 config.use_media_transport_for_media = true;
1133 CreateJsepTransportController(config);
1134
1135 // Media Transport is only used with bundle.
1136 auto description = CreateSessionDescriptionWithBundleGroup();
1137 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001138 EXPECT_NE(absl::nullopt,
1139 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001140 EXPECT_TRUE(transport_controller_
1141 ->SetLocalDescription(SdpType::kOffer, description.get())
1142 .ok());
1143
1144 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1145 transport_controller_->GetDtlsTransport(kAudioMid1));
1146 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1147 transport_controller_->GetDtlsTransport(kVideoMid1));
1148
1149 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1150 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1151 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1152 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1153 fake_audio_ice->SetConnectionCount(2);
1154 fake_audio_ice->SetConnectionCount(1);
1155 fake_video_ice->SetConnectionCount(2);
1156 fake_video_ice->SetConnectionCount(1);
1157 fake_audio_ice->SetWritable(true);
1158 fake_video_ice->SetWritable(true);
1159 fake_audio_dtls->SetWritable(true);
1160 fake_video_dtls->SetWritable(true);
1161
1162 // Still not connected, because we are waiting for media transport.
1163 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1164 kTimeout);
1165
1166 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1167 transport_controller_->GetMediaTransport(kAudioMid1));
1168
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001169 ASSERT_NE(nullptr, media_transport);
1170
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001171 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1172 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1173 kTimeout);
1174
1175 // Still waiting for the second media transport.
1176 media_transport = static_cast<FakeMediaTransport*>(
1177 transport_controller_->GetMediaTransport(kVideoMid1));
1178 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1179
1180 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
1181}
1182
1183TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001184 SignalConnectionStateFailedWhenMediaTransportClosedCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001185 FakeMediaTransportFactory fake_media_transport_factory;
1186 JsepTransportController::Config config;
1187 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001188 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1189 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001190 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001191 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001192 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001193 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001194 EXPECT_NE(absl::nullopt,
1195 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001196 EXPECT_TRUE(transport_controller_
1197 ->SetLocalDescription(SdpType::kOffer, description.get())
1198 .ok());
1199
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001200 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1201 transport_controller_->GetDtlsTransport(kAudioMid1));
1202 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1203 transport_controller_->GetDtlsTransport(kVideoMid1));
1204
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001205 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1206 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1207 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1208 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1209 fake_audio_ice->SetWritable(true);
1210 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001211 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001212 fake_audio_ice->SetConnectionCount(2);
1213 fake_audio_ice->SetConnectionCount(1);
1214 fake_video_ice->SetConnectionCount(2);
1215 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001216
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001217 fake_audio_dtls->SetWritable(true);
1218 fake_video_dtls->SetWritable(true);
1219
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001220 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1221 transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001222 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001223 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1224
1225 media_transport = static_cast<FakeMediaTransport*>(
1226 transport_controller_->GetMediaTransport(kVideoMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001227 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001228
1229 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1230
Alex Loiko9289eda2018-11-23 16:18:59 +00001231 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001232
1233 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +00001234 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001235}
1236
Zhi Huange818b6e2018-02-22 15:26:27 -08001237TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1238 CreateJsepTransportController(JsepTransportController::Config());
1239 auto description = CreateSessionDescriptionWithoutBundle();
1240 EXPECT_TRUE(transport_controller_
1241 ->SetLocalDescription(SdpType::kOffer, description.get())
1242 .ok());
1243
1244 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1245 transport_controller_->GetDtlsTransport(kAudioMid1));
1246 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1247 transport_controller_->GetDtlsTransport(kVideoMid1));
1248
1249 // First, have one transport connect, and another fail, to ensure that
1250 // the first transport connecting didn't trigger a "connected" state signal.
1251 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001252 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1253 IceTransportState::kCompleted,
1254 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001255 fake_audio_dtls->SetWritable(true);
1256 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001257
1258 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1259 ice_connection_state_, kTimeout);
1260 EXPECT_EQ(1, ice_connection_state_signal_count_);
1261 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1262 combined_connection_state_, kTimeout);
1263 EXPECT_EQ(1, combined_connection_state_signal_count_);
1264
1265 fake_video_dtls->fake_ice_transport()->SetTransportState(
1266 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001267 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1268
Alex Loiko9289eda2018-11-23 16:18:59 +00001269 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001270 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001271 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1272 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001273 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001274 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1275 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001276 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001277
Jonas Olsson635474e2018-10-18 15:58:17 +02001278 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1279 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001280 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1281 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001282 fake_video_dtls->fake_ice_transport()->SetTransportState(
1283 IceTransportState::kCompleted,
1284 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001285 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001286 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +01001287 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001288 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1289 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001290 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001291 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1292 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001293 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001294}
1295
1296TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1297 CreateJsepTransportController(JsepTransportController::Config());
1298 auto description = CreateSessionDescriptionWithoutBundle();
1299 EXPECT_TRUE(transport_controller_
1300 ->SetLocalDescription(SdpType::kOffer, description.get())
1301 .ok());
1302
1303 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1304 transport_controller_->GetDtlsTransport(kAudioMid1));
1305 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1306 // Should be in the gathering state as soon as any transport starts gathering.
1307 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1308 EXPECT_EQ(1, gathering_state_signal_count_);
1309}
1310
1311TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1312 CreateJsepTransportController(JsepTransportController::Config());
1313 auto description = CreateSessionDescriptionWithoutBundle();
1314 EXPECT_TRUE(transport_controller_
1315 ->SetLocalDescription(SdpType::kOffer, description.get())
1316 .ok());
1317
1318 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1319 transport_controller_->GetDtlsTransport(kAudioMid1));
1320 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1321 transport_controller_->GetDtlsTransport(kVideoMid1));
1322
1323 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1324 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1325 EXPECT_EQ(1, gathering_state_signal_count_);
1326
1327 // Have one transport finish gathering, to make sure gathering
1328 // completion wasn't signalled if only one transport finished gathering.
1329 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1330 EXPECT_EQ(1, gathering_state_signal_count_);
1331
1332 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1333 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1334 EXPECT_EQ(1, gathering_state_signal_count_);
1335
1336 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1337 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1338 EXPECT_EQ(2, gathering_state_signal_count_);
1339}
1340
1341// Test that when the last transport that hasn't finished connecting and/or
1342// gathering is destroyed, the aggregate state jumps to "completed". This can
1343// happen if, for example, we have an audio and video transport, the audio
1344// transport completes, then we start bundling video on the audio transport.
1345TEST_F(JsepTransportControllerTest,
1346 SignalingWhenLastIncompleteTransportDestroyed) {
1347 CreateJsepTransportController(JsepTransportController::Config());
1348 auto description = CreateSessionDescriptionWithBundleGroup();
1349 EXPECT_TRUE(transport_controller_
1350 ->SetLocalDescription(SdpType::kOffer, description.get())
1351 .ok());
1352
1353 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1354 transport_controller_->GetDtlsTransport(kAudioMid1));
1355 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1356 transport_controller_->GetDtlsTransport(kVideoMid1));
1357 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1358
1359 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1360 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1361 EXPECT_EQ(1, gathering_state_signal_count_);
1362
1363 // Let the audio transport complete.
1364 fake_audio_dtls->SetWritable(true);
1365 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1366 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001367 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001368 EXPECT_EQ(1, gathering_state_signal_count_);
1369
1370 // Set the remote description and enable the bundle.
1371 EXPECT_TRUE(transport_controller_
1372 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1373 .ok());
1374 // The BUNDLE should be enabled, the incomplete video transport should be
1375 // deleted and the states shoud be updated.
1376 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1377 transport_controller_->GetDtlsTransport(kVideoMid1));
1378 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001379 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1380 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1381 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001382 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1383 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001384 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1385 EXPECT_EQ(2, gathering_state_signal_count_);
1386}
1387
1388TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1389 CreateJsepTransportController(JsepTransportController::Config());
1390 auto description = CreateSessionDescriptionWithBundleGroup();
1391 EXPECT_TRUE(transport_controller_
1392 ->SetLocalDescription(SdpType::kOffer, description.get())
1393 .ok());
1394 transport_controller_->MaybeStartGathering();
1395
1396 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1397 transport_controller_->GetDtlsTransport(kAudioMid1));
1398 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1399 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1400 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1401 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1402}
1403
1404TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1405 network_thread_ = rtc::Thread::CreateWithSocketServer();
1406 network_thread_->Start();
1407 CreateJsepTransportController(JsepTransportController::Config(),
1408 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 14:57:52 +01001409 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 15:26:27 -08001410 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1411
1412 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001413 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001414 EXPECT_EQ(2, connection_state_signal_count_);
1415
1416 // new --> gathering --> complete
1417 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1418 EXPECT_EQ(2, gathering_state_signal_count_);
1419
1420 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1421 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1422 EXPECT_EQ(2, candidates_signal_count_);
1423
1424 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1425}
1426
1427// Older versions of Chrome expect the ICE role to be re-determined when an
1428// ICE restart occurs, and also don't perform conflict resolution correctly,
1429// so for now we can't safely stop doing this.
1430// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1431// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1432// enough population.
1433TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1434 CreateJsepTransportController(JsepTransportController::Config());
1435 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001436 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001437 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1438 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1439 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001440 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001441 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1442 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1443 nullptr);
1444
1445 EXPECT_TRUE(transport_controller_
1446 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1447 .ok());
1448 EXPECT_TRUE(transport_controller_
1449 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1450 .ok());
1451
1452 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1453 transport_controller_->GetDtlsTransport(kAudioMid1));
1454 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1455 fake_dtls->fake_ice_transport()->GetIceRole());
1456
1457 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001458 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001459 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1460 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1461 nullptr);
1462 EXPECT_TRUE(
1463 transport_controller_
1464 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1465 .ok());
1466 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1467 fake_dtls->fake_ice_transport()->GetIceRole());
1468}
1469
1470// Test that if the TransportController was created with the
1471// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1472// redetermined on an ICE restart.
1473TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1474 JsepTransportController::Config config;
1475 config.redetermine_role_on_ice_restart = false;
1476
1477 CreateJsepTransportController(config);
1478 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001479 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001480 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1481 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1482 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001483 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001484 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1485 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1486 nullptr);
1487
1488 EXPECT_TRUE(transport_controller_
1489 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1490 .ok());
1491 EXPECT_TRUE(transport_controller_
1492 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1493 .ok());
1494
1495 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1496 transport_controller_->GetDtlsTransport(kAudioMid1));
1497 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1498 fake_dtls->fake_ice_transport()->GetIceRole());
1499
1500 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001501 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001502 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1503 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1504 nullptr);
1505 EXPECT_TRUE(
1506 transport_controller_
1507 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1508 .ok());
1509 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1510 fake_dtls->fake_ice_transport()->GetIceRole());
1511}
1512
1513// Tests ICE-Lite mode in remote answer.
1514TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1515 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001516 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001517 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1518 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1519 nullptr);
1520 EXPECT_TRUE(transport_controller_
1521 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1522 .ok());
1523 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1524 transport_controller_->GetDtlsTransport(kAudioMid1));
1525 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1526 fake_dtls->fake_ice_transport()->GetIceRole());
1527 EXPECT_EQ(cricket::ICEMODE_FULL,
1528 fake_dtls->fake_ice_transport()->remote_ice_mode());
1529
Karl Wiberg918f50c2018-07-05 11:40:33 +02001530 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001531 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1532 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1533 nullptr);
1534 EXPECT_TRUE(transport_controller_
1535 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1536 .ok());
1537 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1538 fake_dtls->fake_ice_transport()->GetIceRole());
1539 EXPECT_EQ(cricket::ICEMODE_LITE,
1540 fake_dtls->fake_ice_transport()->remote_ice_mode());
1541}
1542
1543// Tests that the ICE role remains "controlling" if a subsequent offer that
1544// does an ICE restart is received from an ICE lite endpoint. Regression test
1545// for: https://crbug.com/710760
1546TEST_F(JsepTransportControllerTest,
1547 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1548 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001549 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001550 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1551 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1552 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001553 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001554 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1555 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1556 nullptr);
1557 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1558 // local side is the controlling.
1559 EXPECT_TRUE(transport_controller_
1560 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1561 .ok());
1562 EXPECT_TRUE(transport_controller_
1563 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1564 .ok());
1565 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1566 transport_controller_->GetDtlsTransport(kAudioMid1));
1567 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1568 fake_dtls->fake_ice_transport()->GetIceRole());
1569
1570 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001571 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001572 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1573 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1574 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001575 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001576 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1577 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1578 nullptr);
1579 EXPECT_TRUE(transport_controller_
1580 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1581 .ok());
1582 EXPECT_TRUE(transport_controller_
1583 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1584 .ok());
1585 fake_dtls = static_cast<FakeDtlsTransport*>(
1586 transport_controller_->GetDtlsTransport(kAudioMid1));
1587 // The local side is still the controlling role since the remote side is using
1588 // ICE-Lite.
1589 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1590 fake_dtls->fake_ice_transport()->GetIceRole());
1591}
1592
1593// Tests that the SDP has more than one audio/video m= sections.
1594TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1595 CreateJsepTransportController(JsepTransportController::Config());
1596 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1597 bundle_group.AddContentName(kAudioMid1);
1598 bundle_group.AddContentName(kAudioMid2);
1599 bundle_group.AddContentName(kVideoMid1);
1600 bundle_group.AddContentName(kDataMid1);
1601
Karl Wiberg918f50c2018-07-05 11:40:33 +02001602 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001603 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1604 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1605 nullptr);
1606 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1607 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1608 nullptr);
1609 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1610 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1611 nullptr);
1612 AddDataSection(local_offer.get(), kDataMid1,
1613 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1614 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1615 nullptr);
1616
Karl Wiberg918f50c2018-07-05 11:40:33 +02001617 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001618 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1619 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1620 nullptr);
1621 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1622 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1623 nullptr);
1624 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1625 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1626 nullptr);
1627 AddDataSection(remote_answer.get(), kDataMid1,
1628 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1629 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1630 nullptr);
1631
1632 local_offer->AddGroup(bundle_group);
1633 remote_answer->AddGroup(bundle_group);
1634
1635 EXPECT_TRUE(transport_controller_
1636 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1637 .ok());
1638 EXPECT_TRUE(transport_controller_
1639 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1640 .ok());
1641 // Verify that all the sections are bundled on kAudio1.
1642 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1643 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1644 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1645 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1646 EXPECT_EQ(transport1, transport2);
1647 EXPECT_EQ(transport1, transport3);
1648 EXPECT_EQ(transport1, transport4);
1649
Harald Alvestrandad88c882018-11-28 16:47:46 +01001650 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1651 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1652
Zhi Huange818b6e2018-02-22 15:26:27 -08001653 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1654 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1655 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1656 EXPECT_EQ(transport1, it->second);
1657 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1658 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1659 EXPECT_EQ(transport1, it->second);
1660 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1661 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1662 EXPECT_EQ(transport1, it->second);
1663 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1664 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1665 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1666 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1667}
1668
1669// Tests that only a subset of all the m= sections are bundled.
1670TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1671 CreateJsepTransportController(JsepTransportController::Config());
1672 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1673 bundle_group.AddContentName(kAudioMid1);
1674 bundle_group.AddContentName(kVideoMid1);
1675
Karl Wiberg918f50c2018-07-05 11:40:33 +02001676 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001677 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1678 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1679 nullptr);
1680 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1681 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1682 nullptr);
1683 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1684 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1685 nullptr);
1686
Karl Wiberg918f50c2018-07-05 11:40:33 +02001687 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001688 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1689 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1690 nullptr);
1691 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1692 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1693 nullptr);
1694 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1695 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1696 nullptr);
1697
1698 local_offer->AddGroup(bundle_group);
1699 remote_answer->AddGroup(bundle_group);
1700 EXPECT_TRUE(transport_controller_
1701 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1702 .ok());
1703 EXPECT_TRUE(transport_controller_
1704 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1705 .ok());
1706
1707 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1708 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1709 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1710 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1711 EXPECT_NE(transport1, transport2);
1712 EXPECT_EQ(transport1, transport3);
1713
1714 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1715 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1716 EXPECT_EQ(transport1, it->second);
1717 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001718 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001719}
1720
1721// Tests that the initial offer/answer only have data section and audio/video
1722// sections are added in the subsequent offer.
1723TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1724 CreateJsepTransportController(JsepTransportController::Config());
1725 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1726 bundle_group.AddContentName(kDataMid1);
1727
Karl Wiberg918f50c2018-07-05 11:40:33 +02001728 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001729 AddDataSection(local_offer.get(), kDataMid1,
1730 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1731 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1732 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001733 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001734 AddDataSection(remote_answer.get(), kDataMid1,
1735 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1736 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1737 nullptr);
1738 local_offer->AddGroup(bundle_group);
1739 remote_answer->AddGroup(bundle_group);
1740
1741 EXPECT_TRUE(transport_controller_
1742 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1743 .ok());
1744 EXPECT_TRUE(transport_controller_
1745 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1746 .ok());
1747 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1748
1749 // Add audio/video sections in subsequent offer.
1750 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1751 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1752 nullptr);
1753 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1754 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1755 nullptr);
1756 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1757 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1758 nullptr);
1759 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1760 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1761 nullptr);
1762
1763 // Reset the bundle group and do another offer/answer exchange.
1764 bundle_group.AddContentName(kAudioMid1);
1765 bundle_group.AddContentName(kVideoMid1);
1766 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1767 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1768 local_offer->AddGroup(bundle_group);
1769 remote_answer->AddGroup(bundle_group);
1770
1771 EXPECT_TRUE(transport_controller_
1772 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1773 .ok());
1774 EXPECT_TRUE(transport_controller_
1775 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1776 .ok());
1777
1778 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1779 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1780 EXPECT_EQ(data_transport, audio_transport);
1781 EXPECT_EQ(data_transport, video_transport);
1782}
1783
1784TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1785 CreateJsepTransportController(JsepTransportController::Config());
1786 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1787 bundle_group.AddContentName(kAudioMid1);
1788 bundle_group.AddContentName(kVideoMid1);
1789 bundle_group.AddContentName(kDataMid1);
1790
Karl Wiberg918f50c2018-07-05 11:40:33 +02001791 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001792 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1793 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1794 nullptr);
1795 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1796 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1797 nullptr);
1798 AddDataSection(local_offer.get(), kDataMid1,
1799 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1800 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1801 nullptr);
1802
Karl Wiberg918f50c2018-07-05 11:40:33 +02001803 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001804 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1805 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1806 nullptr);
1807 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1808 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1809 nullptr);
1810 AddDataSection(remote_answer.get(), kDataMid1,
1811 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1812 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1813 nullptr);
1814 // Reject video and data section.
1815 remote_answer->contents()[1].rejected = true;
1816 remote_answer->contents()[2].rejected = true;
1817
1818 local_offer->AddGroup(bundle_group);
1819 remote_answer->AddGroup(bundle_group);
1820
1821 EXPECT_TRUE(transport_controller_
1822 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1823 .ok());
1824 EXPECT_TRUE(transport_controller_
1825 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1826 .ok());
1827
1828 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1829 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1830 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1831 // Verify the signals are fired correctly.
1832 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1833 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1834 EXPECT_EQ(nullptr, it->second);
1835 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1836 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1837 EXPECT_EQ(nullptr, it2->second);
1838}
1839
1840// Tests that changing the bundled MID in subsequent offer/answer exchange is
1841// not supported.
1842// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1843// fixed
1844TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1845 CreateJsepTransportController(JsepTransportController::Config());
1846 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1847 bundle_group.AddContentName(kAudioMid1);
1848 bundle_group.AddContentName(kVideoMid1);
1849
Karl Wiberg918f50c2018-07-05 11:40:33 +02001850 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001851 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1852 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1853 nullptr);
1854 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1855 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1856 nullptr);
1857
Karl Wiberg918f50c2018-07-05 11:40:33 +02001858 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001859 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1860 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1861 nullptr);
1862 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1863 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1864 nullptr);
1865
1866 local_offer->AddGroup(bundle_group);
1867 remote_answer->AddGroup(bundle_group);
1868 EXPECT_TRUE(transport_controller_
1869 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1870 .ok());
1871 EXPECT_TRUE(transport_controller_
1872 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1873 .ok());
1874 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1875 transport_controller_->GetRtpTransport(kVideoMid1));
1876
1877 // Reorder the bundle group.
1878 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1879 bundle_group.AddContentName(kAudioMid1);
1880 // The answerer uses the new bundle group and now the bundle mid is changed to
1881 // |kVideo1|.
1882 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1883 remote_answer->AddGroup(bundle_group);
1884 EXPECT_TRUE(transport_controller_
1885 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1886 .ok());
1887 EXPECT_FALSE(transport_controller_
1888 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1889 .ok());
1890}
Zhi Huange830e682018-03-30 10:48:35 -07001891// Test that rejecting only the first m= section of a BUNDLE group is treated as
1892// an error, but rejecting all of them works as expected.
1893TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1894 CreateJsepTransportController(JsepTransportController::Config());
1895 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1896 bundle_group.AddContentName(kAudioMid1);
1897 bundle_group.AddContentName(kVideoMid1);
1898 bundle_group.AddContentName(kDataMid1);
1899
Karl Wiberg918f50c2018-07-05 11:40:33 +02001900 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001901 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1902 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1903 nullptr);
1904 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1905 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1906 nullptr);
1907 AddDataSection(local_offer.get(), kDataMid1,
1908 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1909 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1910 nullptr);
1911
Karl Wiberg918f50c2018-07-05 11:40:33 +02001912 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001913 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1914 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1915 nullptr);
1916 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1917 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1918 nullptr);
1919 AddDataSection(remote_answer.get(), kDataMid1,
1920 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1921 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1922 nullptr);
1923 // Reject audio content in answer.
1924 remote_answer->contents()[0].rejected = true;
1925
1926 local_offer->AddGroup(bundle_group);
1927 remote_answer->AddGroup(bundle_group);
1928
1929 EXPECT_TRUE(transport_controller_
1930 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1931 .ok());
1932 EXPECT_FALSE(transport_controller_
1933 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1934 .ok());
1935
1936 // Reject all the contents.
1937 remote_answer->contents()[1].rejected = true;
1938 remote_answer->contents()[2].rejected = true;
1939 EXPECT_TRUE(transport_controller_
1940 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1941 .ok());
1942 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1943 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1944 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1945}
1946
1947// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1948// is used.
1949TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1950 JsepTransportController::Config config;
1951 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1952 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001953 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001954 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1955 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1956 nullptr);
1957
1958 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1959 // Applying a non-RTCP-mux offer is expected to fail.
1960 EXPECT_FALSE(transport_controller_
1961 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1962 .ok());
1963}
1964
1965// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1966// is used.
1967TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1968 JsepTransportController::Config config;
1969 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1970 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001971 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001972 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1973 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1974 nullptr);
1975 EXPECT_TRUE(transport_controller_
1976 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1977 .ok());
1978
Karl Wiberg918f50c2018-07-05 11:40:33 +02001979 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001980 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1981 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1982 nullptr);
1983 // Applying a non-RTCP-mux answer is expected to fail.
1984 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1985 EXPECT_FALSE(transport_controller_
1986 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1987 .ok());
1988}
Zhi Huange818b6e2018-02-22 15:26:27 -08001989
Zhi Huangd2248f82018-04-10 14:41:03 -07001990// This tests that the BUNDLE group in answer should be a subset of the offered
1991// group.
1992TEST_F(JsepTransportControllerTest,
1993 AddContentToBundleGroupInAnswerNotSupported) {
1994 CreateJsepTransportController(JsepTransportController::Config());
1995 auto local_offer = CreateSessionDescriptionWithoutBundle();
1996 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1997
1998 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1999 offer_bundle_group.AddContentName(kAudioMid1);
2000 local_offer->AddGroup(offer_bundle_group);
2001
2002 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2003 answer_bundle_group.AddContentName(kAudioMid1);
2004 answer_bundle_group.AddContentName(kVideoMid1);
2005 remote_answer->AddGroup(answer_bundle_group);
2006 EXPECT_TRUE(transport_controller_
2007 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2008 .ok());
2009 EXPECT_FALSE(transport_controller_
2010 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2011 .ok());
2012}
2013
2014// This tests that the BUNDLE group with non-existing MID should be rejectd.
2015TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
2016 CreateJsepTransportController(JsepTransportController::Config());
2017 auto local_offer = CreateSessionDescriptionWithoutBundle();
2018 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2019
2020 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2021 // The BUNDLE group is invalid because there is no data section in the
2022 // description.
2023 invalid_bundle_group.AddContentName(kDataMid1);
2024 local_offer->AddGroup(invalid_bundle_group);
2025 remote_answer->AddGroup(invalid_bundle_group);
2026
2027 EXPECT_FALSE(transport_controller_
2028 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2029 .ok());
2030 EXPECT_FALSE(transport_controller_
2031 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2032 .ok());
2033}
2034
2035// This tests that an answer shouldn't be able to remove an m= section from an
2036// established group without rejecting it.
2037TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
2038 CreateJsepTransportController(JsepTransportController::Config());
2039
2040 auto local_offer = CreateSessionDescriptionWithBundleGroup();
2041 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
2042 EXPECT_TRUE(transport_controller_
2043 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2044 .ok());
2045 EXPECT_TRUE(transport_controller_
2046 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2047 .ok());
2048
2049 // Do an re-offer/answer.
2050 EXPECT_TRUE(transport_controller_
2051 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2052 .ok());
2053 auto new_answer = CreateSessionDescriptionWithoutBundle();
2054 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2055 // The answer removes video from the BUNDLE group without rejecting it is
2056 // invalid.
2057 new_bundle_group.AddContentName(kAudioMid1);
2058 new_answer->AddGroup(new_bundle_group);
2059
2060 // Applying invalid answer is expected to fail.
2061 EXPECT_FALSE(transport_controller_
2062 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2063 .ok());
2064
2065 // Rejected the video content.
2066 auto video_content = new_answer->GetContentByName(kVideoMid1);
2067 ASSERT_TRUE(video_content);
2068 video_content->rejected = true;
2069 EXPECT_TRUE(transport_controller_
2070 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2071 .ok());
2072}
2073
Steve Anton2bed3972019-01-04 17:04:30 -08002074// Test that the JsepTransportController can process a new local and remote
2075// description that changes the tagged BUNDLE group with the max-bundle policy
2076// specified.
2077// This is a regression test for bugs.webrtc.org/9954
2078TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
2079 CreateJsepTransportController(JsepTransportController::Config());
2080
2081 auto local_offer = absl::make_unique<cricket::SessionDescription>();
2082 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2083 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2084 nullptr);
2085 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
2086 bundle_group.AddContentName(kAudioMid1);
2087 local_offer->AddGroup(bundle_group);
2088 EXPECT_TRUE(transport_controller_
2089 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2090 .ok());
2091
2092 std::unique_ptr<cricket::SessionDescription> remote_answer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002093 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002094 EXPECT_TRUE(transport_controller_
2095 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2096 .ok());
2097
2098 std::unique_ptr<cricket::SessionDescription> local_reoffer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002099 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002100 local_reoffer->contents()[0].rejected = true;
2101 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
2102 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2103 nullptr);
2104 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
2105 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2106 new_bundle_group.AddContentName(kVideoMid1);
2107 local_reoffer->AddGroup(new_bundle_group);
2108
2109 EXPECT_TRUE(transport_controller_
2110 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
2111 .ok());
2112
2113 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002114 local_reoffer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002115 EXPECT_TRUE(
2116 transport_controller_
2117 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
2118 .ok());
2119}
2120
Zhi Huange818b6e2018-02-22 15:26:27 -08002121} // namespace webrtc