blob: b96a99937553fa369587c0e14eb1fcce1ad603bc [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
Anton Sukhanov7940da02018-10-10 10:34:49 -070016#include "api/test/fake_media_transport.h"
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -080017#include "api/test/loopback_media_transport.h"
Niels Möller65f17ca2019-09-12 13:59:36 +020018#include "api/transport/media/media_transport_interface.h"
Qingsi Wang25ec8882019-11-15 12:33:05 -080019#include "p2p/base/dtls_transport_factory.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_info.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080025#include "rtc_base/thread.h"
26#include "test/gtest.h"
27
Zhi Huange818b6e2018-02-22 15:26:27 -080028using cricket::Candidate;
29using cricket::Candidates;
Jonas Olssona4d87372019-07-05 19:08:33 +020030using cricket::FakeDtlsTransport;
Zhi Huange818b6e2018-02-22 15:26:27 -080031using webrtc::SdpType;
32
33static const int kTimeout = 100;
34static const char kIceUfrag1[] = "u0001";
35static const char kIcePwd1[] = "TESTICEPWD00000000000001";
36static const char kIceUfrag2[] = "u0002";
37static const char kIcePwd2[] = "TESTICEPWD00000000000002";
38static const char kIceUfrag3[] = "u0003";
39static const char kIcePwd3[] = "TESTICEPWD00000000000003";
40static const char kAudioMid1[] = "audio1";
41static const char kAudioMid2[] = "audio2";
42static const char kVideoMid1[] = "video1";
43static const char kVideoMid2[] = "video2";
44static const char kDataMid1[] = "data1";
45
46namespace webrtc {
47
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070048namespace {
49
50// Media transport factory requires crypto settings to be present in order to
51// create media transport.
52void AddCryptoSettings(cricket::SessionDescription* description) {
53 for (auto& content : description->contents()) {
54 content.media_description()->AddCrypto(cricket::CryptoParams(
55 /*t=*/0, std::string(rtc::CS_AES_CM_128_HMAC_SHA1_80),
56 "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2", ""));
57 }
58}
59
60} // namespace
61
Qingsi Wang25ec8882019-11-15 12:33:05 -080062class FakeIceTransportFactory : public webrtc::IceTransportFactory {
Zhi Huange818b6e2018-02-22 15:26:27 -080063 public:
Qingsi Wang25ec8882019-11-15 12:33:05 -080064 ~FakeIceTransportFactory() override = default;
65 rtc::scoped_refptr<IceTransportInterface> CreateIceTransport(
Zhi Huange818b6e2018-02-22 15:26:27 -080066 const std::string& transport_name,
Qingsi Wang25ec8882019-11-15 12:33:05 -080067 int component,
68 IceTransportInit init) override {
69 return new rtc::RefCountedObject<cricket::FakeIceTransportWrapper>(
70 std::make_unique<cricket::FakeIceTransport>(transport_name, component));
Zhi Huange818b6e2018-02-22 15:26:27 -080071 }
Qingsi Wang25ec8882019-11-15 12:33:05 -080072};
Zhi Huange818b6e2018-02-22 15:26:27 -080073
Qingsi Wang25ec8882019-11-15 12:33:05 -080074class FakeDtlsTransportFactory : public cricket::DtlsTransportFactory {
75 public:
Zhi Huange818b6e2018-02-22 15:26:27 -080076 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070077 cricket::IceTransportInternal* ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070078 const webrtc::CryptoOptions& crypto_options) override {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020079 return std::make_unique<FakeDtlsTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070080 static_cast<cricket::FakeIceTransport*>(ice));
Zhi Huange818b6e2018-02-22 15:26:27 -080081 }
82};
83
Zhi Huang365381f2018-04-13 16:44:34 -070084class JsepTransportControllerTest : public JsepTransportController::Observer,
Mirko Bonadei6a489f22019-04-09 15:11:12 +020085 public ::testing::Test,
Zhi Huange818b6e2018-02-22 15:26:27 -080086 public sigslot::has_slots<> {
87 public:
88 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Qingsi Wang25ec8882019-11-15 12:33:05 -080089 fake_ice_transport_factory_ = std::make_unique<FakeIceTransportFactory>();
90 fake_dtls_transport_factory_ = std::make_unique<FakeDtlsTransportFactory>();
Zhi Huange818b6e2018-02-22 15:26:27 -080091 }
92
93 void CreateJsepTransportController(
94 JsepTransportController::Config config,
95 rtc::Thread* signaling_thread = rtc::Thread::Current(),
96 rtc::Thread* network_thread = rtc::Thread::Current(),
97 cricket::PortAllocator* port_allocator = nullptr) {
Zhi Huang365381f2018-04-13 16:44:34 -070098 config.transport_observer = this;
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +020099 config.rtcp_handler = [](const rtc::CopyOnWriteBuffer& packet,
100 int64_t packet_time_us) { RTC_NOTREACHED(); };
Qingsi Wang25ec8882019-11-15 12:33:05 -0800101 config.ice_transport_factory = fake_ice_transport_factory_.get();
102 config.dtls_transport_factory = fake_dtls_transport_factory_.get();
Zach Steine20867f2018-08-02 13:20:15 -0700103 // TODO(zstein): Provide an AsyncResolverFactory once it is required.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200104 transport_controller_ = std::make_unique<JsepTransportController>(
Zach Steine20867f2018-08-02 13:20:15 -0700105 signaling_thread, network_thread, port_allocator, nullptr, config);
Zhi Huange818b6e2018-02-22 15:26:27 -0800106 ConnectTransportControllerSignals();
107 }
108
109 void ConnectTransportControllerSignals() {
110 transport_controller_->SignalIceConnectionState.connect(
111 this, &JsepTransportControllerTest::OnConnectionState);
Alex Loiko9289eda2018-11-23 16:18:59 +0000112 transport_controller_->SignalStandardizedIceConnectionState.connect(
113 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200114 transport_controller_->SignalConnectionState.connect(
115 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800116 transport_controller_->SignalIceGatheringState.connect(
117 this, &JsepTransportControllerTest::OnGatheringState);
118 transport_controller_->SignalIceCandidatesGathered.connect(
119 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800120 }
121
122 std::unique_ptr<cricket::SessionDescription>
123 CreateSessionDescriptionWithoutBundle() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200124 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800125 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
126 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
127 nullptr);
128 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
129 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
130 nullptr);
131 return description;
132 }
133
134 std::unique_ptr<cricket::SessionDescription>
135 CreateSessionDescriptionWithBundleGroup() {
136 auto description = CreateSessionDescriptionWithoutBundle();
137 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
138 bundle_group.AddContentName(kAudioMid1);
139 bundle_group.AddContentName(kVideoMid1);
140 description->AddGroup(bundle_group);
141
142 return description;
143 }
144
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700145 std::unique_ptr<cricket::SessionDescription>
146 CreateSessionDescriptionWithBundledData() {
147 auto description = CreateSessionDescriptionWithoutBundle();
148 AddDataSection(description.get(), kDataMid1,
149 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
150 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
151 nullptr);
152 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
153 bundle_group.AddContentName(kAudioMid1);
154 bundle_group.AddContentName(kVideoMid1);
155 bundle_group.AddContentName(kDataMid1);
156 description->AddGroup(bundle_group);
157 return description;
158 }
159
Zhi Huange818b6e2018-02-22 15:26:27 -0800160 void AddAudioSection(cricket::SessionDescription* description,
161 const std::string& mid,
162 const std::string& ufrag,
163 const std::string& pwd,
164 cricket::IceMode ice_mode,
165 cricket::ConnectionRole conn_role,
166 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
167 std::unique_ptr<cricket::AudioContentDescription> audio(
168 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700169 // Set RTCP-mux to be true because the default policy is "mux required".
170 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800171 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200172 /*rejected=*/false, std::move(audio));
Zhi Huange818b6e2018-02-22 15:26:27 -0800173 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
174 }
175
176 void AddVideoSection(cricket::SessionDescription* description,
177 const std::string& mid,
178 const std::string& ufrag,
179 const std::string& pwd,
180 cricket::IceMode ice_mode,
181 cricket::ConnectionRole conn_role,
182 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
183 std::unique_ptr<cricket::VideoContentDescription> video(
184 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700185 // Set RTCP-mux to be true because the default policy is "mux required".
186 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800187 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200188 /*rejected=*/false, std::move(video));
Zhi Huange818b6e2018-02-22 15:26:27 -0800189 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
190 }
191
192 void AddDataSection(cricket::SessionDescription* description,
193 const std::string& mid,
194 cricket::MediaProtocolType protocol_type,
195 const std::string& ufrag,
196 const std::string& pwd,
197 cricket::IceMode ice_mode,
198 cricket::ConnectionRole conn_role,
199 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200200 RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp);
201 std::unique_ptr<cricket::SctpDataContentDescription> data(
202 new cricket::SctpDataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700203 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800204 description->AddContent(mid, protocol_type,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200205 /*rejected=*/false, std::move(data));
Zhi Huange818b6e2018-02-22 15:26:27 -0800206 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
207 }
208
209 void AddTransportInfo(cricket::SessionDescription* description,
210 const std::string& mid,
211 const std::string& ufrag,
212 const std::string& pwd,
213 cricket::IceMode ice_mode,
214 cricket::ConnectionRole conn_role,
215 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
216 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
217 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700218 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800219 }
220
221 cricket::TransportDescription transport_desc(std::vector<std::string>(),
222 ufrag, pwd, ice_mode,
223 conn_role, fingerprint.get());
224 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
225 }
226
227 cricket::IceConfig CreateIceConfig(
228 int receiving_timeout,
229 cricket::ContinualGatheringPolicy continual_gathering_policy) {
230 cricket::IceConfig config;
231 config.receiving_timeout = receiving_timeout;
232 config.continual_gathering_policy = continual_gathering_policy;
233 return config;
234 }
235
236 Candidate CreateCandidate(const std::string& transport_name, int component) {
237 Candidate c;
238 c.set_transport_name(transport_name);
239 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
240 c.set_component(component);
241 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
242 c.set_priority(1);
243 return c;
244 }
245
246 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
247 if (!network_thread_->IsCurrent()) {
248 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
249 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
250 });
251 return;
252 }
253
254 auto description = CreateSessionDescriptionWithBundleGroup();
255 EXPECT_TRUE(transport_controller_
256 ->SetLocalDescription(SdpType::kOffer, description.get())
257 .ok());
258
259 transport_controller_->MaybeStartGathering();
260 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
261 transport_controller_->GetDtlsTransport(kAudioMid1));
262 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
263 transport_controller_->GetDtlsTransport(kVideoMid1));
264 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
265 fake_audio_dtls->fake_ice_transport(),
266 CreateCandidate(kAudioMid1, /*component=*/1));
267 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
268 fake_video_dtls->fake_ice_transport(),
269 CreateCandidate(kVideoMid1, /*component=*/1));
270 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
271 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
272 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
273 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
274 fake_audio_dtls->SetReceiving(true);
275 fake_video_dtls->SetReceiving(true);
276 fake_audio_dtls->SetWritable(true);
277 fake_video_dtls->SetWritable(true);
278 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
279 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
280 }
281
282 protected:
Alex Loiko9289eda2018-11-23 16:18:59 +0000283 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800284 if (!signaling_thread_->IsCurrent()) {
285 signaled_on_non_signaling_thread_ = true;
286 }
287 connection_state_ = state;
288 ++connection_state_signal_count_;
289 }
290
Alex Loiko9289eda2018-11-23 16:18:59 +0000291 void OnStandardizedIceConnectionState(
292 PeerConnectionInterface::IceConnectionState state) {
293 if (!signaling_thread_->IsCurrent()) {
294 signaled_on_non_signaling_thread_ = true;
295 }
296 ice_connection_state_ = state;
297 ++ice_connection_state_signal_count_;
298 }
299
Jonas Olsson635474e2018-10-18 15:58:17 +0200300 void OnCombinedConnectionState(
301 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100302 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
303 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 15:58:17 +0200304 if (!signaling_thread_->IsCurrent()) {
305 signaled_on_non_signaling_thread_ = true;
306 }
307 combined_connection_state_ = state;
308 ++combined_connection_state_signal_count_;
309 }
310
Zhi Huange818b6e2018-02-22 15:26:27 -0800311 void OnGatheringState(cricket::IceGatheringState state) {
312 if (!signaling_thread_->IsCurrent()) {
313 signaled_on_non_signaling_thread_ = true;
314 }
315 gathering_state_ = state;
316 ++gathering_state_signal_count_;
317 }
318
319 void OnCandidatesGathered(const std::string& transport_name,
320 const Candidates& candidates) {
321 if (!signaling_thread_->IsCurrent()) {
322 signaled_on_non_signaling_thread_ = true;
323 }
324 candidates_[transport_name].insert(candidates_[transport_name].end(),
325 candidates.begin(), candidates.end());
326 ++candidates_signal_count_;
327 }
328
Zhi Huang365381f2018-04-13 16:44:34 -0700329 // JsepTransportController::Observer overrides.
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700330 bool OnTransportChanged(
331 const std::string& mid,
332 RtpTransportInternal* rtp_transport,
333 rtc::scoped_refptr<DtlsTransport> dtls_transport,
334 MediaTransportInterface* media_transport,
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700335 DataChannelTransportInterface* data_channel_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700336 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100337 if (dtls_transport) {
338 changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
339 } else {
340 changed_dtls_transport_by_mid_[mid] = nullptr;
341 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800342 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700343 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800344 }
345
346 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000347 cricket::IceConnectionState connection_state_ =
348 cricket::kIceConnectionConnecting;
349 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200350 PeerConnectionInterface::kIceConnectionNew;
351 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
352 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800353 bool receiving_ = false;
354 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
355 // transport_name => candidates
356 std::map<std::string, Candidates> candidates_;
357 // Counts of each signal emitted.
358 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000359 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200360 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800361 int receiving_signal_count_ = 0;
362 int gathering_state_signal_count_ = 0;
363 int candidates_signal_count_ = 0;
364
365 // |network_thread_| should be destroyed after |transport_controller_|
366 std::unique_ptr<rtc::Thread> network_thread_;
Qingsi Wang25ec8882019-11-15 12:33:05 -0800367 std::unique_ptr<FakeIceTransportFactory> fake_ice_transport_factory_;
368 std::unique_ptr<FakeDtlsTransportFactory> fake_dtls_transport_factory_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800369 rtc::Thread* const signaling_thread_ = nullptr;
370 bool signaled_on_non_signaling_thread_ = false;
371 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
372 // signaled correctly.
373 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
374 std::map<std::string, cricket::DtlsTransportInternal*>
375 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800376 std::map<std::string, MediaTransportInterface*>
377 changed_media_transport_by_mid_;
378
379 // Transport controller needs to be destroyed first, because it may issue
380 // callbacks that modify the changed_*_by_mid in the destructor.
381 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800382};
383
384TEST_F(JsepTransportControllerTest, GetRtpTransport) {
385 CreateJsepTransportController(JsepTransportController::Config());
386 auto description = CreateSessionDescriptionWithoutBundle();
387 EXPECT_TRUE(transport_controller_
388 ->SetLocalDescription(SdpType::kOffer, description.get())
389 .ok());
390 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
391 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
392 EXPECT_NE(nullptr, audio_rtp_transport);
393 EXPECT_NE(nullptr, video_rtp_transport);
394 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
395 // Return nullptr for non-existing ones.
396 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
397}
398
399TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
400 JsepTransportController::Config config;
401 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
402 CreateJsepTransportController(config);
403 auto description = CreateSessionDescriptionWithoutBundle();
404 EXPECT_TRUE(transport_controller_
405 ->SetLocalDescription(SdpType::kOffer, description.get())
406 .ok());
407 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
408 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100409 EXPECT_NE(nullptr,
410 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800411 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
412 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100413 EXPECT_NE(nullptr,
414 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
415 // Lookup for all MIDs should return different transports (no bundle)
416 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
417 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800418 // Return nullptr for non-existing ones.
419 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
420 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100421 EXPECT_EQ(nullptr,
422 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100423 // Take a pointer to a transport, shut down the transport controller,
424 // and verify that the resulting container is empty.
425 auto dtls_transport =
426 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
427 webrtc::DtlsTransport* my_transport =
428 static_cast<DtlsTransport*>(dtls_transport.get());
429 EXPECT_NE(nullptr, my_transport->internal());
430 transport_controller_.reset();
431 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800432}
433
Zhi Huange830e682018-03-30 10:48:35 -0700434TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
435 JsepTransportController::Config config;
436 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
437 CreateJsepTransportController(config);
438 auto description = CreateSessionDescriptionWithoutBundle();
439 EXPECT_TRUE(transport_controller_
440 ->SetLocalDescription(SdpType::kOffer, description.get())
441 .ok());
442 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
443 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
444 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
445 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700446 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
447}
448
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800449TEST_F(JsepTransportControllerTest,
450 DtlsIsStillCreatedIfMediaTransportIsOnlyUsedForDataChannels) {
451 FakeMediaTransportFactory fake_media_transport_factory;
452 JsepTransportController::Config config;
453
454 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800455 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800456 config.media_transport_factory = &fake_media_transport_factory;
457 config.use_media_transport_for_data_channels = true;
458 CreateJsepTransportController(config);
459 auto description = CreateSessionDescriptionWithBundleGroup();
460 AddCryptoSettings(description.get());
461
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800462 EXPECT_NE(absl::nullopt,
463 transport_controller_->GenerateOrGetLastMediaTransportOffer());
464
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800465 EXPECT_TRUE(transport_controller_
466 ->SetLocalDescription(SdpType::kOffer, description.get())
467 .ok());
468
469 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700470 transport_controller_->GetDataChannelTransport(kAudioMid1));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800471
472 ASSERT_NE(nullptr, media_transport);
473
474 // After SetLocalDescription, media transport should be created as caller.
475 EXPECT_TRUE(media_transport->is_caller());
476 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
477
478 // Return nullptr for non-existing mids.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700479 EXPECT_EQ(nullptr,
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700480 transport_controller_->GetDataChannelTransport(kVideoMid2));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800481
482 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
483 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
484 << "Media transport for media was not enabled, and so DTLS transport "
485 "should be created.";
486}
487
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700488TEST_F(JsepTransportControllerTest,
489 DtlsIsStillCreatedIfDatagramTransportIsOnlyUsedForDataChannels) {
490 FakeMediaTransportFactory fake_media_transport_factory("transport_params");
491 JsepTransportController::Config config;
492
493 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
494 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
495 config.media_transport_factory = &fake_media_transport_factory;
496 config.use_datagram_transport_for_data_channels = true;
497 CreateJsepTransportController(config);
498
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700499 auto description = CreateSessionDescriptionWithBundledData();
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700500 AddCryptoSettings(description.get());
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700501
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700502 absl::optional<cricket::OpaqueTransportParameters> params =
503 transport_controller_->GetTransportParameters(kAudioMid1);
504 for (auto& info : description->transport_infos()) {
505 info.description.opaque_parameters = params;
506 }
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700507 for (cricket::ContentInfo& content_info : description->contents()) {
508 if (content_info.media_description()->type() == cricket::MEDIA_TYPE_DATA) {
509 content_info.media_description()->set_alt_protocol(params->protocol);
510 }
511 }
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700512
513 EXPECT_TRUE(transport_controller_
514 ->SetLocalDescription(SdpType::kOffer, description.get())
515 .ok());
516 EXPECT_TRUE(transport_controller_
517 ->SetRemoteDescription(SdpType::kAnswer, description.get())
518 .ok());
519
520 FakeDatagramTransport* datagram_transport =
521 static_cast<FakeDatagramTransport*>(
522 transport_controller_->GetDataChannelTransport(kAudioMid1));
523
524 ASSERT_NE(nullptr, datagram_transport);
525
526 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
527 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
528 << "Datagram transport for media was not enabled, and so DTLS transport "
529 "should be created.";
530
531 // Datagram transport is not used for media, so no max packet size is
532 // specified.
533 EXPECT_EQ(transport_controller_->GetMediaTransportConfig(kAudioMid1)
534 .rtp_max_packet_size,
535 absl::nullopt);
536
537 // Since datagram transport is not used for RTP, setting it to writable should
538 // not make the RTP transport writable.
539 datagram_transport->set_state(MediaTransportState::kWritable);
540 EXPECT_FALSE(transport_controller_->GetRtpTransport(kAudioMid1)
541 ->IsWritable(/*rtcp=*/false));
542}
543
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700544// An offer that bundles different alt-protocols should be rejected.
545TEST_F(JsepTransportControllerTest, CannotBundleDifferentAltProtocols) {
546 FakeMediaTransportFactory fake_media_transport_factory("transport_params");
547 JsepTransportController::Config config;
548 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
549 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
550 config.media_transport_factory = &fake_media_transport_factory;
551 config.use_datagram_transport = true;
552 config.use_datagram_transport_for_data_channels = true;
553 CreateJsepTransportController(config);
554
555 auto description = CreateSessionDescriptionWithBundledData();
556 AddCryptoSettings(description.get());
557
558 absl::optional<cricket::OpaqueTransportParameters> params =
559 transport_controller_->GetTransportParameters(kAudioMid1);
560 for (auto& info : description->transport_infos()) {
561 info.description.opaque_parameters = params;
562 }
563
564 // Append a different alt-protocol to each of the sections.
565 for (cricket::ContentInfo& content_info : description->contents()) {
566 content_info.media_description()->set_alt_protocol(params->protocol + "-" +
567 content_info.name);
568 }
569
570 EXPECT_FALSE(transport_controller_
571 ->SetLocalDescription(SdpType::kOffer, description.get())
572 .ok());
573 EXPECT_FALSE(transport_controller_
574 ->SetRemoteDescription(SdpType::kAnswer, description.get())
575 .ok());
576}
577
Anton Sukhanov7940da02018-10-10 10:34:49 -0700578TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
579 FakeMediaTransportFactory fake_media_transport_factory;
580 JsepTransportController::Config config;
581
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800582 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800583 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700584 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800585 config.use_media_transport_for_data_channels = true;
586 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700587 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800588 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700589 AddCryptoSettings(description.get());
590
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800591 EXPECT_NE(absl::nullopt,
592 transport_controller_->GenerateOrGetLastMediaTransportOffer());
593
Anton Sukhanov7940da02018-10-10 10:34:49 -0700594 EXPECT_TRUE(transport_controller_
595 ->SetLocalDescription(SdpType::kOffer, description.get())
596 .ok());
597
598 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
599 transport_controller_->GetMediaTransport(kAudioMid1));
600
601 ASSERT_NE(nullptr, media_transport);
602
603 // After SetLocalDescription, media transport should be created as caller.
604 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800605 // We set the pre-shared key on the caller.
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700606 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800607 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700608
609 // Return nullptr for non-existing mids.
610 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800611
612 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
613 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
614 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700615}
616
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800617TEST_F(JsepTransportControllerTest,
618 GetMediaTransportOfferInTheConfigOnSubsequentCalls) {
619 FakeMediaTransportFactory fake_media_transport_factory;
620 WrapperMediaTransportFactory wrapping_factory(&fake_media_transport_factory);
621 JsepTransportController::Config config;
622
623 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
624 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
625 config.media_transport_factory = &wrapping_factory;
626 config.use_media_transport_for_data_channels = true;
627 config.use_media_transport_for_media = true;
628 CreateJsepTransportController(config);
629 auto description = CreateSessionDescriptionWithBundleGroup();
630 AddCryptoSettings(description.get());
631
632 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
633 transport_controller_->GenerateOrGetLastMediaTransportOffer();
634 ASSERT_NE(absl::nullopt, settings);
635
636 EXPECT_TRUE(transport_controller_
637 ->SetLocalDescription(SdpType::kOffer, description.get())
638 .ok());
639
640 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
641 transport_controller_->GetMediaTransport(kAudioMid1));
642
643 ASSERT_NE(nullptr, media_transport);
644
645 absl::optional<cricket::SessionDescription::MediaTransportSetting>
646 new_settings =
647 transport_controller_->GenerateOrGetLastMediaTransportOffer();
648 ASSERT_NE(absl::nullopt, new_settings);
649 EXPECT_EQ(settings->transport_name, new_settings->transport_name);
650 EXPECT_EQ(settings->transport_setting, new_settings->transport_setting);
651 EXPECT_EQ(1, wrapping_factory.created_transport_count());
652}
653
Anton Sukhanov7940da02018-10-10 10:34:49 -0700654TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
655 FakeMediaTransportFactory fake_media_transport_factory;
656 JsepTransportController::Config config;
657
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800658 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700659 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800660 config.use_media_transport_for_data_channels = true;
661 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700662 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800663 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700664 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800665 description->AddMediaTransportSetting("fake", "fake-remote-settings");
Anton Sukhanov7940da02018-10-10 10:34:49 -0700666 EXPECT_TRUE(transport_controller_
667 ->SetRemoteDescription(SdpType::kOffer, description.get())
668 .ok());
669
670 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
671 transport_controller_->GetMediaTransport(kAudioMid1));
672
673 ASSERT_NE(nullptr, media_transport);
674
675 // After SetRemoteDescription, media transport should be created as callee.
676 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800677 // We do not set pre-shared key on the callee, it comes in media transport
678 // settings.
679 EXPECT_EQ(absl::nullopt, media_transport->settings().pre_shared_key);
680 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700681
682 // Return nullptr for non-existing mids.
683 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800684
685 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
686 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
687 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700688}
689
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800690TEST_F(JsepTransportControllerTest, GetMediaTransportInCalleePassesSdp) {
691 FakeMediaTransportFactory fake_media_transport_factory;
692 JsepTransportController::Config config;
693
694 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
695 config.media_transport_factory = &fake_media_transport_factory;
696 config.use_media_transport_for_data_channels = true;
697 config.use_media_transport_for_media = true;
698 CreateJsepTransportController(config);
699 auto description = CreateSessionDescriptionWithBundleGroup();
700 AddCryptoSettings(description.get());
701 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
702 EXPECT_TRUE(transport_controller_
703 ->SetRemoteDescription(SdpType::kOffer, description.get())
704 .ok());
705
706 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
707 transport_controller_->GetMediaTransport(kAudioMid1));
708
709 ASSERT_NE(nullptr, media_transport);
710
711 EXPECT_EQ("this-is-a-test-setting",
712 media_transport->settings().remote_transport_parameters);
713}
714
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800715// Caller generates the offer if media transport returns empty offer (no
716// parameters).
717TEST_F(JsepTransportControllerTest, MediaTransportGeneratesSessionDescription) {
718 FakeMediaTransportFactory fake_media_transport_factory(
719 /*transport_offer=*/"");
720 JsepTransportController::Config config;
721
722 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
723 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
724 config.media_transport_factory = &fake_media_transport_factory;
725 config.use_media_transport_for_data_channels = true;
726 config.use_media_transport_for_media = true;
727 CreateJsepTransportController(config);
728 auto description = CreateSessionDescriptionWithBundleGroup();
729 AddCryptoSettings(description.get());
730 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
731 transport_controller_->GenerateOrGetLastMediaTransportOffer();
732
733 ASSERT_TRUE(settings.has_value());
734 EXPECT_EQ("fake", settings->transport_name);
735 // Fake media transport returns empty settings (but not nullopt settings!)
736 EXPECT_EQ("", settings->transport_setting);
737}
738
739// Caller generates the offer if media transport returns offer with parameters.
740TEST_F(JsepTransportControllerTest,
741 MediaTransportGeneratesSessionDescriptionWithOfferParams) {
742 FakeMediaTransportFactory fake_media_transport_factory(
743 /*transport_offer=*/"offer-params");
744 JsepTransportController::Config config;
745
746 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
747 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
748 config.media_transport_factory = &fake_media_transport_factory;
749 config.use_media_transport_for_data_channels = true;
750 config.use_media_transport_for_media = true;
751 CreateJsepTransportController(config);
752 auto description = CreateSessionDescriptionWithBundleGroup();
753 AddCryptoSettings(description.get());
754 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
755 transport_controller_->GenerateOrGetLastMediaTransportOffer();
756
757 ASSERT_TRUE(settings.has_value());
758 EXPECT_EQ("fake", settings->transport_name);
759 EXPECT_EQ("offer-params", settings->transport_setting);
760}
761
762// Caller skips the offer if media transport requests it.
763TEST_F(JsepTransportControllerTest,
764 MediaTransportGeneratesSkipsSessionDescription) {
765 FakeMediaTransportFactory fake_media_transport_factory(
766 /*transport_offer=*/absl::nullopt);
767 JsepTransportController::Config config;
768
769 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
770 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
771 config.media_transport_factory = &fake_media_transport_factory;
772 config.use_media_transport_for_data_channels = true;
773 config.use_media_transport_for_media = true;
774 CreateJsepTransportController(config);
775 auto description = CreateSessionDescriptionWithBundleGroup();
776 AddCryptoSettings(description.get());
777 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
778 transport_controller_->GenerateOrGetLastMediaTransportOffer();
779
780 // Fake media transport returns nullopt settings
781 ASSERT_EQ(absl::nullopt, settings);
782}
783
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800784// Caller ignores its own outgoing parameters.
785TEST_F(JsepTransportControllerTest,
786 GetMediaTransportInCallerIgnoresXmtSection) {
787 FakeMediaTransportFactory fake_media_transport_factory;
788 JsepTransportController::Config config;
789
790 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800791 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800792 config.media_transport_factory = &fake_media_transport_factory;
793 config.use_media_transport_for_data_channels = true;
794 config.use_media_transport_for_media = true;
795 CreateJsepTransportController(config);
796 auto description = CreateSessionDescriptionWithBundleGroup();
797 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800798 EXPECT_NE(absl::nullopt,
799 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800800 EXPECT_TRUE(transport_controller_
801 ->SetLocalDescription(SdpType::kOffer, description.get())
802 .ok());
803
804 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
805 transport_controller_->GetMediaTransport(kAudioMid1));
806
807 ASSERT_NE(nullptr, media_transport);
808
809 // Remote parameters are nullopt, because we are the offerer (we don't)
810 // have the remote transport parameters, only ours.
811 EXPECT_EQ(absl::nullopt,
812 media_transport->settings().remote_transport_parameters);
813}
814
815TEST_F(JsepTransportControllerTest,
816 GetMediaTransportInCalleeIgnoresDifferentTransport) {
817 FakeMediaTransportFactory fake_media_transport_factory;
818 JsepTransportController::Config config;
819
820 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800821 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800822 config.media_transport_factory = &fake_media_transport_factory;
823 config.use_media_transport_for_data_channels = true;
824 config.use_media_transport_for_media = true;
825 CreateJsepTransportController(config);
826 auto description = CreateSessionDescriptionWithBundleGroup();
827 AddCryptoSettings(description.get());
828 description->AddMediaTransportSetting("not-a-fake-transport",
829 "this-is-a-test-setting");
830 EXPECT_TRUE(transport_controller_
831 ->SetRemoteDescription(SdpType::kOffer, description.get())
832 .ok());
833
834 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
835 transport_controller_->GetMediaTransport(kAudioMid1));
836
837 ASSERT_NE(nullptr, media_transport);
838
839 EXPECT_EQ(absl::nullopt,
840 media_transport->settings().remote_transport_parameters);
841}
842
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700843TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
844 FakeMediaTransportFactory fake_media_transport_factory;
845 JsepTransportController::Config config;
846
847 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800848 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700849 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800850 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700851 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800852 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700853 EXPECT_TRUE(transport_controller_
854 ->SetRemoteDescription(SdpType::kOffer, description.get())
855 .ok());
856
857 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
858
859 // Even if we set local description with crypto now (after the remote offer
860 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800861 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700862 AddCryptoSettings(description2.get());
863 EXPECT_TRUE(transport_controller_
864 ->SetLocalDescription(SdpType::kAnswer, description2.get())
865 .ok());
866
867 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800868 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
869 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
870 << "Because media transport is NOT used (fallback to RTP), expected "
871 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700872}
873
874TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800875 AfterSettingAnswerTheSameMediaTransportIsReturnedCallee) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700876 FakeMediaTransportFactory fake_media_transport_factory;
877 JsepTransportController::Config config;
878
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800879 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800880 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700881 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800882 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700883 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800884 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700885 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800886 description->AddMediaTransportSetting("fake", "fake-settings");
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700887 EXPECT_TRUE(transport_controller_
888 ->SetRemoteDescription(SdpType::kOffer, description.get())
889 .ok());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700890 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
891 transport_controller_->GetMediaTransport(kAudioMid1));
892 EXPECT_NE(nullptr, media_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800893 EXPECT_FALSE(media_transport->pre_shared_key().has_value())
894 << "On the callee, preshared key is passed through the media-transport "
895 "settings (x-mt)";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700896
897 // Even if we set local description with crypto now (after the remote offer
898 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800899 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700900 AddCryptoSettings(description2.get());
901
902 RTCError result = transport_controller_->SetLocalDescription(
903 SdpType::kAnswer, description2.get());
904 EXPECT_TRUE(result.ok()) << result.message();
905
906 // Media transport did not change.
907 EXPECT_EQ(media_transport,
908 transport_controller_->GetMediaTransport(kAudioMid1));
909}
910
Zhi Huange818b6e2018-02-22 15:26:27 -0800911TEST_F(JsepTransportControllerTest, SetIceConfig) {
912 CreateJsepTransportController(JsepTransportController::Config());
913 auto description = CreateSessionDescriptionWithoutBundle();
914 EXPECT_TRUE(transport_controller_
915 ->SetLocalDescription(SdpType::kOffer, description.get())
916 .ok());
917
918 transport_controller_->SetIceConfig(
919 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
920 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
921 transport_controller_->GetDtlsTransport(kAudioMid1));
922 ASSERT_NE(nullptr, fake_audio_dtls);
923 EXPECT_EQ(kTimeout,
924 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
925 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
926
927 // Test that value stored in controller is applied to new transports.
928 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
929 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
930 nullptr);
931
932 EXPECT_TRUE(transport_controller_
933 ->SetLocalDescription(SdpType::kOffer, description.get())
934 .ok());
935 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
936 transport_controller_->GetDtlsTransport(kAudioMid2));
937 ASSERT_NE(nullptr, fake_audio_dtls);
938 EXPECT_EQ(kTimeout,
939 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
940 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
941}
942
943// Tests the getter and setter of the ICE restart flag.
944TEST_F(JsepTransportControllerTest, NeedIceRestart) {
945 CreateJsepTransportController(JsepTransportController::Config());
946 auto description = CreateSessionDescriptionWithoutBundle();
947 EXPECT_TRUE(transport_controller_
948 ->SetLocalDescription(SdpType::kOffer, description.get())
949 .ok());
950 EXPECT_TRUE(transport_controller_
951 ->SetRemoteDescription(SdpType::kAnswer, description.get())
952 .ok());
953
954 // Initially NeedsIceRestart should return false.
955 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
956 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
957 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
958 // true.
959 transport_controller_->SetNeedsIceRestartFlag();
960 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
961 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
962 // For a nonexistent transport, false should be returned.
963 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
964
965 // Reset the ice_ufrag/ice_pwd for audio.
966 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
967 audio_transport_info->description.ice_ufrag = kIceUfrag2;
968 audio_transport_info->description.ice_pwd = kIcePwd2;
969 EXPECT_TRUE(transport_controller_
970 ->SetLocalDescription(SdpType::kOffer, description.get())
971 .ok());
972 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
973 // return false for audio and true for video.
974 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
975 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
976}
977
978TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
979 CreateJsepTransportController(JsepTransportController::Config());
980 auto description = CreateSessionDescriptionWithBundleGroup();
981 EXPECT_TRUE(transport_controller_
982 ->SetLocalDescription(SdpType::kOffer, description.get())
983 .ok());
984 // After setting the local description, we should be able to start gathering
985 // candidates.
986 transport_controller_->MaybeStartGathering();
987 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
988 EXPECT_EQ(1, gathering_state_signal_count_);
989}
990
991TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
992 CreateJsepTransportController(JsepTransportController::Config());
993 auto description = CreateSessionDescriptionWithoutBundle();
994 transport_controller_->SetLocalDescription(SdpType::kOffer,
995 description.get());
996 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
997 description.get());
998 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
999 transport_controller_->GetDtlsTransport(kAudioMid1));
1000 ASSERT_NE(nullptr, fake_audio_dtls);
1001 Candidates candidates;
1002 candidates.push_back(
1003 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
1004 EXPECT_TRUE(
1005 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
1006 EXPECT_EQ(1U,
1007 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
1008
1009 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
1010 EXPECT_EQ(0U,
1011 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
1012}
1013
1014TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
1015 CreateJsepTransportController(JsepTransportController::Config());
1016
1017 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
1018 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1019 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
1020 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
1021
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001022 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001023 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1024 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1025 certificate1);
1026
1027 // Apply the local certificate.
1028 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
1029 // Apply the local description.
1030 EXPECT_TRUE(transport_controller_
1031 ->SetLocalDescription(SdpType::kOffer, description.get())
1032 .ok());
1033 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
1034 EXPECT_TRUE(returned_certificate);
1035 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
1036 returned_certificate->identity()->certificate().ToPEMString());
1037
1038 // Should fail if called for a nonexistant transport.
1039 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
1040
1041 // Shouldn't be able to change the identity once set.
1042 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
1043 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1044 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
1045 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
1046}
1047
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001048TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001049 CreateJsepTransportController(JsepTransportController::Config());
1050 auto description = CreateSessionDescriptionWithBundleGroup();
1051 EXPECT_TRUE(transport_controller_
1052 ->SetLocalDescription(SdpType::kOffer, description.get())
1053 .ok());
1054 rtc::FakeSSLCertificate fake_certificate("fake_data");
1055
1056 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1057 transport_controller_->GetDtlsTransport(kAudioMid1));
1058 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001059 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
1060 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
1061 ASSERT_TRUE(returned_cert_chain);
1062 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -08001063 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001064 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -08001065
1066 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001067 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -08001068}
1069
1070TEST_F(JsepTransportControllerTest, GetDtlsRole) {
1071 CreateJsepTransportController(JsepTransportController::Config());
1072 auto offer_certificate =
1073 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1074 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
1075 auto answer_certificate =
1076 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1077 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
1078 transport_controller_->SetLocalCertificate(offer_certificate);
1079
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001080 auto offer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001081 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1082 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1083 offer_certificate);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001084 auto answer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001085 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1086 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1087 answer_certificate);
1088
1089 EXPECT_TRUE(transport_controller_
1090 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
1091 .ok());
1092
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001093 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -08001094 transport_controller_->GetDtlsRole(kAudioMid1);
1095 // The DTLS role is not decided yet.
1096 EXPECT_FALSE(role);
1097 EXPECT_TRUE(transport_controller_
1098 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
1099 .ok());
1100 role = transport_controller_->GetDtlsRole(kAudioMid1);
1101
1102 ASSERT_TRUE(role);
1103 EXPECT_EQ(rtc::SSL_CLIENT, *role);
1104}
1105
1106TEST_F(JsepTransportControllerTest, GetStats) {
1107 CreateJsepTransportController(JsepTransportController::Config());
1108 auto description = CreateSessionDescriptionWithBundleGroup();
1109 EXPECT_TRUE(transport_controller_
1110 ->SetLocalDescription(SdpType::kOffer, description.get())
1111 .ok());
1112
1113 cricket::TransportStats stats;
1114 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
1115 EXPECT_EQ(kAudioMid1, stats.transport_name);
1116 EXPECT_EQ(1u, stats.channel_stats.size());
1117 // Return false for non-existing transport.
1118 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
1119}
1120
1121TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
1122 CreateJsepTransportController(JsepTransportController::Config());
1123 auto description = CreateSessionDescriptionWithoutBundle();
1124 EXPECT_TRUE(transport_controller_
1125 ->SetLocalDescription(SdpType::kOffer, description.get())
1126 .ok());
1127
1128 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
1129 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1130 fake_ice->SetCandidatesGatheringComplete();
1131 fake_ice->SetConnectionCount(1);
1132 // The connection stats will be failed if there is no active connection.
1133 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +00001134 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001135 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001136 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1137 ice_connection_state_, kTimeout);
1138 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001139 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1140 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +02001141 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001142}
1143
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001144TEST_F(JsepTransportControllerTest,
1145 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001146 CreateJsepTransportController(JsepTransportController::Config());
1147 auto description = CreateSessionDescriptionWithoutBundle();
1148 EXPECT_TRUE(transport_controller_
1149 ->SetLocalDescription(SdpType::kOffer, description.get())
1150 .ok());
1151
1152 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1153 transport_controller_->GetDtlsTransport(kAudioMid1));
1154 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1155 transport_controller_->GetDtlsTransport(kVideoMid1));
1156
1157 // First, have one transport connect, and another fail, to ensure that
1158 // the first transport connecting didn't trigger a "connected" state signal.
1159 // We should only get a signal when all are connected.
1160 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
1161 fake_audio_dtls->SetWritable(true);
1162 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1163 // Decrease the number of the connection to trigger the signal.
1164 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
1165 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
1166 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1167
Alex Loiko9289eda2018-11-23 16:18:59 +00001168 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001169 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001170 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1171 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001172 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001173 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1174 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001175 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001176
Jonas Olsson635474e2018-10-18 15:58:17 +02001177 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1178 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001179 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
1180 // the transport state to be STATE_CONNECTING.
1181 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
1182 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001183 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001184 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001185 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
1186 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001187 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001188 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1189 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001190 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001191}
1192
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001193TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001194 SignalConnectionStateConnectedWithMediaTransportAndNoDtlsCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001195 FakeMediaTransportFactory fake_media_transport_factory;
1196 JsepTransportController::Config config;
1197 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001198 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1199 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001200 config.use_media_transport_for_data_channels = true;
1201 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001202 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001203
1204 // Media Transport is only used with bundle.
1205 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001206 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001207 EXPECT_NE(absl::nullopt,
1208 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001209 EXPECT_TRUE(transport_controller_
1210 ->SetLocalDescription(SdpType::kOffer, description.get())
1211 .ok());
1212
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001213 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1214 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1215 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1216 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001217 EXPECT_EQ(fake_audio_ice, fake_video_ice);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001218 fake_audio_ice->SetConnectionCount(2);
1219 fake_audio_ice->SetConnectionCount(1);
1220 fake_video_ice->SetConnectionCount(2);
1221 fake_video_ice->SetConnectionCount(1);
1222 fake_audio_ice->SetWritable(true);
1223 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001224
1225 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001226 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1227 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001228
1229 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1230 transport_controller_->GetMediaTransport(kAudioMid1));
1231
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001232 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001233
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001234 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001235 // Only one media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001236 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001237}
1238
1239TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001240 SignalConnectionStateConnectedWithMediaTransportCaller) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001241 FakeMediaTransportFactory fake_media_transport_factory;
1242 JsepTransportController::Config config;
1243 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001244 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1245 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001246 config.use_media_transport_for_media = true;
1247 CreateJsepTransportController(config);
1248
1249 // Media Transport is only used with bundle.
1250 auto description = CreateSessionDescriptionWithBundleGroup();
1251 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001252 EXPECT_NE(absl::nullopt,
1253 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001254 EXPECT_TRUE(transport_controller_
1255 ->SetLocalDescription(SdpType::kOffer, description.get())
1256 .ok());
1257
1258 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1259 transport_controller_->GetDtlsTransport(kAudioMid1));
1260 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1261 transport_controller_->GetDtlsTransport(kVideoMid1));
1262
1263 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1264 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1265 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1266 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1267 fake_audio_ice->SetConnectionCount(2);
1268 fake_audio_ice->SetConnectionCount(1);
1269 fake_video_ice->SetConnectionCount(2);
1270 fake_video_ice->SetConnectionCount(1);
1271 fake_audio_ice->SetWritable(true);
1272 fake_video_ice->SetWritable(true);
1273 fake_audio_dtls->SetWritable(true);
1274 fake_video_dtls->SetWritable(true);
1275
1276 // Still not connected, because we are waiting for media transport.
1277 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1278 kTimeout);
1279
1280 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1281 transport_controller_->GetMediaTransport(kAudioMid1));
1282
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001283 ASSERT_NE(nullptr, media_transport);
1284
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001285 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1286 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1287 kTimeout);
1288
1289 // Still waiting for the second media transport.
1290 media_transport = static_cast<FakeMediaTransport*>(
1291 transport_controller_->GetMediaTransport(kVideoMid1));
1292 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1293
1294 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
1295}
1296
1297TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001298 SignalConnectionStateFailedWhenMediaTransportClosedCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001299 FakeMediaTransportFactory fake_media_transport_factory;
1300 JsepTransportController::Config config;
1301 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001302 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1303 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001304 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001305 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001306 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001307 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001308 EXPECT_NE(absl::nullopt,
1309 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001310 EXPECT_TRUE(transport_controller_
1311 ->SetLocalDescription(SdpType::kOffer, description.get())
1312 .ok());
1313
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001314 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1315 transport_controller_->GetDtlsTransport(kAudioMid1));
1316 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1317 transport_controller_->GetDtlsTransport(kVideoMid1));
1318
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001319 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1320 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1321 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1322 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1323 fake_audio_ice->SetWritable(true);
1324 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001325 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001326 fake_audio_ice->SetConnectionCount(2);
1327 fake_audio_ice->SetConnectionCount(1);
1328 fake_video_ice->SetConnectionCount(2);
1329 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001330
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001331 fake_audio_dtls->SetWritable(true);
1332 fake_video_dtls->SetWritable(true);
1333
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001334 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1335 transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001336 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001337 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1338
1339 media_transport = static_cast<FakeMediaTransport*>(
1340 transport_controller_->GetMediaTransport(kVideoMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001341 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001342
1343 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1344
Alex Loiko9289eda2018-11-23 16:18:59 +00001345 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001346
1347 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +00001348 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001349}
1350
Zhi Huange818b6e2018-02-22 15:26:27 -08001351TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1352 CreateJsepTransportController(JsepTransportController::Config());
1353 auto description = CreateSessionDescriptionWithoutBundle();
1354 EXPECT_TRUE(transport_controller_
1355 ->SetLocalDescription(SdpType::kOffer, description.get())
1356 .ok());
1357
1358 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1359 transport_controller_->GetDtlsTransport(kAudioMid1));
1360 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1361 transport_controller_->GetDtlsTransport(kVideoMid1));
1362
1363 // First, have one transport connect, and another fail, to ensure that
1364 // the first transport connecting didn't trigger a "connected" state signal.
1365 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001366 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1367 IceTransportState::kCompleted,
1368 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001369 fake_audio_dtls->SetWritable(true);
1370 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001371
1372 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1373 ice_connection_state_, kTimeout);
1374 EXPECT_EQ(1, ice_connection_state_signal_count_);
1375 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1376 combined_connection_state_, kTimeout);
1377 EXPECT_EQ(1, combined_connection_state_signal_count_);
1378
1379 fake_video_dtls->fake_ice_transport()->SetTransportState(
1380 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001381 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1382
Alex Loiko9289eda2018-11-23 16:18:59 +00001383 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001384 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001385 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1386 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001387 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001388 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1389 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001390 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001391
Jonas Olsson635474e2018-10-18 15:58:17 +02001392 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1393 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001394 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1395 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001396 fake_video_dtls->fake_ice_transport()->SetTransportState(
1397 IceTransportState::kCompleted,
1398 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001399 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001400 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +01001401 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001402 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1403 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001404 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001405 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1406 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001407 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001408}
1409
1410TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1411 CreateJsepTransportController(JsepTransportController::Config());
1412 auto description = CreateSessionDescriptionWithoutBundle();
1413 EXPECT_TRUE(transport_controller_
1414 ->SetLocalDescription(SdpType::kOffer, description.get())
1415 .ok());
1416
1417 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1418 transport_controller_->GetDtlsTransport(kAudioMid1));
1419 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1420 // Should be in the gathering state as soon as any transport starts gathering.
1421 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1422 EXPECT_EQ(1, gathering_state_signal_count_);
1423}
1424
1425TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1426 CreateJsepTransportController(JsepTransportController::Config());
1427 auto description = CreateSessionDescriptionWithoutBundle();
1428 EXPECT_TRUE(transport_controller_
1429 ->SetLocalDescription(SdpType::kOffer, description.get())
1430 .ok());
1431
1432 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1433 transport_controller_->GetDtlsTransport(kAudioMid1));
1434 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1435 transport_controller_->GetDtlsTransport(kVideoMid1));
1436
1437 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1438 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1439 EXPECT_EQ(1, gathering_state_signal_count_);
1440
1441 // Have one transport finish gathering, to make sure gathering
1442 // completion wasn't signalled if only one transport finished gathering.
1443 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1444 EXPECT_EQ(1, gathering_state_signal_count_);
1445
1446 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1447 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1448 EXPECT_EQ(1, gathering_state_signal_count_);
1449
1450 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1451 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1452 EXPECT_EQ(2, gathering_state_signal_count_);
1453}
1454
1455// Test that when the last transport that hasn't finished connecting and/or
1456// gathering is destroyed, the aggregate state jumps to "completed". This can
1457// happen if, for example, we have an audio and video transport, the audio
1458// transport completes, then we start bundling video on the audio transport.
1459TEST_F(JsepTransportControllerTest,
1460 SignalingWhenLastIncompleteTransportDestroyed) {
1461 CreateJsepTransportController(JsepTransportController::Config());
1462 auto description = CreateSessionDescriptionWithBundleGroup();
1463 EXPECT_TRUE(transport_controller_
1464 ->SetLocalDescription(SdpType::kOffer, description.get())
1465 .ok());
1466
1467 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1468 transport_controller_->GetDtlsTransport(kAudioMid1));
1469 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1470 transport_controller_->GetDtlsTransport(kVideoMid1));
1471 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1472
1473 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1474 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1475 EXPECT_EQ(1, gathering_state_signal_count_);
1476
1477 // Let the audio transport complete.
1478 fake_audio_dtls->SetWritable(true);
1479 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1480 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001481 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001482 EXPECT_EQ(1, gathering_state_signal_count_);
1483
1484 // Set the remote description and enable the bundle.
1485 EXPECT_TRUE(transport_controller_
1486 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1487 .ok());
1488 // The BUNDLE should be enabled, the incomplete video transport should be
1489 // deleted and the states shoud be updated.
1490 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1491 transport_controller_->GetDtlsTransport(kVideoMid1));
1492 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001493 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1494 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1495 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001496 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1497 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001498 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1499 EXPECT_EQ(2, gathering_state_signal_count_);
1500}
1501
1502TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1503 CreateJsepTransportController(JsepTransportController::Config());
1504 auto description = CreateSessionDescriptionWithBundleGroup();
1505 EXPECT_TRUE(transport_controller_
1506 ->SetLocalDescription(SdpType::kOffer, description.get())
1507 .ok());
1508 transport_controller_->MaybeStartGathering();
1509
1510 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1511 transport_controller_->GetDtlsTransport(kAudioMid1));
1512 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1513 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1514 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1515 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1516}
1517
1518TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1519 network_thread_ = rtc::Thread::CreateWithSocketServer();
1520 network_thread_->Start();
1521 CreateJsepTransportController(JsepTransportController::Config(),
1522 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 14:57:52 +01001523 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 15:26:27 -08001524 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1525
1526 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001527 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001528 EXPECT_EQ(2, connection_state_signal_count_);
1529
1530 // new --> gathering --> complete
1531 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1532 EXPECT_EQ(2, gathering_state_signal_count_);
1533
1534 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1535 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1536 EXPECT_EQ(2, candidates_signal_count_);
1537
1538 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1539}
1540
1541// Older versions of Chrome expect the ICE role to be re-determined when an
1542// ICE restart occurs, and also don't perform conflict resolution correctly,
1543// so for now we can't safely stop doing this.
1544// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1545// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1546// enough population.
1547TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1548 CreateJsepTransportController(JsepTransportController::Config());
1549 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001550 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001551 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1552 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1553 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001554 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001555 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1556 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1557 nullptr);
1558
1559 EXPECT_TRUE(transport_controller_
1560 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1561 .ok());
1562 EXPECT_TRUE(transport_controller_
1563 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1564 .ok());
1565
1566 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1567 transport_controller_->GetDtlsTransport(kAudioMid1));
1568 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1569 fake_dtls->fake_ice_transport()->GetIceRole());
1570
1571 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001572 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001573 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1574 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1575 nullptr);
1576 EXPECT_TRUE(
1577 transport_controller_
1578 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1579 .ok());
1580 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1581 fake_dtls->fake_ice_transport()->GetIceRole());
1582}
1583
1584// Test that if the TransportController was created with the
1585// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1586// redetermined on an ICE restart.
1587TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1588 JsepTransportController::Config config;
1589 config.redetermine_role_on_ice_restart = false;
1590
1591 CreateJsepTransportController(config);
1592 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001593 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001594 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1595 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1596 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001597 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001598 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1599 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1600 nullptr);
1601
1602 EXPECT_TRUE(transport_controller_
1603 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1604 .ok());
1605 EXPECT_TRUE(transport_controller_
1606 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1607 .ok());
1608
1609 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1610 transport_controller_->GetDtlsTransport(kAudioMid1));
1611 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1612 fake_dtls->fake_ice_transport()->GetIceRole());
1613
1614 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001615 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001616 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1617 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1618 nullptr);
1619 EXPECT_TRUE(
1620 transport_controller_
1621 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1622 .ok());
1623 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1624 fake_dtls->fake_ice_transport()->GetIceRole());
1625}
1626
1627// Tests ICE-Lite mode in remote answer.
1628TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1629 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001630 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001631 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1632 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1633 nullptr);
1634 EXPECT_TRUE(transport_controller_
1635 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1636 .ok());
1637 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1638 transport_controller_->GetDtlsTransport(kAudioMid1));
1639 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1640 fake_dtls->fake_ice_transport()->GetIceRole());
1641 EXPECT_EQ(cricket::ICEMODE_FULL,
1642 fake_dtls->fake_ice_transport()->remote_ice_mode());
1643
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001644 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001645 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1646 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1647 nullptr);
1648 EXPECT_TRUE(transport_controller_
1649 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1650 .ok());
1651 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1652 fake_dtls->fake_ice_transport()->GetIceRole());
1653 EXPECT_EQ(cricket::ICEMODE_LITE,
1654 fake_dtls->fake_ice_transport()->remote_ice_mode());
1655}
1656
1657// Tests that the ICE role remains "controlling" if a subsequent offer that
1658// does an ICE restart is received from an ICE lite endpoint. Regression test
1659// for: https://crbug.com/710760
1660TEST_F(JsepTransportControllerTest,
1661 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1662 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001663 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001664 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1665 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1666 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001667 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001668 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1669 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1670 nullptr);
1671 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1672 // local side is the controlling.
1673 EXPECT_TRUE(transport_controller_
1674 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1675 .ok());
1676 EXPECT_TRUE(transport_controller_
1677 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1678 .ok());
1679 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1680 transport_controller_->GetDtlsTransport(kAudioMid1));
1681 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1682 fake_dtls->fake_ice_transport()->GetIceRole());
1683
1684 // In the subsequence remote offer triggers an ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001685 auto remote_offer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001686 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1687 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1688 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001689 auto local_answer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001690 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1691 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1692 nullptr);
1693 EXPECT_TRUE(transport_controller_
1694 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1695 .ok());
1696 EXPECT_TRUE(transport_controller_
1697 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1698 .ok());
1699 fake_dtls = static_cast<FakeDtlsTransport*>(
1700 transport_controller_->GetDtlsTransport(kAudioMid1));
1701 // The local side is still the controlling role since the remote side is using
1702 // ICE-Lite.
1703 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1704 fake_dtls->fake_ice_transport()->GetIceRole());
1705}
1706
1707// Tests that the SDP has more than one audio/video m= sections.
1708TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1709 CreateJsepTransportController(JsepTransportController::Config());
1710 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1711 bundle_group.AddContentName(kAudioMid1);
1712 bundle_group.AddContentName(kAudioMid2);
1713 bundle_group.AddContentName(kVideoMid1);
1714 bundle_group.AddContentName(kDataMid1);
1715
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001716 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001717 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1718 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1719 nullptr);
1720 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1721 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1722 nullptr);
1723 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1724 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1725 nullptr);
1726 AddDataSection(local_offer.get(), kDataMid1,
1727 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1728 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1729 nullptr);
1730
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001731 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001732 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1733 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1734 nullptr);
1735 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1736 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1737 nullptr);
1738 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1739 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1740 nullptr);
1741 AddDataSection(remote_answer.get(), kDataMid1,
1742 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1743 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1744 nullptr);
1745
1746 local_offer->AddGroup(bundle_group);
1747 remote_answer->AddGroup(bundle_group);
1748
1749 EXPECT_TRUE(transport_controller_
1750 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1751 .ok());
1752 EXPECT_TRUE(transport_controller_
1753 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1754 .ok());
1755 // Verify that all the sections are bundled on kAudio1.
1756 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1757 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1758 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1759 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1760 EXPECT_EQ(transport1, transport2);
1761 EXPECT_EQ(transport1, transport3);
1762 EXPECT_EQ(transport1, transport4);
1763
Harald Alvestrandad88c882018-11-28 16:47:46 +01001764 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1765 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1766
Zhi Huange818b6e2018-02-22 15:26:27 -08001767 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1768 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1769 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1770 EXPECT_EQ(transport1, it->second);
1771 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1772 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1773 EXPECT_EQ(transport1, it->second);
1774 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1775 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1776 EXPECT_EQ(transport1, it->second);
1777 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1778 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1779 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
Zhi Huange818b6e2018-02-22 15:26:27 -08001780}
1781
1782// Tests that only a subset of all the m= sections are bundled.
1783TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1784 CreateJsepTransportController(JsepTransportController::Config());
1785 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1786 bundle_group.AddContentName(kAudioMid1);
1787 bundle_group.AddContentName(kVideoMid1);
1788
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001789 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001790 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1791 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1792 nullptr);
1793 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1794 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1795 nullptr);
1796 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1797 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1798 nullptr);
1799
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001800 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001801 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1802 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1803 nullptr);
1804 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1805 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1806 nullptr);
1807 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1808 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1809 nullptr);
1810
1811 local_offer->AddGroup(bundle_group);
1812 remote_answer->AddGroup(bundle_group);
1813 EXPECT_TRUE(transport_controller_
1814 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1815 .ok());
1816 EXPECT_TRUE(transport_controller_
1817 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1818 .ok());
1819
1820 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1821 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1822 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1823 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1824 EXPECT_NE(transport1, transport2);
1825 EXPECT_EQ(transport1, transport3);
1826
1827 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1828 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1829 EXPECT_EQ(transport1, it->second);
1830 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001831 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001832}
1833
1834// Tests that the initial offer/answer only have data section and audio/video
1835// sections are added in the subsequent offer.
1836TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1837 CreateJsepTransportController(JsepTransportController::Config());
1838 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1839 bundle_group.AddContentName(kDataMid1);
1840
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001841 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001842 AddDataSection(local_offer.get(), kDataMid1,
1843 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1844 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1845 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001846 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001847 AddDataSection(remote_answer.get(), kDataMid1,
1848 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1849 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1850 nullptr);
1851 local_offer->AddGroup(bundle_group);
1852 remote_answer->AddGroup(bundle_group);
1853
1854 EXPECT_TRUE(transport_controller_
1855 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1856 .ok());
1857 EXPECT_TRUE(transport_controller_
1858 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1859 .ok());
1860 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1861
1862 // Add audio/video sections in subsequent offer.
1863 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1864 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1865 nullptr);
1866 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1867 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1868 nullptr);
1869 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1870 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1871 nullptr);
1872 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1873 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1874 nullptr);
1875
1876 // Reset the bundle group and do another offer/answer exchange.
1877 bundle_group.AddContentName(kAudioMid1);
1878 bundle_group.AddContentName(kVideoMid1);
1879 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1880 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1881 local_offer->AddGroup(bundle_group);
1882 remote_answer->AddGroup(bundle_group);
1883
1884 EXPECT_TRUE(transport_controller_
1885 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1886 .ok());
1887 EXPECT_TRUE(transport_controller_
1888 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1889 .ok());
1890
1891 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1892 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1893 EXPECT_EQ(data_transport, audio_transport);
1894 EXPECT_EQ(data_transport, video_transport);
1895}
1896
1897TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1898 CreateJsepTransportController(JsepTransportController::Config());
1899 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1900 bundle_group.AddContentName(kAudioMid1);
1901 bundle_group.AddContentName(kVideoMid1);
1902 bundle_group.AddContentName(kDataMid1);
1903
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001904 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001905 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1906 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1907 nullptr);
1908 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1909 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1910 nullptr);
1911 AddDataSection(local_offer.get(), kDataMid1,
1912 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1913 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1914 nullptr);
1915
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001916 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001917 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1918 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1919 nullptr);
1920 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1921 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1922 nullptr);
1923 AddDataSection(remote_answer.get(), kDataMid1,
1924 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1925 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1926 nullptr);
1927 // Reject video and data section.
1928 remote_answer->contents()[1].rejected = true;
1929 remote_answer->contents()[2].rejected = true;
1930
1931 local_offer->AddGroup(bundle_group);
1932 remote_answer->AddGroup(bundle_group);
1933
1934 EXPECT_TRUE(transport_controller_
1935 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1936 .ok());
1937 EXPECT_TRUE(transport_controller_
1938 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1939 .ok());
1940
1941 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1942 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1943 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1944 // Verify the signals are fired correctly.
1945 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1946 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1947 EXPECT_EQ(nullptr, it->second);
1948 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1949 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1950 EXPECT_EQ(nullptr, it2->second);
1951}
1952
1953// Tests that changing the bundled MID in subsequent offer/answer exchange is
1954// not supported.
1955// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1956// fixed
1957TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1958 CreateJsepTransportController(JsepTransportController::Config());
1959 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1960 bundle_group.AddContentName(kAudioMid1);
1961 bundle_group.AddContentName(kVideoMid1);
1962
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001963 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001964 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1965 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1966 nullptr);
1967 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1968 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1969 nullptr);
1970
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001971 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001972 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1973 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1974 nullptr);
1975 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1976 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1977 nullptr);
1978
1979 local_offer->AddGroup(bundle_group);
1980 remote_answer->AddGroup(bundle_group);
1981 EXPECT_TRUE(transport_controller_
1982 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1983 .ok());
1984 EXPECT_TRUE(transport_controller_
1985 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1986 .ok());
1987 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1988 transport_controller_->GetRtpTransport(kVideoMid1));
1989
1990 // Reorder the bundle group.
1991 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1992 bundle_group.AddContentName(kAudioMid1);
1993 // The answerer uses the new bundle group and now the bundle mid is changed to
1994 // |kVideo1|.
1995 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1996 remote_answer->AddGroup(bundle_group);
1997 EXPECT_TRUE(transport_controller_
1998 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1999 .ok());
2000 EXPECT_FALSE(transport_controller_
2001 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2002 .ok());
2003}
Zhi Huange830e682018-03-30 10:48:35 -07002004// Test that rejecting only the first m= section of a BUNDLE group is treated as
2005// an error, but rejecting all of them works as expected.
2006TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
2007 CreateJsepTransportController(JsepTransportController::Config());
2008 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
2009 bundle_group.AddContentName(kAudioMid1);
2010 bundle_group.AddContentName(kVideoMid1);
2011 bundle_group.AddContentName(kDataMid1);
2012
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002013 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002014 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2015 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2016 nullptr);
2017 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
2018 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2019 nullptr);
2020 AddDataSection(local_offer.get(), kDataMid1,
2021 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
2022 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2023 nullptr);
2024
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002025 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002026 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2027 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
2028 nullptr);
2029 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
2030 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
2031 nullptr);
2032 AddDataSection(remote_answer.get(), kDataMid1,
2033 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
2034 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
2035 nullptr);
2036 // Reject audio content in answer.
2037 remote_answer->contents()[0].rejected = true;
2038
2039 local_offer->AddGroup(bundle_group);
2040 remote_answer->AddGroup(bundle_group);
2041
2042 EXPECT_TRUE(transport_controller_
2043 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2044 .ok());
2045 EXPECT_FALSE(transport_controller_
2046 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2047 .ok());
2048
2049 // Reject all the contents.
2050 remote_answer->contents()[1].rejected = true;
2051 remote_answer->contents()[2].rejected = true;
2052 EXPECT_TRUE(transport_controller_
2053 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2054 .ok());
2055 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
2056 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
2057 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
2058}
2059
2060// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
2061// is used.
2062TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
2063 JsepTransportController::Config config;
2064 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2065 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002066 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002067 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2068 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2069 nullptr);
2070
2071 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
2072 // Applying a non-RTCP-mux offer is expected to fail.
2073 EXPECT_FALSE(transport_controller_
2074 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2075 .ok());
2076}
2077
2078// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
2079// is used.
2080TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
2081 JsepTransportController::Config config;
2082 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2083 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002084 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002085 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2086 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2087 nullptr);
2088 EXPECT_TRUE(transport_controller_
2089 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2090 .ok());
2091
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002092 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002093 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2094 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
2095 nullptr);
2096 // Applying a non-RTCP-mux answer is expected to fail.
2097 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
2098 EXPECT_FALSE(transport_controller_
2099 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2100 .ok());
2101}
Zhi Huange818b6e2018-02-22 15:26:27 -08002102
Zhi Huangd2248f82018-04-10 14:41:03 -07002103// This tests that the BUNDLE group in answer should be a subset of the offered
2104// group.
2105TEST_F(JsepTransportControllerTest,
2106 AddContentToBundleGroupInAnswerNotSupported) {
2107 CreateJsepTransportController(JsepTransportController::Config());
2108 auto local_offer = CreateSessionDescriptionWithoutBundle();
2109 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2110
2111 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2112 offer_bundle_group.AddContentName(kAudioMid1);
2113 local_offer->AddGroup(offer_bundle_group);
2114
2115 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2116 answer_bundle_group.AddContentName(kAudioMid1);
2117 answer_bundle_group.AddContentName(kVideoMid1);
2118 remote_answer->AddGroup(answer_bundle_group);
2119 EXPECT_TRUE(transport_controller_
2120 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2121 .ok());
2122 EXPECT_FALSE(transport_controller_
2123 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2124 .ok());
2125}
2126
2127// This tests that the BUNDLE group with non-existing MID should be rejectd.
2128TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
2129 CreateJsepTransportController(JsepTransportController::Config());
2130 auto local_offer = CreateSessionDescriptionWithoutBundle();
2131 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2132
2133 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2134 // The BUNDLE group is invalid because there is no data section in the
2135 // description.
2136 invalid_bundle_group.AddContentName(kDataMid1);
2137 local_offer->AddGroup(invalid_bundle_group);
2138 remote_answer->AddGroup(invalid_bundle_group);
2139
2140 EXPECT_FALSE(transport_controller_
2141 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2142 .ok());
2143 EXPECT_FALSE(transport_controller_
2144 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2145 .ok());
2146}
2147
2148// This tests that an answer shouldn't be able to remove an m= section from an
2149// established group without rejecting it.
2150TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
2151 CreateJsepTransportController(JsepTransportController::Config());
2152
2153 auto local_offer = CreateSessionDescriptionWithBundleGroup();
2154 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
2155 EXPECT_TRUE(transport_controller_
2156 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2157 .ok());
2158 EXPECT_TRUE(transport_controller_
2159 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2160 .ok());
2161
2162 // Do an re-offer/answer.
2163 EXPECT_TRUE(transport_controller_
2164 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2165 .ok());
2166 auto new_answer = CreateSessionDescriptionWithoutBundle();
2167 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2168 // The answer removes video from the BUNDLE group without rejecting it is
2169 // invalid.
2170 new_bundle_group.AddContentName(kAudioMid1);
2171 new_answer->AddGroup(new_bundle_group);
2172
2173 // Applying invalid answer is expected to fail.
2174 EXPECT_FALSE(transport_controller_
2175 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2176 .ok());
2177
2178 // Rejected the video content.
2179 auto video_content = new_answer->GetContentByName(kVideoMid1);
2180 ASSERT_TRUE(video_content);
2181 video_content->rejected = true;
2182 EXPECT_TRUE(transport_controller_
2183 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2184 .ok());
2185}
2186
Steve Anton2bed3972019-01-04 17:04:30 -08002187// Test that the JsepTransportController can process a new local and remote
2188// description that changes the tagged BUNDLE group with the max-bundle policy
2189// specified.
2190// This is a regression test for bugs.webrtc.org/9954
2191TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
2192 CreateJsepTransportController(JsepTransportController::Config());
2193
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002194 auto local_offer = std::make_unique<cricket::SessionDescription>();
Steve Anton2bed3972019-01-04 17:04:30 -08002195 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2196 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2197 nullptr);
2198 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
2199 bundle_group.AddContentName(kAudioMid1);
2200 local_offer->AddGroup(bundle_group);
2201 EXPECT_TRUE(transport_controller_
2202 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2203 .ok());
2204
2205 std::unique_ptr<cricket::SessionDescription> remote_answer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002206 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002207 EXPECT_TRUE(transport_controller_
2208 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2209 .ok());
2210
2211 std::unique_ptr<cricket::SessionDescription> local_reoffer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002212 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002213 local_reoffer->contents()[0].rejected = true;
2214 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
2215 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2216 nullptr);
2217 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
2218 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2219 new_bundle_group.AddContentName(kVideoMid1);
2220 local_reoffer->AddGroup(new_bundle_group);
2221
2222 EXPECT_TRUE(transport_controller_
2223 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
2224 .ok());
2225
2226 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002227 local_reoffer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002228 EXPECT_TRUE(
2229 transport_controller_
2230 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
2231 .ok());
2232}
2233
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07002234constexpr char kFakeTransportParameters[] = "fake-params";
2235
2236// Test fixture that provides common setup and helpers for tests related to the
2237// datagram transport.
2238class JsepTransportControllerDatagramTest
2239 : public JsepTransportControllerTest,
2240 public testing::WithParamInterface<bool> {
2241 public:
2242 JsepTransportControllerDatagramTest()
2243 : JsepTransportControllerTest(),
2244 fake_media_transport_factory_(kFakeTransportParameters) {
2245 JsepTransportController::Config config;
2246 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2247 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2248 config.media_transport_factory = &fake_media_transport_factory_;
2249 config.use_datagram_transport = true;
2250 CreateJsepTransportController(config);
2251 }
2252
2253 // Whether the JsepTransportController under test acts as the offerer or
2254 // answerer in this test.
2255 bool IsOfferer() { return GetParam(); }
2256
2257 // Sets a description as local or remote based on type and current
2258 // perspective.
2259 RTCError SetDescription(SdpType type,
2260 const cricket::SessionDescription* description) {
2261 if (IsOfferer() == (type == SdpType::kOffer)) {
2262 return transport_controller_->SetLocalDescription(type, description);
2263 } else {
2264 return transport_controller_->SetRemoteDescription(type, description);
2265 }
2266 }
2267
2268 // Creates a session description with the settings necessary for datagram
2269 // transport (bundle + crypto) and the given |transport_params|.
2270 std::unique_ptr<cricket::SessionDescription>
2271 CreateSessionDescriptionForDatagramTransport(
2272 absl::optional<cricket::OpaqueTransportParameters> transport_params) {
2273 auto description = CreateSessionDescriptionWithBundleGroup();
2274 AddCryptoSettings(description.get());
2275
2276 for (auto& info : description->transport_infos()) {
2277 info.description.opaque_parameters = transport_params;
2278 }
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07002279 if (transport_params) {
2280 for (auto& content_info : description->contents()) {
2281 content_info.media_description()->set_alt_protocol(
2282 transport_params->protocol);
2283 }
2284 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07002285 return description;
2286 }
2287
2288 // Creates transport parameters with |protocol| and |parameters|
2289 // matching what |fake_media_transport_factory_| provides.
2290 cricket::OpaqueTransportParameters CreateTransportParameters() {
2291 cricket::OpaqueTransportParameters params;
2292 params.protocol = fake_media_transport_factory_.GetTransportName();
2293 params.parameters = "fake-params";
2294 return params;
2295 }
2296
2297 protected:
2298 FakeMediaTransportFactory fake_media_transport_factory_;
2299};
2300
2301TEST_P(JsepTransportControllerDatagramTest, InitDatagramTransport) {
2302 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2303 if (IsOfferer()) {
2304 // Getting transport parameters is allowed before setting a description.
2305 // This is necessary so that the offerer can include these params.
2306 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2307 fake_params);
2308 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2309 fake_params);
2310 }
2311
2312 // Setting a description activates the datagram transport without changing
2313 // transport parameters.
2314 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2315 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2316
2317 // After setting an offer with transport parameters, those parameters are
2318 // reflected by the controller.
2319 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2320 fake_params);
2321 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2322 fake_params);
2323}
2324
2325TEST_P(JsepTransportControllerDatagramTest,
2326 OfferMissingDatagramTransportParams) {
2327 if (IsOfferer()) {
2328 // This test doesn't make sense from the offerer's perspective, as the offer
2329 // must contain datagram transport params if the offerer supports it.
2330 return;
2331 }
2332
2333 auto description =
2334 CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2335 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2336
2337 // The offer didn't contain any datagram transport parameters, so the answer
2338 // won't either.
2339 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2340 absl::nullopt);
2341 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2342 absl::nullopt);
2343}
2344
2345TEST_P(JsepTransportControllerDatagramTest, OfferHasWrongTransportName) {
2346 if (IsOfferer()) {
2347 // This test doesn't make sense from the offerer's perspective, as the
2348 // offerer cannot offer itself the wrong transport.
2349 return;
2350 }
2351
2352 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2353 fake_params.protocol = "wrong-name";
2354
2355 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2356 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2357
2358 // The offerer and answerer support different datagram transports, so the
2359 // answerer rejects the offered parameters.
2360 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2361 absl::nullopt);
2362 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2363 absl::nullopt);
2364}
2365
2366TEST_P(JsepTransportControllerDatagramTest, AnswerRejectsDatagram) {
2367 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2368 if (IsOfferer()) {
2369 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2370 fake_params);
2371 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2372 fake_params);
2373 }
2374
2375 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2376 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2377
2378 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2379 fake_params);
2380 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2381 fake_params);
2382
2383 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2384 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2385
2386 // The answer rejected datagram transport, so its parameters are empty.
2387 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2388 absl::nullopt);
2389 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2390 absl::nullopt);
2391}
2392
2393TEST_P(JsepTransportControllerDatagramTest, AnswerAcceptsDatagram) {
2394 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2395 if (IsOfferer()) {
2396 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2397 fake_params);
2398 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2399 fake_params);
2400 }
2401
2402 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2403 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2404
2405 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2406 fake_params);
2407 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2408 fake_params);
2409
2410 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2411 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2412
2413 // The answer accepted datagram transport, so it is present.
2414 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2415 fake_params);
2416 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2417 fake_params);
2418}
2419
2420TEST_P(JsepTransportControllerDatagramTest, PrAnswerRejectsDatagram) {
2421 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2422 if (IsOfferer()) {
2423 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2424 fake_params);
2425 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2426 fake_params);
2427 }
2428
2429 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2430 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2431
2432 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2433 fake_params);
2434 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2435 fake_params);
2436
2437 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2438 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2439
2440 // The answer rejected datagram transport, but it's provisional, so the
2441 // transport is kept around for now.
2442 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2443 fake_params);
2444 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2445 fake_params);
2446}
2447
2448TEST_P(JsepTransportControllerDatagramTest, PrAnswerAcceptsDatagram) {
2449 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2450 if (IsOfferer()) {
2451 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2452 fake_params);
2453 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2454 fake_params);
2455 }
2456
2457 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2458 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2459
2460 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2461 fake_params);
2462 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2463 fake_params);
2464
2465 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2466 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2467
2468 // The answer provisionally accepted datagram transport, so it's kept.
2469 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2470 fake_params);
2471 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2472 fake_params);
2473}
2474
2475TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotAddDatagram) {
2476 auto offer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2477 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2478
2479 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2480 absl::nullopt);
2481 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2482 absl::nullopt);
2483
2484 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2485 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2486
2487 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2488 absl::nullopt);
2489 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2490 absl::nullopt);
2491
2492 // Attempting to add a datagram transport on a re-offer does not cause an
2493 // error, but also does not add a datagram transport.
2494 auto reoffer =
2495 CreateSessionDescriptionForDatagramTransport(CreateTransportParameters());
2496 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2497
2498 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2499 absl::nullopt);
2500 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2501 absl::nullopt);
2502}
2503
2504TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotRemoveDatagram) {
2505 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2506 if (IsOfferer()) {
2507 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2508 fake_params);
2509 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2510 fake_params);
2511 }
2512
2513 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2514 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2515
2516 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2517 fake_params);
2518 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2519 fake_params);
2520
2521 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2522 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2523
2524 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2525 fake_params);
2526 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2527 fake_params);
2528
2529 // Attempting to remove a datagram transport on a re-offer does not cause an
2530 // error, but also does not remove the datagram transport.
2531 auto reoffer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2532 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2533
2534 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2535 fake_params);
2536 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2537 fake_params);
2538}
2539
2540TEST_P(JsepTransportControllerDatagramTest,
2541 RenegotiationKeepsDatagramTransport) {
2542 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2543 if (IsOfferer()) {
2544 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2545 fake_params);
2546 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2547 fake_params);
2548 }
2549
2550 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2551 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2552
2553 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2554 fake_params);
2555 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2556 fake_params);
2557
2558 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2559 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2560
2561 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2562 fake_params);
2563 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2564 fake_params);
2565
2566 // Attempting to remove a datagram transport on a re-offer does not cause an
2567 // error, but also does not remove the datagram transport.
2568 auto reoffer = CreateSessionDescriptionForDatagramTransport(fake_params);
2569 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2570
2571 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2572 fake_params);
2573 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2574 fake_params);
2575
2576 auto reanswer = CreateSessionDescriptionForDatagramTransport(fake_params);
2577 EXPECT_TRUE(SetDescription(SdpType::kAnswer, reanswer.get()).ok());
2578
2579 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2580 fake_params);
2581 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2582 fake_params);
2583}
2584
2585INSTANTIATE_TEST_SUITE_P(
2586 JsepTransportControllerDatagramTests,
2587 JsepTransportControllerDatagramTest,
2588 testing::Values(true, false),
2589 // The parameter value is the local perspective (offerer or answerer).
2590 [](const testing::TestParamInfo<bool>& info) {
2591 return info.param ? "Offerer" : "Answerer";
2592 });
2593
Zhi Huange818b6e2018-02-22 15:26:27 -08002594} // namespace webrtc