blob: 8461e86b00caca975debb03548aebece3a873742 [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"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "p2p/base/fake_dtls_transport.h"
20#include "p2p/base/fake_ice_transport.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080021#include "p2p/base/no_op_dtls_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "p2p/base/transport_factory_interface.h"
23#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
Zhi Huange818b6e2018-02-22 15:26:27 -080062class FakeTransportFactory : public cricket::TransportFactoryInterface {
63 public:
64 std::unique_ptr<cricket::IceTransportInternal> CreateIceTransport(
65 const std::string& transport_name,
66 int component) override {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020067 return std::make_unique<cricket::FakeIceTransport>(transport_name,
68 component);
Zhi Huange818b6e2018-02-22 15:26:27 -080069 }
70
71 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070072 cricket::IceTransportInternal* ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070073 const webrtc::CryptoOptions& crypto_options) override {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020074 return std::make_unique<FakeDtlsTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070075 static_cast<cricket::FakeIceTransport*>(ice));
Zhi Huange818b6e2018-02-22 15:26:27 -080076 }
77};
78
Zhi Huang365381f2018-04-13 16:44:34 -070079class JsepTransportControllerTest : public JsepTransportController::Observer,
Mirko Bonadei6a489f22019-04-09 15:11:12 +020080 public ::testing::Test,
Zhi Huange818b6e2018-02-22 15:26:27 -080081 public sigslot::has_slots<> {
82 public:
83 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020084 fake_transport_factory_ = std::make_unique<FakeTransportFactory>();
Zhi Huange818b6e2018-02-22 15:26:27 -080085 }
86
87 void CreateJsepTransportController(
88 JsepTransportController::Config config,
89 rtc::Thread* signaling_thread = rtc::Thread::Current(),
90 rtc::Thread* network_thread = rtc::Thread::Current(),
91 cricket::PortAllocator* port_allocator = nullptr) {
Zhi Huang365381f2018-04-13 16:44:34 -070092 config.transport_observer = this;
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +020093 config.rtcp_handler = [](const rtc::CopyOnWriteBuffer& packet,
94 int64_t packet_time_us) { RTC_NOTREACHED(); };
Zhi Huange818b6e2018-02-22 15:26:27 -080095 // The tests only works with |fake_transport_factory|;
96 config.external_transport_factory = fake_transport_factory_.get();
Zach Steine20867f2018-08-02 13:20:15 -070097 // TODO(zstein): Provide an AsyncResolverFactory once it is required.
Mirko Bonadei317a1f02019-09-17 17:06:18 +020098 transport_controller_ = std::make_unique<JsepTransportController>(
Zach Steine20867f2018-08-02 13:20:15 -070099 signaling_thread, network_thread, port_allocator, nullptr, config);
Zhi Huange818b6e2018-02-22 15:26:27 -0800100 ConnectTransportControllerSignals();
101 }
102
103 void ConnectTransportControllerSignals() {
104 transport_controller_->SignalIceConnectionState.connect(
105 this, &JsepTransportControllerTest::OnConnectionState);
Alex Loiko9289eda2018-11-23 16:18:59 +0000106 transport_controller_->SignalStandardizedIceConnectionState.connect(
107 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200108 transport_controller_->SignalConnectionState.connect(
109 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800110 transport_controller_->SignalIceGatheringState.connect(
111 this, &JsepTransportControllerTest::OnGatheringState);
112 transport_controller_->SignalIceCandidatesGathered.connect(
113 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800114 }
115
116 std::unique_ptr<cricket::SessionDescription>
117 CreateSessionDescriptionWithoutBundle() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200118 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800119 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
120 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
121 nullptr);
122 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
123 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
124 nullptr);
125 return description;
126 }
127
128 std::unique_ptr<cricket::SessionDescription>
129 CreateSessionDescriptionWithBundleGroup() {
130 auto description = CreateSessionDescriptionWithoutBundle();
131 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
132 bundle_group.AddContentName(kAudioMid1);
133 bundle_group.AddContentName(kVideoMid1);
134 description->AddGroup(bundle_group);
135
136 return description;
137 }
138
139 void AddAudioSection(cricket::SessionDescription* description,
140 const std::string& mid,
141 const std::string& ufrag,
142 const std::string& pwd,
143 cricket::IceMode ice_mode,
144 cricket::ConnectionRole conn_role,
145 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
146 std::unique_ptr<cricket::AudioContentDescription> audio(
147 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700148 // Set RTCP-mux to be true because the default policy is "mux required".
149 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800150 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200151 /*rejected=*/false, std::move(audio));
Zhi Huange818b6e2018-02-22 15:26:27 -0800152 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
153 }
154
155 void AddVideoSection(cricket::SessionDescription* description,
156 const std::string& mid,
157 const std::string& ufrag,
158 const std::string& pwd,
159 cricket::IceMode ice_mode,
160 cricket::ConnectionRole conn_role,
161 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
162 std::unique_ptr<cricket::VideoContentDescription> video(
163 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700164 // Set RTCP-mux to be true because the default policy is "mux required".
165 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800166 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200167 /*rejected=*/false, std::move(video));
Zhi Huange818b6e2018-02-22 15:26:27 -0800168 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
169 }
170
171 void AddDataSection(cricket::SessionDescription* description,
172 const std::string& mid,
173 cricket::MediaProtocolType protocol_type,
174 const std::string& ufrag,
175 const std::string& pwd,
176 cricket::IceMode ice_mode,
177 cricket::ConnectionRole conn_role,
178 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200179 RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp);
180 std::unique_ptr<cricket::SctpDataContentDescription> data(
181 new cricket::SctpDataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700182 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800183 description->AddContent(mid, protocol_type,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200184 /*rejected=*/false, std::move(data));
Zhi Huange818b6e2018-02-22 15:26:27 -0800185 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
186 }
187
188 void AddTransportInfo(cricket::SessionDescription* description,
189 const std::string& mid,
190 const std::string& ufrag,
191 const std::string& pwd,
192 cricket::IceMode ice_mode,
193 cricket::ConnectionRole conn_role,
194 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
195 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
196 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700197 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800198 }
199
200 cricket::TransportDescription transport_desc(std::vector<std::string>(),
201 ufrag, pwd, ice_mode,
202 conn_role, fingerprint.get());
203 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
204 }
205
206 cricket::IceConfig CreateIceConfig(
207 int receiving_timeout,
208 cricket::ContinualGatheringPolicy continual_gathering_policy) {
209 cricket::IceConfig config;
210 config.receiving_timeout = receiving_timeout;
211 config.continual_gathering_policy = continual_gathering_policy;
212 return config;
213 }
214
215 Candidate CreateCandidate(const std::string& transport_name, int component) {
216 Candidate c;
217 c.set_transport_name(transport_name);
218 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
219 c.set_component(component);
220 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
221 c.set_priority(1);
222 return c;
223 }
224
225 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
226 if (!network_thread_->IsCurrent()) {
227 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
228 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
229 });
230 return;
231 }
232
233 auto description = CreateSessionDescriptionWithBundleGroup();
234 EXPECT_TRUE(transport_controller_
235 ->SetLocalDescription(SdpType::kOffer, description.get())
236 .ok());
237
238 transport_controller_->MaybeStartGathering();
239 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
240 transport_controller_->GetDtlsTransport(kAudioMid1));
241 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
242 transport_controller_->GetDtlsTransport(kVideoMid1));
243 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
244 fake_audio_dtls->fake_ice_transport(),
245 CreateCandidate(kAudioMid1, /*component=*/1));
246 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
247 fake_video_dtls->fake_ice_transport(),
248 CreateCandidate(kVideoMid1, /*component=*/1));
249 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
250 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
251 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
252 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
253 fake_audio_dtls->SetReceiving(true);
254 fake_video_dtls->SetReceiving(true);
255 fake_audio_dtls->SetWritable(true);
256 fake_video_dtls->SetWritable(true);
257 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
258 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
259 }
260
261 protected:
Alex Loiko9289eda2018-11-23 16:18:59 +0000262 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800263 if (!signaling_thread_->IsCurrent()) {
264 signaled_on_non_signaling_thread_ = true;
265 }
266 connection_state_ = state;
267 ++connection_state_signal_count_;
268 }
269
Alex Loiko9289eda2018-11-23 16:18:59 +0000270 void OnStandardizedIceConnectionState(
271 PeerConnectionInterface::IceConnectionState state) {
272 if (!signaling_thread_->IsCurrent()) {
273 signaled_on_non_signaling_thread_ = true;
274 }
275 ice_connection_state_ = state;
276 ++ice_connection_state_signal_count_;
277 }
278
Jonas Olsson635474e2018-10-18 15:58:17 +0200279 void OnCombinedConnectionState(
280 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100281 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
282 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 15:58:17 +0200283 if (!signaling_thread_->IsCurrent()) {
284 signaled_on_non_signaling_thread_ = true;
285 }
286 combined_connection_state_ = state;
287 ++combined_connection_state_signal_count_;
288 }
289
Zhi Huange818b6e2018-02-22 15:26:27 -0800290 void OnGatheringState(cricket::IceGatheringState state) {
291 if (!signaling_thread_->IsCurrent()) {
292 signaled_on_non_signaling_thread_ = true;
293 }
294 gathering_state_ = state;
295 ++gathering_state_signal_count_;
296 }
297
298 void OnCandidatesGathered(const std::string& transport_name,
299 const Candidates& candidates) {
300 if (!signaling_thread_->IsCurrent()) {
301 signaled_on_non_signaling_thread_ = true;
302 }
303 candidates_[transport_name].insert(candidates_[transport_name].end(),
304 candidates.begin(), candidates.end());
305 ++candidates_signal_count_;
306 }
307
Zhi Huang365381f2018-04-13 16:44:34 -0700308 // JsepTransportController::Observer overrides.
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700309 bool OnTransportChanged(
310 const std::string& mid,
311 RtpTransportInternal* rtp_transport,
312 rtc::scoped_refptr<DtlsTransport> dtls_transport,
313 MediaTransportInterface* media_transport,
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700314 DataChannelTransportInterface* data_channel_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700315 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100316 if (dtls_transport) {
317 changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
318 } else {
319 changed_dtls_transport_by_mid_[mid] = nullptr;
320 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800321 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700322 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800323 }
324
325 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000326 cricket::IceConnectionState connection_state_ =
327 cricket::kIceConnectionConnecting;
328 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200329 PeerConnectionInterface::kIceConnectionNew;
330 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
331 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800332 bool receiving_ = false;
333 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
334 // transport_name => candidates
335 std::map<std::string, Candidates> candidates_;
336 // Counts of each signal emitted.
337 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000338 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200339 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800340 int receiving_signal_count_ = 0;
341 int gathering_state_signal_count_ = 0;
342 int candidates_signal_count_ = 0;
343
344 // |network_thread_| should be destroyed after |transport_controller_|
345 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800346 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
347 rtc::Thread* const signaling_thread_ = nullptr;
348 bool signaled_on_non_signaling_thread_ = false;
349 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
350 // signaled correctly.
351 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
352 std::map<std::string, cricket::DtlsTransportInternal*>
353 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800354 std::map<std::string, MediaTransportInterface*>
355 changed_media_transport_by_mid_;
356
357 // Transport controller needs to be destroyed first, because it may issue
358 // callbacks that modify the changed_*_by_mid in the destructor.
359 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800360};
361
362TEST_F(JsepTransportControllerTest, GetRtpTransport) {
363 CreateJsepTransportController(JsepTransportController::Config());
364 auto description = CreateSessionDescriptionWithoutBundle();
365 EXPECT_TRUE(transport_controller_
366 ->SetLocalDescription(SdpType::kOffer, description.get())
367 .ok());
368 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
369 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
370 EXPECT_NE(nullptr, audio_rtp_transport);
371 EXPECT_NE(nullptr, video_rtp_transport);
372 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
373 // Return nullptr for non-existing ones.
374 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
375}
376
377TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
378 JsepTransportController::Config config;
379 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
380 CreateJsepTransportController(config);
381 auto description = CreateSessionDescriptionWithoutBundle();
382 EXPECT_TRUE(transport_controller_
383 ->SetLocalDescription(SdpType::kOffer, description.get())
384 .ok());
385 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
386 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100387 EXPECT_NE(nullptr,
388 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800389 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
390 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100391 EXPECT_NE(nullptr,
392 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
393 // Lookup for all MIDs should return different transports (no bundle)
394 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
395 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800396 // Return nullptr for non-existing ones.
397 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
398 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100399 EXPECT_EQ(nullptr,
400 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100401 // Take a pointer to a transport, shut down the transport controller,
402 // and verify that the resulting container is empty.
403 auto dtls_transport =
404 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
405 webrtc::DtlsTransport* my_transport =
406 static_cast<DtlsTransport*>(dtls_transport.get());
407 EXPECT_NE(nullptr, my_transport->internal());
408 transport_controller_.reset();
409 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800410}
411
Zhi Huange830e682018-03-30 10:48:35 -0700412TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
413 JsepTransportController::Config config;
414 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
415 CreateJsepTransportController(config);
416 auto description = CreateSessionDescriptionWithoutBundle();
417 EXPECT_TRUE(transport_controller_
418 ->SetLocalDescription(SdpType::kOffer, description.get())
419 .ok());
420 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
421 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
422 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
423 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700424 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
425}
426
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800427TEST_F(JsepTransportControllerTest,
428 DtlsIsStillCreatedIfMediaTransportIsOnlyUsedForDataChannels) {
429 FakeMediaTransportFactory fake_media_transport_factory;
430 JsepTransportController::Config config;
431
432 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800433 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800434 config.media_transport_factory = &fake_media_transport_factory;
435 config.use_media_transport_for_data_channels = true;
436 CreateJsepTransportController(config);
437 auto description = CreateSessionDescriptionWithBundleGroup();
438 AddCryptoSettings(description.get());
439
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800440 EXPECT_NE(absl::nullopt,
441 transport_controller_->GenerateOrGetLastMediaTransportOffer());
442
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800443 EXPECT_TRUE(transport_controller_
444 ->SetLocalDescription(SdpType::kOffer, description.get())
445 .ok());
446
447 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700448 transport_controller_->GetDataChannelTransport(kAudioMid1));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800449
450 ASSERT_NE(nullptr, media_transport);
451
452 // After SetLocalDescription, media transport should be created as caller.
453 EXPECT_TRUE(media_transport->is_caller());
454 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
455
456 // Return nullptr for non-existing mids.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700457 EXPECT_EQ(nullptr,
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700458 transport_controller_->GetDataChannelTransport(kVideoMid2));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800459
460 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
461 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
462 << "Media transport for media was not enabled, and so DTLS transport "
463 "should be created.";
464}
465
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700466TEST_F(JsepTransportControllerTest,
467 DtlsIsStillCreatedIfDatagramTransportIsOnlyUsedForDataChannels) {
468 FakeMediaTransportFactory fake_media_transport_factory("transport_params");
469 JsepTransportController::Config config;
470
471 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
472 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
473 config.media_transport_factory = &fake_media_transport_factory;
474 config.use_datagram_transport_for_data_channels = true;
475 CreateJsepTransportController(config);
476
477 auto description = CreateSessionDescriptionWithBundleGroup();
478 AddCryptoSettings(description.get());
479 absl::optional<cricket::OpaqueTransportParameters> params =
480 transport_controller_->GetTransportParameters(kAudioMid1);
481 for (auto& info : description->transport_infos()) {
482 info.description.opaque_parameters = params;
483 }
484
485 EXPECT_TRUE(transport_controller_
486 ->SetLocalDescription(SdpType::kOffer, description.get())
487 .ok());
488 EXPECT_TRUE(transport_controller_
489 ->SetRemoteDescription(SdpType::kAnswer, description.get())
490 .ok());
491
492 FakeDatagramTransport* datagram_transport =
493 static_cast<FakeDatagramTransport*>(
494 transport_controller_->GetDataChannelTransport(kAudioMid1));
495
496 ASSERT_NE(nullptr, datagram_transport);
497
498 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
499 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
500 << "Datagram transport for media was not enabled, and so DTLS transport "
501 "should be created.";
502
503 // Datagram transport is not used for media, so no max packet size is
504 // specified.
505 EXPECT_EQ(transport_controller_->GetMediaTransportConfig(kAudioMid1)
506 .rtp_max_packet_size,
507 absl::nullopt);
508
509 // Since datagram transport is not used for RTP, setting it to writable should
510 // not make the RTP transport writable.
511 datagram_transport->set_state(MediaTransportState::kWritable);
512 EXPECT_FALSE(transport_controller_->GetRtpTransport(kAudioMid1)
513 ->IsWritable(/*rtcp=*/false));
514}
515
Anton Sukhanov7940da02018-10-10 10:34:49 -0700516TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
517 FakeMediaTransportFactory fake_media_transport_factory;
518 JsepTransportController::Config config;
519
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800520 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800521 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700522 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800523 config.use_media_transport_for_data_channels = true;
524 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700525 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800526 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700527 AddCryptoSettings(description.get());
528
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800529 EXPECT_NE(absl::nullopt,
530 transport_controller_->GenerateOrGetLastMediaTransportOffer());
531
Anton Sukhanov7940da02018-10-10 10:34:49 -0700532 EXPECT_TRUE(transport_controller_
533 ->SetLocalDescription(SdpType::kOffer, description.get())
534 .ok());
535
536 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
537 transport_controller_->GetMediaTransport(kAudioMid1));
538
539 ASSERT_NE(nullptr, media_transport);
540
541 // After SetLocalDescription, media transport should be created as caller.
542 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800543 // We set the pre-shared key on the caller.
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700544 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800545 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700546
547 // Return nullptr for non-existing mids.
548 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800549
550 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
551 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
552 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700553}
554
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800555TEST_F(JsepTransportControllerTest,
556 GetMediaTransportOfferInTheConfigOnSubsequentCalls) {
557 FakeMediaTransportFactory fake_media_transport_factory;
558 WrapperMediaTransportFactory wrapping_factory(&fake_media_transport_factory);
559 JsepTransportController::Config config;
560
561 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
562 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
563 config.media_transport_factory = &wrapping_factory;
564 config.use_media_transport_for_data_channels = true;
565 config.use_media_transport_for_media = true;
566 CreateJsepTransportController(config);
567 auto description = CreateSessionDescriptionWithBundleGroup();
568 AddCryptoSettings(description.get());
569
570 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
571 transport_controller_->GenerateOrGetLastMediaTransportOffer();
572 ASSERT_NE(absl::nullopt, settings);
573
574 EXPECT_TRUE(transport_controller_
575 ->SetLocalDescription(SdpType::kOffer, description.get())
576 .ok());
577
578 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
579 transport_controller_->GetMediaTransport(kAudioMid1));
580
581 ASSERT_NE(nullptr, media_transport);
582
583 absl::optional<cricket::SessionDescription::MediaTransportSetting>
584 new_settings =
585 transport_controller_->GenerateOrGetLastMediaTransportOffer();
586 ASSERT_NE(absl::nullopt, new_settings);
587 EXPECT_EQ(settings->transport_name, new_settings->transport_name);
588 EXPECT_EQ(settings->transport_setting, new_settings->transport_setting);
589 EXPECT_EQ(1, wrapping_factory.created_transport_count());
590}
591
Anton Sukhanov7940da02018-10-10 10:34:49 -0700592TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
593 FakeMediaTransportFactory fake_media_transport_factory;
594 JsepTransportController::Config config;
595
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800596 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700597 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800598 config.use_media_transport_for_data_channels = true;
599 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700600 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800601 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700602 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800603 description->AddMediaTransportSetting("fake", "fake-remote-settings");
Anton Sukhanov7940da02018-10-10 10:34:49 -0700604 EXPECT_TRUE(transport_controller_
605 ->SetRemoteDescription(SdpType::kOffer, description.get())
606 .ok());
607
608 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
609 transport_controller_->GetMediaTransport(kAudioMid1));
610
611 ASSERT_NE(nullptr, media_transport);
612
613 // After SetRemoteDescription, media transport should be created as callee.
614 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800615 // We do not set pre-shared key on the callee, it comes in media transport
616 // settings.
617 EXPECT_EQ(absl::nullopt, media_transport->settings().pre_shared_key);
618 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700619
620 // Return nullptr for non-existing mids.
621 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800622
623 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
624 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
625 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700626}
627
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800628TEST_F(JsepTransportControllerTest, GetMediaTransportInCalleePassesSdp) {
629 FakeMediaTransportFactory fake_media_transport_factory;
630 JsepTransportController::Config config;
631
632 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
633 config.media_transport_factory = &fake_media_transport_factory;
634 config.use_media_transport_for_data_channels = true;
635 config.use_media_transport_for_media = true;
636 CreateJsepTransportController(config);
637 auto description = CreateSessionDescriptionWithBundleGroup();
638 AddCryptoSettings(description.get());
639 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
640 EXPECT_TRUE(transport_controller_
641 ->SetRemoteDescription(SdpType::kOffer, description.get())
642 .ok());
643
644 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
645 transport_controller_->GetMediaTransport(kAudioMid1));
646
647 ASSERT_NE(nullptr, media_transport);
648
649 EXPECT_EQ("this-is-a-test-setting",
650 media_transport->settings().remote_transport_parameters);
651}
652
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800653// Caller generates the offer if media transport returns empty offer (no
654// parameters).
655TEST_F(JsepTransportControllerTest, MediaTransportGeneratesSessionDescription) {
656 FakeMediaTransportFactory fake_media_transport_factory(
657 /*transport_offer=*/"");
658 JsepTransportController::Config config;
659
660 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
661 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
662 config.media_transport_factory = &fake_media_transport_factory;
663 config.use_media_transport_for_data_channels = true;
664 config.use_media_transport_for_media = true;
665 CreateJsepTransportController(config);
666 auto description = CreateSessionDescriptionWithBundleGroup();
667 AddCryptoSettings(description.get());
668 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
669 transport_controller_->GenerateOrGetLastMediaTransportOffer();
670
671 ASSERT_TRUE(settings.has_value());
672 EXPECT_EQ("fake", settings->transport_name);
673 // Fake media transport returns empty settings (but not nullopt settings!)
674 EXPECT_EQ("", settings->transport_setting);
675}
676
677// Caller generates the offer if media transport returns offer with parameters.
678TEST_F(JsepTransportControllerTest,
679 MediaTransportGeneratesSessionDescriptionWithOfferParams) {
680 FakeMediaTransportFactory fake_media_transport_factory(
681 /*transport_offer=*/"offer-params");
682 JsepTransportController::Config config;
683
684 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
685 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
686 config.media_transport_factory = &fake_media_transport_factory;
687 config.use_media_transport_for_data_channels = true;
688 config.use_media_transport_for_media = true;
689 CreateJsepTransportController(config);
690 auto description = CreateSessionDescriptionWithBundleGroup();
691 AddCryptoSettings(description.get());
692 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
693 transport_controller_->GenerateOrGetLastMediaTransportOffer();
694
695 ASSERT_TRUE(settings.has_value());
696 EXPECT_EQ("fake", settings->transport_name);
697 EXPECT_EQ("offer-params", settings->transport_setting);
698}
699
700// Caller skips the offer if media transport requests it.
701TEST_F(JsepTransportControllerTest,
702 MediaTransportGeneratesSkipsSessionDescription) {
703 FakeMediaTransportFactory fake_media_transport_factory(
704 /*transport_offer=*/absl::nullopt);
705 JsepTransportController::Config config;
706
707 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
708 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
709 config.media_transport_factory = &fake_media_transport_factory;
710 config.use_media_transport_for_data_channels = true;
711 config.use_media_transport_for_media = true;
712 CreateJsepTransportController(config);
713 auto description = CreateSessionDescriptionWithBundleGroup();
714 AddCryptoSettings(description.get());
715 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
716 transport_controller_->GenerateOrGetLastMediaTransportOffer();
717
718 // Fake media transport returns nullopt settings
719 ASSERT_EQ(absl::nullopt, settings);
720}
721
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800722// Caller ignores its own outgoing parameters.
723TEST_F(JsepTransportControllerTest,
724 GetMediaTransportInCallerIgnoresXmtSection) {
725 FakeMediaTransportFactory fake_media_transport_factory;
726 JsepTransportController::Config config;
727
728 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800729 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800730 config.media_transport_factory = &fake_media_transport_factory;
731 config.use_media_transport_for_data_channels = true;
732 config.use_media_transport_for_media = true;
733 CreateJsepTransportController(config);
734 auto description = CreateSessionDescriptionWithBundleGroup();
735 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800736 EXPECT_NE(absl::nullopt,
737 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800738 EXPECT_TRUE(transport_controller_
739 ->SetLocalDescription(SdpType::kOffer, description.get())
740 .ok());
741
742 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
743 transport_controller_->GetMediaTransport(kAudioMid1));
744
745 ASSERT_NE(nullptr, media_transport);
746
747 // Remote parameters are nullopt, because we are the offerer (we don't)
748 // have the remote transport parameters, only ours.
749 EXPECT_EQ(absl::nullopt,
750 media_transport->settings().remote_transport_parameters);
751}
752
753TEST_F(JsepTransportControllerTest,
754 GetMediaTransportInCalleeIgnoresDifferentTransport) {
755 FakeMediaTransportFactory fake_media_transport_factory;
756 JsepTransportController::Config config;
757
758 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800759 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800760 config.media_transport_factory = &fake_media_transport_factory;
761 config.use_media_transport_for_data_channels = true;
762 config.use_media_transport_for_media = true;
763 CreateJsepTransportController(config);
764 auto description = CreateSessionDescriptionWithBundleGroup();
765 AddCryptoSettings(description.get());
766 description->AddMediaTransportSetting("not-a-fake-transport",
767 "this-is-a-test-setting");
768 EXPECT_TRUE(transport_controller_
769 ->SetRemoteDescription(SdpType::kOffer, description.get())
770 .ok());
771
772 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
773 transport_controller_->GetMediaTransport(kAudioMid1));
774
775 ASSERT_NE(nullptr, media_transport);
776
777 EXPECT_EQ(absl::nullopt,
778 media_transport->settings().remote_transport_parameters);
779}
780
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700781TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
782 FakeMediaTransportFactory fake_media_transport_factory;
783 JsepTransportController::Config config;
784
785 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800786 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700787 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800788 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700789 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800790 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700791 EXPECT_TRUE(transport_controller_
792 ->SetRemoteDescription(SdpType::kOffer, description.get())
793 .ok());
794
795 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
796
797 // Even if we set local description with crypto now (after the remote offer
798 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800799 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700800 AddCryptoSettings(description2.get());
801 EXPECT_TRUE(transport_controller_
802 ->SetLocalDescription(SdpType::kAnswer, description2.get())
803 .ok());
804
805 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800806 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
807 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
808 << "Because media transport is NOT used (fallback to RTP), expected "
809 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700810}
811
812TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800813 AfterSettingAnswerTheSameMediaTransportIsReturnedCallee) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700814 FakeMediaTransportFactory fake_media_transport_factory;
815 JsepTransportController::Config config;
816
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800817 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800818 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700819 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800820 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700821 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800822 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700823 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800824 description->AddMediaTransportSetting("fake", "fake-settings");
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700825 EXPECT_TRUE(transport_controller_
826 ->SetRemoteDescription(SdpType::kOffer, description.get())
827 .ok());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700828 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
829 transport_controller_->GetMediaTransport(kAudioMid1));
830 EXPECT_NE(nullptr, media_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800831 EXPECT_FALSE(media_transport->pre_shared_key().has_value())
832 << "On the callee, preshared key is passed through the media-transport "
833 "settings (x-mt)";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700834
835 // Even if we set local description with crypto now (after the remote offer
836 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800837 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700838 AddCryptoSettings(description2.get());
839
840 RTCError result = transport_controller_->SetLocalDescription(
841 SdpType::kAnswer, description2.get());
842 EXPECT_TRUE(result.ok()) << result.message();
843
844 // Media transport did not change.
845 EXPECT_EQ(media_transport,
846 transport_controller_->GetMediaTransport(kAudioMid1));
847}
848
Zhi Huange818b6e2018-02-22 15:26:27 -0800849TEST_F(JsepTransportControllerTest, SetIceConfig) {
850 CreateJsepTransportController(JsepTransportController::Config());
851 auto description = CreateSessionDescriptionWithoutBundle();
852 EXPECT_TRUE(transport_controller_
853 ->SetLocalDescription(SdpType::kOffer, description.get())
854 .ok());
855
856 transport_controller_->SetIceConfig(
857 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
858 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
859 transport_controller_->GetDtlsTransport(kAudioMid1));
860 ASSERT_NE(nullptr, fake_audio_dtls);
861 EXPECT_EQ(kTimeout,
862 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
863 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
864
865 // Test that value stored in controller is applied to new transports.
866 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
867 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
868 nullptr);
869
870 EXPECT_TRUE(transport_controller_
871 ->SetLocalDescription(SdpType::kOffer, description.get())
872 .ok());
873 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
874 transport_controller_->GetDtlsTransport(kAudioMid2));
875 ASSERT_NE(nullptr, fake_audio_dtls);
876 EXPECT_EQ(kTimeout,
877 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
878 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
879}
880
881// Tests the getter and setter of the ICE restart flag.
882TEST_F(JsepTransportControllerTest, NeedIceRestart) {
883 CreateJsepTransportController(JsepTransportController::Config());
884 auto description = CreateSessionDescriptionWithoutBundle();
885 EXPECT_TRUE(transport_controller_
886 ->SetLocalDescription(SdpType::kOffer, description.get())
887 .ok());
888 EXPECT_TRUE(transport_controller_
889 ->SetRemoteDescription(SdpType::kAnswer, description.get())
890 .ok());
891
892 // Initially NeedsIceRestart should return false.
893 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
894 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
895 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
896 // true.
897 transport_controller_->SetNeedsIceRestartFlag();
898 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
899 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
900 // For a nonexistent transport, false should be returned.
901 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
902
903 // Reset the ice_ufrag/ice_pwd for audio.
904 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
905 audio_transport_info->description.ice_ufrag = kIceUfrag2;
906 audio_transport_info->description.ice_pwd = kIcePwd2;
907 EXPECT_TRUE(transport_controller_
908 ->SetLocalDescription(SdpType::kOffer, description.get())
909 .ok());
910 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
911 // return false for audio and true for video.
912 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
913 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
914}
915
916TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
917 CreateJsepTransportController(JsepTransportController::Config());
918 auto description = CreateSessionDescriptionWithBundleGroup();
919 EXPECT_TRUE(transport_controller_
920 ->SetLocalDescription(SdpType::kOffer, description.get())
921 .ok());
922 // After setting the local description, we should be able to start gathering
923 // candidates.
924 transport_controller_->MaybeStartGathering();
925 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
926 EXPECT_EQ(1, gathering_state_signal_count_);
927}
928
929TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
930 CreateJsepTransportController(JsepTransportController::Config());
931 auto description = CreateSessionDescriptionWithoutBundle();
932 transport_controller_->SetLocalDescription(SdpType::kOffer,
933 description.get());
934 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
935 description.get());
936 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
937 transport_controller_->GetDtlsTransport(kAudioMid1));
938 ASSERT_NE(nullptr, fake_audio_dtls);
939 Candidates candidates;
940 candidates.push_back(
941 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
942 EXPECT_TRUE(
943 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
944 EXPECT_EQ(1U,
945 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
946
947 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
948 EXPECT_EQ(0U,
949 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
950}
951
952TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
953 CreateJsepTransportController(JsepTransportController::Config());
954
955 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
956 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
957 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
958 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
959
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200960 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800961 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
962 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
963 certificate1);
964
965 // Apply the local certificate.
966 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
967 // Apply the local description.
968 EXPECT_TRUE(transport_controller_
969 ->SetLocalDescription(SdpType::kOffer, description.get())
970 .ok());
971 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
972 EXPECT_TRUE(returned_certificate);
973 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
974 returned_certificate->identity()->certificate().ToPEMString());
975
976 // Should fail if called for a nonexistant transport.
977 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
978
979 // Shouldn't be able to change the identity once set.
980 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
981 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
982 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
983 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
984}
985
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800986TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800987 CreateJsepTransportController(JsepTransportController::Config());
988 auto description = CreateSessionDescriptionWithBundleGroup();
989 EXPECT_TRUE(transport_controller_
990 ->SetLocalDescription(SdpType::kOffer, description.get())
991 .ok());
992 rtc::FakeSSLCertificate fake_certificate("fake_data");
993
994 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
995 transport_controller_->GetDtlsTransport(kAudioMid1));
996 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800997 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
998 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
999 ASSERT_TRUE(returned_cert_chain);
1000 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -08001001 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001002 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -08001003
1004 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001005 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -08001006}
1007
1008TEST_F(JsepTransportControllerTest, GetDtlsRole) {
1009 CreateJsepTransportController(JsepTransportController::Config());
1010 auto offer_certificate =
1011 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1012 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
1013 auto answer_certificate =
1014 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1015 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
1016 transport_controller_->SetLocalCertificate(offer_certificate);
1017
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001018 auto offer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001019 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1020 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1021 offer_certificate);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001022 auto answer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001023 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1024 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1025 answer_certificate);
1026
1027 EXPECT_TRUE(transport_controller_
1028 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
1029 .ok());
1030
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001031 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -08001032 transport_controller_->GetDtlsRole(kAudioMid1);
1033 // The DTLS role is not decided yet.
1034 EXPECT_FALSE(role);
1035 EXPECT_TRUE(transport_controller_
1036 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
1037 .ok());
1038 role = transport_controller_->GetDtlsRole(kAudioMid1);
1039
1040 ASSERT_TRUE(role);
1041 EXPECT_EQ(rtc::SSL_CLIENT, *role);
1042}
1043
1044TEST_F(JsepTransportControllerTest, GetStats) {
1045 CreateJsepTransportController(JsepTransportController::Config());
1046 auto description = CreateSessionDescriptionWithBundleGroup();
1047 EXPECT_TRUE(transport_controller_
1048 ->SetLocalDescription(SdpType::kOffer, description.get())
1049 .ok());
1050
1051 cricket::TransportStats stats;
1052 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
1053 EXPECT_EQ(kAudioMid1, stats.transport_name);
1054 EXPECT_EQ(1u, stats.channel_stats.size());
1055 // Return false for non-existing transport.
1056 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
1057}
1058
1059TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
1060 CreateJsepTransportController(JsepTransportController::Config());
1061 auto description = CreateSessionDescriptionWithoutBundle();
1062 EXPECT_TRUE(transport_controller_
1063 ->SetLocalDescription(SdpType::kOffer, description.get())
1064 .ok());
1065
1066 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
1067 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1068 fake_ice->SetCandidatesGatheringComplete();
1069 fake_ice->SetConnectionCount(1);
1070 // The connection stats will be failed if there is no active connection.
1071 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +00001072 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001073 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001074 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1075 ice_connection_state_, kTimeout);
1076 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001077 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1078 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +02001079 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001080}
1081
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001082TEST_F(JsepTransportControllerTest,
1083 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001084 CreateJsepTransportController(JsepTransportController::Config());
1085 auto description = CreateSessionDescriptionWithoutBundle();
1086 EXPECT_TRUE(transport_controller_
1087 ->SetLocalDescription(SdpType::kOffer, description.get())
1088 .ok());
1089
1090 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1091 transport_controller_->GetDtlsTransport(kAudioMid1));
1092 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1093 transport_controller_->GetDtlsTransport(kVideoMid1));
1094
1095 // First, have one transport connect, and another fail, to ensure that
1096 // the first transport connecting didn't trigger a "connected" state signal.
1097 // We should only get a signal when all are connected.
1098 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
1099 fake_audio_dtls->SetWritable(true);
1100 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1101 // Decrease the number of the connection to trigger the signal.
1102 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
1103 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
1104 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1105
Alex Loiko9289eda2018-11-23 16:18:59 +00001106 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001107 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001108 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1109 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001110 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001111 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1112 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001113 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001114
Jonas Olsson635474e2018-10-18 15:58:17 +02001115 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1116 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001117 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
1118 // the transport state to be STATE_CONNECTING.
1119 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
1120 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001121 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001122 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001123 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
1124 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001125 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001126 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1127 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001128 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001129}
1130
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001131TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001132 SignalConnectionStateConnectedWithMediaTransportAndNoDtlsCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001133 FakeMediaTransportFactory fake_media_transport_factory;
1134 JsepTransportController::Config config;
1135 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001136 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1137 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001138 config.use_media_transport_for_data_channels = true;
1139 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001140 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001141
1142 // Media Transport is only used with bundle.
1143 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001144 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001145 EXPECT_NE(absl::nullopt,
1146 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001147 EXPECT_TRUE(transport_controller_
1148 ->SetLocalDescription(SdpType::kOffer, description.get())
1149 .ok());
1150
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001151 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1152 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1153 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1154 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001155 EXPECT_EQ(fake_audio_ice, fake_video_ice);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001156 fake_audio_ice->SetConnectionCount(2);
1157 fake_audio_ice->SetConnectionCount(1);
1158 fake_video_ice->SetConnectionCount(2);
1159 fake_video_ice->SetConnectionCount(1);
1160 fake_audio_ice->SetWritable(true);
1161 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001162
1163 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001164 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1165 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001166
1167 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1168 transport_controller_->GetMediaTransport(kAudioMid1));
1169
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001170 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001171
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001172 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001173 // Only one media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001174 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001175}
1176
1177TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001178 SignalConnectionStateConnectedWithMediaTransportCaller) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001179 FakeMediaTransportFactory fake_media_transport_factory;
1180 JsepTransportController::Config config;
1181 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001182 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1183 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001184 config.use_media_transport_for_media = true;
1185 CreateJsepTransportController(config);
1186
1187 // Media Transport is only used with bundle.
1188 auto description = CreateSessionDescriptionWithBundleGroup();
1189 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001190 EXPECT_NE(absl::nullopt,
1191 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001192 EXPECT_TRUE(transport_controller_
1193 ->SetLocalDescription(SdpType::kOffer, description.get())
1194 .ok());
1195
1196 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1197 transport_controller_->GetDtlsTransport(kAudioMid1));
1198 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1199 transport_controller_->GetDtlsTransport(kVideoMid1));
1200
1201 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1202 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1203 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1204 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1205 fake_audio_ice->SetConnectionCount(2);
1206 fake_audio_ice->SetConnectionCount(1);
1207 fake_video_ice->SetConnectionCount(2);
1208 fake_video_ice->SetConnectionCount(1);
1209 fake_audio_ice->SetWritable(true);
1210 fake_video_ice->SetWritable(true);
1211 fake_audio_dtls->SetWritable(true);
1212 fake_video_dtls->SetWritable(true);
1213
1214 // Still not connected, because we are waiting for media transport.
1215 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1216 kTimeout);
1217
1218 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1219 transport_controller_->GetMediaTransport(kAudioMid1));
1220
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001221 ASSERT_NE(nullptr, media_transport);
1222
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001223 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1224 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1225 kTimeout);
1226
1227 // Still waiting for the second media transport.
1228 media_transport = static_cast<FakeMediaTransport*>(
1229 transport_controller_->GetMediaTransport(kVideoMid1));
1230 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1231
1232 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
1233}
1234
1235TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001236 SignalConnectionStateFailedWhenMediaTransportClosedCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001237 FakeMediaTransportFactory fake_media_transport_factory;
1238 JsepTransportController::Config config;
1239 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001240 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1241 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001242 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001243 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001244 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001245 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001246 EXPECT_NE(absl::nullopt,
1247 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001248 EXPECT_TRUE(transport_controller_
1249 ->SetLocalDescription(SdpType::kOffer, description.get())
1250 .ok());
1251
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001252 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1253 transport_controller_->GetDtlsTransport(kAudioMid1));
1254 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1255 transport_controller_->GetDtlsTransport(kVideoMid1));
1256
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001257 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1258 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1259 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1260 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1261 fake_audio_ice->SetWritable(true);
1262 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001263 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001264 fake_audio_ice->SetConnectionCount(2);
1265 fake_audio_ice->SetConnectionCount(1);
1266 fake_video_ice->SetConnectionCount(2);
1267 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001268
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001269 fake_audio_dtls->SetWritable(true);
1270 fake_video_dtls->SetWritable(true);
1271
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001272 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1273 transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001274 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001275 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1276
1277 media_transport = static_cast<FakeMediaTransport*>(
1278 transport_controller_->GetMediaTransport(kVideoMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001279 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001280
1281 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1282
Alex Loiko9289eda2018-11-23 16:18:59 +00001283 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001284
1285 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +00001286 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001287}
1288
Zhi Huange818b6e2018-02-22 15:26:27 -08001289TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1290 CreateJsepTransportController(JsepTransportController::Config());
1291 auto description = CreateSessionDescriptionWithoutBundle();
1292 EXPECT_TRUE(transport_controller_
1293 ->SetLocalDescription(SdpType::kOffer, description.get())
1294 .ok());
1295
1296 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1297 transport_controller_->GetDtlsTransport(kAudioMid1));
1298 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1299 transport_controller_->GetDtlsTransport(kVideoMid1));
1300
1301 // First, have one transport connect, and another fail, to ensure that
1302 // the first transport connecting didn't trigger a "connected" state signal.
1303 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001304 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1305 IceTransportState::kCompleted,
1306 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001307 fake_audio_dtls->SetWritable(true);
1308 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001309
1310 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1311 ice_connection_state_, kTimeout);
1312 EXPECT_EQ(1, ice_connection_state_signal_count_);
1313 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1314 combined_connection_state_, kTimeout);
1315 EXPECT_EQ(1, combined_connection_state_signal_count_);
1316
1317 fake_video_dtls->fake_ice_transport()->SetTransportState(
1318 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001319 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1320
Alex Loiko9289eda2018-11-23 16:18:59 +00001321 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001322 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001323 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1324 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001325 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001326 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1327 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001328 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001329
Jonas Olsson635474e2018-10-18 15:58:17 +02001330 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1331 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001332 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1333 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001334 fake_video_dtls->fake_ice_transport()->SetTransportState(
1335 IceTransportState::kCompleted,
1336 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001337 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001338 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +01001339 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001340 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1341 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001342 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001343 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1344 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001345 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001346}
1347
1348TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1349 CreateJsepTransportController(JsepTransportController::Config());
1350 auto description = CreateSessionDescriptionWithoutBundle();
1351 EXPECT_TRUE(transport_controller_
1352 ->SetLocalDescription(SdpType::kOffer, description.get())
1353 .ok());
1354
1355 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1356 transport_controller_->GetDtlsTransport(kAudioMid1));
1357 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1358 // Should be in the gathering state as soon as any transport starts gathering.
1359 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1360 EXPECT_EQ(1, gathering_state_signal_count_);
1361}
1362
1363TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1364 CreateJsepTransportController(JsepTransportController::Config());
1365 auto description = CreateSessionDescriptionWithoutBundle();
1366 EXPECT_TRUE(transport_controller_
1367 ->SetLocalDescription(SdpType::kOffer, description.get())
1368 .ok());
1369
1370 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1371 transport_controller_->GetDtlsTransport(kAudioMid1));
1372 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1373 transport_controller_->GetDtlsTransport(kVideoMid1));
1374
1375 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1376 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1377 EXPECT_EQ(1, gathering_state_signal_count_);
1378
1379 // Have one transport finish gathering, to make sure gathering
1380 // completion wasn't signalled if only one transport finished gathering.
1381 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1382 EXPECT_EQ(1, gathering_state_signal_count_);
1383
1384 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1385 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1386 EXPECT_EQ(1, gathering_state_signal_count_);
1387
1388 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1389 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1390 EXPECT_EQ(2, gathering_state_signal_count_);
1391}
1392
1393// Test that when the last transport that hasn't finished connecting and/or
1394// gathering is destroyed, the aggregate state jumps to "completed". This can
1395// happen if, for example, we have an audio and video transport, the audio
1396// transport completes, then we start bundling video on the audio transport.
1397TEST_F(JsepTransportControllerTest,
1398 SignalingWhenLastIncompleteTransportDestroyed) {
1399 CreateJsepTransportController(JsepTransportController::Config());
1400 auto description = CreateSessionDescriptionWithBundleGroup();
1401 EXPECT_TRUE(transport_controller_
1402 ->SetLocalDescription(SdpType::kOffer, description.get())
1403 .ok());
1404
1405 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1406 transport_controller_->GetDtlsTransport(kAudioMid1));
1407 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1408 transport_controller_->GetDtlsTransport(kVideoMid1));
1409 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1410
1411 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1412 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1413 EXPECT_EQ(1, gathering_state_signal_count_);
1414
1415 // Let the audio transport complete.
1416 fake_audio_dtls->SetWritable(true);
1417 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1418 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001419 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001420 EXPECT_EQ(1, gathering_state_signal_count_);
1421
1422 // Set the remote description and enable the bundle.
1423 EXPECT_TRUE(transport_controller_
1424 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1425 .ok());
1426 // The BUNDLE should be enabled, the incomplete video transport should be
1427 // deleted and the states shoud be updated.
1428 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1429 transport_controller_->GetDtlsTransport(kVideoMid1));
1430 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001431 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1432 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1433 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001434 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1435 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001436 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1437 EXPECT_EQ(2, gathering_state_signal_count_);
1438}
1439
1440TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1441 CreateJsepTransportController(JsepTransportController::Config());
1442 auto description = CreateSessionDescriptionWithBundleGroup();
1443 EXPECT_TRUE(transport_controller_
1444 ->SetLocalDescription(SdpType::kOffer, description.get())
1445 .ok());
1446 transport_controller_->MaybeStartGathering();
1447
1448 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1449 transport_controller_->GetDtlsTransport(kAudioMid1));
1450 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1451 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1452 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1453 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1454}
1455
1456TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1457 network_thread_ = rtc::Thread::CreateWithSocketServer();
1458 network_thread_->Start();
1459 CreateJsepTransportController(JsepTransportController::Config(),
1460 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 14:57:52 +01001461 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 15:26:27 -08001462 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1463
1464 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001465 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001466 EXPECT_EQ(2, connection_state_signal_count_);
1467
1468 // new --> gathering --> complete
1469 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1470 EXPECT_EQ(2, gathering_state_signal_count_);
1471
1472 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1473 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1474 EXPECT_EQ(2, candidates_signal_count_);
1475
1476 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1477}
1478
1479// Older versions of Chrome expect the ICE role to be re-determined when an
1480// ICE restart occurs, and also don't perform conflict resolution correctly,
1481// so for now we can't safely stop doing this.
1482// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1483// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1484// enough population.
1485TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1486 CreateJsepTransportController(JsepTransportController::Config());
1487 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001488 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001489 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1490 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1491 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001492 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001493 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1494 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1495 nullptr);
1496
1497 EXPECT_TRUE(transport_controller_
1498 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1499 .ok());
1500 EXPECT_TRUE(transport_controller_
1501 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1502 .ok());
1503
1504 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1505 transport_controller_->GetDtlsTransport(kAudioMid1));
1506 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1507 fake_dtls->fake_ice_transport()->GetIceRole());
1508
1509 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001510 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001511 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1512 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1513 nullptr);
1514 EXPECT_TRUE(
1515 transport_controller_
1516 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1517 .ok());
1518 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1519 fake_dtls->fake_ice_transport()->GetIceRole());
1520}
1521
1522// Test that if the TransportController was created with the
1523// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1524// redetermined on an ICE restart.
1525TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1526 JsepTransportController::Config config;
1527 config.redetermine_role_on_ice_restart = false;
1528
1529 CreateJsepTransportController(config);
1530 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001531 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001532 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1533 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1534 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001535 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001536 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1537 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1538 nullptr);
1539
1540 EXPECT_TRUE(transport_controller_
1541 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1542 .ok());
1543 EXPECT_TRUE(transport_controller_
1544 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1545 .ok());
1546
1547 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1548 transport_controller_->GetDtlsTransport(kAudioMid1));
1549 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1550 fake_dtls->fake_ice_transport()->GetIceRole());
1551
1552 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001553 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001554 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1555 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1556 nullptr);
1557 EXPECT_TRUE(
1558 transport_controller_
1559 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1560 .ok());
1561 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1562 fake_dtls->fake_ice_transport()->GetIceRole());
1563}
1564
1565// Tests ICE-Lite mode in remote answer.
1566TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1567 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001568 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001569 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1570 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1571 nullptr);
1572 EXPECT_TRUE(transport_controller_
1573 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1574 .ok());
1575 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1576 transport_controller_->GetDtlsTransport(kAudioMid1));
1577 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1578 fake_dtls->fake_ice_transport()->GetIceRole());
1579 EXPECT_EQ(cricket::ICEMODE_FULL,
1580 fake_dtls->fake_ice_transport()->remote_ice_mode());
1581
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001582 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001583 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1584 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1585 nullptr);
1586 EXPECT_TRUE(transport_controller_
1587 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1588 .ok());
1589 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1590 fake_dtls->fake_ice_transport()->GetIceRole());
1591 EXPECT_EQ(cricket::ICEMODE_LITE,
1592 fake_dtls->fake_ice_transport()->remote_ice_mode());
1593}
1594
1595// Tests that the ICE role remains "controlling" if a subsequent offer that
1596// does an ICE restart is received from an ICE lite endpoint. Regression test
1597// for: https://crbug.com/710760
1598TEST_F(JsepTransportControllerTest,
1599 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1600 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001601 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001602 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1603 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1604 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001605 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001606 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1607 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1608 nullptr);
1609 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1610 // local side is the controlling.
1611 EXPECT_TRUE(transport_controller_
1612 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1613 .ok());
1614 EXPECT_TRUE(transport_controller_
1615 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1616 .ok());
1617 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1618 transport_controller_->GetDtlsTransport(kAudioMid1));
1619 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1620 fake_dtls->fake_ice_transport()->GetIceRole());
1621
1622 // In the subsequence remote offer triggers an ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001623 auto remote_offer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001624 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1625 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1626 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001627 auto local_answer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001628 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1629 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1630 nullptr);
1631 EXPECT_TRUE(transport_controller_
1632 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1633 .ok());
1634 EXPECT_TRUE(transport_controller_
1635 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1636 .ok());
1637 fake_dtls = static_cast<FakeDtlsTransport*>(
1638 transport_controller_->GetDtlsTransport(kAudioMid1));
1639 // The local side is still the controlling role since the remote side is using
1640 // ICE-Lite.
1641 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1642 fake_dtls->fake_ice_transport()->GetIceRole());
1643}
1644
1645// Tests that the SDP has more than one audio/video m= sections.
1646TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1647 CreateJsepTransportController(JsepTransportController::Config());
1648 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1649 bundle_group.AddContentName(kAudioMid1);
1650 bundle_group.AddContentName(kAudioMid2);
1651 bundle_group.AddContentName(kVideoMid1);
1652 bundle_group.AddContentName(kDataMid1);
1653
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001654 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001655 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1656 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1657 nullptr);
1658 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1659 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1660 nullptr);
1661 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1662 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1663 nullptr);
1664 AddDataSection(local_offer.get(), kDataMid1,
1665 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1666 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1667 nullptr);
1668
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001669 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001670 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1671 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1672 nullptr);
1673 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1674 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1675 nullptr);
1676 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1677 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1678 nullptr);
1679 AddDataSection(remote_answer.get(), kDataMid1,
1680 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1681 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1682 nullptr);
1683
1684 local_offer->AddGroup(bundle_group);
1685 remote_answer->AddGroup(bundle_group);
1686
1687 EXPECT_TRUE(transport_controller_
1688 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1689 .ok());
1690 EXPECT_TRUE(transport_controller_
1691 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1692 .ok());
1693 // Verify that all the sections are bundled on kAudio1.
1694 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1695 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1696 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1697 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1698 EXPECT_EQ(transport1, transport2);
1699 EXPECT_EQ(transport1, transport3);
1700 EXPECT_EQ(transport1, transport4);
1701
Harald Alvestrandad88c882018-11-28 16:47:46 +01001702 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1703 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1704
Zhi Huange818b6e2018-02-22 15:26:27 -08001705 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1706 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1707 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1708 EXPECT_EQ(transport1, it->second);
1709 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1710 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1711 EXPECT_EQ(transport1, it->second);
1712 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1713 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1714 EXPECT_EQ(transport1, it->second);
1715 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1716 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1717 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
Zhi Huange818b6e2018-02-22 15:26:27 -08001718}
1719
1720// Tests that only a subset of all the m= sections are bundled.
1721TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1722 CreateJsepTransportController(JsepTransportController::Config());
1723 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1724 bundle_group.AddContentName(kAudioMid1);
1725 bundle_group.AddContentName(kVideoMid1);
1726
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001727 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001728 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1729 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1730 nullptr);
1731 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1732 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1733 nullptr);
1734 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1735 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1736 nullptr);
1737
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001738 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001739 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1740 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1741 nullptr);
1742 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1743 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1744 nullptr);
1745 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1746 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1747 nullptr);
1748
1749 local_offer->AddGroup(bundle_group);
1750 remote_answer->AddGroup(bundle_group);
1751 EXPECT_TRUE(transport_controller_
1752 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1753 .ok());
1754 EXPECT_TRUE(transport_controller_
1755 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1756 .ok());
1757
1758 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1759 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1760 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1761 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1762 EXPECT_NE(transport1, transport2);
1763 EXPECT_EQ(transport1, transport3);
1764
1765 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1766 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1767 EXPECT_EQ(transport1, it->second);
1768 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001769 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001770}
1771
1772// Tests that the initial offer/answer only have data section and audio/video
1773// sections are added in the subsequent offer.
1774TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1775 CreateJsepTransportController(JsepTransportController::Config());
1776 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1777 bundle_group.AddContentName(kDataMid1);
1778
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001779 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001780 AddDataSection(local_offer.get(), kDataMid1,
1781 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1782 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1783 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001784 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001785 AddDataSection(remote_answer.get(), kDataMid1,
1786 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1787 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1788 nullptr);
1789 local_offer->AddGroup(bundle_group);
1790 remote_answer->AddGroup(bundle_group);
1791
1792 EXPECT_TRUE(transport_controller_
1793 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1794 .ok());
1795 EXPECT_TRUE(transport_controller_
1796 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1797 .ok());
1798 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1799
1800 // Add audio/video sections in subsequent offer.
1801 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1802 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1803 nullptr);
1804 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1805 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1806 nullptr);
1807 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1808 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1809 nullptr);
1810 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1811 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1812 nullptr);
1813
1814 // Reset the bundle group and do another offer/answer exchange.
1815 bundle_group.AddContentName(kAudioMid1);
1816 bundle_group.AddContentName(kVideoMid1);
1817 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1818 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1819 local_offer->AddGroup(bundle_group);
1820 remote_answer->AddGroup(bundle_group);
1821
1822 EXPECT_TRUE(transport_controller_
1823 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1824 .ok());
1825 EXPECT_TRUE(transport_controller_
1826 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1827 .ok());
1828
1829 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1830 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1831 EXPECT_EQ(data_transport, audio_transport);
1832 EXPECT_EQ(data_transport, video_transport);
1833}
1834
1835TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1836 CreateJsepTransportController(JsepTransportController::Config());
1837 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1838 bundle_group.AddContentName(kAudioMid1);
1839 bundle_group.AddContentName(kVideoMid1);
1840 bundle_group.AddContentName(kDataMid1);
1841
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001842 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001843 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1844 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1845 nullptr);
1846 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1847 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1848 nullptr);
1849 AddDataSection(local_offer.get(), kDataMid1,
1850 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1851 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1852 nullptr);
1853
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001854 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001855 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1856 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1857 nullptr);
1858 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1859 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1860 nullptr);
1861 AddDataSection(remote_answer.get(), kDataMid1,
1862 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1863 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1864 nullptr);
1865 // Reject video and data section.
1866 remote_answer->contents()[1].rejected = true;
1867 remote_answer->contents()[2].rejected = true;
1868
1869 local_offer->AddGroup(bundle_group);
1870 remote_answer->AddGroup(bundle_group);
1871
1872 EXPECT_TRUE(transport_controller_
1873 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1874 .ok());
1875 EXPECT_TRUE(transport_controller_
1876 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1877 .ok());
1878
1879 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1880 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1881 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1882 // Verify the signals are fired correctly.
1883 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1884 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1885 EXPECT_EQ(nullptr, it->second);
1886 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1887 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1888 EXPECT_EQ(nullptr, it2->second);
1889}
1890
1891// Tests that changing the bundled MID in subsequent offer/answer exchange is
1892// not supported.
1893// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1894// fixed
1895TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1896 CreateJsepTransportController(JsepTransportController::Config());
1897 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1898 bundle_group.AddContentName(kAudioMid1);
1899 bundle_group.AddContentName(kVideoMid1);
1900
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001901 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001902 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1903 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1904 nullptr);
1905 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1906 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1907 nullptr);
1908
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001909 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001910 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1911 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1912 nullptr);
1913 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1914 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1915 nullptr);
1916
1917 local_offer->AddGroup(bundle_group);
1918 remote_answer->AddGroup(bundle_group);
1919 EXPECT_TRUE(transport_controller_
1920 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1921 .ok());
1922 EXPECT_TRUE(transport_controller_
1923 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1924 .ok());
1925 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1926 transport_controller_->GetRtpTransport(kVideoMid1));
1927
1928 // Reorder the bundle group.
1929 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1930 bundle_group.AddContentName(kAudioMid1);
1931 // The answerer uses the new bundle group and now the bundle mid is changed to
1932 // |kVideo1|.
1933 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1934 remote_answer->AddGroup(bundle_group);
1935 EXPECT_TRUE(transport_controller_
1936 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1937 .ok());
1938 EXPECT_FALSE(transport_controller_
1939 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1940 .ok());
1941}
Zhi Huange830e682018-03-30 10:48:35 -07001942// Test that rejecting only the first m= section of a BUNDLE group is treated as
1943// an error, but rejecting all of them works as expected.
1944TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1945 CreateJsepTransportController(JsepTransportController::Config());
1946 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1947 bundle_group.AddContentName(kAudioMid1);
1948 bundle_group.AddContentName(kVideoMid1);
1949 bundle_group.AddContentName(kDataMid1);
1950
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001951 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001952 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1953 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1954 nullptr);
1955 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1956 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1957 nullptr);
1958 AddDataSection(local_offer.get(), kDataMid1,
1959 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1960 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1961 nullptr);
1962
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001963 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001964 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1965 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1966 nullptr);
1967 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1968 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1969 nullptr);
1970 AddDataSection(remote_answer.get(), kDataMid1,
1971 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1972 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1973 nullptr);
1974 // Reject audio content in answer.
1975 remote_answer->contents()[0].rejected = true;
1976
1977 local_offer->AddGroup(bundle_group);
1978 remote_answer->AddGroup(bundle_group);
1979
1980 EXPECT_TRUE(transport_controller_
1981 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1982 .ok());
1983 EXPECT_FALSE(transport_controller_
1984 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1985 .ok());
1986
1987 // Reject all the contents.
1988 remote_answer->contents()[1].rejected = true;
1989 remote_answer->contents()[2].rejected = true;
1990 EXPECT_TRUE(transport_controller_
1991 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1992 .ok());
1993 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1994 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1995 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1996}
1997
1998// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1999// is used.
2000TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
2001 JsepTransportController::Config config;
2002 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2003 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002004 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002005 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2006 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2007 nullptr);
2008
2009 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
2010 // Applying a non-RTCP-mux offer is expected to fail.
2011 EXPECT_FALSE(transport_controller_
2012 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2013 .ok());
2014}
2015
2016// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
2017// is used.
2018TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
2019 JsepTransportController::Config config;
2020 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2021 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002022 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002023 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2024 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2025 nullptr);
2026 EXPECT_TRUE(transport_controller_
2027 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2028 .ok());
2029
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002030 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002031 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2032 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
2033 nullptr);
2034 // Applying a non-RTCP-mux answer is expected to fail.
2035 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
2036 EXPECT_FALSE(transport_controller_
2037 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2038 .ok());
2039}
Zhi Huange818b6e2018-02-22 15:26:27 -08002040
Zhi Huangd2248f82018-04-10 14:41:03 -07002041// This tests that the BUNDLE group in answer should be a subset of the offered
2042// group.
2043TEST_F(JsepTransportControllerTest,
2044 AddContentToBundleGroupInAnswerNotSupported) {
2045 CreateJsepTransportController(JsepTransportController::Config());
2046 auto local_offer = CreateSessionDescriptionWithoutBundle();
2047 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2048
2049 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2050 offer_bundle_group.AddContentName(kAudioMid1);
2051 local_offer->AddGroup(offer_bundle_group);
2052
2053 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2054 answer_bundle_group.AddContentName(kAudioMid1);
2055 answer_bundle_group.AddContentName(kVideoMid1);
2056 remote_answer->AddGroup(answer_bundle_group);
2057 EXPECT_TRUE(transport_controller_
2058 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2059 .ok());
2060 EXPECT_FALSE(transport_controller_
2061 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2062 .ok());
2063}
2064
2065// This tests that the BUNDLE group with non-existing MID should be rejectd.
2066TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
2067 CreateJsepTransportController(JsepTransportController::Config());
2068 auto local_offer = CreateSessionDescriptionWithoutBundle();
2069 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2070
2071 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2072 // The BUNDLE group is invalid because there is no data section in the
2073 // description.
2074 invalid_bundle_group.AddContentName(kDataMid1);
2075 local_offer->AddGroup(invalid_bundle_group);
2076 remote_answer->AddGroup(invalid_bundle_group);
2077
2078 EXPECT_FALSE(transport_controller_
2079 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2080 .ok());
2081 EXPECT_FALSE(transport_controller_
2082 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2083 .ok());
2084}
2085
2086// This tests that an answer shouldn't be able to remove an m= section from an
2087// established group without rejecting it.
2088TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
2089 CreateJsepTransportController(JsepTransportController::Config());
2090
2091 auto local_offer = CreateSessionDescriptionWithBundleGroup();
2092 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
2093 EXPECT_TRUE(transport_controller_
2094 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2095 .ok());
2096 EXPECT_TRUE(transport_controller_
2097 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2098 .ok());
2099
2100 // Do an re-offer/answer.
2101 EXPECT_TRUE(transport_controller_
2102 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2103 .ok());
2104 auto new_answer = CreateSessionDescriptionWithoutBundle();
2105 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2106 // The answer removes video from the BUNDLE group without rejecting it is
2107 // invalid.
2108 new_bundle_group.AddContentName(kAudioMid1);
2109 new_answer->AddGroup(new_bundle_group);
2110
2111 // Applying invalid answer is expected to fail.
2112 EXPECT_FALSE(transport_controller_
2113 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2114 .ok());
2115
2116 // Rejected the video content.
2117 auto video_content = new_answer->GetContentByName(kVideoMid1);
2118 ASSERT_TRUE(video_content);
2119 video_content->rejected = true;
2120 EXPECT_TRUE(transport_controller_
2121 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2122 .ok());
2123}
2124
Steve Anton2bed3972019-01-04 17:04:30 -08002125// Test that the JsepTransportController can process a new local and remote
2126// description that changes the tagged BUNDLE group with the max-bundle policy
2127// specified.
2128// This is a regression test for bugs.webrtc.org/9954
2129TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
2130 CreateJsepTransportController(JsepTransportController::Config());
2131
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002132 auto local_offer = std::make_unique<cricket::SessionDescription>();
Steve Anton2bed3972019-01-04 17:04:30 -08002133 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2134 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2135 nullptr);
2136 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
2137 bundle_group.AddContentName(kAudioMid1);
2138 local_offer->AddGroup(bundle_group);
2139 EXPECT_TRUE(transport_controller_
2140 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2141 .ok());
2142
2143 std::unique_ptr<cricket::SessionDescription> remote_answer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002144 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002145 EXPECT_TRUE(transport_controller_
2146 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2147 .ok());
2148
2149 std::unique_ptr<cricket::SessionDescription> local_reoffer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002150 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002151 local_reoffer->contents()[0].rejected = true;
2152 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
2153 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2154 nullptr);
2155 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
2156 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2157 new_bundle_group.AddContentName(kVideoMid1);
2158 local_reoffer->AddGroup(new_bundle_group);
2159
2160 EXPECT_TRUE(transport_controller_
2161 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
2162 .ok());
2163
2164 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002165 local_reoffer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002166 EXPECT_TRUE(
2167 transport_controller_
2168 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
2169 .ok());
2170}
2171
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07002172constexpr char kFakeTransportParameters[] = "fake-params";
2173
2174// Test fixture that provides common setup and helpers for tests related to the
2175// datagram transport.
2176class JsepTransportControllerDatagramTest
2177 : public JsepTransportControllerTest,
2178 public testing::WithParamInterface<bool> {
2179 public:
2180 JsepTransportControllerDatagramTest()
2181 : JsepTransportControllerTest(),
2182 fake_media_transport_factory_(kFakeTransportParameters) {
2183 JsepTransportController::Config config;
2184 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2185 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2186 config.media_transport_factory = &fake_media_transport_factory_;
2187 config.use_datagram_transport = true;
2188 CreateJsepTransportController(config);
2189 }
2190
2191 // Whether the JsepTransportController under test acts as the offerer or
2192 // answerer in this test.
2193 bool IsOfferer() { return GetParam(); }
2194
2195 // Sets a description as local or remote based on type and current
2196 // perspective.
2197 RTCError SetDescription(SdpType type,
2198 const cricket::SessionDescription* description) {
2199 if (IsOfferer() == (type == SdpType::kOffer)) {
2200 return transport_controller_->SetLocalDescription(type, description);
2201 } else {
2202 return transport_controller_->SetRemoteDescription(type, description);
2203 }
2204 }
2205
2206 // Creates a session description with the settings necessary for datagram
2207 // transport (bundle + crypto) and the given |transport_params|.
2208 std::unique_ptr<cricket::SessionDescription>
2209 CreateSessionDescriptionForDatagramTransport(
2210 absl::optional<cricket::OpaqueTransportParameters> transport_params) {
2211 auto description = CreateSessionDescriptionWithBundleGroup();
2212 AddCryptoSettings(description.get());
2213
2214 for (auto& info : description->transport_infos()) {
2215 info.description.opaque_parameters = transport_params;
2216 }
2217 return description;
2218 }
2219
2220 // Creates transport parameters with |protocol| and |parameters|
2221 // matching what |fake_media_transport_factory_| provides.
2222 cricket::OpaqueTransportParameters CreateTransportParameters() {
2223 cricket::OpaqueTransportParameters params;
2224 params.protocol = fake_media_transport_factory_.GetTransportName();
2225 params.parameters = "fake-params";
2226 return params;
2227 }
2228
2229 protected:
2230 FakeMediaTransportFactory fake_media_transport_factory_;
2231};
2232
2233TEST_P(JsepTransportControllerDatagramTest, InitDatagramTransport) {
2234 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2235 if (IsOfferer()) {
2236 // Getting transport parameters is allowed before setting a description.
2237 // This is necessary so that the offerer can include these params.
2238 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2239 fake_params);
2240 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2241 fake_params);
2242 }
2243
2244 // Setting a description activates the datagram transport without changing
2245 // transport parameters.
2246 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2247 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2248
2249 // After setting an offer with transport parameters, those parameters are
2250 // reflected by the controller.
2251 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2252 fake_params);
2253 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2254 fake_params);
2255}
2256
2257TEST_P(JsepTransportControllerDatagramTest,
2258 OfferMissingDatagramTransportParams) {
2259 if (IsOfferer()) {
2260 // This test doesn't make sense from the offerer's perspective, as the offer
2261 // must contain datagram transport params if the offerer supports it.
2262 return;
2263 }
2264
2265 auto description =
2266 CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2267 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2268
2269 // The offer didn't contain any datagram transport parameters, so the answer
2270 // won't either.
2271 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2272 absl::nullopt);
2273 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2274 absl::nullopt);
2275}
2276
2277TEST_P(JsepTransportControllerDatagramTest, OfferHasWrongTransportName) {
2278 if (IsOfferer()) {
2279 // This test doesn't make sense from the offerer's perspective, as the
2280 // offerer cannot offer itself the wrong transport.
2281 return;
2282 }
2283
2284 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2285 fake_params.protocol = "wrong-name";
2286
2287 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2288 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2289
2290 // The offerer and answerer support different datagram transports, so the
2291 // answerer rejects the offered parameters.
2292 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2293 absl::nullopt);
2294 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2295 absl::nullopt);
2296}
2297
2298TEST_P(JsepTransportControllerDatagramTest, AnswerRejectsDatagram) {
2299 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2300 if (IsOfferer()) {
2301 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2302 fake_params);
2303 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2304 fake_params);
2305 }
2306
2307 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2308 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2309
2310 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2311 fake_params);
2312 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2313 fake_params);
2314
2315 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2316 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2317
2318 // The answer rejected datagram transport, so its parameters are empty.
2319 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2320 absl::nullopt);
2321 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2322 absl::nullopt);
2323}
2324
2325TEST_P(JsepTransportControllerDatagramTest, AnswerAcceptsDatagram) {
2326 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2327 if (IsOfferer()) {
2328 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2329 fake_params);
2330 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2331 fake_params);
2332 }
2333
2334 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2335 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2336
2337 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2338 fake_params);
2339 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2340 fake_params);
2341
2342 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2343 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2344
2345 // The answer accepted datagram transport, so it is present.
2346 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2347 fake_params);
2348 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2349 fake_params);
2350}
2351
2352TEST_P(JsepTransportControllerDatagramTest, PrAnswerRejectsDatagram) {
2353 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2354 if (IsOfferer()) {
2355 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2356 fake_params);
2357 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2358 fake_params);
2359 }
2360
2361 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2362 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2363
2364 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2365 fake_params);
2366 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2367 fake_params);
2368
2369 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2370 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2371
2372 // The answer rejected datagram transport, but it's provisional, so the
2373 // transport is kept around for now.
2374 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2375 fake_params);
2376 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2377 fake_params);
2378}
2379
2380TEST_P(JsepTransportControllerDatagramTest, PrAnswerAcceptsDatagram) {
2381 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2382 if (IsOfferer()) {
2383 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2384 fake_params);
2385 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2386 fake_params);
2387 }
2388
2389 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2390 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2391
2392 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2393 fake_params);
2394 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2395 fake_params);
2396
2397 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2398 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2399
2400 // The answer provisionally accepted datagram transport, so it's kept.
2401 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2402 fake_params);
2403 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2404 fake_params);
2405}
2406
2407TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotAddDatagram) {
2408 auto offer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2409 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2410
2411 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2412 absl::nullopt);
2413 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2414 absl::nullopt);
2415
2416 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2417 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2418
2419 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2420 absl::nullopt);
2421 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2422 absl::nullopt);
2423
2424 // Attempting to add a datagram transport on a re-offer does not cause an
2425 // error, but also does not add a datagram transport.
2426 auto reoffer =
2427 CreateSessionDescriptionForDatagramTransport(CreateTransportParameters());
2428 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2429
2430 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2431 absl::nullopt);
2432 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2433 absl::nullopt);
2434}
2435
2436TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotRemoveDatagram) {
2437 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2438 if (IsOfferer()) {
2439 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2440 fake_params);
2441 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2442 fake_params);
2443 }
2444
2445 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2446 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2447
2448 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2449 fake_params);
2450 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2451 fake_params);
2452
2453 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2454 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2455
2456 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2457 fake_params);
2458 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2459 fake_params);
2460
2461 // Attempting to remove a datagram transport on a re-offer does not cause an
2462 // error, but also does not remove the datagram transport.
2463 auto reoffer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2464 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2465
2466 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2467 fake_params);
2468 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2469 fake_params);
2470}
2471
2472TEST_P(JsepTransportControllerDatagramTest,
2473 RenegotiationKeepsDatagramTransport) {
2474 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2475 if (IsOfferer()) {
2476 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2477 fake_params);
2478 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2479 fake_params);
2480 }
2481
2482 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2483 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2484
2485 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2486 fake_params);
2487 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2488 fake_params);
2489
2490 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2491 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2492
2493 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2494 fake_params);
2495 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2496 fake_params);
2497
2498 // Attempting to remove a datagram transport on a re-offer does not cause an
2499 // error, but also does not remove the datagram transport.
2500 auto reoffer = CreateSessionDescriptionForDatagramTransport(fake_params);
2501 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2502
2503 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2504 fake_params);
2505 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2506 fake_params);
2507
2508 auto reanswer = CreateSessionDescriptionForDatagramTransport(fake_params);
2509 EXPECT_TRUE(SetDescription(SdpType::kAnswer, reanswer.get()).ok());
2510
2511 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2512 fake_params);
2513 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2514 fake_params);
2515}
2516
2517INSTANTIATE_TEST_SUITE_P(
2518 JsepTransportControllerDatagramTests,
2519 JsepTransportControllerDatagramTest,
2520 testing::Values(true, false),
2521 // The parameter value is the local perspective (offerer or answerer).
2522 [](const testing::TestParamInfo<bool>& info) {
2523 return info.param ? "Offerer" : "Answerer";
2524 });
2525
Zhi Huange818b6e2018-02-22 15:26:27 -08002526} // namespace webrtc