blob: 458e09c38af507abed5f5b48d95aa76306c2c566 [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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/jsep_transport_controller.h"
12
Zhi Huange818b6e2018-02-22 15:26:27 -080013#include <map>
14#include <memory>
15
Steve Anton2bed3972019-01-04 17:04:30 -080016#include "absl/memory/memory.h"
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -080017#include "api/media_transport_interface.h"
Anton Sukhanov7940da02018-10-10 10:34:49 -070018#include "api/test/fake_media_transport.h"
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -080019#include "api/test/loopback_media_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "p2p/base/fake_dtls_transport.h"
21#include "p2p/base/fake_ice_transport.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080022#include "p2p/base/no_op_dtls_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "p2p/base/transport_factory_interface.h"
24#include "p2p/base/transport_info.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080025#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080026#include "rtc_base/thread.h"
27#include "test/gtest.h"
28
Zhi Huange818b6e2018-02-22 15:26:27 -080029using cricket::Candidate;
30using cricket::Candidates;
Jonas Olssona4d87372019-07-05 19:08:33 +020031using cricket::FakeDtlsTransport;
Zhi Huange818b6e2018-02-22 15:26:27 -080032using webrtc::SdpType;
33
34static const int kTimeout = 100;
35static const char kIceUfrag1[] = "u0001";
36static const char kIcePwd1[] = "TESTICEPWD00000000000001";
37static const char kIceUfrag2[] = "u0002";
38static const char kIcePwd2[] = "TESTICEPWD00000000000002";
39static const char kIceUfrag3[] = "u0003";
40static const char kIcePwd3[] = "TESTICEPWD00000000000003";
41static const char kAudioMid1[] = "audio1";
42static const char kAudioMid2[] = "audio2";
43static const char kVideoMid1[] = "video1";
44static const char kVideoMid2[] = "video2";
45static const char kDataMid1[] = "data1";
46
47namespace webrtc {
48
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070049namespace {
50
51// Media transport factory requires crypto settings to be present in order to
52// create media transport.
53void AddCryptoSettings(cricket::SessionDescription* description) {
54 for (auto& content : description->contents()) {
55 content.media_description()->AddCrypto(cricket::CryptoParams(
56 /*t=*/0, std::string(rtc::CS_AES_CM_128_HMAC_SHA1_80),
57 "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2", ""));
58 }
59}
60
61} // namespace
62
Zhi Huange818b6e2018-02-22 15:26:27 -080063class FakeTransportFactory : public cricket::TransportFactoryInterface {
64 public:
65 std::unique_ptr<cricket::IceTransportInternal> CreateIceTransport(
66 const std::string& transport_name,
67 int component) override {
Karl Wiberg918f50c2018-07-05 11:40:33 +020068 return absl::make_unique<cricket::FakeIceTransport>(transport_name,
69 component);
Zhi Huange818b6e2018-02-22 15:26:27 -080070 }
71
72 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070073 cricket::IceTransportInternal* ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070074 const webrtc::CryptoOptions& crypto_options) override {
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070075 return absl::make_unique<FakeDtlsTransport>(
76 static_cast<cricket::FakeIceTransport*>(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,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200150 /*rejected=*/false, std::move(audio));
Zhi Huange818b6e2018-02-22 15:26:27 -0800151 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,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200166 /*rejected=*/false, std::move(video));
Zhi Huange818b6e2018-02-22 15:26:27 -0800167 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,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200183 /*rejected=*/false, std::move(data));
Zhi Huange818b6e2018-02-22 15:26:27 -0800184 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.
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700308 bool OnTransportChanged(
309 const std::string& mid,
310 RtpTransportInternal* rtp_transport,
311 rtc::scoped_refptr<DtlsTransport> dtls_transport,
312 MediaTransportInterface* media_transport,
313 DataChannelTransportInterface* data_channel_transport,
314 JsepTransportController::NegotiationState negotiation_state) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700315 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100316 if (dtls_transport) {
317 changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
318 } else {
319 changed_dtls_transport_by_mid_[mid] = nullptr;
320 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800321 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700322 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800323 }
324
325 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000326 cricket::IceConnectionState connection_state_ =
327 cricket::kIceConnectionConnecting;
328 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200329 PeerConnectionInterface::kIceConnectionNew;
330 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
331 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800332 bool receiving_ = false;
333 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
334 // transport_name => candidates
335 std::map<std::string, Candidates> candidates_;
336 // Counts of each signal emitted.
337 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000338 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200339 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800340 int receiving_signal_count_ = 0;
341 int gathering_state_signal_count_ = 0;
342 int candidates_signal_count_ = 0;
343
344 // |network_thread_| should be destroyed after |transport_controller_|
345 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800346 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
347 rtc::Thread* const signaling_thread_ = nullptr;
348 bool signaled_on_non_signaling_thread_ = false;
349 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
350 // signaled correctly.
351 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
352 std::map<std::string, cricket::DtlsTransportInternal*>
353 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800354 std::map<std::string, MediaTransportInterface*>
355 changed_media_transport_by_mid_;
356
357 // Transport controller needs to be destroyed first, because it may issue
358 // callbacks that modify the changed_*_by_mid in the destructor.
359 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800360};
361
362TEST_F(JsepTransportControllerTest, GetRtpTransport) {
363 CreateJsepTransportController(JsepTransportController::Config());
364 auto description = CreateSessionDescriptionWithoutBundle();
365 EXPECT_TRUE(transport_controller_
366 ->SetLocalDescription(SdpType::kOffer, description.get())
367 .ok());
368 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
369 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
370 EXPECT_NE(nullptr, audio_rtp_transport);
371 EXPECT_NE(nullptr, video_rtp_transport);
372 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
373 // Return nullptr for non-existing ones.
374 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
375}
376
377TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
378 JsepTransportController::Config config;
379 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
380 CreateJsepTransportController(config);
381 auto description = CreateSessionDescriptionWithoutBundle();
382 EXPECT_TRUE(transport_controller_
383 ->SetLocalDescription(SdpType::kOffer, description.get())
384 .ok());
385 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
386 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100387 EXPECT_NE(nullptr,
388 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800389 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
390 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100391 EXPECT_NE(nullptr,
392 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
393 // Lookup for all MIDs should return different transports (no bundle)
394 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
395 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800396 // Return nullptr for non-existing ones.
397 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
398 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100399 EXPECT_EQ(nullptr,
400 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100401 // Take a pointer to a transport, shut down the transport controller,
402 // and verify that the resulting container is empty.
403 auto dtls_transport =
404 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
405 webrtc::DtlsTransport* my_transport =
406 static_cast<DtlsTransport*>(dtls_transport.get());
407 EXPECT_NE(nullptr, my_transport->internal());
408 transport_controller_.reset();
409 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800410}
411
Zhi Huange830e682018-03-30 10:48:35 -0700412TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
413 JsepTransportController::Config config;
414 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
415 CreateJsepTransportController(config);
416 auto description = CreateSessionDescriptionWithoutBundle();
417 EXPECT_TRUE(transport_controller_
418 ->SetLocalDescription(SdpType::kOffer, description.get())
419 .ok());
420 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
421 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
422 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
423 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700424 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
425}
426
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800427TEST_F(JsepTransportControllerTest,
428 DtlsIsStillCreatedIfMediaTransportIsOnlyUsedForDataChannels) {
429 FakeMediaTransportFactory fake_media_transport_factory;
430 JsepTransportController::Config config;
431
432 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800433 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800434 config.media_transport_factory = &fake_media_transport_factory;
435 config.use_media_transport_for_data_channels = true;
436 CreateJsepTransportController(config);
437 auto description = CreateSessionDescriptionWithBundleGroup();
438 AddCryptoSettings(description.get());
439
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800440 EXPECT_NE(absl::nullopt,
441 transport_controller_->GenerateOrGetLastMediaTransportOffer());
442
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800443 EXPECT_TRUE(transport_controller_
444 ->SetLocalDescription(SdpType::kOffer, description.get())
445 .ok());
446
447 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700448 transport_controller_->GetDataChannelTransport(kAudioMid1));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800449
450 ASSERT_NE(nullptr, media_transport);
451
452 // After SetLocalDescription, media transport should be created as caller.
453 EXPECT_TRUE(media_transport->is_caller());
454 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
455
456 // Return nullptr for non-existing mids.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700457 EXPECT_EQ(nullptr,
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700458 transport_controller_->GetDataChannelTransport(kVideoMid2));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800459
460 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
461 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
462 << "Media transport for media was not enabled, and so DTLS transport "
463 "should be created.";
464}
465
Anton Sukhanov7940da02018-10-10 10:34:49 -0700466TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
467 FakeMediaTransportFactory fake_media_transport_factory;
468 JsepTransportController::Config config;
469
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800470 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800471 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700472 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800473 config.use_media_transport_for_data_channels = true;
474 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700475 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800476 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700477 AddCryptoSettings(description.get());
478
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800479 EXPECT_NE(absl::nullopt,
480 transport_controller_->GenerateOrGetLastMediaTransportOffer());
481
Anton Sukhanov7940da02018-10-10 10:34:49 -0700482 EXPECT_TRUE(transport_controller_
483 ->SetLocalDescription(SdpType::kOffer, description.get())
484 .ok());
485
486 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
487 transport_controller_->GetMediaTransport(kAudioMid1));
488
489 ASSERT_NE(nullptr, media_transport);
490
491 // After SetLocalDescription, media transport should be created as caller.
492 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800493 // We set the pre-shared key on the caller.
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700494 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800495 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700496
497 // Return nullptr for non-existing mids.
498 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800499
500 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
501 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
502 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700503}
504
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800505TEST_F(JsepTransportControllerTest,
506 GetMediaTransportOfferInTheConfigOnSubsequentCalls) {
507 FakeMediaTransportFactory fake_media_transport_factory;
508 WrapperMediaTransportFactory wrapping_factory(&fake_media_transport_factory);
509 JsepTransportController::Config config;
510
511 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
512 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
513 config.media_transport_factory = &wrapping_factory;
514 config.use_media_transport_for_data_channels = true;
515 config.use_media_transport_for_media = true;
516 CreateJsepTransportController(config);
517 auto description = CreateSessionDescriptionWithBundleGroup();
518 AddCryptoSettings(description.get());
519
520 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
521 transport_controller_->GenerateOrGetLastMediaTransportOffer();
522 ASSERT_NE(absl::nullopt, settings);
523
524 EXPECT_TRUE(transport_controller_
525 ->SetLocalDescription(SdpType::kOffer, description.get())
526 .ok());
527
528 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
529 transport_controller_->GetMediaTransport(kAudioMid1));
530
531 ASSERT_NE(nullptr, media_transport);
532
533 absl::optional<cricket::SessionDescription::MediaTransportSetting>
534 new_settings =
535 transport_controller_->GenerateOrGetLastMediaTransportOffer();
536 ASSERT_NE(absl::nullopt, new_settings);
537 EXPECT_EQ(settings->transport_name, new_settings->transport_name);
538 EXPECT_EQ(settings->transport_setting, new_settings->transport_setting);
539 EXPECT_EQ(1, wrapping_factory.created_transport_count());
540}
541
Anton Sukhanov7940da02018-10-10 10:34:49 -0700542TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
543 FakeMediaTransportFactory fake_media_transport_factory;
544 JsepTransportController::Config config;
545
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800546 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700547 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800548 config.use_media_transport_for_data_channels = true;
549 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700550 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800551 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700552 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800553 description->AddMediaTransportSetting("fake", "fake-remote-settings");
Anton Sukhanov7940da02018-10-10 10:34:49 -0700554 EXPECT_TRUE(transport_controller_
555 ->SetRemoteDescription(SdpType::kOffer, description.get())
556 .ok());
557
558 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
559 transport_controller_->GetMediaTransport(kAudioMid1));
560
561 ASSERT_NE(nullptr, media_transport);
562
563 // After SetRemoteDescription, media transport should be created as callee.
564 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800565 // We do not set pre-shared key on the callee, it comes in media transport
566 // settings.
567 EXPECT_EQ(absl::nullopt, media_transport->settings().pre_shared_key);
568 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700569
570 // Return nullptr for non-existing mids.
571 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800572
573 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
574 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
575 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700576}
577
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800578TEST_F(JsepTransportControllerTest, GetMediaTransportInCalleePassesSdp) {
579 FakeMediaTransportFactory fake_media_transport_factory;
580 JsepTransportController::Config config;
581
582 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
583 config.media_transport_factory = &fake_media_transport_factory;
584 config.use_media_transport_for_data_channels = true;
585 config.use_media_transport_for_media = true;
586 CreateJsepTransportController(config);
587 auto description = CreateSessionDescriptionWithBundleGroup();
588 AddCryptoSettings(description.get());
589 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
590 EXPECT_TRUE(transport_controller_
591 ->SetRemoteDescription(SdpType::kOffer, description.get())
592 .ok());
593
594 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
595 transport_controller_->GetMediaTransport(kAudioMid1));
596
597 ASSERT_NE(nullptr, media_transport);
598
599 EXPECT_EQ("this-is-a-test-setting",
600 media_transport->settings().remote_transport_parameters);
601}
602
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800603// Caller generates the offer if media transport returns empty offer (no
604// parameters).
605TEST_F(JsepTransportControllerTest, MediaTransportGeneratesSessionDescription) {
606 FakeMediaTransportFactory fake_media_transport_factory(
607 /*transport_offer=*/"");
608 JsepTransportController::Config config;
609
610 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
611 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
612 config.media_transport_factory = &fake_media_transport_factory;
613 config.use_media_transport_for_data_channels = true;
614 config.use_media_transport_for_media = true;
615 CreateJsepTransportController(config);
616 auto description = CreateSessionDescriptionWithBundleGroup();
617 AddCryptoSettings(description.get());
618 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
619 transport_controller_->GenerateOrGetLastMediaTransportOffer();
620
621 ASSERT_TRUE(settings.has_value());
622 EXPECT_EQ("fake", settings->transport_name);
623 // Fake media transport returns empty settings (but not nullopt settings!)
624 EXPECT_EQ("", settings->transport_setting);
625}
626
627// Caller generates the offer if media transport returns offer with parameters.
628TEST_F(JsepTransportControllerTest,
629 MediaTransportGeneratesSessionDescriptionWithOfferParams) {
630 FakeMediaTransportFactory fake_media_transport_factory(
631 /*transport_offer=*/"offer-params");
632 JsepTransportController::Config config;
633
634 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
635 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
636 config.media_transport_factory = &fake_media_transport_factory;
637 config.use_media_transport_for_data_channels = true;
638 config.use_media_transport_for_media = true;
639 CreateJsepTransportController(config);
640 auto description = CreateSessionDescriptionWithBundleGroup();
641 AddCryptoSettings(description.get());
642 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
643 transport_controller_->GenerateOrGetLastMediaTransportOffer();
644
645 ASSERT_TRUE(settings.has_value());
646 EXPECT_EQ("fake", settings->transport_name);
647 EXPECT_EQ("offer-params", settings->transport_setting);
648}
649
650// Caller skips the offer if media transport requests it.
651TEST_F(JsepTransportControllerTest,
652 MediaTransportGeneratesSkipsSessionDescription) {
653 FakeMediaTransportFactory fake_media_transport_factory(
654 /*transport_offer=*/absl::nullopt);
655 JsepTransportController::Config config;
656
657 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
658 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
659 config.media_transport_factory = &fake_media_transport_factory;
660 config.use_media_transport_for_data_channels = true;
661 config.use_media_transport_for_media = true;
662 CreateJsepTransportController(config);
663 auto description = CreateSessionDescriptionWithBundleGroup();
664 AddCryptoSettings(description.get());
665 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
666 transport_controller_->GenerateOrGetLastMediaTransportOffer();
667
668 // Fake media transport returns nullopt settings
669 ASSERT_EQ(absl::nullopt, settings);
670}
671
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800672// Caller ignores its own outgoing parameters.
673TEST_F(JsepTransportControllerTest,
674 GetMediaTransportInCallerIgnoresXmtSection) {
675 FakeMediaTransportFactory fake_media_transport_factory;
676 JsepTransportController::Config config;
677
678 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800679 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800680 config.media_transport_factory = &fake_media_transport_factory;
681 config.use_media_transport_for_data_channels = true;
682 config.use_media_transport_for_media = true;
683 CreateJsepTransportController(config);
684 auto description = CreateSessionDescriptionWithBundleGroup();
685 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800686 EXPECT_NE(absl::nullopt,
687 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800688 EXPECT_TRUE(transport_controller_
689 ->SetLocalDescription(SdpType::kOffer, description.get())
690 .ok());
691
692 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
693 transport_controller_->GetMediaTransport(kAudioMid1));
694
695 ASSERT_NE(nullptr, media_transport);
696
697 // Remote parameters are nullopt, because we are the offerer (we don't)
698 // have the remote transport parameters, only ours.
699 EXPECT_EQ(absl::nullopt,
700 media_transport->settings().remote_transport_parameters);
701}
702
703TEST_F(JsepTransportControllerTest,
704 GetMediaTransportInCalleeIgnoresDifferentTransport) {
705 FakeMediaTransportFactory fake_media_transport_factory;
706 JsepTransportController::Config config;
707
708 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800709 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800710 config.media_transport_factory = &fake_media_transport_factory;
711 config.use_media_transport_for_data_channels = true;
712 config.use_media_transport_for_media = true;
713 CreateJsepTransportController(config);
714 auto description = CreateSessionDescriptionWithBundleGroup();
715 AddCryptoSettings(description.get());
716 description->AddMediaTransportSetting("not-a-fake-transport",
717 "this-is-a-test-setting");
718 EXPECT_TRUE(transport_controller_
719 ->SetRemoteDescription(SdpType::kOffer, description.get())
720 .ok());
721
722 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
723 transport_controller_->GetMediaTransport(kAudioMid1));
724
725 ASSERT_NE(nullptr, media_transport);
726
727 EXPECT_EQ(absl::nullopt,
728 media_transport->settings().remote_transport_parameters);
729}
730
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700731TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
732 FakeMediaTransportFactory fake_media_transport_factory;
733 JsepTransportController::Config config;
734
735 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800736 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700737 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800738 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700739 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800740 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700741 EXPECT_TRUE(transport_controller_
742 ->SetRemoteDescription(SdpType::kOffer, description.get())
743 .ok());
744
745 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
746
747 // Even if we set local description with crypto now (after the remote offer
748 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800749 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700750 AddCryptoSettings(description2.get());
751 EXPECT_TRUE(transport_controller_
752 ->SetLocalDescription(SdpType::kAnswer, description2.get())
753 .ok());
754
755 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800756 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
757 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
758 << "Because media transport is NOT used (fallback to RTP), expected "
759 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700760}
761
762TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800763 AfterSettingAnswerTheSameMediaTransportIsReturnedCallee) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700764 FakeMediaTransportFactory fake_media_transport_factory;
765 JsepTransportController::Config config;
766
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800767 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800768 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700769 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800770 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700771 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800772 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700773 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800774 description->AddMediaTransportSetting("fake", "fake-settings");
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700775 EXPECT_TRUE(transport_controller_
776 ->SetRemoteDescription(SdpType::kOffer, description.get())
777 .ok());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700778 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
779 transport_controller_->GetMediaTransport(kAudioMid1));
780 EXPECT_NE(nullptr, media_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800781 EXPECT_FALSE(media_transport->pre_shared_key().has_value())
782 << "On the callee, preshared key is passed through the media-transport "
783 "settings (x-mt)";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700784
785 // Even if we set local description with crypto now (after the remote offer
786 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800787 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700788 AddCryptoSettings(description2.get());
789
790 RTCError result = transport_controller_->SetLocalDescription(
791 SdpType::kAnswer, description2.get());
792 EXPECT_TRUE(result.ok()) << result.message();
793
794 // Media transport did not change.
795 EXPECT_EQ(media_transport,
796 transport_controller_->GetMediaTransport(kAudioMid1));
797}
798
Zhi Huange818b6e2018-02-22 15:26:27 -0800799TEST_F(JsepTransportControllerTest, SetIceConfig) {
800 CreateJsepTransportController(JsepTransportController::Config());
801 auto description = CreateSessionDescriptionWithoutBundle();
802 EXPECT_TRUE(transport_controller_
803 ->SetLocalDescription(SdpType::kOffer, description.get())
804 .ok());
805
806 transport_controller_->SetIceConfig(
807 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
808 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
809 transport_controller_->GetDtlsTransport(kAudioMid1));
810 ASSERT_NE(nullptr, fake_audio_dtls);
811 EXPECT_EQ(kTimeout,
812 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
813 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
814
815 // Test that value stored in controller is applied to new transports.
816 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
817 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
818 nullptr);
819
820 EXPECT_TRUE(transport_controller_
821 ->SetLocalDescription(SdpType::kOffer, description.get())
822 .ok());
823 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
824 transport_controller_->GetDtlsTransport(kAudioMid2));
825 ASSERT_NE(nullptr, fake_audio_dtls);
826 EXPECT_EQ(kTimeout,
827 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
828 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
829}
830
831// Tests the getter and setter of the ICE restart flag.
832TEST_F(JsepTransportControllerTest, NeedIceRestart) {
833 CreateJsepTransportController(JsepTransportController::Config());
834 auto description = CreateSessionDescriptionWithoutBundle();
835 EXPECT_TRUE(transport_controller_
836 ->SetLocalDescription(SdpType::kOffer, description.get())
837 .ok());
838 EXPECT_TRUE(transport_controller_
839 ->SetRemoteDescription(SdpType::kAnswer, description.get())
840 .ok());
841
842 // Initially NeedsIceRestart should return false.
843 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
844 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
845 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
846 // true.
847 transport_controller_->SetNeedsIceRestartFlag();
848 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
849 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
850 // For a nonexistent transport, false should be returned.
851 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
852
853 // Reset the ice_ufrag/ice_pwd for audio.
854 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
855 audio_transport_info->description.ice_ufrag = kIceUfrag2;
856 audio_transport_info->description.ice_pwd = kIcePwd2;
857 EXPECT_TRUE(transport_controller_
858 ->SetLocalDescription(SdpType::kOffer, description.get())
859 .ok());
860 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
861 // return false for audio and true for video.
862 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
863 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
864}
865
866TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
867 CreateJsepTransportController(JsepTransportController::Config());
868 auto description = CreateSessionDescriptionWithBundleGroup();
869 EXPECT_TRUE(transport_controller_
870 ->SetLocalDescription(SdpType::kOffer, description.get())
871 .ok());
872 // After setting the local description, we should be able to start gathering
873 // candidates.
874 transport_controller_->MaybeStartGathering();
875 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
876 EXPECT_EQ(1, gathering_state_signal_count_);
877}
878
879TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
880 CreateJsepTransportController(JsepTransportController::Config());
881 auto description = CreateSessionDescriptionWithoutBundle();
882 transport_controller_->SetLocalDescription(SdpType::kOffer,
883 description.get());
884 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
885 description.get());
886 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
887 transport_controller_->GetDtlsTransport(kAudioMid1));
888 ASSERT_NE(nullptr, fake_audio_dtls);
889 Candidates candidates;
890 candidates.push_back(
891 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
892 EXPECT_TRUE(
893 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
894 EXPECT_EQ(1U,
895 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
896
897 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
898 EXPECT_EQ(0U,
899 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
900}
901
902TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
903 CreateJsepTransportController(JsepTransportController::Config());
904
905 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
906 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
907 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
908 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
909
Karl Wiberg918f50c2018-07-05 11:40:33 +0200910 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800911 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
912 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
913 certificate1);
914
915 // Apply the local certificate.
916 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
917 // Apply the local description.
918 EXPECT_TRUE(transport_controller_
919 ->SetLocalDescription(SdpType::kOffer, description.get())
920 .ok());
921 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
922 EXPECT_TRUE(returned_certificate);
923 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
924 returned_certificate->identity()->certificate().ToPEMString());
925
926 // Should fail if called for a nonexistant transport.
927 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
928
929 // Shouldn't be able to change the identity once set.
930 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
931 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
932 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
933 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
934}
935
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800936TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800937 CreateJsepTransportController(JsepTransportController::Config());
938 auto description = CreateSessionDescriptionWithBundleGroup();
939 EXPECT_TRUE(transport_controller_
940 ->SetLocalDescription(SdpType::kOffer, description.get())
941 .ok());
942 rtc::FakeSSLCertificate fake_certificate("fake_data");
943
944 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
945 transport_controller_->GetDtlsTransport(kAudioMid1));
946 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800947 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
948 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
949 ASSERT_TRUE(returned_cert_chain);
950 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800951 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800952 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800953
954 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800955 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800956}
957
958TEST_F(JsepTransportControllerTest, GetDtlsRole) {
959 CreateJsepTransportController(JsepTransportController::Config());
960 auto offer_certificate =
961 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
962 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
963 auto answer_certificate =
964 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
965 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
966 transport_controller_->SetLocalCertificate(offer_certificate);
967
Karl Wiberg918f50c2018-07-05 11:40:33 +0200968 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800969 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
970 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
971 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200972 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800973 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
974 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
975 answer_certificate);
976
977 EXPECT_TRUE(transport_controller_
978 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
979 .ok());
980
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200981 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800982 transport_controller_->GetDtlsRole(kAudioMid1);
983 // The DTLS role is not decided yet.
984 EXPECT_FALSE(role);
985 EXPECT_TRUE(transport_controller_
986 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
987 .ok());
988 role = transport_controller_->GetDtlsRole(kAudioMid1);
989
990 ASSERT_TRUE(role);
991 EXPECT_EQ(rtc::SSL_CLIENT, *role);
992}
993
994TEST_F(JsepTransportControllerTest, GetStats) {
995 CreateJsepTransportController(JsepTransportController::Config());
996 auto description = CreateSessionDescriptionWithBundleGroup();
997 EXPECT_TRUE(transport_controller_
998 ->SetLocalDescription(SdpType::kOffer, description.get())
999 .ok());
1000
1001 cricket::TransportStats stats;
1002 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
1003 EXPECT_EQ(kAudioMid1, stats.transport_name);
1004 EXPECT_EQ(1u, stats.channel_stats.size());
1005 // Return false for non-existing transport.
1006 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
1007}
1008
1009TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
1010 CreateJsepTransportController(JsepTransportController::Config());
1011 auto description = CreateSessionDescriptionWithoutBundle();
1012 EXPECT_TRUE(transport_controller_
1013 ->SetLocalDescription(SdpType::kOffer, description.get())
1014 .ok());
1015
1016 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
1017 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1018 fake_ice->SetCandidatesGatheringComplete();
1019 fake_ice->SetConnectionCount(1);
1020 // The connection stats will be failed if there is no active connection.
1021 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +00001022 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001023 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001024 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1025 ice_connection_state_, kTimeout);
1026 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001027 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1028 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +02001029 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001030}
1031
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001032TEST_F(JsepTransportControllerTest,
1033 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001034 CreateJsepTransportController(JsepTransportController::Config());
1035 auto description = CreateSessionDescriptionWithoutBundle();
1036 EXPECT_TRUE(transport_controller_
1037 ->SetLocalDescription(SdpType::kOffer, description.get())
1038 .ok());
1039
1040 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1041 transport_controller_->GetDtlsTransport(kAudioMid1));
1042 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1043 transport_controller_->GetDtlsTransport(kVideoMid1));
1044
1045 // First, have one transport connect, and another fail, to ensure that
1046 // the first transport connecting didn't trigger a "connected" state signal.
1047 // We should only get a signal when all are connected.
1048 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
1049 fake_audio_dtls->SetWritable(true);
1050 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1051 // Decrease the number of the connection to trigger the signal.
1052 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
1053 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
1054 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1055
Alex Loiko9289eda2018-11-23 16:18:59 +00001056 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001057 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001058 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1059 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001060 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001061 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1062 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001063 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001064
Jonas Olsson635474e2018-10-18 15:58:17 +02001065 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1066 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001067 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
1068 // the transport state to be STATE_CONNECTING.
1069 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
1070 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001071 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001072 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001073 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
1074 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001075 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001076 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1077 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001078 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001079}
1080
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001081TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001082 SignalConnectionStateConnectedWithMediaTransportAndNoDtlsCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001083 FakeMediaTransportFactory fake_media_transport_factory;
1084 JsepTransportController::Config config;
1085 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001086 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1087 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001088 config.use_media_transport_for_data_channels = true;
1089 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001090 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001091
1092 // Media Transport is only used with bundle.
1093 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001094 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001095 EXPECT_NE(absl::nullopt,
1096 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001097 EXPECT_TRUE(transport_controller_
1098 ->SetLocalDescription(SdpType::kOffer, description.get())
1099 .ok());
1100
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001101 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1102 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1103 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1104 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001105 EXPECT_EQ(fake_audio_ice, fake_video_ice);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001106 fake_audio_ice->SetConnectionCount(2);
1107 fake_audio_ice->SetConnectionCount(1);
1108 fake_video_ice->SetConnectionCount(2);
1109 fake_video_ice->SetConnectionCount(1);
1110 fake_audio_ice->SetWritable(true);
1111 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001112
1113 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001114 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1115 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001116
1117 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1118 transport_controller_->GetMediaTransport(kAudioMid1));
1119
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001120 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001121
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001122 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001123 // Only one media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001124 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001125}
1126
1127TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001128 SignalConnectionStateConnectedWithMediaTransportCaller) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001129 FakeMediaTransportFactory fake_media_transport_factory;
1130 JsepTransportController::Config config;
1131 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001132 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1133 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001134 config.use_media_transport_for_media = true;
1135 CreateJsepTransportController(config);
1136
1137 // Media Transport is only used with bundle.
1138 auto description = CreateSessionDescriptionWithBundleGroup();
1139 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001140 EXPECT_NE(absl::nullopt,
1141 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001142 EXPECT_TRUE(transport_controller_
1143 ->SetLocalDescription(SdpType::kOffer, description.get())
1144 .ok());
1145
1146 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1147 transport_controller_->GetDtlsTransport(kAudioMid1));
1148 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1149 transport_controller_->GetDtlsTransport(kVideoMid1));
1150
1151 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1152 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1153 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1154 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1155 fake_audio_ice->SetConnectionCount(2);
1156 fake_audio_ice->SetConnectionCount(1);
1157 fake_video_ice->SetConnectionCount(2);
1158 fake_video_ice->SetConnectionCount(1);
1159 fake_audio_ice->SetWritable(true);
1160 fake_video_ice->SetWritable(true);
1161 fake_audio_dtls->SetWritable(true);
1162 fake_video_dtls->SetWritable(true);
1163
1164 // Still not connected, because we are waiting for media transport.
1165 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1166 kTimeout);
1167
1168 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1169 transport_controller_->GetMediaTransport(kAudioMid1));
1170
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001171 ASSERT_NE(nullptr, media_transport);
1172
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001173 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1174 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1175 kTimeout);
1176
1177 // Still waiting for the second media transport.
1178 media_transport = static_cast<FakeMediaTransport*>(
1179 transport_controller_->GetMediaTransport(kVideoMid1));
1180 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1181
1182 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
1183}
1184
1185TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001186 SignalConnectionStateFailedWhenMediaTransportClosedCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001187 FakeMediaTransportFactory fake_media_transport_factory;
1188 JsepTransportController::Config config;
1189 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001190 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1191 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001192 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001193 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001194 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001195 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001196 EXPECT_NE(absl::nullopt,
1197 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001198 EXPECT_TRUE(transport_controller_
1199 ->SetLocalDescription(SdpType::kOffer, description.get())
1200 .ok());
1201
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001202 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1203 transport_controller_->GetDtlsTransport(kAudioMid1));
1204 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1205 transport_controller_->GetDtlsTransport(kVideoMid1));
1206
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001207 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1208 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1209 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1210 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1211 fake_audio_ice->SetWritable(true);
1212 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001213 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001214 fake_audio_ice->SetConnectionCount(2);
1215 fake_audio_ice->SetConnectionCount(1);
1216 fake_video_ice->SetConnectionCount(2);
1217 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001218
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001219 fake_audio_dtls->SetWritable(true);
1220 fake_video_dtls->SetWritable(true);
1221
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001222 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1223 transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001224 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001225 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1226
1227 media_transport = static_cast<FakeMediaTransport*>(
1228 transport_controller_->GetMediaTransport(kVideoMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001229 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001230
1231 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1232
Alex Loiko9289eda2018-11-23 16:18:59 +00001233 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001234
1235 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +00001236 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001237}
1238
Zhi Huange818b6e2018-02-22 15:26:27 -08001239TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1240 CreateJsepTransportController(JsepTransportController::Config());
1241 auto description = CreateSessionDescriptionWithoutBundle();
1242 EXPECT_TRUE(transport_controller_
1243 ->SetLocalDescription(SdpType::kOffer, description.get())
1244 .ok());
1245
1246 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1247 transport_controller_->GetDtlsTransport(kAudioMid1));
1248 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1249 transport_controller_->GetDtlsTransport(kVideoMid1));
1250
1251 // First, have one transport connect, and another fail, to ensure that
1252 // the first transport connecting didn't trigger a "connected" state signal.
1253 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001254 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1255 IceTransportState::kCompleted,
1256 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001257 fake_audio_dtls->SetWritable(true);
1258 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001259
1260 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1261 ice_connection_state_, kTimeout);
1262 EXPECT_EQ(1, ice_connection_state_signal_count_);
1263 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1264 combined_connection_state_, kTimeout);
1265 EXPECT_EQ(1, combined_connection_state_signal_count_);
1266
1267 fake_video_dtls->fake_ice_transport()->SetTransportState(
1268 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001269 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1270
Alex Loiko9289eda2018-11-23 16:18:59 +00001271 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001272 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001273 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1274 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001275 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001276 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1277 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001278 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001279
Jonas Olsson635474e2018-10-18 15:58:17 +02001280 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1281 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001282 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1283 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001284 fake_video_dtls->fake_ice_transport()->SetTransportState(
1285 IceTransportState::kCompleted,
1286 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001287 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001288 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +01001289 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001290 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1291 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001292 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001293 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1294 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001295 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001296}
1297
1298TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1299 CreateJsepTransportController(JsepTransportController::Config());
1300 auto description = CreateSessionDescriptionWithoutBundle();
1301 EXPECT_TRUE(transport_controller_
1302 ->SetLocalDescription(SdpType::kOffer, description.get())
1303 .ok());
1304
1305 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1306 transport_controller_->GetDtlsTransport(kAudioMid1));
1307 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1308 // Should be in the gathering state as soon as any transport starts gathering.
1309 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1310 EXPECT_EQ(1, gathering_state_signal_count_);
1311}
1312
1313TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1314 CreateJsepTransportController(JsepTransportController::Config());
1315 auto description = CreateSessionDescriptionWithoutBundle();
1316 EXPECT_TRUE(transport_controller_
1317 ->SetLocalDescription(SdpType::kOffer, description.get())
1318 .ok());
1319
1320 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1321 transport_controller_->GetDtlsTransport(kAudioMid1));
1322 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1323 transport_controller_->GetDtlsTransport(kVideoMid1));
1324
1325 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1326 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1327 EXPECT_EQ(1, gathering_state_signal_count_);
1328
1329 // Have one transport finish gathering, to make sure gathering
1330 // completion wasn't signalled if only one transport finished gathering.
1331 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1332 EXPECT_EQ(1, gathering_state_signal_count_);
1333
1334 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1335 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1336 EXPECT_EQ(1, gathering_state_signal_count_);
1337
1338 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1339 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1340 EXPECT_EQ(2, gathering_state_signal_count_);
1341}
1342
1343// Test that when the last transport that hasn't finished connecting and/or
1344// gathering is destroyed, the aggregate state jumps to "completed". This can
1345// happen if, for example, we have an audio and video transport, the audio
1346// transport completes, then we start bundling video on the audio transport.
1347TEST_F(JsepTransportControllerTest,
1348 SignalingWhenLastIncompleteTransportDestroyed) {
1349 CreateJsepTransportController(JsepTransportController::Config());
1350 auto description = CreateSessionDescriptionWithBundleGroup();
1351 EXPECT_TRUE(transport_controller_
1352 ->SetLocalDescription(SdpType::kOffer, description.get())
1353 .ok());
1354
1355 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1356 transport_controller_->GetDtlsTransport(kAudioMid1));
1357 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1358 transport_controller_->GetDtlsTransport(kVideoMid1));
1359 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1360
1361 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1362 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1363 EXPECT_EQ(1, gathering_state_signal_count_);
1364
1365 // Let the audio transport complete.
1366 fake_audio_dtls->SetWritable(true);
1367 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1368 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001369 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001370 EXPECT_EQ(1, gathering_state_signal_count_);
1371
1372 // Set the remote description and enable the bundle.
1373 EXPECT_TRUE(transport_controller_
1374 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1375 .ok());
1376 // The BUNDLE should be enabled, the incomplete video transport should be
1377 // deleted and the states shoud be updated.
1378 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1379 transport_controller_->GetDtlsTransport(kVideoMid1));
1380 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001381 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1382 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1383 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001384 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1385 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001386 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1387 EXPECT_EQ(2, gathering_state_signal_count_);
1388}
1389
1390TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1391 CreateJsepTransportController(JsepTransportController::Config());
1392 auto description = CreateSessionDescriptionWithBundleGroup();
1393 EXPECT_TRUE(transport_controller_
1394 ->SetLocalDescription(SdpType::kOffer, description.get())
1395 .ok());
1396 transport_controller_->MaybeStartGathering();
1397
1398 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1399 transport_controller_->GetDtlsTransport(kAudioMid1));
1400 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1401 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1402 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1403 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1404}
1405
1406TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1407 network_thread_ = rtc::Thread::CreateWithSocketServer();
1408 network_thread_->Start();
1409 CreateJsepTransportController(JsepTransportController::Config(),
1410 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 14:57:52 +01001411 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 15:26:27 -08001412 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1413
1414 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001415 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001416 EXPECT_EQ(2, connection_state_signal_count_);
1417
1418 // new --> gathering --> complete
1419 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1420 EXPECT_EQ(2, gathering_state_signal_count_);
1421
1422 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1423 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1424 EXPECT_EQ(2, candidates_signal_count_);
1425
1426 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1427}
1428
1429// Older versions of Chrome expect the ICE role to be re-determined when an
1430// ICE restart occurs, and also don't perform conflict resolution correctly,
1431// so for now we can't safely stop doing this.
1432// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1433// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1434// enough population.
1435TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1436 CreateJsepTransportController(JsepTransportController::Config());
1437 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001438 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001439 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1440 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1441 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001442 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001443 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1444 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1445 nullptr);
1446
1447 EXPECT_TRUE(transport_controller_
1448 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1449 .ok());
1450 EXPECT_TRUE(transport_controller_
1451 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1452 .ok());
1453
1454 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1455 transport_controller_->GetDtlsTransport(kAudioMid1));
1456 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1457 fake_dtls->fake_ice_transport()->GetIceRole());
1458
1459 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001460 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001461 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1462 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1463 nullptr);
1464 EXPECT_TRUE(
1465 transport_controller_
1466 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1467 .ok());
1468 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1469 fake_dtls->fake_ice_transport()->GetIceRole());
1470}
1471
1472// Test that if the TransportController was created with the
1473// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1474// redetermined on an ICE restart.
1475TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1476 JsepTransportController::Config config;
1477 config.redetermine_role_on_ice_restart = false;
1478
1479 CreateJsepTransportController(config);
1480 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001481 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001482 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1483 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1484 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001485 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001486 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1487 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1488 nullptr);
1489
1490 EXPECT_TRUE(transport_controller_
1491 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1492 .ok());
1493 EXPECT_TRUE(transport_controller_
1494 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1495 .ok());
1496
1497 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1498 transport_controller_->GetDtlsTransport(kAudioMid1));
1499 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1500 fake_dtls->fake_ice_transport()->GetIceRole());
1501
1502 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001503 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001504 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1505 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1506 nullptr);
1507 EXPECT_TRUE(
1508 transport_controller_
1509 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1510 .ok());
1511 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1512 fake_dtls->fake_ice_transport()->GetIceRole());
1513}
1514
1515// Tests ICE-Lite mode in remote answer.
1516TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1517 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001518 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001519 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1520 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1521 nullptr);
1522 EXPECT_TRUE(transport_controller_
1523 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1524 .ok());
1525 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1526 transport_controller_->GetDtlsTransport(kAudioMid1));
1527 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1528 fake_dtls->fake_ice_transport()->GetIceRole());
1529 EXPECT_EQ(cricket::ICEMODE_FULL,
1530 fake_dtls->fake_ice_transport()->remote_ice_mode());
1531
Karl Wiberg918f50c2018-07-05 11:40:33 +02001532 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001533 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1534 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1535 nullptr);
1536 EXPECT_TRUE(transport_controller_
1537 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1538 .ok());
1539 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1540 fake_dtls->fake_ice_transport()->GetIceRole());
1541 EXPECT_EQ(cricket::ICEMODE_LITE,
1542 fake_dtls->fake_ice_transport()->remote_ice_mode());
1543}
1544
1545// Tests that the ICE role remains "controlling" if a subsequent offer that
1546// does an ICE restart is received from an ICE lite endpoint. Regression test
1547// for: https://crbug.com/710760
1548TEST_F(JsepTransportControllerTest,
1549 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1550 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001551 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001552 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1553 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1554 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001555 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001556 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1557 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1558 nullptr);
1559 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1560 // local side is the controlling.
1561 EXPECT_TRUE(transport_controller_
1562 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1563 .ok());
1564 EXPECT_TRUE(transport_controller_
1565 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1566 .ok());
1567 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1568 transport_controller_->GetDtlsTransport(kAudioMid1));
1569 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1570 fake_dtls->fake_ice_transport()->GetIceRole());
1571
1572 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001573 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001574 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1575 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1576 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001577 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001578 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1579 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1580 nullptr);
1581 EXPECT_TRUE(transport_controller_
1582 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1583 .ok());
1584 EXPECT_TRUE(transport_controller_
1585 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1586 .ok());
1587 fake_dtls = static_cast<FakeDtlsTransport*>(
1588 transport_controller_->GetDtlsTransport(kAudioMid1));
1589 // The local side is still the controlling role since the remote side is using
1590 // ICE-Lite.
1591 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1592 fake_dtls->fake_ice_transport()->GetIceRole());
1593}
1594
1595// Tests that the SDP has more than one audio/video m= sections.
1596TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1597 CreateJsepTransportController(JsepTransportController::Config());
1598 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1599 bundle_group.AddContentName(kAudioMid1);
1600 bundle_group.AddContentName(kAudioMid2);
1601 bundle_group.AddContentName(kVideoMid1);
1602 bundle_group.AddContentName(kDataMid1);
1603
Karl Wiberg918f50c2018-07-05 11:40:33 +02001604 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001605 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1606 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1607 nullptr);
1608 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1609 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1610 nullptr);
1611 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1612 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1613 nullptr);
1614 AddDataSection(local_offer.get(), kDataMid1,
1615 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1616 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1617 nullptr);
1618
Karl Wiberg918f50c2018-07-05 11:40:33 +02001619 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001620 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1621 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1622 nullptr);
1623 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1624 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1625 nullptr);
1626 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1627 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1628 nullptr);
1629 AddDataSection(remote_answer.get(), kDataMid1,
1630 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1631 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1632 nullptr);
1633
1634 local_offer->AddGroup(bundle_group);
1635 remote_answer->AddGroup(bundle_group);
1636
1637 EXPECT_TRUE(transport_controller_
1638 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1639 .ok());
1640 EXPECT_TRUE(transport_controller_
1641 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1642 .ok());
1643 // Verify that all the sections are bundled on kAudio1.
1644 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1645 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1646 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1647 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1648 EXPECT_EQ(transport1, transport2);
1649 EXPECT_EQ(transport1, transport3);
1650 EXPECT_EQ(transport1, transport4);
1651
Harald Alvestrandad88c882018-11-28 16:47:46 +01001652 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1653 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1654
Zhi Huange818b6e2018-02-22 15:26:27 -08001655 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1656 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1657 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1658 EXPECT_EQ(transport1, it->second);
1659 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1660 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1661 EXPECT_EQ(transport1, it->second);
1662 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1663 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1664 EXPECT_EQ(transport1, it->second);
1665 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1666 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1667 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
Zhi Huange818b6e2018-02-22 15:26:27 -08001668}
1669
1670// Tests that only a subset of all the m= sections are bundled.
1671TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1672 CreateJsepTransportController(JsepTransportController::Config());
1673 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1674 bundle_group.AddContentName(kAudioMid1);
1675 bundle_group.AddContentName(kVideoMid1);
1676
Karl Wiberg918f50c2018-07-05 11:40:33 +02001677 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001678 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1679 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1680 nullptr);
1681 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1682 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1683 nullptr);
1684 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1685 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1686 nullptr);
1687
Karl Wiberg918f50c2018-07-05 11:40:33 +02001688 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001689 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1690 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1691 nullptr);
1692 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1693 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1694 nullptr);
1695 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1696 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1697 nullptr);
1698
1699 local_offer->AddGroup(bundle_group);
1700 remote_answer->AddGroup(bundle_group);
1701 EXPECT_TRUE(transport_controller_
1702 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1703 .ok());
1704 EXPECT_TRUE(transport_controller_
1705 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1706 .ok());
1707
1708 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1709 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1710 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1711 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1712 EXPECT_NE(transport1, transport2);
1713 EXPECT_EQ(transport1, transport3);
1714
1715 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1716 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1717 EXPECT_EQ(transport1, it->second);
1718 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001719 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001720}
1721
1722// Tests that the initial offer/answer only have data section and audio/video
1723// sections are added in the subsequent offer.
1724TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1725 CreateJsepTransportController(JsepTransportController::Config());
1726 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1727 bundle_group.AddContentName(kDataMid1);
1728
Karl Wiberg918f50c2018-07-05 11:40:33 +02001729 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001730 AddDataSection(local_offer.get(), kDataMid1,
1731 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1732 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1733 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001734 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001735 AddDataSection(remote_answer.get(), kDataMid1,
1736 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1737 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1738 nullptr);
1739 local_offer->AddGroup(bundle_group);
1740 remote_answer->AddGroup(bundle_group);
1741
1742 EXPECT_TRUE(transport_controller_
1743 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1744 .ok());
1745 EXPECT_TRUE(transport_controller_
1746 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1747 .ok());
1748 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1749
1750 // Add audio/video sections in subsequent offer.
1751 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1752 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1753 nullptr);
1754 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1755 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1756 nullptr);
1757 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1758 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1759 nullptr);
1760 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1761 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1762 nullptr);
1763
1764 // Reset the bundle group and do another offer/answer exchange.
1765 bundle_group.AddContentName(kAudioMid1);
1766 bundle_group.AddContentName(kVideoMid1);
1767 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1768 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1769 local_offer->AddGroup(bundle_group);
1770 remote_answer->AddGroup(bundle_group);
1771
1772 EXPECT_TRUE(transport_controller_
1773 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1774 .ok());
1775 EXPECT_TRUE(transport_controller_
1776 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1777 .ok());
1778
1779 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1780 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1781 EXPECT_EQ(data_transport, audio_transport);
1782 EXPECT_EQ(data_transport, video_transport);
1783}
1784
1785TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1786 CreateJsepTransportController(JsepTransportController::Config());
1787 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1788 bundle_group.AddContentName(kAudioMid1);
1789 bundle_group.AddContentName(kVideoMid1);
1790 bundle_group.AddContentName(kDataMid1);
1791
Karl Wiberg918f50c2018-07-05 11:40:33 +02001792 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001793 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1794 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1795 nullptr);
1796 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1797 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1798 nullptr);
1799 AddDataSection(local_offer.get(), kDataMid1,
1800 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1801 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1802 nullptr);
1803
Karl Wiberg918f50c2018-07-05 11:40:33 +02001804 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001805 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1806 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1807 nullptr);
1808 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1809 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1810 nullptr);
1811 AddDataSection(remote_answer.get(), kDataMid1,
1812 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1813 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1814 nullptr);
1815 // Reject video and data section.
1816 remote_answer->contents()[1].rejected = true;
1817 remote_answer->contents()[2].rejected = true;
1818
1819 local_offer->AddGroup(bundle_group);
1820 remote_answer->AddGroup(bundle_group);
1821
1822 EXPECT_TRUE(transport_controller_
1823 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1824 .ok());
1825 EXPECT_TRUE(transport_controller_
1826 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1827 .ok());
1828
1829 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1830 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1831 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1832 // Verify the signals are fired correctly.
1833 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1834 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1835 EXPECT_EQ(nullptr, it->second);
1836 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1837 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1838 EXPECT_EQ(nullptr, it2->second);
1839}
1840
1841// Tests that changing the bundled MID in subsequent offer/answer exchange is
1842// not supported.
1843// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1844// fixed
1845TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1846 CreateJsepTransportController(JsepTransportController::Config());
1847 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1848 bundle_group.AddContentName(kAudioMid1);
1849 bundle_group.AddContentName(kVideoMid1);
1850
Karl Wiberg918f50c2018-07-05 11:40:33 +02001851 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001852 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1853 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1854 nullptr);
1855 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1856 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1857 nullptr);
1858
Karl Wiberg918f50c2018-07-05 11:40:33 +02001859 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001860 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1861 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1862 nullptr);
1863 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1864 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1865 nullptr);
1866
1867 local_offer->AddGroup(bundle_group);
1868 remote_answer->AddGroup(bundle_group);
1869 EXPECT_TRUE(transport_controller_
1870 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1871 .ok());
1872 EXPECT_TRUE(transport_controller_
1873 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1874 .ok());
1875 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1876 transport_controller_->GetRtpTransport(kVideoMid1));
1877
1878 // Reorder the bundle group.
1879 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1880 bundle_group.AddContentName(kAudioMid1);
1881 // The answerer uses the new bundle group and now the bundle mid is changed to
1882 // |kVideo1|.
1883 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1884 remote_answer->AddGroup(bundle_group);
1885 EXPECT_TRUE(transport_controller_
1886 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1887 .ok());
1888 EXPECT_FALSE(transport_controller_
1889 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1890 .ok());
1891}
Zhi Huange830e682018-03-30 10:48:35 -07001892// Test that rejecting only the first m= section of a BUNDLE group is treated as
1893// an error, but rejecting all of them works as expected.
1894TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1895 CreateJsepTransportController(JsepTransportController::Config());
1896 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1897 bundle_group.AddContentName(kAudioMid1);
1898 bundle_group.AddContentName(kVideoMid1);
1899 bundle_group.AddContentName(kDataMid1);
1900
Karl Wiberg918f50c2018-07-05 11:40:33 +02001901 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001902 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1903 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1904 nullptr);
1905 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1906 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1907 nullptr);
1908 AddDataSection(local_offer.get(), kDataMid1,
1909 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1910 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1911 nullptr);
1912
Karl Wiberg918f50c2018-07-05 11:40:33 +02001913 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001914 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1915 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1916 nullptr);
1917 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1918 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1919 nullptr);
1920 AddDataSection(remote_answer.get(), kDataMid1,
1921 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1922 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1923 nullptr);
1924 // Reject audio content in answer.
1925 remote_answer->contents()[0].rejected = true;
1926
1927 local_offer->AddGroup(bundle_group);
1928 remote_answer->AddGroup(bundle_group);
1929
1930 EXPECT_TRUE(transport_controller_
1931 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1932 .ok());
1933 EXPECT_FALSE(transport_controller_
1934 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1935 .ok());
1936
1937 // Reject all the contents.
1938 remote_answer->contents()[1].rejected = true;
1939 remote_answer->contents()[2].rejected = true;
1940 EXPECT_TRUE(transport_controller_
1941 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1942 .ok());
1943 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1944 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1945 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1946}
1947
1948// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1949// is used.
1950TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1951 JsepTransportController::Config config;
1952 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1953 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001954 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001955 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1956 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1957 nullptr);
1958
1959 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1960 // Applying a non-RTCP-mux offer is expected to fail.
1961 EXPECT_FALSE(transport_controller_
1962 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1963 .ok());
1964}
1965
1966// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1967// is used.
1968TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1969 JsepTransportController::Config config;
1970 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1971 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001972 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001973 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1974 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1975 nullptr);
1976 EXPECT_TRUE(transport_controller_
1977 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1978 .ok());
1979
Karl Wiberg918f50c2018-07-05 11:40:33 +02001980 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001981 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1982 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1983 nullptr);
1984 // Applying a non-RTCP-mux answer is expected to fail.
1985 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1986 EXPECT_FALSE(transport_controller_
1987 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1988 .ok());
1989}
Zhi Huange818b6e2018-02-22 15:26:27 -08001990
Zhi Huangd2248f82018-04-10 14:41:03 -07001991// This tests that the BUNDLE group in answer should be a subset of the offered
1992// group.
1993TEST_F(JsepTransportControllerTest,
1994 AddContentToBundleGroupInAnswerNotSupported) {
1995 CreateJsepTransportController(JsepTransportController::Config());
1996 auto local_offer = CreateSessionDescriptionWithoutBundle();
1997 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1998
1999 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2000 offer_bundle_group.AddContentName(kAudioMid1);
2001 local_offer->AddGroup(offer_bundle_group);
2002
2003 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2004 answer_bundle_group.AddContentName(kAudioMid1);
2005 answer_bundle_group.AddContentName(kVideoMid1);
2006 remote_answer->AddGroup(answer_bundle_group);
2007 EXPECT_TRUE(transport_controller_
2008 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2009 .ok());
2010 EXPECT_FALSE(transport_controller_
2011 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2012 .ok());
2013}
2014
2015// This tests that the BUNDLE group with non-existing MID should be rejectd.
2016TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
2017 CreateJsepTransportController(JsepTransportController::Config());
2018 auto local_offer = CreateSessionDescriptionWithoutBundle();
2019 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2020
2021 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2022 // The BUNDLE group is invalid because there is no data section in the
2023 // description.
2024 invalid_bundle_group.AddContentName(kDataMid1);
2025 local_offer->AddGroup(invalid_bundle_group);
2026 remote_answer->AddGroup(invalid_bundle_group);
2027
2028 EXPECT_FALSE(transport_controller_
2029 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2030 .ok());
2031 EXPECT_FALSE(transport_controller_
2032 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2033 .ok());
2034}
2035
2036// This tests that an answer shouldn't be able to remove an m= section from an
2037// established group without rejecting it.
2038TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
2039 CreateJsepTransportController(JsepTransportController::Config());
2040
2041 auto local_offer = CreateSessionDescriptionWithBundleGroup();
2042 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
2043 EXPECT_TRUE(transport_controller_
2044 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2045 .ok());
2046 EXPECT_TRUE(transport_controller_
2047 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2048 .ok());
2049
2050 // Do an re-offer/answer.
2051 EXPECT_TRUE(transport_controller_
2052 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2053 .ok());
2054 auto new_answer = CreateSessionDescriptionWithoutBundle();
2055 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2056 // The answer removes video from the BUNDLE group without rejecting it is
2057 // invalid.
2058 new_bundle_group.AddContentName(kAudioMid1);
2059 new_answer->AddGroup(new_bundle_group);
2060
2061 // Applying invalid answer is expected to fail.
2062 EXPECT_FALSE(transport_controller_
2063 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2064 .ok());
2065
2066 // Rejected the video content.
2067 auto video_content = new_answer->GetContentByName(kVideoMid1);
2068 ASSERT_TRUE(video_content);
2069 video_content->rejected = true;
2070 EXPECT_TRUE(transport_controller_
2071 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2072 .ok());
2073}
2074
Steve Anton2bed3972019-01-04 17:04:30 -08002075// Test that the JsepTransportController can process a new local and remote
2076// description that changes the tagged BUNDLE group with the max-bundle policy
2077// specified.
2078// This is a regression test for bugs.webrtc.org/9954
2079TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
2080 CreateJsepTransportController(JsepTransportController::Config());
2081
2082 auto local_offer = absl::make_unique<cricket::SessionDescription>();
2083 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2084 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2085 nullptr);
2086 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
2087 bundle_group.AddContentName(kAudioMid1);
2088 local_offer->AddGroup(bundle_group);
2089 EXPECT_TRUE(transport_controller_
2090 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2091 .ok());
2092
2093 std::unique_ptr<cricket::SessionDescription> remote_answer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002094 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002095 EXPECT_TRUE(transport_controller_
2096 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2097 .ok());
2098
2099 std::unique_ptr<cricket::SessionDescription> local_reoffer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002100 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002101 local_reoffer->contents()[0].rejected = true;
2102 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
2103 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2104 nullptr);
2105 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
2106 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2107 new_bundle_group.AddContentName(kVideoMid1);
2108 local_reoffer->AddGroup(new_bundle_group);
2109
2110 EXPECT_TRUE(transport_controller_
2111 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
2112 .ok());
2113
2114 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002115 local_reoffer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002116 EXPECT_TRUE(
2117 transport_controller_
2118 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
2119 .ok());
2120}
2121
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07002122constexpr char kFakeTransportParameters[] = "fake-params";
2123
2124// Test fixture that provides common setup and helpers for tests related to the
2125// datagram transport.
2126class JsepTransportControllerDatagramTest
2127 : public JsepTransportControllerTest,
2128 public testing::WithParamInterface<bool> {
2129 public:
2130 JsepTransportControllerDatagramTest()
2131 : JsepTransportControllerTest(),
2132 fake_media_transport_factory_(kFakeTransportParameters) {
2133 JsepTransportController::Config config;
2134 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2135 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2136 config.media_transport_factory = &fake_media_transport_factory_;
2137 config.use_datagram_transport = true;
2138 CreateJsepTransportController(config);
2139 }
2140
2141 // Whether the JsepTransportController under test acts as the offerer or
2142 // answerer in this test.
2143 bool IsOfferer() { return GetParam(); }
2144
2145 // Sets a description as local or remote based on type and current
2146 // perspective.
2147 RTCError SetDescription(SdpType type,
2148 const cricket::SessionDescription* description) {
2149 if (IsOfferer() == (type == SdpType::kOffer)) {
2150 return transport_controller_->SetLocalDescription(type, description);
2151 } else {
2152 return transport_controller_->SetRemoteDescription(type, description);
2153 }
2154 }
2155
2156 // Creates a session description with the settings necessary for datagram
2157 // transport (bundle + crypto) and the given |transport_params|.
2158 std::unique_ptr<cricket::SessionDescription>
2159 CreateSessionDescriptionForDatagramTransport(
2160 absl::optional<cricket::OpaqueTransportParameters> transport_params) {
2161 auto description = CreateSessionDescriptionWithBundleGroup();
2162 AddCryptoSettings(description.get());
2163
2164 for (auto& info : description->transport_infos()) {
2165 info.description.opaque_parameters = transport_params;
2166 }
2167 return description;
2168 }
2169
2170 // Creates transport parameters with |protocol| and |parameters|
2171 // matching what |fake_media_transport_factory_| provides.
2172 cricket::OpaqueTransportParameters CreateTransportParameters() {
2173 cricket::OpaqueTransportParameters params;
2174 params.protocol = fake_media_transport_factory_.GetTransportName();
2175 params.parameters = "fake-params";
2176 return params;
2177 }
2178
2179 protected:
2180 FakeMediaTransportFactory fake_media_transport_factory_;
2181};
2182
2183TEST_P(JsepTransportControllerDatagramTest, InitDatagramTransport) {
2184 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2185 if (IsOfferer()) {
2186 // Getting transport parameters is allowed before setting a description.
2187 // This is necessary so that the offerer can include these params.
2188 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2189 fake_params);
2190 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2191 fake_params);
2192 }
2193
2194 // Setting a description activates the datagram transport without changing
2195 // transport parameters.
2196 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2197 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2198
2199 // After setting an offer with transport parameters, those parameters are
2200 // reflected by the controller.
2201 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2202 fake_params);
2203 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2204 fake_params);
2205}
2206
2207TEST_P(JsepTransportControllerDatagramTest,
2208 OfferMissingDatagramTransportParams) {
2209 if (IsOfferer()) {
2210 // This test doesn't make sense from the offerer's perspective, as the offer
2211 // must contain datagram transport params if the offerer supports it.
2212 return;
2213 }
2214
2215 auto description =
2216 CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2217 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2218
2219 // The offer didn't contain any datagram transport parameters, so the answer
2220 // won't either.
2221 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2222 absl::nullopt);
2223 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2224 absl::nullopt);
2225}
2226
2227TEST_P(JsepTransportControllerDatagramTest, OfferHasWrongTransportName) {
2228 if (IsOfferer()) {
2229 // This test doesn't make sense from the offerer's perspective, as the
2230 // offerer cannot offer itself the wrong transport.
2231 return;
2232 }
2233
2234 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2235 fake_params.protocol = "wrong-name";
2236
2237 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2238 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2239
2240 // The offerer and answerer support different datagram transports, so the
2241 // answerer rejects the offered parameters.
2242 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2243 absl::nullopt);
2244 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2245 absl::nullopt);
2246}
2247
2248TEST_P(JsepTransportControllerDatagramTest, AnswerRejectsDatagram) {
2249 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2250 if (IsOfferer()) {
2251 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2252 fake_params);
2253 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2254 fake_params);
2255 }
2256
2257 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2258 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2259
2260 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2261 fake_params);
2262 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2263 fake_params);
2264
2265 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2266 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2267
2268 // The answer rejected datagram transport, so its parameters are empty.
2269 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2270 absl::nullopt);
2271 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2272 absl::nullopt);
2273}
2274
2275TEST_P(JsepTransportControllerDatagramTest, AnswerAcceptsDatagram) {
2276 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2277 if (IsOfferer()) {
2278 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2279 fake_params);
2280 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2281 fake_params);
2282 }
2283
2284 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2285 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2286
2287 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2288 fake_params);
2289 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2290 fake_params);
2291
2292 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2293 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2294
2295 // The answer accepted datagram transport, so it is present.
2296 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2297 fake_params);
2298 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2299 fake_params);
2300}
2301
2302TEST_P(JsepTransportControllerDatagramTest, PrAnswerRejectsDatagram) {
2303 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2304 if (IsOfferer()) {
2305 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2306 fake_params);
2307 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2308 fake_params);
2309 }
2310
2311 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2312 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2313
2314 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2315 fake_params);
2316 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2317 fake_params);
2318
2319 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2320 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2321
2322 // The answer rejected datagram transport, but it's provisional, so the
2323 // transport is kept around for now.
2324 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2325 fake_params);
2326 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2327 fake_params);
2328}
2329
2330TEST_P(JsepTransportControllerDatagramTest, PrAnswerAcceptsDatagram) {
2331 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2332 if (IsOfferer()) {
2333 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2334 fake_params);
2335 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2336 fake_params);
2337 }
2338
2339 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2340 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2341
2342 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2343 fake_params);
2344 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2345 fake_params);
2346
2347 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2348 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2349
2350 // The answer provisionally accepted datagram transport, so it's kept.
2351 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2352 fake_params);
2353 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2354 fake_params);
2355}
2356
2357TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotAddDatagram) {
2358 auto offer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2359 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2360
2361 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2362 absl::nullopt);
2363 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2364 absl::nullopt);
2365
2366 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2367 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2368
2369 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2370 absl::nullopt);
2371 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2372 absl::nullopt);
2373
2374 // Attempting to add a datagram transport on a re-offer does not cause an
2375 // error, but also does not add a datagram transport.
2376 auto reoffer =
2377 CreateSessionDescriptionForDatagramTransport(CreateTransportParameters());
2378 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2379
2380 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2381 absl::nullopt);
2382 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2383 absl::nullopt);
2384}
2385
2386TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotRemoveDatagram) {
2387 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2388 if (IsOfferer()) {
2389 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2390 fake_params);
2391 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2392 fake_params);
2393 }
2394
2395 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2396 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2397
2398 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2399 fake_params);
2400 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2401 fake_params);
2402
2403 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2404 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2405
2406 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2407 fake_params);
2408 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2409 fake_params);
2410
2411 // Attempting to remove a datagram transport on a re-offer does not cause an
2412 // error, but also does not remove the datagram transport.
2413 auto reoffer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2414 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2415
2416 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2417 fake_params);
2418 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2419 fake_params);
2420}
2421
2422TEST_P(JsepTransportControllerDatagramTest,
2423 RenegotiationKeepsDatagramTransport) {
2424 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2425 if (IsOfferer()) {
2426 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2427 fake_params);
2428 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2429 fake_params);
2430 }
2431
2432 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2433 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2434
2435 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2436 fake_params);
2437 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2438 fake_params);
2439
2440 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2441 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2442
2443 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2444 fake_params);
2445 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2446 fake_params);
2447
2448 // Attempting to remove a datagram transport on a re-offer does not cause an
2449 // error, but also does not remove the datagram transport.
2450 auto reoffer = CreateSessionDescriptionForDatagramTransport(fake_params);
2451 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2452
2453 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2454 fake_params);
2455 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2456 fake_params);
2457
2458 auto reanswer = CreateSessionDescriptionForDatagramTransport(fake_params);
2459 EXPECT_TRUE(SetDescription(SdpType::kAnswer, reanswer.get()).ok());
2460
2461 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2462 fake_params);
2463 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2464 fake_params);
2465}
2466
2467INSTANTIATE_TEST_SUITE_P(
2468 JsepTransportControllerDatagramTests,
2469 JsepTransportControllerDatagramTest,
2470 testing::Values(true, false),
2471 // The parameter value is the local perspective (offerer or answerer).
2472 [](const testing::TestParamInfo<bool>& info) {
2473 return info.param ? "Offerer" : "Answerer";
2474 });
2475
Zhi Huange818b6e2018-02-22 15:26:27 -08002476} // namespace webrtc