blob: 70cbe961a5ea3a9f6de45c202d802d06b2964137 [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;
Zhi Huange818b6e2018-02-22 15:26:27 -080093 // The tests only works with |fake_transport_factory|;
94 config.external_transport_factory = fake_transport_factory_.get();
Zach Steine20867f2018-08-02 13:20:15 -070095 // TODO(zstein): Provide an AsyncResolverFactory once it is required.
Mirko Bonadei317a1f02019-09-17 17:06:18 +020096 transport_controller_ = std::make_unique<JsepTransportController>(
Zach Steine20867f2018-08-02 13:20:15 -070097 signaling_thread, network_thread, port_allocator, nullptr, config);
Zhi Huange818b6e2018-02-22 15:26:27 -080098 ConnectTransportControllerSignals();
99 }
100
101 void ConnectTransportControllerSignals() {
102 transport_controller_->SignalIceConnectionState.connect(
103 this, &JsepTransportControllerTest::OnConnectionState);
Alex Loiko9289eda2018-11-23 16:18:59 +0000104 transport_controller_->SignalStandardizedIceConnectionState.connect(
105 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200106 transport_controller_->SignalConnectionState.connect(
107 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800108 transport_controller_->SignalIceGatheringState.connect(
109 this, &JsepTransportControllerTest::OnGatheringState);
110 transport_controller_->SignalIceCandidatesGathered.connect(
111 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800112 }
113
114 std::unique_ptr<cricket::SessionDescription>
115 CreateSessionDescriptionWithoutBundle() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200116 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800117 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
118 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
119 nullptr);
120 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
121 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
122 nullptr);
123 return description;
124 }
125
126 std::unique_ptr<cricket::SessionDescription>
127 CreateSessionDescriptionWithBundleGroup() {
128 auto description = CreateSessionDescriptionWithoutBundle();
129 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
130 bundle_group.AddContentName(kAudioMid1);
131 bundle_group.AddContentName(kVideoMid1);
132 description->AddGroup(bundle_group);
133
134 return description;
135 }
136
137 void AddAudioSection(cricket::SessionDescription* description,
138 const std::string& mid,
139 const std::string& ufrag,
140 const std::string& pwd,
141 cricket::IceMode ice_mode,
142 cricket::ConnectionRole conn_role,
143 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
144 std::unique_ptr<cricket::AudioContentDescription> audio(
145 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700146 // Set RTCP-mux to be true because the default policy is "mux required".
147 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800148 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200149 /*rejected=*/false, std::move(audio));
Zhi Huange818b6e2018-02-22 15:26:27 -0800150 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
151 }
152
153 void AddVideoSection(cricket::SessionDescription* description,
154 const std::string& mid,
155 const std::string& ufrag,
156 const std::string& pwd,
157 cricket::IceMode ice_mode,
158 cricket::ConnectionRole conn_role,
159 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
160 std::unique_ptr<cricket::VideoContentDescription> video(
161 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700162 // Set RTCP-mux to be true because the default policy is "mux required".
163 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800164 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200165 /*rejected=*/false, std::move(video));
Zhi Huange818b6e2018-02-22 15:26:27 -0800166 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
167 }
168
169 void AddDataSection(cricket::SessionDescription* description,
170 const std::string& mid,
171 cricket::MediaProtocolType protocol_type,
172 const std::string& ufrag,
173 const std::string& pwd,
174 cricket::IceMode ice_mode,
175 cricket::ConnectionRole conn_role,
176 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200177 RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp);
178 std::unique_ptr<cricket::SctpDataContentDescription> data(
179 new cricket::SctpDataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700180 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800181 description->AddContent(mid, protocol_type,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200182 /*rejected=*/false, std::move(data));
Zhi Huange818b6e2018-02-22 15:26:27 -0800183 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
184 }
185
186 void AddTransportInfo(cricket::SessionDescription* description,
187 const std::string& mid,
188 const std::string& ufrag,
189 const std::string& pwd,
190 cricket::IceMode ice_mode,
191 cricket::ConnectionRole conn_role,
192 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
193 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
194 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700195 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800196 }
197
198 cricket::TransportDescription transport_desc(std::vector<std::string>(),
199 ufrag, pwd, ice_mode,
200 conn_role, fingerprint.get());
201 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
202 }
203
204 cricket::IceConfig CreateIceConfig(
205 int receiving_timeout,
206 cricket::ContinualGatheringPolicy continual_gathering_policy) {
207 cricket::IceConfig config;
208 config.receiving_timeout = receiving_timeout;
209 config.continual_gathering_policy = continual_gathering_policy;
210 return config;
211 }
212
213 Candidate CreateCandidate(const std::string& transport_name, int component) {
214 Candidate c;
215 c.set_transport_name(transport_name);
216 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
217 c.set_component(component);
218 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
219 c.set_priority(1);
220 return c;
221 }
222
223 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
224 if (!network_thread_->IsCurrent()) {
225 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
226 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
227 });
228 return;
229 }
230
231 auto description = CreateSessionDescriptionWithBundleGroup();
232 EXPECT_TRUE(transport_controller_
233 ->SetLocalDescription(SdpType::kOffer, description.get())
234 .ok());
235
236 transport_controller_->MaybeStartGathering();
237 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
238 transport_controller_->GetDtlsTransport(kAudioMid1));
239 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
240 transport_controller_->GetDtlsTransport(kVideoMid1));
241 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
242 fake_audio_dtls->fake_ice_transport(),
243 CreateCandidate(kAudioMid1, /*component=*/1));
244 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
245 fake_video_dtls->fake_ice_transport(),
246 CreateCandidate(kVideoMid1, /*component=*/1));
247 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
248 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
249 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
250 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
251 fake_audio_dtls->SetReceiving(true);
252 fake_video_dtls->SetReceiving(true);
253 fake_audio_dtls->SetWritable(true);
254 fake_video_dtls->SetWritable(true);
255 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
256 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
257 }
258
259 protected:
Alex Loiko9289eda2018-11-23 16:18:59 +0000260 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800261 if (!signaling_thread_->IsCurrent()) {
262 signaled_on_non_signaling_thread_ = true;
263 }
264 connection_state_ = state;
265 ++connection_state_signal_count_;
266 }
267
Alex Loiko9289eda2018-11-23 16:18:59 +0000268 void OnStandardizedIceConnectionState(
269 PeerConnectionInterface::IceConnectionState state) {
270 if (!signaling_thread_->IsCurrent()) {
271 signaled_on_non_signaling_thread_ = true;
272 }
273 ice_connection_state_ = state;
274 ++ice_connection_state_signal_count_;
275 }
276
Jonas Olsson635474e2018-10-18 15:58:17 +0200277 void OnCombinedConnectionState(
278 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100279 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
280 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 15:58:17 +0200281 if (!signaling_thread_->IsCurrent()) {
282 signaled_on_non_signaling_thread_ = true;
283 }
284 combined_connection_state_ = state;
285 ++combined_connection_state_signal_count_;
286 }
287
Zhi Huange818b6e2018-02-22 15:26:27 -0800288 void OnGatheringState(cricket::IceGatheringState state) {
289 if (!signaling_thread_->IsCurrent()) {
290 signaled_on_non_signaling_thread_ = true;
291 }
292 gathering_state_ = state;
293 ++gathering_state_signal_count_;
294 }
295
296 void OnCandidatesGathered(const std::string& transport_name,
297 const Candidates& candidates) {
298 if (!signaling_thread_->IsCurrent()) {
299 signaled_on_non_signaling_thread_ = true;
300 }
301 candidates_[transport_name].insert(candidates_[transport_name].end(),
302 candidates.begin(), candidates.end());
303 ++candidates_signal_count_;
304 }
305
Zhi Huang365381f2018-04-13 16:44:34 -0700306 // JsepTransportController::Observer overrides.
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700307 bool OnTransportChanged(
308 const std::string& mid,
309 RtpTransportInternal* rtp_transport,
310 rtc::scoped_refptr<DtlsTransport> dtls_transport,
311 MediaTransportInterface* media_transport,
Qingsi Wang437077d2019-09-10 17:52:26 +0000312 DataChannelTransportInterface* data_channel_transport,
313 JsepTransportController::NegotiationState negotiation_state) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700314 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100315 if (dtls_transport) {
316 changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
317 } else {
318 changed_dtls_transport_by_mid_[mid] = nullptr;
319 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800320 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700321 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800322 }
323
324 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000325 cricket::IceConnectionState connection_state_ =
326 cricket::kIceConnectionConnecting;
327 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200328 PeerConnectionInterface::kIceConnectionNew;
329 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
330 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800331 bool receiving_ = false;
332 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
333 // transport_name => candidates
334 std::map<std::string, Candidates> candidates_;
335 // Counts of each signal emitted.
336 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000337 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200338 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800339 int receiving_signal_count_ = 0;
340 int gathering_state_signal_count_ = 0;
341 int candidates_signal_count_ = 0;
342
343 // |network_thread_| should be destroyed after |transport_controller_|
344 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800345 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
346 rtc::Thread* const signaling_thread_ = nullptr;
347 bool signaled_on_non_signaling_thread_ = false;
348 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
349 // signaled correctly.
350 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
351 std::map<std::string, cricket::DtlsTransportInternal*>
352 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800353 std::map<std::string, MediaTransportInterface*>
354 changed_media_transport_by_mid_;
355
356 // Transport controller needs to be destroyed first, because it may issue
357 // callbacks that modify the changed_*_by_mid in the destructor.
358 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800359};
360
361TEST_F(JsepTransportControllerTest, GetRtpTransport) {
362 CreateJsepTransportController(JsepTransportController::Config());
363 auto description = CreateSessionDescriptionWithoutBundle();
364 EXPECT_TRUE(transport_controller_
365 ->SetLocalDescription(SdpType::kOffer, description.get())
366 .ok());
367 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
368 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
369 EXPECT_NE(nullptr, audio_rtp_transport);
370 EXPECT_NE(nullptr, video_rtp_transport);
371 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
372 // Return nullptr for non-existing ones.
373 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
374}
375
376TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
377 JsepTransportController::Config config;
378 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
379 CreateJsepTransportController(config);
380 auto description = CreateSessionDescriptionWithoutBundle();
381 EXPECT_TRUE(transport_controller_
382 ->SetLocalDescription(SdpType::kOffer, description.get())
383 .ok());
384 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
385 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100386 EXPECT_NE(nullptr,
387 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800388 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
389 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100390 EXPECT_NE(nullptr,
391 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
392 // Lookup for all MIDs should return different transports (no bundle)
393 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
394 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800395 // Return nullptr for non-existing ones.
396 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
397 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100398 EXPECT_EQ(nullptr,
399 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100400 // Take a pointer to a transport, shut down the transport controller,
401 // and verify that the resulting container is empty.
402 auto dtls_transport =
403 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
404 webrtc::DtlsTransport* my_transport =
405 static_cast<DtlsTransport*>(dtls_transport.get());
406 EXPECT_NE(nullptr, my_transport->internal());
407 transport_controller_.reset();
408 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800409}
410
Zhi Huange830e682018-03-30 10:48:35 -0700411TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
412 JsepTransportController::Config config;
413 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
414 CreateJsepTransportController(config);
415 auto description = CreateSessionDescriptionWithoutBundle();
416 EXPECT_TRUE(transport_controller_
417 ->SetLocalDescription(SdpType::kOffer, description.get())
418 .ok());
419 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
420 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
421 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
422 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700423 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
424}
425
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800426TEST_F(JsepTransportControllerTest,
427 DtlsIsStillCreatedIfMediaTransportIsOnlyUsedForDataChannels) {
428 FakeMediaTransportFactory fake_media_transport_factory;
429 JsepTransportController::Config config;
430
431 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800432 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800433 config.media_transport_factory = &fake_media_transport_factory;
434 config.use_media_transport_for_data_channels = true;
435 CreateJsepTransportController(config);
436 auto description = CreateSessionDescriptionWithBundleGroup();
437 AddCryptoSettings(description.get());
438
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800439 EXPECT_NE(absl::nullopt,
440 transport_controller_->GenerateOrGetLastMediaTransportOffer());
441
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800442 EXPECT_TRUE(transport_controller_
443 ->SetLocalDescription(SdpType::kOffer, description.get())
444 .ok());
445
446 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700447 transport_controller_->GetDataChannelTransport(kAudioMid1));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800448
449 ASSERT_NE(nullptr, media_transport);
450
451 // After SetLocalDescription, media transport should be created as caller.
452 EXPECT_TRUE(media_transport->is_caller());
453 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
454
455 // Return nullptr for non-existing mids.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700456 EXPECT_EQ(nullptr,
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700457 transport_controller_->GetDataChannelTransport(kVideoMid2));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800458
459 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
460 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
461 << "Media transport for media was not enabled, and so DTLS transport "
462 "should be created.";
463}
464
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700465TEST_F(JsepTransportControllerTest,
466 DtlsIsStillCreatedIfDatagramTransportIsOnlyUsedForDataChannels) {
467 FakeMediaTransportFactory fake_media_transport_factory("transport_params");
468 JsepTransportController::Config config;
469
470 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
471 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
472 config.media_transport_factory = &fake_media_transport_factory;
473 config.use_datagram_transport_for_data_channels = true;
474 CreateJsepTransportController(config);
475
476 auto description = CreateSessionDescriptionWithBundleGroup();
477 AddCryptoSettings(description.get());
478 absl::optional<cricket::OpaqueTransportParameters> params =
479 transport_controller_->GetTransportParameters(kAudioMid1);
480 for (auto& info : description->transport_infos()) {
481 info.description.opaque_parameters = params;
482 }
483
484 EXPECT_TRUE(transport_controller_
485 ->SetLocalDescription(SdpType::kOffer, description.get())
486 .ok());
487 EXPECT_TRUE(transport_controller_
488 ->SetRemoteDescription(SdpType::kAnswer, description.get())
489 .ok());
490
491 FakeDatagramTransport* datagram_transport =
492 static_cast<FakeDatagramTransport*>(
493 transport_controller_->GetDataChannelTransport(kAudioMid1));
494
495 ASSERT_NE(nullptr, datagram_transport);
496
497 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
498 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
499 << "Datagram transport for media was not enabled, and so DTLS transport "
500 "should be created.";
501
502 // Datagram transport is not used for media, so no max packet size is
503 // specified.
504 EXPECT_EQ(transport_controller_->GetMediaTransportConfig(kAudioMid1)
505 .rtp_max_packet_size,
506 absl::nullopt);
507
508 // Since datagram transport is not used for RTP, setting it to writable should
509 // not make the RTP transport writable.
510 datagram_transport->set_state(MediaTransportState::kWritable);
511 EXPECT_FALSE(transport_controller_->GetRtpTransport(kAudioMid1)
512 ->IsWritable(/*rtcp=*/false));
513}
514
Anton Sukhanov7940da02018-10-10 10:34:49 -0700515TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
516 FakeMediaTransportFactory fake_media_transport_factory;
517 JsepTransportController::Config config;
518
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800519 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800520 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700521 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800522 config.use_media_transport_for_data_channels = true;
523 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700524 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800525 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700526 AddCryptoSettings(description.get());
527
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800528 EXPECT_NE(absl::nullopt,
529 transport_controller_->GenerateOrGetLastMediaTransportOffer());
530
Anton Sukhanov7940da02018-10-10 10:34:49 -0700531 EXPECT_TRUE(transport_controller_
532 ->SetLocalDescription(SdpType::kOffer, description.get())
533 .ok());
534
535 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
536 transport_controller_->GetMediaTransport(kAudioMid1));
537
538 ASSERT_NE(nullptr, media_transport);
539
540 // After SetLocalDescription, media transport should be created as caller.
541 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800542 // We set the pre-shared key on the caller.
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700543 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800544 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700545
546 // Return nullptr for non-existing mids.
547 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800548
549 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
550 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
551 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700552}
553
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800554TEST_F(JsepTransportControllerTest,
555 GetMediaTransportOfferInTheConfigOnSubsequentCalls) {
556 FakeMediaTransportFactory fake_media_transport_factory;
557 WrapperMediaTransportFactory wrapping_factory(&fake_media_transport_factory);
558 JsepTransportController::Config config;
559
560 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
561 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
562 config.media_transport_factory = &wrapping_factory;
563 config.use_media_transport_for_data_channels = true;
564 config.use_media_transport_for_media = true;
565 CreateJsepTransportController(config);
566 auto description = CreateSessionDescriptionWithBundleGroup();
567 AddCryptoSettings(description.get());
568
569 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
570 transport_controller_->GenerateOrGetLastMediaTransportOffer();
571 ASSERT_NE(absl::nullopt, settings);
572
573 EXPECT_TRUE(transport_controller_
574 ->SetLocalDescription(SdpType::kOffer, description.get())
575 .ok());
576
577 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
578 transport_controller_->GetMediaTransport(kAudioMid1));
579
580 ASSERT_NE(nullptr, media_transport);
581
582 absl::optional<cricket::SessionDescription::MediaTransportSetting>
583 new_settings =
584 transport_controller_->GenerateOrGetLastMediaTransportOffer();
585 ASSERT_NE(absl::nullopt, new_settings);
586 EXPECT_EQ(settings->transport_name, new_settings->transport_name);
587 EXPECT_EQ(settings->transport_setting, new_settings->transport_setting);
588 EXPECT_EQ(1, wrapping_factory.created_transport_count());
589}
590
Anton Sukhanov7940da02018-10-10 10:34:49 -0700591TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
592 FakeMediaTransportFactory fake_media_transport_factory;
593 JsepTransportController::Config config;
594
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800595 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700596 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800597 config.use_media_transport_for_data_channels = true;
598 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700599 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800600 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700601 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800602 description->AddMediaTransportSetting("fake", "fake-remote-settings");
Anton Sukhanov7940da02018-10-10 10:34:49 -0700603 EXPECT_TRUE(transport_controller_
604 ->SetRemoteDescription(SdpType::kOffer, description.get())
605 .ok());
606
607 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
608 transport_controller_->GetMediaTransport(kAudioMid1));
609
610 ASSERT_NE(nullptr, media_transport);
611
612 // After SetRemoteDescription, media transport should be created as callee.
613 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800614 // We do not set pre-shared key on the callee, it comes in media transport
615 // settings.
616 EXPECT_EQ(absl::nullopt, media_transport->settings().pre_shared_key);
617 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700618
619 // Return nullptr for non-existing mids.
620 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800621
622 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
623 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
624 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700625}
626
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800627TEST_F(JsepTransportControllerTest, GetMediaTransportInCalleePassesSdp) {
628 FakeMediaTransportFactory fake_media_transport_factory;
629 JsepTransportController::Config config;
630
631 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
632 config.media_transport_factory = &fake_media_transport_factory;
633 config.use_media_transport_for_data_channels = true;
634 config.use_media_transport_for_media = true;
635 CreateJsepTransportController(config);
636 auto description = CreateSessionDescriptionWithBundleGroup();
637 AddCryptoSettings(description.get());
638 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
639 EXPECT_TRUE(transport_controller_
640 ->SetRemoteDescription(SdpType::kOffer, description.get())
641 .ok());
642
643 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
644 transport_controller_->GetMediaTransport(kAudioMid1));
645
646 ASSERT_NE(nullptr, media_transport);
647
648 EXPECT_EQ("this-is-a-test-setting",
649 media_transport->settings().remote_transport_parameters);
650}
651
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800652// Caller generates the offer if media transport returns empty offer (no
653// parameters).
654TEST_F(JsepTransportControllerTest, MediaTransportGeneratesSessionDescription) {
655 FakeMediaTransportFactory fake_media_transport_factory(
656 /*transport_offer=*/"");
657 JsepTransportController::Config config;
658
659 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
660 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
661 config.media_transport_factory = &fake_media_transport_factory;
662 config.use_media_transport_for_data_channels = true;
663 config.use_media_transport_for_media = true;
664 CreateJsepTransportController(config);
665 auto description = CreateSessionDescriptionWithBundleGroup();
666 AddCryptoSettings(description.get());
667 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
668 transport_controller_->GenerateOrGetLastMediaTransportOffer();
669
670 ASSERT_TRUE(settings.has_value());
671 EXPECT_EQ("fake", settings->transport_name);
672 // Fake media transport returns empty settings (but not nullopt settings!)
673 EXPECT_EQ("", settings->transport_setting);
674}
675
676// Caller generates the offer if media transport returns offer with parameters.
677TEST_F(JsepTransportControllerTest,
678 MediaTransportGeneratesSessionDescriptionWithOfferParams) {
679 FakeMediaTransportFactory fake_media_transport_factory(
680 /*transport_offer=*/"offer-params");
681 JsepTransportController::Config config;
682
683 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
684 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
685 config.media_transport_factory = &fake_media_transport_factory;
686 config.use_media_transport_for_data_channels = true;
687 config.use_media_transport_for_media = true;
688 CreateJsepTransportController(config);
689 auto description = CreateSessionDescriptionWithBundleGroup();
690 AddCryptoSettings(description.get());
691 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
692 transport_controller_->GenerateOrGetLastMediaTransportOffer();
693
694 ASSERT_TRUE(settings.has_value());
695 EXPECT_EQ("fake", settings->transport_name);
696 EXPECT_EQ("offer-params", settings->transport_setting);
697}
698
699// Caller skips the offer if media transport requests it.
700TEST_F(JsepTransportControllerTest,
701 MediaTransportGeneratesSkipsSessionDescription) {
702 FakeMediaTransportFactory fake_media_transport_factory(
703 /*transport_offer=*/absl::nullopt);
704 JsepTransportController::Config config;
705
706 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
707 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
708 config.media_transport_factory = &fake_media_transport_factory;
709 config.use_media_transport_for_data_channels = true;
710 config.use_media_transport_for_media = true;
711 CreateJsepTransportController(config);
712 auto description = CreateSessionDescriptionWithBundleGroup();
713 AddCryptoSettings(description.get());
714 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
715 transport_controller_->GenerateOrGetLastMediaTransportOffer();
716
717 // Fake media transport returns nullopt settings
718 ASSERT_EQ(absl::nullopt, settings);
719}
720
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800721// Caller ignores its own outgoing parameters.
722TEST_F(JsepTransportControllerTest,
723 GetMediaTransportInCallerIgnoresXmtSection) {
724 FakeMediaTransportFactory fake_media_transport_factory;
725 JsepTransportController::Config config;
726
727 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800728 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800729 config.media_transport_factory = &fake_media_transport_factory;
730 config.use_media_transport_for_data_channels = true;
731 config.use_media_transport_for_media = true;
732 CreateJsepTransportController(config);
733 auto description = CreateSessionDescriptionWithBundleGroup();
734 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800735 EXPECT_NE(absl::nullopt,
736 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800737 EXPECT_TRUE(transport_controller_
738 ->SetLocalDescription(SdpType::kOffer, description.get())
739 .ok());
740
741 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
742 transport_controller_->GetMediaTransport(kAudioMid1));
743
744 ASSERT_NE(nullptr, media_transport);
745
746 // Remote parameters are nullopt, because we are the offerer (we don't)
747 // have the remote transport parameters, only ours.
748 EXPECT_EQ(absl::nullopt,
749 media_transport->settings().remote_transport_parameters);
750}
751
752TEST_F(JsepTransportControllerTest,
753 GetMediaTransportInCalleeIgnoresDifferentTransport) {
754 FakeMediaTransportFactory fake_media_transport_factory;
755 JsepTransportController::Config config;
756
757 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800758 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800759 config.media_transport_factory = &fake_media_transport_factory;
760 config.use_media_transport_for_data_channels = true;
761 config.use_media_transport_for_media = true;
762 CreateJsepTransportController(config);
763 auto description = CreateSessionDescriptionWithBundleGroup();
764 AddCryptoSettings(description.get());
765 description->AddMediaTransportSetting("not-a-fake-transport",
766 "this-is-a-test-setting");
767 EXPECT_TRUE(transport_controller_
768 ->SetRemoteDescription(SdpType::kOffer, description.get())
769 .ok());
770
771 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
772 transport_controller_->GetMediaTransport(kAudioMid1));
773
774 ASSERT_NE(nullptr, media_transport);
775
776 EXPECT_EQ(absl::nullopt,
777 media_transport->settings().remote_transport_parameters);
778}
779
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700780TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
781 FakeMediaTransportFactory fake_media_transport_factory;
782 JsepTransportController::Config config;
783
784 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800785 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700786 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800787 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700788 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800789 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700790 EXPECT_TRUE(transport_controller_
791 ->SetRemoteDescription(SdpType::kOffer, description.get())
792 .ok());
793
794 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
795
796 // Even if we set local description with crypto now (after the remote offer
797 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800798 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700799 AddCryptoSettings(description2.get());
800 EXPECT_TRUE(transport_controller_
801 ->SetLocalDescription(SdpType::kAnswer, description2.get())
802 .ok());
803
804 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800805 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
806 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
807 << "Because media transport is NOT used (fallback to RTP), expected "
808 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700809}
810
811TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800812 AfterSettingAnswerTheSameMediaTransportIsReturnedCallee) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700813 FakeMediaTransportFactory fake_media_transport_factory;
814 JsepTransportController::Config config;
815
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800816 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800817 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700818 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800819 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700820 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800821 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700822 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800823 description->AddMediaTransportSetting("fake", "fake-settings");
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700824 EXPECT_TRUE(transport_controller_
825 ->SetRemoteDescription(SdpType::kOffer, description.get())
826 .ok());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700827 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
828 transport_controller_->GetMediaTransport(kAudioMid1));
829 EXPECT_NE(nullptr, media_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800830 EXPECT_FALSE(media_transport->pre_shared_key().has_value())
831 << "On the callee, preshared key is passed through the media-transport "
832 "settings (x-mt)";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700833
834 // Even if we set local description with crypto now (after the remote offer
835 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800836 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700837 AddCryptoSettings(description2.get());
838
839 RTCError result = transport_controller_->SetLocalDescription(
840 SdpType::kAnswer, description2.get());
841 EXPECT_TRUE(result.ok()) << result.message();
842
843 // Media transport did not change.
844 EXPECT_EQ(media_transport,
845 transport_controller_->GetMediaTransport(kAudioMid1));
846}
847
Zhi Huange818b6e2018-02-22 15:26:27 -0800848TEST_F(JsepTransportControllerTest, SetIceConfig) {
849 CreateJsepTransportController(JsepTransportController::Config());
850 auto description = CreateSessionDescriptionWithoutBundle();
851 EXPECT_TRUE(transport_controller_
852 ->SetLocalDescription(SdpType::kOffer, description.get())
853 .ok());
854
855 transport_controller_->SetIceConfig(
856 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
857 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
858 transport_controller_->GetDtlsTransport(kAudioMid1));
859 ASSERT_NE(nullptr, fake_audio_dtls);
860 EXPECT_EQ(kTimeout,
861 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
862 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
863
864 // Test that value stored in controller is applied to new transports.
865 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
866 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
867 nullptr);
868
869 EXPECT_TRUE(transport_controller_
870 ->SetLocalDescription(SdpType::kOffer, description.get())
871 .ok());
872 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
873 transport_controller_->GetDtlsTransport(kAudioMid2));
874 ASSERT_NE(nullptr, fake_audio_dtls);
875 EXPECT_EQ(kTimeout,
876 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
877 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
878}
879
880// Tests the getter and setter of the ICE restart flag.
881TEST_F(JsepTransportControllerTest, NeedIceRestart) {
882 CreateJsepTransportController(JsepTransportController::Config());
883 auto description = CreateSessionDescriptionWithoutBundle();
884 EXPECT_TRUE(transport_controller_
885 ->SetLocalDescription(SdpType::kOffer, description.get())
886 .ok());
887 EXPECT_TRUE(transport_controller_
888 ->SetRemoteDescription(SdpType::kAnswer, description.get())
889 .ok());
890
891 // Initially NeedsIceRestart should return false.
892 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
893 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
894 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
895 // true.
896 transport_controller_->SetNeedsIceRestartFlag();
897 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
898 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
899 // For a nonexistent transport, false should be returned.
900 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
901
902 // Reset the ice_ufrag/ice_pwd for audio.
903 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
904 audio_transport_info->description.ice_ufrag = kIceUfrag2;
905 audio_transport_info->description.ice_pwd = kIcePwd2;
906 EXPECT_TRUE(transport_controller_
907 ->SetLocalDescription(SdpType::kOffer, description.get())
908 .ok());
909 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
910 // return false for audio and true for video.
911 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
912 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
913}
914
915TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
916 CreateJsepTransportController(JsepTransportController::Config());
917 auto description = CreateSessionDescriptionWithBundleGroup();
918 EXPECT_TRUE(transport_controller_
919 ->SetLocalDescription(SdpType::kOffer, description.get())
920 .ok());
921 // After setting the local description, we should be able to start gathering
922 // candidates.
923 transport_controller_->MaybeStartGathering();
924 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
925 EXPECT_EQ(1, gathering_state_signal_count_);
926}
927
928TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
929 CreateJsepTransportController(JsepTransportController::Config());
930 auto description = CreateSessionDescriptionWithoutBundle();
931 transport_controller_->SetLocalDescription(SdpType::kOffer,
932 description.get());
933 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
934 description.get());
935 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
936 transport_controller_->GetDtlsTransport(kAudioMid1));
937 ASSERT_NE(nullptr, fake_audio_dtls);
938 Candidates candidates;
939 candidates.push_back(
940 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
941 EXPECT_TRUE(
942 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
943 EXPECT_EQ(1U,
944 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
945
946 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
947 EXPECT_EQ(0U,
948 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
949}
950
951TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
952 CreateJsepTransportController(JsepTransportController::Config());
953
954 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
955 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
956 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
957 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
958
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200959 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800960 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
961 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
962 certificate1);
963
964 // Apply the local certificate.
965 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
966 // Apply the local description.
967 EXPECT_TRUE(transport_controller_
968 ->SetLocalDescription(SdpType::kOffer, description.get())
969 .ok());
970 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
971 EXPECT_TRUE(returned_certificate);
972 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
973 returned_certificate->identity()->certificate().ToPEMString());
974
975 // Should fail if called for a nonexistant transport.
976 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
977
978 // Shouldn't be able to change the identity once set.
979 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
980 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
981 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
982 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
983}
984
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800985TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800986 CreateJsepTransportController(JsepTransportController::Config());
987 auto description = CreateSessionDescriptionWithBundleGroup();
988 EXPECT_TRUE(transport_controller_
989 ->SetLocalDescription(SdpType::kOffer, description.get())
990 .ok());
991 rtc::FakeSSLCertificate fake_certificate("fake_data");
992
993 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
994 transport_controller_->GetDtlsTransport(kAudioMid1));
995 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800996 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
997 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
998 ASSERT_TRUE(returned_cert_chain);
999 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -08001000 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001001 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -08001002
1003 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001004 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -08001005}
1006
1007TEST_F(JsepTransportControllerTest, GetDtlsRole) {
1008 CreateJsepTransportController(JsepTransportController::Config());
1009 auto offer_certificate =
1010 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1011 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
1012 auto answer_certificate =
1013 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1014 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
1015 transport_controller_->SetLocalCertificate(offer_certificate);
1016
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001017 auto offer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001018 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1019 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1020 offer_certificate);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001021 auto answer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001022 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1023 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1024 answer_certificate);
1025
1026 EXPECT_TRUE(transport_controller_
1027 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
1028 .ok());
1029
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001030 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -08001031 transport_controller_->GetDtlsRole(kAudioMid1);
1032 // The DTLS role is not decided yet.
1033 EXPECT_FALSE(role);
1034 EXPECT_TRUE(transport_controller_
1035 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
1036 .ok());
1037 role = transport_controller_->GetDtlsRole(kAudioMid1);
1038
1039 ASSERT_TRUE(role);
1040 EXPECT_EQ(rtc::SSL_CLIENT, *role);
1041}
1042
1043TEST_F(JsepTransportControllerTest, GetStats) {
1044 CreateJsepTransportController(JsepTransportController::Config());
1045 auto description = CreateSessionDescriptionWithBundleGroup();
1046 EXPECT_TRUE(transport_controller_
1047 ->SetLocalDescription(SdpType::kOffer, description.get())
1048 .ok());
1049
1050 cricket::TransportStats stats;
1051 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
1052 EXPECT_EQ(kAudioMid1, stats.transport_name);
1053 EXPECT_EQ(1u, stats.channel_stats.size());
1054 // Return false for non-existing transport.
1055 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
1056}
1057
1058TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
1059 CreateJsepTransportController(JsepTransportController::Config());
1060 auto description = CreateSessionDescriptionWithoutBundle();
1061 EXPECT_TRUE(transport_controller_
1062 ->SetLocalDescription(SdpType::kOffer, description.get())
1063 .ok());
1064
1065 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
1066 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1067 fake_ice->SetCandidatesGatheringComplete();
1068 fake_ice->SetConnectionCount(1);
1069 // The connection stats will be failed if there is no active connection.
1070 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +00001071 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001072 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001073 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1074 ice_connection_state_, kTimeout);
1075 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001076 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1077 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +02001078 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001079}
1080
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001081TEST_F(JsepTransportControllerTest,
1082 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001083 CreateJsepTransportController(JsepTransportController::Config());
1084 auto description = CreateSessionDescriptionWithoutBundle();
1085 EXPECT_TRUE(transport_controller_
1086 ->SetLocalDescription(SdpType::kOffer, description.get())
1087 .ok());
1088
1089 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1090 transport_controller_->GetDtlsTransport(kAudioMid1));
1091 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1092 transport_controller_->GetDtlsTransport(kVideoMid1));
1093
1094 // First, have one transport connect, and another fail, to ensure that
1095 // the first transport connecting didn't trigger a "connected" state signal.
1096 // We should only get a signal when all are connected.
1097 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
1098 fake_audio_dtls->SetWritable(true);
1099 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1100 // Decrease the number of the connection to trigger the signal.
1101 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
1102 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
1103 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1104
Alex Loiko9289eda2018-11-23 16:18:59 +00001105 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001106 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001107 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1108 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001109 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001110 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1111 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001112 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001113
Jonas Olsson635474e2018-10-18 15:58:17 +02001114 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1115 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001116 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
1117 // the transport state to be STATE_CONNECTING.
1118 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
1119 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001120 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001121 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001122 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
1123 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001124 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001125 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1126 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001127 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001128}
1129
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001130TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001131 SignalConnectionStateConnectedWithMediaTransportAndNoDtlsCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001132 FakeMediaTransportFactory fake_media_transport_factory;
1133 JsepTransportController::Config config;
1134 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001135 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1136 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001137 config.use_media_transport_for_data_channels = true;
1138 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001139 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001140
1141 // Media Transport is only used with bundle.
1142 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001143 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001144 EXPECT_NE(absl::nullopt,
1145 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001146 EXPECT_TRUE(transport_controller_
1147 ->SetLocalDescription(SdpType::kOffer, description.get())
1148 .ok());
1149
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001150 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1151 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1152 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1153 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001154 EXPECT_EQ(fake_audio_ice, fake_video_ice);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001155 fake_audio_ice->SetConnectionCount(2);
1156 fake_audio_ice->SetConnectionCount(1);
1157 fake_video_ice->SetConnectionCount(2);
1158 fake_video_ice->SetConnectionCount(1);
1159 fake_audio_ice->SetWritable(true);
1160 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001161
1162 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001163 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1164 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001165
1166 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1167 transport_controller_->GetMediaTransport(kAudioMid1));
1168
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001169 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001170
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001171 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001172 // Only one media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001173 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001174}
1175
1176TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001177 SignalConnectionStateConnectedWithMediaTransportCaller) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001178 FakeMediaTransportFactory fake_media_transport_factory;
1179 JsepTransportController::Config config;
1180 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001181 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1182 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001183 config.use_media_transport_for_media = true;
1184 CreateJsepTransportController(config);
1185
1186 // Media Transport is only used with bundle.
1187 auto description = CreateSessionDescriptionWithBundleGroup();
1188 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001189 EXPECT_NE(absl::nullopt,
1190 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001191 EXPECT_TRUE(transport_controller_
1192 ->SetLocalDescription(SdpType::kOffer, description.get())
1193 .ok());
1194
1195 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1196 transport_controller_->GetDtlsTransport(kAudioMid1));
1197 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1198 transport_controller_->GetDtlsTransport(kVideoMid1));
1199
1200 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1201 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1202 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1203 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1204 fake_audio_ice->SetConnectionCount(2);
1205 fake_audio_ice->SetConnectionCount(1);
1206 fake_video_ice->SetConnectionCount(2);
1207 fake_video_ice->SetConnectionCount(1);
1208 fake_audio_ice->SetWritable(true);
1209 fake_video_ice->SetWritable(true);
1210 fake_audio_dtls->SetWritable(true);
1211 fake_video_dtls->SetWritable(true);
1212
1213 // Still not connected, because we are waiting for media transport.
1214 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1215 kTimeout);
1216
1217 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1218 transport_controller_->GetMediaTransport(kAudioMid1));
1219
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001220 ASSERT_NE(nullptr, media_transport);
1221
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001222 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1223 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1224 kTimeout);
1225
1226 // Still waiting for the second media transport.
1227 media_transport = static_cast<FakeMediaTransport*>(
1228 transport_controller_->GetMediaTransport(kVideoMid1));
1229 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1230
1231 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
1232}
1233
1234TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001235 SignalConnectionStateFailedWhenMediaTransportClosedCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001236 FakeMediaTransportFactory fake_media_transport_factory;
1237 JsepTransportController::Config config;
1238 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001239 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1240 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001241 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001242 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001243 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001244 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001245 EXPECT_NE(absl::nullopt,
1246 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001247 EXPECT_TRUE(transport_controller_
1248 ->SetLocalDescription(SdpType::kOffer, description.get())
1249 .ok());
1250
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001251 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1252 transport_controller_->GetDtlsTransport(kAudioMid1));
1253 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1254 transport_controller_->GetDtlsTransport(kVideoMid1));
1255
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001256 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1257 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1258 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1259 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1260 fake_audio_ice->SetWritable(true);
1261 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001262 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001263 fake_audio_ice->SetConnectionCount(2);
1264 fake_audio_ice->SetConnectionCount(1);
1265 fake_video_ice->SetConnectionCount(2);
1266 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001267
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001268 fake_audio_dtls->SetWritable(true);
1269 fake_video_dtls->SetWritable(true);
1270
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001271 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1272 transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001273 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001274 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1275
1276 media_transport = static_cast<FakeMediaTransport*>(
1277 transport_controller_->GetMediaTransport(kVideoMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001278 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001279
1280 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1281
Alex Loiko9289eda2018-11-23 16:18:59 +00001282 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001283
1284 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +00001285 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001286}
1287
Zhi Huange818b6e2018-02-22 15:26:27 -08001288TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1289 CreateJsepTransportController(JsepTransportController::Config());
1290 auto description = CreateSessionDescriptionWithoutBundle();
1291 EXPECT_TRUE(transport_controller_
1292 ->SetLocalDescription(SdpType::kOffer, description.get())
1293 .ok());
1294
1295 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1296 transport_controller_->GetDtlsTransport(kAudioMid1));
1297 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1298 transport_controller_->GetDtlsTransport(kVideoMid1));
1299
1300 // First, have one transport connect, and another fail, to ensure that
1301 // the first transport connecting didn't trigger a "connected" state signal.
1302 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001303 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1304 IceTransportState::kCompleted,
1305 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001306 fake_audio_dtls->SetWritable(true);
1307 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001308
1309 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1310 ice_connection_state_, kTimeout);
1311 EXPECT_EQ(1, ice_connection_state_signal_count_);
1312 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1313 combined_connection_state_, kTimeout);
1314 EXPECT_EQ(1, combined_connection_state_signal_count_);
1315
1316 fake_video_dtls->fake_ice_transport()->SetTransportState(
1317 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001318 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1319
Alex Loiko9289eda2018-11-23 16:18:59 +00001320 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001321 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001322 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1323 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001324 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001325 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1326 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001327 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001328
Jonas Olsson635474e2018-10-18 15:58:17 +02001329 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1330 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001331 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1332 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001333 fake_video_dtls->fake_ice_transport()->SetTransportState(
1334 IceTransportState::kCompleted,
1335 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001336 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001337 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +01001338 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001339 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1340 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001341 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001342 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1343 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001344 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001345}
1346
1347TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1348 CreateJsepTransportController(JsepTransportController::Config());
1349 auto description = CreateSessionDescriptionWithoutBundle();
1350 EXPECT_TRUE(transport_controller_
1351 ->SetLocalDescription(SdpType::kOffer, description.get())
1352 .ok());
1353
1354 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1355 transport_controller_->GetDtlsTransport(kAudioMid1));
1356 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1357 // Should be in the gathering state as soon as any transport starts gathering.
1358 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1359 EXPECT_EQ(1, gathering_state_signal_count_);
1360}
1361
1362TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1363 CreateJsepTransportController(JsepTransportController::Config());
1364 auto description = CreateSessionDescriptionWithoutBundle();
1365 EXPECT_TRUE(transport_controller_
1366 ->SetLocalDescription(SdpType::kOffer, description.get())
1367 .ok());
1368
1369 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1370 transport_controller_->GetDtlsTransport(kAudioMid1));
1371 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1372 transport_controller_->GetDtlsTransport(kVideoMid1));
1373
1374 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1375 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1376 EXPECT_EQ(1, gathering_state_signal_count_);
1377
1378 // Have one transport finish gathering, to make sure gathering
1379 // completion wasn't signalled if only one transport finished gathering.
1380 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1381 EXPECT_EQ(1, gathering_state_signal_count_);
1382
1383 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1384 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1385 EXPECT_EQ(1, gathering_state_signal_count_);
1386
1387 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1388 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1389 EXPECT_EQ(2, gathering_state_signal_count_);
1390}
1391
1392// Test that when the last transport that hasn't finished connecting and/or
1393// gathering is destroyed, the aggregate state jumps to "completed". This can
1394// happen if, for example, we have an audio and video transport, the audio
1395// transport completes, then we start bundling video on the audio transport.
1396TEST_F(JsepTransportControllerTest,
1397 SignalingWhenLastIncompleteTransportDestroyed) {
1398 CreateJsepTransportController(JsepTransportController::Config());
1399 auto description = CreateSessionDescriptionWithBundleGroup();
1400 EXPECT_TRUE(transport_controller_
1401 ->SetLocalDescription(SdpType::kOffer, description.get())
1402 .ok());
1403
1404 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1405 transport_controller_->GetDtlsTransport(kAudioMid1));
1406 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1407 transport_controller_->GetDtlsTransport(kVideoMid1));
1408 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1409
1410 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1411 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1412 EXPECT_EQ(1, gathering_state_signal_count_);
1413
1414 // Let the audio transport complete.
1415 fake_audio_dtls->SetWritable(true);
1416 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1417 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001418 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001419 EXPECT_EQ(1, gathering_state_signal_count_);
1420
1421 // Set the remote description and enable the bundle.
1422 EXPECT_TRUE(transport_controller_
1423 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1424 .ok());
1425 // The BUNDLE should be enabled, the incomplete video transport should be
1426 // deleted and the states shoud be updated.
1427 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1428 transport_controller_->GetDtlsTransport(kVideoMid1));
1429 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001430 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1431 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1432 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001433 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1434 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001435 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1436 EXPECT_EQ(2, gathering_state_signal_count_);
1437}
1438
1439TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1440 CreateJsepTransportController(JsepTransportController::Config());
1441 auto description = CreateSessionDescriptionWithBundleGroup();
1442 EXPECT_TRUE(transport_controller_
1443 ->SetLocalDescription(SdpType::kOffer, description.get())
1444 .ok());
1445 transport_controller_->MaybeStartGathering();
1446
1447 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1448 transport_controller_->GetDtlsTransport(kAudioMid1));
1449 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1450 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1451 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1452 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1453}
1454
1455TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1456 network_thread_ = rtc::Thread::CreateWithSocketServer();
1457 network_thread_->Start();
1458 CreateJsepTransportController(JsepTransportController::Config(),
1459 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 14:57:52 +01001460 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 15:26:27 -08001461 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1462
1463 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001464 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001465 EXPECT_EQ(2, connection_state_signal_count_);
1466
1467 // new --> gathering --> complete
1468 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1469 EXPECT_EQ(2, gathering_state_signal_count_);
1470
1471 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1472 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1473 EXPECT_EQ(2, candidates_signal_count_);
1474
1475 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1476}
1477
1478// Older versions of Chrome expect the ICE role to be re-determined when an
1479// ICE restart occurs, and also don't perform conflict resolution correctly,
1480// so for now we can't safely stop doing this.
1481// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1482// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1483// enough population.
1484TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1485 CreateJsepTransportController(JsepTransportController::Config());
1486 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001487 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001488 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1489 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1490 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001491 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001492 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1493 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1494 nullptr);
1495
1496 EXPECT_TRUE(transport_controller_
1497 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1498 .ok());
1499 EXPECT_TRUE(transport_controller_
1500 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1501 .ok());
1502
1503 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1504 transport_controller_->GetDtlsTransport(kAudioMid1));
1505 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1506 fake_dtls->fake_ice_transport()->GetIceRole());
1507
1508 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001509 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001510 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1511 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1512 nullptr);
1513 EXPECT_TRUE(
1514 transport_controller_
1515 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1516 .ok());
1517 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1518 fake_dtls->fake_ice_transport()->GetIceRole());
1519}
1520
1521// Test that if the TransportController was created with the
1522// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1523// redetermined on an ICE restart.
1524TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1525 JsepTransportController::Config config;
1526 config.redetermine_role_on_ice_restart = false;
1527
1528 CreateJsepTransportController(config);
1529 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001530 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001531 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1532 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1533 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001534 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001535 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1536 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1537 nullptr);
1538
1539 EXPECT_TRUE(transport_controller_
1540 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1541 .ok());
1542 EXPECT_TRUE(transport_controller_
1543 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1544 .ok());
1545
1546 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1547 transport_controller_->GetDtlsTransport(kAudioMid1));
1548 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1549 fake_dtls->fake_ice_transport()->GetIceRole());
1550
1551 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001552 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001553 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1554 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1555 nullptr);
1556 EXPECT_TRUE(
1557 transport_controller_
1558 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1559 .ok());
1560 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1561 fake_dtls->fake_ice_transport()->GetIceRole());
1562}
1563
1564// Tests ICE-Lite mode in remote answer.
1565TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1566 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001567 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001568 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1569 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1570 nullptr);
1571 EXPECT_TRUE(transport_controller_
1572 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1573 .ok());
1574 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1575 transport_controller_->GetDtlsTransport(kAudioMid1));
1576 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1577 fake_dtls->fake_ice_transport()->GetIceRole());
1578 EXPECT_EQ(cricket::ICEMODE_FULL,
1579 fake_dtls->fake_ice_transport()->remote_ice_mode());
1580
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001581 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001582 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1583 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1584 nullptr);
1585 EXPECT_TRUE(transport_controller_
1586 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1587 .ok());
1588 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1589 fake_dtls->fake_ice_transport()->GetIceRole());
1590 EXPECT_EQ(cricket::ICEMODE_LITE,
1591 fake_dtls->fake_ice_transport()->remote_ice_mode());
1592}
1593
1594// Tests that the ICE role remains "controlling" if a subsequent offer that
1595// does an ICE restart is received from an ICE lite endpoint. Regression test
1596// for: https://crbug.com/710760
1597TEST_F(JsepTransportControllerTest,
1598 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1599 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001600 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001601 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1602 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1603 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001604 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001605 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1606 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1607 nullptr);
1608 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1609 // local side is the controlling.
1610 EXPECT_TRUE(transport_controller_
1611 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1612 .ok());
1613 EXPECT_TRUE(transport_controller_
1614 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1615 .ok());
1616 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1617 transport_controller_->GetDtlsTransport(kAudioMid1));
1618 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1619 fake_dtls->fake_ice_transport()->GetIceRole());
1620
1621 // In the subsequence remote offer triggers an ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001622 auto remote_offer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001623 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1624 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1625 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001626 auto local_answer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001627 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1628 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1629 nullptr);
1630 EXPECT_TRUE(transport_controller_
1631 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1632 .ok());
1633 EXPECT_TRUE(transport_controller_
1634 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1635 .ok());
1636 fake_dtls = static_cast<FakeDtlsTransport*>(
1637 transport_controller_->GetDtlsTransport(kAudioMid1));
1638 // The local side is still the controlling role since the remote side is using
1639 // ICE-Lite.
1640 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1641 fake_dtls->fake_ice_transport()->GetIceRole());
1642}
1643
1644// Tests that the SDP has more than one audio/video m= sections.
1645TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1646 CreateJsepTransportController(JsepTransportController::Config());
1647 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1648 bundle_group.AddContentName(kAudioMid1);
1649 bundle_group.AddContentName(kAudioMid2);
1650 bundle_group.AddContentName(kVideoMid1);
1651 bundle_group.AddContentName(kDataMid1);
1652
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001653 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001654 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1655 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1656 nullptr);
1657 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1658 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1659 nullptr);
1660 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1661 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1662 nullptr);
1663 AddDataSection(local_offer.get(), kDataMid1,
1664 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1665 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1666 nullptr);
1667
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001668 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001669 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1670 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1671 nullptr);
1672 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1673 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1674 nullptr);
1675 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1676 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1677 nullptr);
1678 AddDataSection(remote_answer.get(), kDataMid1,
1679 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1680 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1681 nullptr);
1682
1683 local_offer->AddGroup(bundle_group);
1684 remote_answer->AddGroup(bundle_group);
1685
1686 EXPECT_TRUE(transport_controller_
1687 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1688 .ok());
1689 EXPECT_TRUE(transport_controller_
1690 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1691 .ok());
1692 // Verify that all the sections are bundled on kAudio1.
1693 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1694 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1695 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1696 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1697 EXPECT_EQ(transport1, transport2);
1698 EXPECT_EQ(transport1, transport3);
1699 EXPECT_EQ(transport1, transport4);
1700
Harald Alvestrandad88c882018-11-28 16:47:46 +01001701 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1702 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1703
Zhi Huange818b6e2018-02-22 15:26:27 -08001704 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1705 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1706 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1707 EXPECT_EQ(transport1, it->second);
1708 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1709 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1710 EXPECT_EQ(transport1, it->second);
1711 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1712 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1713 EXPECT_EQ(transport1, it->second);
1714 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1715 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1716 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
Zhi Huange818b6e2018-02-22 15:26:27 -08001717}
1718
1719// Tests that only a subset of all the m= sections are bundled.
1720TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1721 CreateJsepTransportController(JsepTransportController::Config());
1722 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1723 bundle_group.AddContentName(kAudioMid1);
1724 bundle_group.AddContentName(kVideoMid1);
1725
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001726 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001727 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1728 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1729 nullptr);
1730 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1731 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1732 nullptr);
1733 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1734 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1735 nullptr);
1736
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001737 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001738 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1739 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1740 nullptr);
1741 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1742 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1743 nullptr);
1744 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1745 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1746 nullptr);
1747
1748 local_offer->AddGroup(bundle_group);
1749 remote_answer->AddGroup(bundle_group);
1750 EXPECT_TRUE(transport_controller_
1751 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1752 .ok());
1753 EXPECT_TRUE(transport_controller_
1754 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1755 .ok());
1756
1757 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1758 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1759 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1760 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1761 EXPECT_NE(transport1, transport2);
1762 EXPECT_EQ(transport1, transport3);
1763
1764 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1765 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1766 EXPECT_EQ(transport1, it->second);
1767 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001768 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001769}
1770
1771// Tests that the initial offer/answer only have data section and audio/video
1772// sections are added in the subsequent offer.
1773TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1774 CreateJsepTransportController(JsepTransportController::Config());
1775 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1776 bundle_group.AddContentName(kDataMid1);
1777
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001778 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001779 AddDataSection(local_offer.get(), kDataMid1,
1780 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1781 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1782 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001783 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001784 AddDataSection(remote_answer.get(), kDataMid1,
1785 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1786 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1787 nullptr);
1788 local_offer->AddGroup(bundle_group);
1789 remote_answer->AddGroup(bundle_group);
1790
1791 EXPECT_TRUE(transport_controller_
1792 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1793 .ok());
1794 EXPECT_TRUE(transport_controller_
1795 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1796 .ok());
1797 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1798
1799 // Add audio/video sections in subsequent offer.
1800 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1801 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1802 nullptr);
1803 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1804 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1805 nullptr);
1806 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1807 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1808 nullptr);
1809 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1810 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1811 nullptr);
1812
1813 // Reset the bundle group and do another offer/answer exchange.
1814 bundle_group.AddContentName(kAudioMid1);
1815 bundle_group.AddContentName(kVideoMid1);
1816 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1817 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1818 local_offer->AddGroup(bundle_group);
1819 remote_answer->AddGroup(bundle_group);
1820
1821 EXPECT_TRUE(transport_controller_
1822 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1823 .ok());
1824 EXPECT_TRUE(transport_controller_
1825 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1826 .ok());
1827
1828 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1829 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1830 EXPECT_EQ(data_transport, audio_transport);
1831 EXPECT_EQ(data_transport, video_transport);
1832}
1833
1834TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1835 CreateJsepTransportController(JsepTransportController::Config());
1836 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1837 bundle_group.AddContentName(kAudioMid1);
1838 bundle_group.AddContentName(kVideoMid1);
1839 bundle_group.AddContentName(kDataMid1);
1840
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001841 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001842 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1843 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1844 nullptr);
1845 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1846 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1847 nullptr);
1848 AddDataSection(local_offer.get(), kDataMid1,
1849 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1850 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1851 nullptr);
1852
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001853 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001854 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1855 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1856 nullptr);
1857 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1858 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1859 nullptr);
1860 AddDataSection(remote_answer.get(), kDataMid1,
1861 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1862 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1863 nullptr);
1864 // Reject video and data section.
1865 remote_answer->contents()[1].rejected = true;
1866 remote_answer->contents()[2].rejected = true;
1867
1868 local_offer->AddGroup(bundle_group);
1869 remote_answer->AddGroup(bundle_group);
1870
1871 EXPECT_TRUE(transport_controller_
1872 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1873 .ok());
1874 EXPECT_TRUE(transport_controller_
1875 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1876 .ok());
1877
1878 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1879 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1880 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1881 // Verify the signals are fired correctly.
1882 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1883 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1884 EXPECT_EQ(nullptr, it->second);
1885 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1886 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1887 EXPECT_EQ(nullptr, it2->second);
1888}
1889
1890// Tests that changing the bundled MID in subsequent offer/answer exchange is
1891// not supported.
1892// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1893// fixed
1894TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1895 CreateJsepTransportController(JsepTransportController::Config());
1896 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1897 bundle_group.AddContentName(kAudioMid1);
1898 bundle_group.AddContentName(kVideoMid1);
1899
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001900 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001901 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1902 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1903 nullptr);
1904 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1905 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1906 nullptr);
1907
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001908 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001909 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1910 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1911 nullptr);
1912 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1913 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1914 nullptr);
1915
1916 local_offer->AddGroup(bundle_group);
1917 remote_answer->AddGroup(bundle_group);
1918 EXPECT_TRUE(transport_controller_
1919 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1920 .ok());
1921 EXPECT_TRUE(transport_controller_
1922 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1923 .ok());
1924 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1925 transport_controller_->GetRtpTransport(kVideoMid1));
1926
1927 // Reorder the bundle group.
1928 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1929 bundle_group.AddContentName(kAudioMid1);
1930 // The answerer uses the new bundle group and now the bundle mid is changed to
1931 // |kVideo1|.
1932 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1933 remote_answer->AddGroup(bundle_group);
1934 EXPECT_TRUE(transport_controller_
1935 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1936 .ok());
1937 EXPECT_FALSE(transport_controller_
1938 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1939 .ok());
1940}
Zhi Huange830e682018-03-30 10:48:35 -07001941// Test that rejecting only the first m= section of a BUNDLE group is treated as
1942// an error, but rejecting all of them works as expected.
1943TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1944 CreateJsepTransportController(JsepTransportController::Config());
1945 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1946 bundle_group.AddContentName(kAudioMid1);
1947 bundle_group.AddContentName(kVideoMid1);
1948 bundle_group.AddContentName(kDataMid1);
1949
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001950 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001951 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1952 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1953 nullptr);
1954 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1955 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1956 nullptr);
1957 AddDataSection(local_offer.get(), kDataMid1,
1958 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1959 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1960 nullptr);
1961
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001962 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001963 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1964 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1965 nullptr);
1966 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1967 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1968 nullptr);
1969 AddDataSection(remote_answer.get(), kDataMid1,
1970 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1971 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1972 nullptr);
1973 // Reject audio content in answer.
1974 remote_answer->contents()[0].rejected = true;
1975
1976 local_offer->AddGroup(bundle_group);
1977 remote_answer->AddGroup(bundle_group);
1978
1979 EXPECT_TRUE(transport_controller_
1980 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1981 .ok());
1982 EXPECT_FALSE(transport_controller_
1983 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1984 .ok());
1985
1986 // Reject all the contents.
1987 remote_answer->contents()[1].rejected = true;
1988 remote_answer->contents()[2].rejected = true;
1989 EXPECT_TRUE(transport_controller_
1990 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1991 .ok());
1992 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1993 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1994 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1995}
1996
1997// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1998// is used.
1999TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
2000 JsepTransportController::Config config;
2001 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2002 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002003 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002004 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2005 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2006 nullptr);
2007
2008 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
2009 // Applying a non-RTCP-mux offer is expected to fail.
2010 EXPECT_FALSE(transport_controller_
2011 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2012 .ok());
2013}
2014
2015// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
2016// is used.
2017TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
2018 JsepTransportController::Config config;
2019 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2020 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002021 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002022 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2023 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2024 nullptr);
2025 EXPECT_TRUE(transport_controller_
2026 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2027 .ok());
2028
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002029 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002030 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2031 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
2032 nullptr);
2033 // Applying a non-RTCP-mux answer is expected to fail.
2034 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
2035 EXPECT_FALSE(transport_controller_
2036 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2037 .ok());
2038}
Zhi Huange818b6e2018-02-22 15:26:27 -08002039
Zhi Huangd2248f82018-04-10 14:41:03 -07002040// This tests that the BUNDLE group in answer should be a subset of the offered
2041// group.
2042TEST_F(JsepTransportControllerTest,
2043 AddContentToBundleGroupInAnswerNotSupported) {
2044 CreateJsepTransportController(JsepTransportController::Config());
2045 auto local_offer = CreateSessionDescriptionWithoutBundle();
2046 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2047
2048 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2049 offer_bundle_group.AddContentName(kAudioMid1);
2050 local_offer->AddGroup(offer_bundle_group);
2051
2052 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2053 answer_bundle_group.AddContentName(kAudioMid1);
2054 answer_bundle_group.AddContentName(kVideoMid1);
2055 remote_answer->AddGroup(answer_bundle_group);
2056 EXPECT_TRUE(transport_controller_
2057 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2058 .ok());
2059 EXPECT_FALSE(transport_controller_
2060 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2061 .ok());
2062}
2063
2064// This tests that the BUNDLE group with non-existing MID should be rejectd.
2065TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
2066 CreateJsepTransportController(JsepTransportController::Config());
2067 auto local_offer = CreateSessionDescriptionWithoutBundle();
2068 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2069
2070 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2071 // The BUNDLE group is invalid because there is no data section in the
2072 // description.
2073 invalid_bundle_group.AddContentName(kDataMid1);
2074 local_offer->AddGroup(invalid_bundle_group);
2075 remote_answer->AddGroup(invalid_bundle_group);
2076
2077 EXPECT_FALSE(transport_controller_
2078 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2079 .ok());
2080 EXPECT_FALSE(transport_controller_
2081 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2082 .ok());
2083}
2084
2085// This tests that an answer shouldn't be able to remove an m= section from an
2086// established group without rejecting it.
2087TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
2088 CreateJsepTransportController(JsepTransportController::Config());
2089
2090 auto local_offer = CreateSessionDescriptionWithBundleGroup();
2091 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
2092 EXPECT_TRUE(transport_controller_
2093 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2094 .ok());
2095 EXPECT_TRUE(transport_controller_
2096 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2097 .ok());
2098
2099 // Do an re-offer/answer.
2100 EXPECT_TRUE(transport_controller_
2101 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2102 .ok());
2103 auto new_answer = CreateSessionDescriptionWithoutBundle();
2104 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2105 // The answer removes video from the BUNDLE group without rejecting it is
2106 // invalid.
2107 new_bundle_group.AddContentName(kAudioMid1);
2108 new_answer->AddGroup(new_bundle_group);
2109
2110 // Applying invalid answer is expected to fail.
2111 EXPECT_FALSE(transport_controller_
2112 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2113 .ok());
2114
2115 // Rejected the video content.
2116 auto video_content = new_answer->GetContentByName(kVideoMid1);
2117 ASSERT_TRUE(video_content);
2118 video_content->rejected = true;
2119 EXPECT_TRUE(transport_controller_
2120 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2121 .ok());
2122}
2123
Steve Anton2bed3972019-01-04 17:04:30 -08002124// Test that the JsepTransportController can process a new local and remote
2125// description that changes the tagged BUNDLE group with the max-bundle policy
2126// specified.
2127// This is a regression test for bugs.webrtc.org/9954
2128TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
2129 CreateJsepTransportController(JsepTransportController::Config());
2130
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002131 auto local_offer = std::make_unique<cricket::SessionDescription>();
Steve Anton2bed3972019-01-04 17:04:30 -08002132 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2133 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2134 nullptr);
2135 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
2136 bundle_group.AddContentName(kAudioMid1);
2137 local_offer->AddGroup(bundle_group);
2138 EXPECT_TRUE(transport_controller_
2139 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2140 .ok());
2141
2142 std::unique_ptr<cricket::SessionDescription> remote_answer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002143 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002144 EXPECT_TRUE(transport_controller_
2145 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2146 .ok());
2147
2148 std::unique_ptr<cricket::SessionDescription> local_reoffer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002149 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002150 local_reoffer->contents()[0].rejected = true;
2151 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
2152 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2153 nullptr);
2154 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
2155 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2156 new_bundle_group.AddContentName(kVideoMid1);
2157 local_reoffer->AddGroup(new_bundle_group);
2158
2159 EXPECT_TRUE(transport_controller_
2160 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
2161 .ok());
2162
2163 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002164 local_reoffer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002165 EXPECT_TRUE(
2166 transport_controller_
2167 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
2168 .ok());
2169}
2170
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07002171constexpr char kFakeTransportParameters[] = "fake-params";
2172
2173// Test fixture that provides common setup and helpers for tests related to the
2174// datagram transport.
2175class JsepTransportControllerDatagramTest
2176 : public JsepTransportControllerTest,
2177 public testing::WithParamInterface<bool> {
2178 public:
2179 JsepTransportControllerDatagramTest()
2180 : JsepTransportControllerTest(),
2181 fake_media_transport_factory_(kFakeTransportParameters) {
2182 JsepTransportController::Config config;
2183 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2184 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2185 config.media_transport_factory = &fake_media_transport_factory_;
2186 config.use_datagram_transport = true;
2187 CreateJsepTransportController(config);
2188 }
2189
2190 // Whether the JsepTransportController under test acts as the offerer or
2191 // answerer in this test.
2192 bool IsOfferer() { return GetParam(); }
2193
2194 // Sets a description as local or remote based on type and current
2195 // perspective.
2196 RTCError SetDescription(SdpType type,
2197 const cricket::SessionDescription* description) {
2198 if (IsOfferer() == (type == SdpType::kOffer)) {
2199 return transport_controller_->SetLocalDescription(type, description);
2200 } else {
2201 return transport_controller_->SetRemoteDescription(type, description);
2202 }
2203 }
2204
2205 // Creates a session description with the settings necessary for datagram
2206 // transport (bundle + crypto) and the given |transport_params|.
2207 std::unique_ptr<cricket::SessionDescription>
2208 CreateSessionDescriptionForDatagramTransport(
2209 absl::optional<cricket::OpaqueTransportParameters> transport_params) {
2210 auto description = CreateSessionDescriptionWithBundleGroup();
2211 AddCryptoSettings(description.get());
2212
2213 for (auto& info : description->transport_infos()) {
2214 info.description.opaque_parameters = transport_params;
2215 }
2216 return description;
2217 }
2218
2219 // Creates transport parameters with |protocol| and |parameters|
2220 // matching what |fake_media_transport_factory_| provides.
2221 cricket::OpaqueTransportParameters CreateTransportParameters() {
2222 cricket::OpaqueTransportParameters params;
2223 params.protocol = fake_media_transport_factory_.GetTransportName();
2224 params.parameters = "fake-params";
2225 return params;
2226 }
2227
2228 protected:
2229 FakeMediaTransportFactory fake_media_transport_factory_;
2230};
2231
2232TEST_P(JsepTransportControllerDatagramTest, InitDatagramTransport) {
2233 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2234 if (IsOfferer()) {
2235 // Getting transport parameters is allowed before setting a description.
2236 // This is necessary so that the offerer can include these params.
2237 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2238 fake_params);
2239 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2240 fake_params);
2241 }
2242
2243 // Setting a description activates the datagram transport without changing
2244 // transport parameters.
2245 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2246 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2247
2248 // After setting an offer with transport parameters, those parameters are
2249 // reflected by the controller.
2250 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2251 fake_params);
2252 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2253 fake_params);
2254}
2255
2256TEST_P(JsepTransportControllerDatagramTest,
2257 OfferMissingDatagramTransportParams) {
2258 if (IsOfferer()) {
2259 // This test doesn't make sense from the offerer's perspective, as the offer
2260 // must contain datagram transport params if the offerer supports it.
2261 return;
2262 }
2263
2264 auto description =
2265 CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2266 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2267
2268 // The offer didn't contain any datagram transport parameters, so the answer
2269 // won't either.
2270 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2271 absl::nullopt);
2272 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2273 absl::nullopt);
2274}
2275
2276TEST_P(JsepTransportControllerDatagramTest, OfferHasWrongTransportName) {
2277 if (IsOfferer()) {
2278 // This test doesn't make sense from the offerer's perspective, as the
2279 // offerer cannot offer itself the wrong transport.
2280 return;
2281 }
2282
2283 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2284 fake_params.protocol = "wrong-name";
2285
2286 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2287 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2288
2289 // The offerer and answerer support different datagram transports, so the
2290 // answerer rejects the offered parameters.
2291 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2292 absl::nullopt);
2293 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2294 absl::nullopt);
2295}
2296
2297TEST_P(JsepTransportControllerDatagramTest, AnswerRejectsDatagram) {
2298 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2299 if (IsOfferer()) {
2300 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2301 fake_params);
2302 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2303 fake_params);
2304 }
2305
2306 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2307 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2308
2309 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2310 fake_params);
2311 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2312 fake_params);
2313
2314 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2315 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2316
2317 // The answer rejected datagram transport, so its parameters are empty.
2318 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2319 absl::nullopt);
2320 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2321 absl::nullopt);
2322}
2323
2324TEST_P(JsepTransportControllerDatagramTest, AnswerAcceptsDatagram) {
2325 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2326 if (IsOfferer()) {
2327 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2328 fake_params);
2329 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2330 fake_params);
2331 }
2332
2333 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2334 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2335
2336 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2337 fake_params);
2338 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2339 fake_params);
2340
2341 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2342 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2343
2344 // The answer accepted datagram transport, so it is present.
2345 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2346 fake_params);
2347 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2348 fake_params);
2349}
2350
2351TEST_P(JsepTransportControllerDatagramTest, PrAnswerRejectsDatagram) {
2352 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2353 if (IsOfferer()) {
2354 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2355 fake_params);
2356 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2357 fake_params);
2358 }
2359
2360 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2361 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2362
2363 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2364 fake_params);
2365 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2366 fake_params);
2367
2368 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2369 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2370
2371 // The answer rejected datagram transport, but it's provisional, so the
2372 // transport is kept around for now.
2373 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2374 fake_params);
2375 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2376 fake_params);
2377}
2378
2379TEST_P(JsepTransportControllerDatagramTest, PrAnswerAcceptsDatagram) {
2380 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2381 if (IsOfferer()) {
2382 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2383 fake_params);
2384 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2385 fake_params);
2386 }
2387
2388 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2389 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2390
2391 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2392 fake_params);
2393 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2394 fake_params);
2395
2396 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2397 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2398
2399 // The answer provisionally accepted datagram transport, so it's kept.
2400 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2401 fake_params);
2402 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2403 fake_params);
2404}
2405
2406TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotAddDatagram) {
2407 auto offer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2408 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2409
2410 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2411 absl::nullopt);
2412 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2413 absl::nullopt);
2414
2415 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2416 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2417
2418 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2419 absl::nullopt);
2420 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2421 absl::nullopt);
2422
2423 // Attempting to add a datagram transport on a re-offer does not cause an
2424 // error, but also does not add a datagram transport.
2425 auto reoffer =
2426 CreateSessionDescriptionForDatagramTransport(CreateTransportParameters());
2427 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2428
2429 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2430 absl::nullopt);
2431 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2432 absl::nullopt);
2433}
2434
2435TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotRemoveDatagram) {
2436 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2437 if (IsOfferer()) {
2438 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2439 fake_params);
2440 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2441 fake_params);
2442 }
2443
2444 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2445 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2446
2447 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2448 fake_params);
2449 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2450 fake_params);
2451
2452 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2453 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2454
2455 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2456 fake_params);
2457 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2458 fake_params);
2459
2460 // Attempting to remove a datagram transport on a re-offer does not cause an
2461 // error, but also does not remove the datagram transport.
2462 auto reoffer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2463 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2464
2465 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2466 fake_params);
2467 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2468 fake_params);
2469}
2470
2471TEST_P(JsepTransportControllerDatagramTest,
2472 RenegotiationKeepsDatagramTransport) {
2473 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2474 if (IsOfferer()) {
2475 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2476 fake_params);
2477 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2478 fake_params);
2479 }
2480
2481 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2482 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2483
2484 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2485 fake_params);
2486 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2487 fake_params);
2488
2489 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2490 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2491
2492 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2493 fake_params);
2494 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2495 fake_params);
2496
2497 // Attempting to remove a datagram transport on a re-offer does not cause an
2498 // error, but also does not remove the datagram transport.
2499 auto reoffer = CreateSessionDescriptionForDatagramTransport(fake_params);
2500 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2501
2502 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2503 fake_params);
2504 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2505 fake_params);
2506
2507 auto reanswer = CreateSessionDescriptionForDatagramTransport(fake_params);
2508 EXPECT_TRUE(SetDescription(SdpType::kAnswer, reanswer.get()).ok());
2509
2510 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2511 fake_params);
2512 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2513 fake_params);
2514}
2515
2516INSTANTIATE_TEST_SUITE_P(
2517 JsepTransportControllerDatagramTests,
2518 JsepTransportControllerDatagramTest,
2519 testing::Values(true, false),
2520 // The parameter value is the local perspective (offerer or answerer).
2521 [](const testing::TestParamInfo<bool>& info) {
2522 return info.param ? "Offerer" : "Answerer";
2523 });
2524
Zhi Huange818b6e2018-02-22 15:26:27 -08002525} // namespace webrtc