blob: 408cb019b8bf688f2b042fda1cd18dfa2667fb6c [file] [log] [blame]
Zhi Huange818b6e2018-02-22 23:26:271/*
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 17:08:3311#include "pc/jsep_transport_controller.h"
12
Zhi Huange818b6e2018-02-22 23:26:2713#include <map>
14#include <memory>
15
Anton Sukhanov7940da02018-10-10 17:34:4916#include "api/test/fake_media_transport.h"
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:0517#include "api/test/loopback_media_transport.h"
Niels Möller65f17ca2019-09-12 11:59:3618#include "api/transport/media/media_transport_interface.h"
Steve Anton10542f22019-01-11 17:11:0019#include "p2p/base/fake_dtls_transport.h"
20#include "p2p/base/fake_ice_transport.h"
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:2121#include "p2p/base/no_op_dtls_transport.h"
Steve Anton10542f22019-01-11 17:11:0022#include "p2p/base/transport_factory_interface.h"
23#include "p2p/base/transport_info.h"
Zhi Huange818b6e2018-02-22 23:26:2724#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 23:26:2725#include "rtc_base/thread.h"
26#include "test/gtest.h"
27
Zhi Huange818b6e2018-02-22 23:26:2728using cricket::Candidate;
29using cricket::Candidates;
Jonas Olssona4d87372019-07-05 17:08:3330using cricket::FakeDtlsTransport;
Zhi Huange818b6e2018-02-22 23:26:2731using 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 15:25:2648namespace {
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 23:26:2762class 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 15:06:1867 return std::make_unique<cricket::FakeIceTransport>(transport_name,
68 component);
Zhi Huange818b6e2018-02-22 23:26:2769 }
70
71 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-30 00:34:1372 cricket::IceTransportInternal* ice,
Benjamin Wrighta54daf12018-10-11 22:33:1773 const webrtc::CryptoOptions& crypto_options) override {
Mirko Bonadei317a1f02019-09-17 15:06:1874 return std::make_unique<FakeDtlsTransport>(
Bjorn A Mellem0c1c1b42019-05-30 00:34:1375 static_cast<cricket::FakeIceTransport*>(ice));
Zhi Huange818b6e2018-02-22 23:26:2776 }
77};
78
Zhi Huang365381f2018-04-13 23:44:3479class JsepTransportControllerTest : public JsepTransportController::Observer,
Mirko Bonadei6a489f22019-04-09 13:11:1280 public ::testing::Test,
Zhi Huange818b6e2018-02-22 23:26:2781 public sigslot::has_slots<> {
82 public:
83 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Mirko Bonadei317a1f02019-09-17 15:06:1884 fake_transport_factory_ = std::make_unique<FakeTransportFactory>();
Zhi Huange818b6e2018-02-22 23:26:2785 }
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 23:44:3492 config.transport_observer = this;
Sebastian Jansson1b83a9e2019-09-18 16:22:1293 config.rtcp_handler = [](const rtc::CopyOnWriteBuffer& packet,
94 int64_t packet_time_us) { RTC_NOTREACHED(); };
Zhi Huange818b6e2018-02-22 23:26:2795 // The tests only works with |fake_transport_factory|;
96 config.external_transport_factory = fake_transport_factory_.get();
Zach Steine20867f2018-08-02 20:20:1597 // TODO(zstein): Provide an AsyncResolverFactory once it is required.
Mirko Bonadei317a1f02019-09-17 15:06:1898 transport_controller_ = std::make_unique<JsepTransportController>(
Zach Steine20867f2018-08-02 20:20:1599 signaling_thread, network_thread, port_allocator, nullptr, config);
Zhi Huange818b6e2018-02-22 23:26:27100 ConnectTransportControllerSignals();
101 }
102
103 void ConnectTransportControllerSignals() {
104 transport_controller_->SignalIceConnectionState.connect(
105 this, &JsepTransportControllerTest::OnConnectionState);
Alex Loiko9289eda2018-11-23 16:18:59106 transport_controller_->SignalStandardizedIceConnectionState.connect(
107 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 13:58:17108 transport_controller_->SignalConnectionState.connect(
109 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 23:26:27110 transport_controller_->SignalIceGatheringState.connect(
111 this, &JsepTransportControllerTest::OnGatheringState);
112 transport_controller_->SignalIceCandidatesGathered.connect(
113 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 23:26:27114 }
115
116 std::unique_ptr<cricket::SessionDescription>
117 CreateSessionDescriptionWithoutBundle() {
Mirko Bonadei317a1f02019-09-17 15:06:18118 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27119 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
120 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
121 nullptr);
122 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
123 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
124 nullptr);
125 return description;
126 }
127
128 std::unique_ptr<cricket::SessionDescription>
129 CreateSessionDescriptionWithBundleGroup() {
130 auto description = CreateSessionDescriptionWithoutBundle();
131 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
132 bundle_group.AddContentName(kAudioMid1);
133 bundle_group.AddContentName(kVideoMid1);
134 description->AddGroup(bundle_group);
135
136 return description;
137 }
138
Bjorn A Mellem8e1343a2019-09-30 22:12:47139 std::unique_ptr<cricket::SessionDescription>
140 CreateSessionDescriptionWithBundledData() {
141 auto description = CreateSessionDescriptionWithoutBundle();
142 AddDataSection(description.get(), kDataMid1,
143 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
144 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
145 nullptr);
146 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
147 bundle_group.AddContentName(kAudioMid1);
148 bundle_group.AddContentName(kVideoMid1);
149 bundle_group.AddContentName(kDataMid1);
150 description->AddGroup(bundle_group);
151 return description;
152 }
153
Zhi Huange818b6e2018-02-22 23:26:27154 void AddAudioSection(cricket::SessionDescription* description,
155 const std::string& mid,
156 const std::string& ufrag,
157 const std::string& pwd,
158 cricket::IceMode ice_mode,
159 cricket::ConnectionRole conn_role,
160 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
161 std::unique_ptr<cricket::AudioContentDescription> audio(
162 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 17:48:35163 // Set RTCP-mux to be true because the default policy is "mux required".
164 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 23:26:27165 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 18:35:45166 /*rejected=*/false, std::move(audio));
Zhi Huange818b6e2018-02-22 23:26:27167 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
168 }
169
170 void AddVideoSection(cricket::SessionDescription* description,
171 const std::string& mid,
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) {
177 std::unique_ptr<cricket::VideoContentDescription> video(
178 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 17:48:35179 // Set RTCP-mux to be true because the default policy is "mux required".
180 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 23:26:27181 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 18:35:45182 /*rejected=*/false, std::move(video));
Zhi Huange818b6e2018-02-22 23:26:27183 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
184 }
185
186 void AddDataSection(cricket::SessionDescription* description,
187 const std::string& mid,
188 cricket::MediaProtocolType protocol_type,
189 const std::string& ufrag,
190 const std::string& pwd,
191 cricket::IceMode ice_mode,
192 cricket::ConnectionRole conn_role,
193 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
Harald Alvestrand5fc28b12019-05-13 11:36:16194 RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp);
195 std::unique_ptr<cricket::SctpDataContentDescription> data(
196 new cricket::SctpDataContentDescription());
Zhi Huange830e682018-03-30 17:48:35197 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 23:26:27198 description->AddContent(mid, protocol_type,
Harald Alvestrand1716d392019-06-03 18:35:45199 /*rejected=*/false, std::move(data));
Zhi Huange818b6e2018-02-22 23:26:27200 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
201 }
202
203 void AddTransportInfo(cricket::SessionDescription* description,
204 const std::string& mid,
205 const std::string& ufrag,
206 const std::string& pwd,
207 cricket::IceMode ice_mode,
208 cricket::ConnectionRole conn_role,
209 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
210 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
211 if (cert) {
Steve Anton4905edb2018-10-16 02:27:44212 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 23:26:27213 }
214
215 cricket::TransportDescription transport_desc(std::vector<std::string>(),
216 ufrag, pwd, ice_mode,
217 conn_role, fingerprint.get());
218 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
219 }
220
221 cricket::IceConfig CreateIceConfig(
222 int receiving_timeout,
223 cricket::ContinualGatheringPolicy continual_gathering_policy) {
224 cricket::IceConfig config;
225 config.receiving_timeout = receiving_timeout;
226 config.continual_gathering_policy = continual_gathering_policy;
227 return config;
228 }
229
230 Candidate CreateCandidate(const std::string& transport_name, int component) {
231 Candidate c;
232 c.set_transport_name(transport_name);
233 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
234 c.set_component(component);
235 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
236 c.set_priority(1);
237 return c;
238 }
239
240 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
241 if (!network_thread_->IsCurrent()) {
242 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
243 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
244 });
245 return;
246 }
247
248 auto description = CreateSessionDescriptionWithBundleGroup();
249 EXPECT_TRUE(transport_controller_
250 ->SetLocalDescription(SdpType::kOffer, description.get())
251 .ok());
252
253 transport_controller_->MaybeStartGathering();
254 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
255 transport_controller_->GetDtlsTransport(kAudioMid1));
256 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
257 transport_controller_->GetDtlsTransport(kVideoMid1));
258 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
259 fake_audio_dtls->fake_ice_transport(),
260 CreateCandidate(kAudioMid1, /*component=*/1));
261 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
262 fake_video_dtls->fake_ice_transport(),
263 CreateCandidate(kVideoMid1, /*component=*/1));
264 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
265 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
266 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
267 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
268 fake_audio_dtls->SetReceiving(true);
269 fake_video_dtls->SetReceiving(true);
270 fake_audio_dtls->SetWritable(true);
271 fake_video_dtls->SetWritable(true);
272 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
273 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
274 }
275
276 protected:
Alex Loiko9289eda2018-11-23 16:18:59277 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 23:26:27278 if (!signaling_thread_->IsCurrent()) {
279 signaled_on_non_signaling_thread_ = true;
280 }
281 connection_state_ = state;
282 ++connection_state_signal_count_;
283 }
284
Alex Loiko9289eda2018-11-23 16:18:59285 void OnStandardizedIceConnectionState(
286 PeerConnectionInterface::IceConnectionState state) {
287 if (!signaling_thread_->IsCurrent()) {
288 signaled_on_non_signaling_thread_ = true;
289 }
290 ice_connection_state_ = state;
291 ++ice_connection_state_signal_count_;
292 }
293
Jonas Olsson635474e2018-10-18 13:58:17294 void OnCombinedConnectionState(
295 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 12:11:44296 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
297 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 13:58:17298 if (!signaling_thread_->IsCurrent()) {
299 signaled_on_non_signaling_thread_ = true;
300 }
301 combined_connection_state_ = state;
302 ++combined_connection_state_signal_count_;
303 }
304
Zhi Huange818b6e2018-02-22 23:26:27305 void OnGatheringState(cricket::IceGatheringState state) {
306 if (!signaling_thread_->IsCurrent()) {
307 signaled_on_non_signaling_thread_ = true;
308 }
309 gathering_state_ = state;
310 ++gathering_state_signal_count_;
311 }
312
313 void OnCandidatesGathered(const std::string& transport_name,
314 const Candidates& candidates) {
315 if (!signaling_thread_->IsCurrent()) {
316 signaled_on_non_signaling_thread_ = true;
317 }
318 candidates_[transport_name].insert(candidates_[transport_name].end(),
319 candidates.begin(), candidates.end());
320 ++candidates_signal_count_;
321 }
322
Zhi Huang365381f2018-04-13 23:44:34323 // JsepTransportController::Observer overrides.
Bjorn A Mellemb689af42019-08-21 17:44:59324 bool OnTransportChanged(
325 const std::string& mid,
326 RtpTransportInternal* rtp_transport,
327 rtc::scoped_refptr<DtlsTransport> dtls_transport,
328 MediaTransportInterface* media_transport,
Bjorn A Mellembc3eebc2019-09-23 21:53:54329 DataChannelTransportInterface* data_channel_transport) override {
Taylor Brandstettercbaa2542018-04-16 23:42:14330 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 06:51:00331 if (dtls_transport) {
332 changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
333 } else {
334 changed_dtls_transport_by_mid_[mid] = nullptr;
335 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 16:26:19336 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 23:42:14337 return true;
Zhi Huange818b6e2018-02-22 23:26:27338 }
339
340 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59341 cricket::IceConnectionState connection_state_ =
342 cricket::kIceConnectionConnecting;
343 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 13:58:17344 PeerConnectionInterface::kIceConnectionNew;
345 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
346 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 23:26:27347 bool receiving_ = false;
348 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
349 // transport_name => candidates
350 std::map<std::string, Candidates> candidates_;
351 // Counts of each signal emitted.
352 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59353 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 13:58:17354 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 23:26:27355 int receiving_signal_count_ = 0;
356 int gathering_state_signal_count_ = 0;
357 int candidates_signal_count_ = 0;
358
359 // |network_thread_| should be destroyed after |transport_controller_|
360 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 23:26:27361 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
362 rtc::Thread* const signaling_thread_ = nullptr;
363 bool signaled_on_non_signaling_thread_ = false;
364 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
365 // signaled correctly.
366 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
367 std::map<std::string, cricket::DtlsTransportInternal*>
368 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 16:26:19369 std::map<std::string, MediaTransportInterface*>
370 changed_media_transport_by_mid_;
371
372 // Transport controller needs to be destroyed first, because it may issue
373 // callbacks that modify the changed_*_by_mid in the destructor.
374 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 23:26:27375};
376
377TEST_F(JsepTransportControllerTest, GetRtpTransport) {
378 CreateJsepTransportController(JsepTransportController::Config());
379 auto description = CreateSessionDescriptionWithoutBundle();
380 EXPECT_TRUE(transport_controller_
381 ->SetLocalDescription(SdpType::kOffer, description.get())
382 .ok());
383 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
384 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
385 EXPECT_NE(nullptr, audio_rtp_transport);
386 EXPECT_NE(nullptr, video_rtp_transport);
387 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
388 // Return nullptr for non-existing ones.
389 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
390}
391
392TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
393 JsepTransportController::Config config;
394 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
395 CreateJsepTransportController(config);
396 auto description = CreateSessionDescriptionWithoutBundle();
397 EXPECT_TRUE(transport_controller_
398 ->SetLocalDescription(SdpType::kOffer, description.get())
399 .ok());
400 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
401 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 15:47:46402 EXPECT_NE(nullptr,
403 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 23:26:27404 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
405 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 15:47:46406 EXPECT_NE(nullptr,
407 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
408 // Lookup for all MIDs should return different transports (no bundle)
409 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
410 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 23:26:27411 // Return nullptr for non-existing ones.
412 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
413 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 15:47:46414 EXPECT_EQ(nullptr,
415 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 09:55:20416 // Take a pointer to a transport, shut down the transport controller,
417 // and verify that the resulting container is empty.
418 auto dtls_transport =
419 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
420 webrtc::DtlsTransport* my_transport =
421 static_cast<DtlsTransport*>(dtls_transport.get());
422 EXPECT_NE(nullptr, my_transport->internal());
423 transport_controller_.reset();
424 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 23:26:27425}
426
Zhi Huange830e682018-03-30 17:48:35427TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
428 JsepTransportController::Config config;
429 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
430 CreateJsepTransportController(config);
431 auto description = CreateSessionDescriptionWithoutBundle();
432 EXPECT_TRUE(transport_controller_
433 ->SetLocalDescription(SdpType::kOffer, description.get())
434 .ok());
435 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
436 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
437 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
438 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 17:34:49439 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
440}
441
Piotr (Peter) Slatala55b91b92019-01-25 21:31:15442TEST_F(JsepTransportControllerTest,
443 DtlsIsStillCreatedIfMediaTransportIsOnlyUsedForDataChannels) {
444 FakeMediaTransportFactory fake_media_transport_factory;
445 JsepTransportController::Config config;
446
447 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05448 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 21:31:15449 config.media_transport_factory = &fake_media_transport_factory;
450 config.use_media_transport_for_data_channels = true;
451 CreateJsepTransportController(config);
452 auto description = CreateSessionDescriptionWithBundleGroup();
453 AddCryptoSettings(description.get());
454
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05455 EXPECT_NE(absl::nullopt,
456 transport_controller_->GenerateOrGetLastMediaTransportOffer());
457
Piotr (Peter) Slatala55b91b92019-01-25 21:31:15458 EXPECT_TRUE(transport_controller_
459 ->SetLocalDescription(SdpType::kOffer, description.get())
460 .ok());
461
462 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
Bjorn A Mellemb689af42019-08-21 17:44:59463 transport_controller_->GetDataChannelTransport(kAudioMid1));
Piotr (Peter) Slatala55b91b92019-01-25 21:31:15464
465 ASSERT_NE(nullptr, media_transport);
466
467 // After SetLocalDescription, media transport should be created as caller.
468 EXPECT_TRUE(media_transport->is_caller());
469 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
470
471 // Return nullptr for non-existing mids.
Anton Sukhanov316f3ac2019-05-23 22:50:38472 EXPECT_EQ(nullptr,
Bjorn A Mellemb689af42019-08-21 17:44:59473 transport_controller_->GetDataChannelTransport(kVideoMid2));
Piotr (Peter) Slatala55b91b92019-01-25 21:31:15474
475 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
476 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
477 << "Media transport for media was not enabled, and so DTLS transport "
478 "should be created.";
479}
480
Bjorn A Mellem703ea952019-08-23 17:31:11481TEST_F(JsepTransportControllerTest,
482 DtlsIsStillCreatedIfDatagramTransportIsOnlyUsedForDataChannels) {
483 FakeMediaTransportFactory fake_media_transport_factory("transport_params");
484 JsepTransportController::Config config;
485
486 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
487 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
488 config.media_transport_factory = &fake_media_transport_factory;
489 config.use_datagram_transport_for_data_channels = true;
490 CreateJsepTransportController(config);
491
Bjorn A Mellem8e1343a2019-09-30 22:12:47492 auto description = CreateSessionDescriptionWithBundledData();
Bjorn A Mellem703ea952019-08-23 17:31:11493 AddCryptoSettings(description.get());
Bjorn A Mellem8e1343a2019-09-30 22:12:47494
Bjorn A Mellem703ea952019-08-23 17:31:11495 absl::optional<cricket::OpaqueTransportParameters> params =
496 transport_controller_->GetTransportParameters(kAudioMid1);
497 for (auto& info : description->transport_infos()) {
498 info.description.opaque_parameters = params;
499 }
Bjorn A Mellem8e1343a2019-09-30 22:12:47500 for (cricket::ContentInfo& content_info : description->contents()) {
501 if (content_info.media_description()->type() == cricket::MEDIA_TYPE_DATA) {
502 content_info.media_description()->set_alt_protocol(params->protocol);
503 }
504 }
Bjorn A Mellem703ea952019-08-23 17:31:11505
506 EXPECT_TRUE(transport_controller_
507 ->SetLocalDescription(SdpType::kOffer, description.get())
508 .ok());
509 EXPECT_TRUE(transport_controller_
510 ->SetRemoteDescription(SdpType::kAnswer, description.get())
511 .ok());
512
513 FakeDatagramTransport* datagram_transport =
514 static_cast<FakeDatagramTransport*>(
515 transport_controller_->GetDataChannelTransport(kAudioMid1));
516
517 ASSERT_NE(nullptr, datagram_transport);
518
519 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
520 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
521 << "Datagram transport for media was not enabled, and so DTLS transport "
522 "should be created.";
523
524 // Datagram transport is not used for media, so no max packet size is
525 // specified.
526 EXPECT_EQ(transport_controller_->GetMediaTransportConfig(kAudioMid1)
527 .rtp_max_packet_size,
528 absl::nullopt);
529
530 // Since datagram transport is not used for RTP, setting it to writable should
531 // not make the RTP transport writable.
532 datagram_transport->set_state(MediaTransportState::kWritable);
533 EXPECT_FALSE(transport_controller_->GetRtpTransport(kAudioMid1)
534 ->IsWritable(/*rtcp=*/false));
535}
536
Bjorn A Mellem8e1343a2019-09-30 22:12:47537// An offer that bundles different alt-protocols should be rejected.
538TEST_F(JsepTransportControllerTest, CannotBundleDifferentAltProtocols) {
539 FakeMediaTransportFactory fake_media_transport_factory("transport_params");
540 JsepTransportController::Config config;
541 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
542 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
543 config.media_transport_factory = &fake_media_transport_factory;
544 config.use_datagram_transport = true;
545 config.use_datagram_transport_for_data_channels = true;
546 CreateJsepTransportController(config);
547
548 auto description = CreateSessionDescriptionWithBundledData();
549 AddCryptoSettings(description.get());
550
551 absl::optional<cricket::OpaqueTransportParameters> params =
552 transport_controller_->GetTransportParameters(kAudioMid1);
553 for (auto& info : description->transport_infos()) {
554 info.description.opaque_parameters = params;
555 }
556
557 // Append a different alt-protocol to each of the sections.
558 for (cricket::ContentInfo& content_info : description->contents()) {
559 content_info.media_description()->set_alt_protocol(params->protocol + "-" +
560 content_info.name);
561 }
562
563 EXPECT_FALSE(transport_controller_
564 ->SetLocalDescription(SdpType::kOffer, description.get())
565 .ok());
566 EXPECT_FALSE(transport_controller_
567 ->SetRemoteDescription(SdpType::kAnswer, description.get())
568 .ok());
569}
570
Anton Sukhanov7940da02018-10-10 17:34:49571TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
572 FakeMediaTransportFactory fake_media_transport_factory;
573 JsepTransportController::Config config;
574
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:21575 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05576 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Anton Sukhanov7940da02018-10-10 17:34:49577 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 21:31:15578 config.use_media_transport_for_data_channels = true;
579 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 17:34:49580 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:21581 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 15:25:26582 AddCryptoSettings(description.get());
583
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05584 EXPECT_NE(absl::nullopt,
585 transport_controller_->GenerateOrGetLastMediaTransportOffer());
586
Anton Sukhanov7940da02018-10-10 17:34:49587 EXPECT_TRUE(transport_controller_
588 ->SetLocalDescription(SdpType::kOffer, description.get())
589 .ok());
590
591 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
592 transport_controller_->GetMediaTransport(kAudioMid1));
593
594 ASSERT_NE(nullptr, media_transport);
595
596 // After SetLocalDescription, media transport should be created as caller.
597 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05598 // We set the pre-shared key on the caller.
Piotr (Peter) Slatala9f956252018-10-31 15:25:26599 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05600 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 17:34:49601
602 // Return nullptr for non-existing mids.
603 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:21604
605 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
606 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
607 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 17:34:49608}
609
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05610TEST_F(JsepTransportControllerTest,
611 GetMediaTransportOfferInTheConfigOnSubsequentCalls) {
612 FakeMediaTransportFactory fake_media_transport_factory;
613 WrapperMediaTransportFactory wrapping_factory(&fake_media_transport_factory);
614 JsepTransportController::Config config;
615
616 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
617 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
618 config.media_transport_factory = &wrapping_factory;
619 config.use_media_transport_for_data_channels = true;
620 config.use_media_transport_for_media = true;
621 CreateJsepTransportController(config);
622 auto description = CreateSessionDescriptionWithBundleGroup();
623 AddCryptoSettings(description.get());
624
625 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
626 transport_controller_->GenerateOrGetLastMediaTransportOffer();
627 ASSERT_NE(absl::nullopt, settings);
628
629 EXPECT_TRUE(transport_controller_
630 ->SetLocalDescription(SdpType::kOffer, description.get())
631 .ok());
632
633 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
634 transport_controller_->GetMediaTransport(kAudioMid1));
635
636 ASSERT_NE(nullptr, media_transport);
637
638 absl::optional<cricket::SessionDescription::MediaTransportSetting>
639 new_settings =
640 transport_controller_->GenerateOrGetLastMediaTransportOffer();
641 ASSERT_NE(absl::nullopt, new_settings);
642 EXPECT_EQ(settings->transport_name, new_settings->transport_name);
643 EXPECT_EQ(settings->transport_setting, new_settings->transport_setting);
644 EXPECT_EQ(1, wrapping_factory.created_transport_count());
645}
646
Anton Sukhanov7940da02018-10-10 17:34:49647TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
648 FakeMediaTransportFactory fake_media_transport_factory;
649 JsepTransportController::Config config;
650
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:21651 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 17:34:49652 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 21:31:15653 config.use_media_transport_for_data_channels = true;
654 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 17:34:49655 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:21656 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 15:25:26657 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05658 description->AddMediaTransportSetting("fake", "fake-remote-settings");
Anton Sukhanov7940da02018-10-10 17:34:49659 EXPECT_TRUE(transport_controller_
660 ->SetRemoteDescription(SdpType::kOffer, description.get())
661 .ok());
662
663 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
664 transport_controller_->GetMediaTransport(kAudioMid1));
665
666 ASSERT_NE(nullptr, media_transport);
667
668 // After SetRemoteDescription, media transport should be created as callee.
669 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05670 // We do not set pre-shared key on the callee, it comes in media transport
671 // settings.
672 EXPECT_EQ(absl::nullopt, media_transport->settings().pre_shared_key);
673 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 17:34:49674
675 // Return nullptr for non-existing mids.
676 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:21677
678 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
679 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
680 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 17:48:35681}
682
Piotr (Peter) Slatala105ded32019-02-27 22:26:15683TEST_F(JsepTransportControllerTest, GetMediaTransportInCalleePassesSdp) {
684 FakeMediaTransportFactory fake_media_transport_factory;
685 JsepTransportController::Config config;
686
687 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
688 config.media_transport_factory = &fake_media_transport_factory;
689 config.use_media_transport_for_data_channels = true;
690 config.use_media_transport_for_media = true;
691 CreateJsepTransportController(config);
692 auto description = CreateSessionDescriptionWithBundleGroup();
693 AddCryptoSettings(description.get());
694 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
695 EXPECT_TRUE(transport_controller_
696 ->SetRemoteDescription(SdpType::kOffer, description.get())
697 .ok());
698
699 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
700 transport_controller_->GetMediaTransport(kAudioMid1));
701
702 ASSERT_NE(nullptr, media_transport);
703
704 EXPECT_EQ("this-is-a-test-setting",
705 media_transport->settings().remote_transport_parameters);
706}
707
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05708// Caller generates the offer if media transport returns empty offer (no
709// parameters).
710TEST_F(JsepTransportControllerTest, MediaTransportGeneratesSessionDescription) {
711 FakeMediaTransportFactory fake_media_transport_factory(
712 /*transport_offer=*/"");
713 JsepTransportController::Config config;
714
715 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
716 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
717 config.media_transport_factory = &fake_media_transport_factory;
718 config.use_media_transport_for_data_channels = true;
719 config.use_media_transport_for_media = true;
720 CreateJsepTransportController(config);
721 auto description = CreateSessionDescriptionWithBundleGroup();
722 AddCryptoSettings(description.get());
723 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
724 transport_controller_->GenerateOrGetLastMediaTransportOffer();
725
726 ASSERT_TRUE(settings.has_value());
727 EXPECT_EQ("fake", settings->transport_name);
728 // Fake media transport returns empty settings (but not nullopt settings!)
729 EXPECT_EQ("", settings->transport_setting);
730}
731
732// Caller generates the offer if media transport returns offer with parameters.
733TEST_F(JsepTransportControllerTest,
734 MediaTransportGeneratesSessionDescriptionWithOfferParams) {
735 FakeMediaTransportFactory fake_media_transport_factory(
736 /*transport_offer=*/"offer-params");
737 JsepTransportController::Config config;
738
739 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
740 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
741 config.media_transport_factory = &fake_media_transport_factory;
742 config.use_media_transport_for_data_channels = true;
743 config.use_media_transport_for_media = true;
744 CreateJsepTransportController(config);
745 auto description = CreateSessionDescriptionWithBundleGroup();
746 AddCryptoSettings(description.get());
747 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
748 transport_controller_->GenerateOrGetLastMediaTransportOffer();
749
750 ASSERT_TRUE(settings.has_value());
751 EXPECT_EQ("fake", settings->transport_name);
752 EXPECT_EQ("offer-params", settings->transport_setting);
753}
754
755// Caller skips the offer if media transport requests it.
756TEST_F(JsepTransportControllerTest,
757 MediaTransportGeneratesSkipsSessionDescription) {
758 FakeMediaTransportFactory fake_media_transport_factory(
759 /*transport_offer=*/absl::nullopt);
760 JsepTransportController::Config config;
761
762 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
763 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
764 config.media_transport_factory = &fake_media_transport_factory;
765 config.use_media_transport_for_data_channels = true;
766 config.use_media_transport_for_media = true;
767 CreateJsepTransportController(config);
768 auto description = CreateSessionDescriptionWithBundleGroup();
769 AddCryptoSettings(description.get());
770 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
771 transport_controller_->GenerateOrGetLastMediaTransportOffer();
772
773 // Fake media transport returns nullopt settings
774 ASSERT_EQ(absl::nullopt, settings);
775}
776
Piotr (Peter) Slatala105ded32019-02-27 22:26:15777// Caller ignores its own outgoing parameters.
778TEST_F(JsepTransportControllerTest,
779 GetMediaTransportInCallerIgnoresXmtSection) {
780 FakeMediaTransportFactory fake_media_transport_factory;
781 JsepTransportController::Config config;
782
783 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05784 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 22:26:15785 config.media_transport_factory = &fake_media_transport_factory;
786 config.use_media_transport_for_data_channels = true;
787 config.use_media_transport_for_media = true;
788 CreateJsepTransportController(config);
789 auto description = CreateSessionDescriptionWithBundleGroup();
790 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05791 EXPECT_NE(absl::nullopt,
792 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala105ded32019-02-27 22:26:15793 EXPECT_TRUE(transport_controller_
794 ->SetLocalDescription(SdpType::kOffer, description.get())
795 .ok());
796
797 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
798 transport_controller_->GetMediaTransport(kAudioMid1));
799
800 ASSERT_NE(nullptr, media_transport);
801
802 // Remote parameters are nullopt, because we are the offerer (we don't)
803 // have the remote transport parameters, only ours.
804 EXPECT_EQ(absl::nullopt,
805 media_transport->settings().remote_transport_parameters);
806}
807
808TEST_F(JsepTransportControllerTest,
809 GetMediaTransportInCalleeIgnoresDifferentTransport) {
810 FakeMediaTransportFactory fake_media_transport_factory;
811 JsepTransportController::Config config;
812
813 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05814 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 22:26:15815 config.media_transport_factory = &fake_media_transport_factory;
816 config.use_media_transport_for_data_channels = true;
817 config.use_media_transport_for_media = true;
818 CreateJsepTransportController(config);
819 auto description = CreateSessionDescriptionWithBundleGroup();
820 AddCryptoSettings(description.get());
821 description->AddMediaTransportSetting("not-a-fake-transport",
822 "this-is-a-test-setting");
823 EXPECT_TRUE(transport_controller_
824 ->SetRemoteDescription(SdpType::kOffer, description.get())
825 .ok());
826
827 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
828 transport_controller_->GetMediaTransport(kAudioMid1));
829
830 ASSERT_NE(nullptr, media_transport);
831
832 EXPECT_EQ(absl::nullopt,
833 media_transport->settings().remote_transport_parameters);
834}
835
Piotr (Peter) Slatala9f956252018-10-31 15:25:26836TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
837 FakeMediaTransportFactory fake_media_transport_factory;
838 JsepTransportController::Config config;
839
840 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05841 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 15:25:26842 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 21:31:15843 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 15:25:26844 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05845 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 15:25:26846 EXPECT_TRUE(transport_controller_
847 ->SetRemoteDescription(SdpType::kOffer, description.get())
848 .ok());
849
850 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
851
852 // Even if we set local description with crypto now (after the remote offer
853 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05854 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 15:25:26855 AddCryptoSettings(description2.get());
856 EXPECT_TRUE(transport_controller_
857 ->SetLocalDescription(SdpType::kAnswer, description2.get())
858 .ok());
859
860 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:21861 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
862 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
863 << "Because media transport is NOT used (fallback to RTP), expected "
864 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 15:25:26865}
866
867TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05868 AfterSettingAnswerTheSameMediaTransportIsReturnedCallee) {
Piotr (Peter) Slatala9f956252018-10-31 15:25:26869 FakeMediaTransportFactory fake_media_transport_factory;
870 JsepTransportController::Config config;
871
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:21872 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05873 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 15:25:26874 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 21:31:15875 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 15:25:26876 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05877 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 15:25:26878 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05879 description->AddMediaTransportSetting("fake", "fake-settings");
Piotr (Peter) Slatala9f956252018-10-31 15:25:26880 EXPECT_TRUE(transport_controller_
881 ->SetRemoteDescription(SdpType::kOffer, description.get())
882 .ok());
Piotr (Peter) Slatala9f956252018-10-31 15:25:26883 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
884 transport_controller_->GetMediaTransport(kAudioMid1));
885 EXPECT_NE(nullptr, media_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05886 EXPECT_FALSE(media_transport->pre_shared_key().has_value())
887 << "On the callee, preshared key is passed through the media-transport "
888 "settings (x-mt)";
Piotr (Peter) Slatala9f956252018-10-31 15:25:26889
890 // Even if we set local description with crypto now (after the remote offer
891 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:05892 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 15:25:26893 AddCryptoSettings(description2.get());
894
895 RTCError result = transport_controller_->SetLocalDescription(
896 SdpType::kAnswer, description2.get());
897 EXPECT_TRUE(result.ok()) << result.message();
898
899 // Media transport did not change.
900 EXPECT_EQ(media_transport,
901 transport_controller_->GetMediaTransport(kAudioMid1));
902}
903
Zhi Huange818b6e2018-02-22 23:26:27904TEST_F(JsepTransportControllerTest, SetIceConfig) {
905 CreateJsepTransportController(JsepTransportController::Config());
906 auto description = CreateSessionDescriptionWithoutBundle();
907 EXPECT_TRUE(transport_controller_
908 ->SetLocalDescription(SdpType::kOffer, description.get())
909 .ok());
910
911 transport_controller_->SetIceConfig(
912 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
913 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
914 transport_controller_->GetDtlsTransport(kAudioMid1));
915 ASSERT_NE(nullptr, fake_audio_dtls);
916 EXPECT_EQ(kTimeout,
917 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
918 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
919
920 // Test that value stored in controller is applied to new transports.
921 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
922 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
923 nullptr);
924
925 EXPECT_TRUE(transport_controller_
926 ->SetLocalDescription(SdpType::kOffer, description.get())
927 .ok());
928 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
929 transport_controller_->GetDtlsTransport(kAudioMid2));
930 ASSERT_NE(nullptr, fake_audio_dtls);
931 EXPECT_EQ(kTimeout,
932 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
933 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
934}
935
936// Tests the getter and setter of the ICE restart flag.
937TEST_F(JsepTransportControllerTest, NeedIceRestart) {
938 CreateJsepTransportController(JsepTransportController::Config());
939 auto description = CreateSessionDescriptionWithoutBundle();
940 EXPECT_TRUE(transport_controller_
941 ->SetLocalDescription(SdpType::kOffer, description.get())
942 .ok());
943 EXPECT_TRUE(transport_controller_
944 ->SetRemoteDescription(SdpType::kAnswer, description.get())
945 .ok());
946
947 // Initially NeedsIceRestart should return false.
948 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
949 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
950 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
951 // true.
952 transport_controller_->SetNeedsIceRestartFlag();
953 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
954 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
955 // For a nonexistent transport, false should be returned.
956 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
957
958 // Reset the ice_ufrag/ice_pwd for audio.
959 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
960 audio_transport_info->description.ice_ufrag = kIceUfrag2;
961 audio_transport_info->description.ice_pwd = kIcePwd2;
962 EXPECT_TRUE(transport_controller_
963 ->SetLocalDescription(SdpType::kOffer, description.get())
964 .ok());
965 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
966 // return false for audio and true for video.
967 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
968 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
969}
970
971TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
972 CreateJsepTransportController(JsepTransportController::Config());
973 auto description = CreateSessionDescriptionWithBundleGroup();
974 EXPECT_TRUE(transport_controller_
975 ->SetLocalDescription(SdpType::kOffer, description.get())
976 .ok());
977 // After setting the local description, we should be able to start gathering
978 // candidates.
979 transport_controller_->MaybeStartGathering();
980 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
981 EXPECT_EQ(1, gathering_state_signal_count_);
982}
983
984TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
985 CreateJsepTransportController(JsepTransportController::Config());
986 auto description = CreateSessionDescriptionWithoutBundle();
987 transport_controller_->SetLocalDescription(SdpType::kOffer,
988 description.get());
989 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
990 description.get());
991 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
992 transport_controller_->GetDtlsTransport(kAudioMid1));
993 ASSERT_NE(nullptr, fake_audio_dtls);
994 Candidates candidates;
995 candidates.push_back(
996 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
997 EXPECT_TRUE(
998 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
999 EXPECT_EQ(1U,
1000 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
1001
1002 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
1003 EXPECT_EQ(0U,
1004 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
1005}
1006
1007TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
1008 CreateJsepTransportController(JsepTransportController::Config());
1009
1010 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
1011 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1012 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
1013 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
1014
Mirko Bonadei317a1f02019-09-17 15:06:181015 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271016 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1017 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1018 certificate1);
1019
1020 // Apply the local certificate.
1021 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
1022 // Apply the local description.
1023 EXPECT_TRUE(transport_controller_
1024 ->SetLocalDescription(SdpType::kOffer, description.get())
1025 .ok());
1026 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
1027 EXPECT_TRUE(returned_certificate);
1028 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
1029 returned_certificate->identity()->certificate().ToPEMString());
1030
1031 // Should fail if called for a nonexistant transport.
1032 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
1033
1034 // Shouldn't be able to change the identity once set.
1035 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
1036 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1037 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
1038 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
1039}
1040
Taylor Brandstetterc3928662018-02-23 21:04:511041TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 23:26:271042 CreateJsepTransportController(JsepTransportController::Config());
1043 auto description = CreateSessionDescriptionWithBundleGroup();
1044 EXPECT_TRUE(transport_controller_
1045 ->SetLocalDescription(SdpType::kOffer, description.get())
1046 .ok());
1047 rtc::FakeSSLCertificate fake_certificate("fake_data");
1048
1049 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1050 transport_controller_->GetDtlsTransport(kAudioMid1));
1051 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 21:04:511052 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
1053 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
1054 ASSERT_TRUE(returned_cert_chain);
1055 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 23:26:271056 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 21:04:511057 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 23:26:271058
1059 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 21:04:511060 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 23:26:271061}
1062
1063TEST_F(JsepTransportControllerTest, GetDtlsRole) {
1064 CreateJsepTransportController(JsepTransportController::Config());
1065 auto offer_certificate =
1066 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1067 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
1068 auto answer_certificate =
1069 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1070 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
1071 transport_controller_->SetLocalCertificate(offer_certificate);
1072
Mirko Bonadei317a1f02019-09-17 15:06:181073 auto offer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271074 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1075 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1076 offer_certificate);
Mirko Bonadei317a1f02019-09-17 15:06:181077 auto answer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271078 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1079 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1080 answer_certificate);
1081
1082 EXPECT_TRUE(transport_controller_
1083 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
1084 .ok());
1085
Danil Chapovalov66cadcc2018-06-19 14:47:431086 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 23:26:271087 transport_controller_->GetDtlsRole(kAudioMid1);
1088 // The DTLS role is not decided yet.
1089 EXPECT_FALSE(role);
1090 EXPECT_TRUE(transport_controller_
1091 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
1092 .ok());
1093 role = transport_controller_->GetDtlsRole(kAudioMid1);
1094
1095 ASSERT_TRUE(role);
1096 EXPECT_EQ(rtc::SSL_CLIENT, *role);
1097}
1098
1099TEST_F(JsepTransportControllerTest, GetStats) {
1100 CreateJsepTransportController(JsepTransportController::Config());
1101 auto description = CreateSessionDescriptionWithBundleGroup();
1102 EXPECT_TRUE(transport_controller_
1103 ->SetLocalDescription(SdpType::kOffer, description.get())
1104 .ok());
1105
1106 cricket::TransportStats stats;
1107 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
1108 EXPECT_EQ(kAudioMid1, stats.transport_name);
1109 EXPECT_EQ(1u, stats.channel_stats.size());
1110 // Return false for non-existing transport.
1111 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
1112}
1113
1114TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
1115 CreateJsepTransportController(JsepTransportController::Config());
1116 auto description = CreateSessionDescriptionWithoutBundle();
1117 EXPECT_TRUE(transport_controller_
1118 ->SetLocalDescription(SdpType::kOffer, description.get())
1119 .ok());
1120
1121 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
1122 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1123 fake_ice->SetCandidatesGatheringComplete();
1124 fake_ice->SetConnectionCount(1);
1125 // The connection stats will be failed if there is no active connection.
1126 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:591127 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 15:50:371128 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:591129 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1130 ice_connection_state_, kTimeout);
1131 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 09:51:091132 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1133 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 13:58:171134 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 23:26:271135}
1136
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031137TEST_F(JsepTransportControllerTest,
1138 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 23:26:271139 CreateJsepTransportController(JsepTransportController::Config());
1140 auto description = CreateSessionDescriptionWithoutBundle();
1141 EXPECT_TRUE(transport_controller_
1142 ->SetLocalDescription(SdpType::kOffer, description.get())
1143 .ok());
1144
1145 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1146 transport_controller_->GetDtlsTransport(kAudioMid1));
1147 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1148 transport_controller_->GetDtlsTransport(kVideoMid1));
1149
1150 // First, have one transport connect, and another fail, to ensure that
1151 // the first transport connecting didn't trigger a "connected" state signal.
1152 // We should only get a signal when all are connected.
1153 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
1154 fake_audio_dtls->SetWritable(true);
1155 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1156 // Decrease the number of the connection to trigger the signal.
1157 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
1158 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
1159 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1160
Alex Loiko9289eda2018-11-23 16:18:591161 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 15:50:371162 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:591163 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1164 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:441165 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 09:51:091166 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1167 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:441168 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 23:26:271169
Jonas Olsson635474e2018-10-18 13:58:171170 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1171 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 23:26:271172 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
1173 // the transport state to be STATE_CONNECTING.
1174 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
1175 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:591176 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 15:50:371177 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:591178 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
1179 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:441180 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 09:51:091181 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1182 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:441183 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 23:26:271184}
1185
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031186TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051187 SignalConnectionStateConnectedWithMediaTransportAndNoDtlsCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031188 FakeMediaTransportFactory fake_media_transport_factory;
1189 JsepTransportController::Config config;
1190 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051191 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1192 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 21:31:151193 config.use_media_transport_for_data_channels = true;
1194 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031195 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:211196
1197 // Media Transport is only used with bundle.
1198 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031199 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051200 EXPECT_NE(absl::nullopt,
1201 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031202 EXPECT_TRUE(transport_controller_
1203 ->SetLocalDescription(SdpType::kOffer, description.get())
1204 .ok());
1205
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:211206 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1207 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1208 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1209 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051210 EXPECT_EQ(fake_audio_ice, fake_video_ice);
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:211211 fake_audio_ice->SetConnectionCount(2);
1212 fake_audio_ice->SetConnectionCount(1);
1213 fake_video_ice->SetConnectionCount(2);
1214 fake_video_ice->SetConnectionCount(1);
1215 fake_audio_ice->SetWritable(true);
1216 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031217
1218 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:591219 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1220 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031221
1222 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1223 transport_controller_->GetMediaTransport(kAudioMid1));
1224
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051225 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031226
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031227 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051228 // Only one media transport.
Alex Loiko9289eda2018-11-23 16:18:591229 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031230}
1231
1232TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051233 SignalConnectionStateConnectedWithMediaTransportCaller) {
Piotr (Peter) Slatala55b91b92019-01-25 21:31:151234 FakeMediaTransportFactory fake_media_transport_factory;
1235 JsepTransportController::Config config;
1236 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051237 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1238 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 21:31:151239 config.use_media_transport_for_media = true;
1240 CreateJsepTransportController(config);
1241
1242 // Media Transport is only used with bundle.
1243 auto description = CreateSessionDescriptionWithBundleGroup();
1244 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051245 EXPECT_NE(absl::nullopt,
1246 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala55b91b92019-01-25 21:31:151247 EXPECT_TRUE(transport_controller_
1248 ->SetLocalDescription(SdpType::kOffer, description.get())
1249 .ok());
1250
1251 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
1256 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->SetConnectionCount(2);
1261 fake_audio_ice->SetConnectionCount(1);
1262 fake_video_ice->SetConnectionCount(2);
1263 fake_video_ice->SetConnectionCount(1);
1264 fake_audio_ice->SetWritable(true);
1265 fake_video_ice->SetWritable(true);
1266 fake_audio_dtls->SetWritable(true);
1267 fake_video_dtls->SetWritable(true);
1268
1269 // Still not connected, because we are waiting for media transport.
1270 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1271 kTimeout);
1272
1273 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1274 transport_controller_->GetMediaTransport(kAudioMid1));
1275
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051276 ASSERT_NE(nullptr, media_transport);
1277
Piotr (Peter) Slatala55b91b92019-01-25 21:31:151278 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1279 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1280 kTimeout);
1281
1282 // Still waiting for the second media transport.
1283 media_transport = static_cast<FakeMediaTransport*>(
1284 transport_controller_->GetMediaTransport(kVideoMid1));
1285 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1286
1287 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
1288}
1289
1290TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051291 SignalConnectionStateFailedWhenMediaTransportClosedCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031292 FakeMediaTransportFactory fake_media_transport_factory;
1293 JsepTransportController::Config config;
1294 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051295 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1296 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 21:31:151297 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031298 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051299 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031300 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051301 EXPECT_NE(absl::nullopt,
1302 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031303 EXPECT_TRUE(transport_controller_
1304 ->SetLocalDescription(SdpType::kOffer, description.get())
1305 .ok());
1306
Piotr (Peter) Slatala55b91b92019-01-25 21:31:151307 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1308 transport_controller_->GetDtlsTransport(kAudioMid1));
1309 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1310 transport_controller_->GetDtlsTransport(kVideoMid1));
1311
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:211312 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1313 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1314 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1315 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1316 fake_audio_ice->SetWritable(true);
1317 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031318 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 16:25:211319 fake_audio_ice->SetConnectionCount(2);
1320 fake_audio_ice->SetConnectionCount(1);
1321 fake_video_ice->SetConnectionCount(2);
1322 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031323
Piotr (Peter) Slatala55b91b92019-01-25 21:31:151324 fake_audio_dtls->SetWritable(true);
1325 fake_video_dtls->SetWritable(true);
1326
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031327 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1328 transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051329 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031330 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1331
1332 media_transport = static_cast<FakeMediaTransport*>(
1333 transport_controller_->GetMediaTransport(kVideoMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:051334 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031335
1336 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1337
Alex Loiko9289eda2018-11-23 16:18:591338 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031339
1340 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:591341 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 14:26:031342}
1343
Zhi Huange818b6e2018-02-22 23:26:271344TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1345 CreateJsepTransportController(JsepTransportController::Config());
1346 auto description = CreateSessionDescriptionWithoutBundle();
1347 EXPECT_TRUE(transport_controller_
1348 ->SetLocalDescription(SdpType::kOffer, description.get())
1349 .ok());
1350
1351 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1352 transport_controller_->GetDtlsTransport(kAudioMid1));
1353 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1354 transport_controller_->GetDtlsTransport(kVideoMid1));
1355
1356 // First, have one transport connect, and another fail, to ensure that
1357 // the first transport connecting didn't trigger a "connected" state signal.
1358 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 12:11:441359 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1360 IceTransportState::kCompleted,
1361 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 23:26:271362 fake_audio_dtls->SetWritable(true);
1363 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 12:11:441364
1365 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1366 ice_connection_state_, kTimeout);
1367 EXPECT_EQ(1, ice_connection_state_signal_count_);
1368 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1369 combined_connection_state_, kTimeout);
1370 EXPECT_EQ(1, combined_connection_state_signal_count_);
1371
1372 fake_video_dtls->fake_ice_transport()->SetTransportState(
1373 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 23:26:271374 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1375
Alex Loiko9289eda2018-11-23 16:18:591376 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 15:50:371377 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:591378 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1379 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:441380 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 09:51:091381 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1382 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:441383 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 23:26:271384
Jonas Olsson635474e2018-10-18 13:58:171385 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1386 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 23:26:271387 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1388 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 12:11:441389 fake_video_dtls->fake_ice_transport()->SetTransportState(
1390 IceTransportState::kCompleted,
1391 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 23:26:271392 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:591393 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 15:31:551394 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:591395 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1396 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:441397 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 09:51:091398 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1399 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:441400 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 23:26:271401}
1402
1403TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1404 CreateJsepTransportController(JsepTransportController::Config());
1405 auto description = CreateSessionDescriptionWithoutBundle();
1406 EXPECT_TRUE(transport_controller_
1407 ->SetLocalDescription(SdpType::kOffer, description.get())
1408 .ok());
1409
1410 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1411 transport_controller_->GetDtlsTransport(kAudioMid1));
1412 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1413 // Should be in the gathering state as soon as any transport starts gathering.
1414 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1415 EXPECT_EQ(1, gathering_state_signal_count_);
1416}
1417
1418TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1419 CreateJsepTransportController(JsepTransportController::Config());
1420 auto description = CreateSessionDescriptionWithoutBundle();
1421 EXPECT_TRUE(transport_controller_
1422 ->SetLocalDescription(SdpType::kOffer, description.get())
1423 .ok());
1424
1425 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1426 transport_controller_->GetDtlsTransport(kAudioMid1));
1427 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1428 transport_controller_->GetDtlsTransport(kVideoMid1));
1429
1430 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1431 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1432 EXPECT_EQ(1, gathering_state_signal_count_);
1433
1434 // Have one transport finish gathering, to make sure gathering
1435 // completion wasn't signalled if only one transport finished gathering.
1436 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1437 EXPECT_EQ(1, gathering_state_signal_count_);
1438
1439 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1440 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1441 EXPECT_EQ(1, gathering_state_signal_count_);
1442
1443 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1444 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1445 EXPECT_EQ(2, gathering_state_signal_count_);
1446}
1447
1448// Test that when the last transport that hasn't finished connecting and/or
1449// gathering is destroyed, the aggregate state jumps to "completed". This can
1450// happen if, for example, we have an audio and video transport, the audio
1451// transport completes, then we start bundling video on the audio transport.
1452TEST_F(JsepTransportControllerTest,
1453 SignalingWhenLastIncompleteTransportDestroyed) {
1454 CreateJsepTransportController(JsepTransportController::Config());
1455 auto description = CreateSessionDescriptionWithBundleGroup();
1456 EXPECT_TRUE(transport_controller_
1457 ->SetLocalDescription(SdpType::kOffer, description.get())
1458 .ok());
1459
1460 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1461 transport_controller_->GetDtlsTransport(kAudioMid1));
1462 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1463 transport_controller_->GetDtlsTransport(kVideoMid1));
1464 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1465
1466 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1467 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1468 EXPECT_EQ(1, gathering_state_signal_count_);
1469
1470 // Let the audio transport complete.
1471 fake_audio_dtls->SetWritable(true);
1472 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1473 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 13:58:171474 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 23:26:271475 EXPECT_EQ(1, gathering_state_signal_count_);
1476
1477 // Set the remote description and enable the bundle.
1478 EXPECT_TRUE(transport_controller_
1479 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1480 .ok());
1481 // The BUNDLE should be enabled, the incomplete video transport should be
1482 // deleted and the states shoud be updated.
1483 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1484 transport_controller_->GetDtlsTransport(kVideoMid1));
1485 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:591486 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1487 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1488 ice_connection_state_);
Jonas Olsson635474e2018-10-18 13:58:171489 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1490 combined_connection_state_);
Zhi Huange818b6e2018-02-22 23:26:271491 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1492 EXPECT_EQ(2, gathering_state_signal_count_);
1493}
1494
1495TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1496 CreateJsepTransportController(JsepTransportController::Config());
1497 auto description = CreateSessionDescriptionWithBundleGroup();
1498 EXPECT_TRUE(transport_controller_
1499 ->SetLocalDescription(SdpType::kOffer, description.get())
1500 .ok());
1501 transport_controller_->MaybeStartGathering();
1502
1503 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1504 transport_controller_->GetDtlsTransport(kAudioMid1));
1505 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1506 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1507 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1508 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1509}
1510
1511TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1512 network_thread_ = rtc::Thread::CreateWithSocketServer();
1513 network_thread_->Start();
1514 CreateJsepTransportController(JsepTransportController::Config(),
1515 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 13:57:521516 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 23:26:271517 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1518
1519 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:591520 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 23:26:271521 EXPECT_EQ(2, connection_state_signal_count_);
1522
1523 // new --> gathering --> complete
1524 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1525 EXPECT_EQ(2, gathering_state_signal_count_);
1526
1527 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1528 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1529 EXPECT_EQ(2, candidates_signal_count_);
1530
1531 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1532}
1533
1534// Older versions of Chrome expect the ICE role to be re-determined when an
1535// ICE restart occurs, and also don't perform conflict resolution correctly,
1536// so for now we can't safely stop doing this.
1537// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1538// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1539// enough population.
1540TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1541 CreateJsepTransportController(JsepTransportController::Config());
1542 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 15:06:181543 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271544 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1545 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1546 nullptr);
Mirko Bonadei317a1f02019-09-17 15:06:181547 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271548 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1549 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1550 nullptr);
1551
1552 EXPECT_TRUE(transport_controller_
1553 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1554 .ok());
1555 EXPECT_TRUE(transport_controller_
1556 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1557 .ok());
1558
1559 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1560 transport_controller_->GetDtlsTransport(kAudioMid1));
1561 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1562 fake_dtls->fake_ice_transport()->GetIceRole());
1563
1564 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 15:06:181565 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271566 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1567 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1568 nullptr);
1569 EXPECT_TRUE(
1570 transport_controller_
1571 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1572 .ok());
1573 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1574 fake_dtls->fake_ice_transport()->GetIceRole());
1575}
1576
1577// Test that if the TransportController was created with the
1578// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1579// redetermined on an ICE restart.
1580TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1581 JsepTransportController::Config config;
1582 config.redetermine_role_on_ice_restart = false;
1583
1584 CreateJsepTransportController(config);
1585 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 15:06:181586 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271587 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1588 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1589 nullptr);
Mirko Bonadei317a1f02019-09-17 15:06:181590 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271591 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1592 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1593 nullptr);
1594
1595 EXPECT_TRUE(transport_controller_
1596 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1597 .ok());
1598 EXPECT_TRUE(transport_controller_
1599 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1600 .ok());
1601
1602 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1603 transport_controller_->GetDtlsTransport(kAudioMid1));
1604 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1605 fake_dtls->fake_ice_transport()->GetIceRole());
1606
1607 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 15:06:181608 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271609 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1610 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1611 nullptr);
1612 EXPECT_TRUE(
1613 transport_controller_
1614 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1615 .ok());
1616 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1617 fake_dtls->fake_ice_transport()->GetIceRole());
1618}
1619
1620// Tests ICE-Lite mode in remote answer.
1621TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1622 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 15:06:181623 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271624 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1625 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1626 nullptr);
1627 EXPECT_TRUE(transport_controller_
1628 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1629 .ok());
1630 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1631 transport_controller_->GetDtlsTransport(kAudioMid1));
1632 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1633 fake_dtls->fake_ice_transport()->GetIceRole());
1634 EXPECT_EQ(cricket::ICEMODE_FULL,
1635 fake_dtls->fake_ice_transport()->remote_ice_mode());
1636
Mirko Bonadei317a1f02019-09-17 15:06:181637 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271638 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1639 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1640 nullptr);
1641 EXPECT_TRUE(transport_controller_
1642 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1643 .ok());
1644 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1645 fake_dtls->fake_ice_transport()->GetIceRole());
1646 EXPECT_EQ(cricket::ICEMODE_LITE,
1647 fake_dtls->fake_ice_transport()->remote_ice_mode());
1648}
1649
1650// Tests that the ICE role remains "controlling" if a subsequent offer that
1651// does an ICE restart is received from an ICE lite endpoint. Regression test
1652// for: https://crbug.com/710760
1653TEST_F(JsepTransportControllerTest,
1654 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1655 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 15:06:181656 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271657 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1658 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1659 nullptr);
Mirko Bonadei317a1f02019-09-17 15:06:181660 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271661 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1662 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1663 nullptr);
1664 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1665 // local side is the controlling.
1666 EXPECT_TRUE(transport_controller_
1667 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1668 .ok());
1669 EXPECT_TRUE(transport_controller_
1670 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1671 .ok());
1672 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1673 transport_controller_->GetDtlsTransport(kAudioMid1));
1674 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1675 fake_dtls->fake_ice_transport()->GetIceRole());
1676
1677 // In the subsequence remote offer triggers an ICE restart.
Mirko Bonadei317a1f02019-09-17 15:06:181678 auto remote_offer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271679 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1680 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1681 nullptr);
Mirko Bonadei317a1f02019-09-17 15:06:181682 auto local_answer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271683 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1684 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1685 nullptr);
1686 EXPECT_TRUE(transport_controller_
1687 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1688 .ok());
1689 EXPECT_TRUE(transport_controller_
1690 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1691 .ok());
1692 fake_dtls = static_cast<FakeDtlsTransport*>(
1693 transport_controller_->GetDtlsTransport(kAudioMid1));
1694 // The local side is still the controlling role since the remote side is using
1695 // ICE-Lite.
1696 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1697 fake_dtls->fake_ice_transport()->GetIceRole());
1698}
1699
1700// Tests that the SDP has more than one audio/video m= sections.
1701TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1702 CreateJsepTransportController(JsepTransportController::Config());
1703 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1704 bundle_group.AddContentName(kAudioMid1);
1705 bundle_group.AddContentName(kAudioMid2);
1706 bundle_group.AddContentName(kVideoMid1);
1707 bundle_group.AddContentName(kDataMid1);
1708
Mirko Bonadei317a1f02019-09-17 15:06:181709 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271710 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1711 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1712 nullptr);
1713 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1714 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1715 nullptr);
1716 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1717 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1718 nullptr);
1719 AddDataSection(local_offer.get(), kDataMid1,
1720 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1721 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1722 nullptr);
1723
Mirko Bonadei317a1f02019-09-17 15:06:181724 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271725 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1726 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1727 nullptr);
1728 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1729 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1730 nullptr);
1731 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1732 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1733 nullptr);
1734 AddDataSection(remote_answer.get(), kDataMid1,
1735 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1736 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1737 nullptr);
1738
1739 local_offer->AddGroup(bundle_group);
1740 remote_answer->AddGroup(bundle_group);
1741
1742 EXPECT_TRUE(transport_controller_
1743 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1744 .ok());
1745 EXPECT_TRUE(transport_controller_
1746 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1747 .ok());
1748 // Verify that all the sections are bundled on kAudio1.
1749 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1750 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1751 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1752 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1753 EXPECT_EQ(transport1, transport2);
1754 EXPECT_EQ(transport1, transport3);
1755 EXPECT_EQ(transport1, transport4);
1756
Harald Alvestrandad88c882018-11-28 15:47:461757 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1758 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1759
Zhi Huange818b6e2018-02-22 23:26:271760 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1761 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1762 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1763 EXPECT_EQ(transport1, it->second);
1764 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1765 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1766 EXPECT_EQ(transport1, it->second);
1767 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1768 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1769 EXPECT_EQ(transport1, it->second);
1770 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1771 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1772 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
Zhi Huange818b6e2018-02-22 23:26:271773}
1774
1775// Tests that only a subset of all the m= sections are bundled.
1776TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1777 CreateJsepTransportController(JsepTransportController::Config());
1778 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1779 bundle_group.AddContentName(kAudioMid1);
1780 bundle_group.AddContentName(kVideoMid1);
1781
Mirko Bonadei317a1f02019-09-17 15:06:181782 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271783 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1784 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1785 nullptr);
1786 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1787 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1788 nullptr);
1789 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1790 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1791 nullptr);
1792
Mirko Bonadei317a1f02019-09-17 15:06:181793 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271794 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1795 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1796 nullptr);
1797 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1798 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1799 nullptr);
1800 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1801 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1802 nullptr);
1803
1804 local_offer->AddGroup(bundle_group);
1805 remote_answer->AddGroup(bundle_group);
1806 EXPECT_TRUE(transport_controller_
1807 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1808 .ok());
1809 EXPECT_TRUE(transport_controller_
1810 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1811 .ok());
1812
1813 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1814 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1815 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1816 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1817 EXPECT_NE(transport1, transport2);
1818 EXPECT_EQ(transport1, transport3);
1819
1820 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1821 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1822 EXPECT_EQ(transport1, it->second);
1823 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 21:41:031824 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 23:26:271825}
1826
1827// Tests that the initial offer/answer only have data section and audio/video
1828// sections are added in the subsequent offer.
1829TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1830 CreateJsepTransportController(JsepTransportController::Config());
1831 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1832 bundle_group.AddContentName(kDataMid1);
1833
Mirko Bonadei317a1f02019-09-17 15:06:181834 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271835 AddDataSection(local_offer.get(), kDataMid1,
1836 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1837 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1838 nullptr);
Mirko Bonadei317a1f02019-09-17 15:06:181839 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271840 AddDataSection(remote_answer.get(), kDataMid1,
1841 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1842 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1843 nullptr);
1844 local_offer->AddGroup(bundle_group);
1845 remote_answer->AddGroup(bundle_group);
1846
1847 EXPECT_TRUE(transport_controller_
1848 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1849 .ok());
1850 EXPECT_TRUE(transport_controller_
1851 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1852 .ok());
1853 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1854
1855 // Add audio/video sections in subsequent offer.
1856 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1857 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1858 nullptr);
1859 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1860 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1861 nullptr);
1862 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1863 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1864 nullptr);
1865 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1866 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1867 nullptr);
1868
1869 // Reset the bundle group and do another offer/answer exchange.
1870 bundle_group.AddContentName(kAudioMid1);
1871 bundle_group.AddContentName(kVideoMid1);
1872 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1873 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1874 local_offer->AddGroup(bundle_group);
1875 remote_answer->AddGroup(bundle_group);
1876
1877 EXPECT_TRUE(transport_controller_
1878 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1879 .ok());
1880 EXPECT_TRUE(transport_controller_
1881 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1882 .ok());
1883
1884 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1885 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1886 EXPECT_EQ(data_transport, audio_transport);
1887 EXPECT_EQ(data_transport, video_transport);
1888}
1889
1890TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1891 CreateJsepTransportController(JsepTransportController::Config());
1892 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1893 bundle_group.AddContentName(kAudioMid1);
1894 bundle_group.AddContentName(kVideoMid1);
1895 bundle_group.AddContentName(kDataMid1);
1896
Mirko Bonadei317a1f02019-09-17 15:06:181897 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271898 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1899 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1900 nullptr);
1901 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1902 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1903 nullptr);
1904 AddDataSection(local_offer.get(), kDataMid1,
1905 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1906 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1907 nullptr);
1908
Mirko Bonadei317a1f02019-09-17 15:06:181909 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271910 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1911 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1912 nullptr);
1913 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1914 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1915 nullptr);
1916 AddDataSection(remote_answer.get(), kDataMid1,
1917 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1918 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1919 nullptr);
1920 // Reject video and data section.
1921 remote_answer->contents()[1].rejected = true;
1922 remote_answer->contents()[2].rejected = true;
1923
1924 local_offer->AddGroup(bundle_group);
1925 remote_answer->AddGroup(bundle_group);
1926
1927 EXPECT_TRUE(transport_controller_
1928 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1929 .ok());
1930 EXPECT_TRUE(transport_controller_
1931 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1932 .ok());
1933
1934 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1935 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1936 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1937 // Verify the signals are fired correctly.
1938 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1939 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1940 EXPECT_EQ(nullptr, it->second);
1941 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1942 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1943 EXPECT_EQ(nullptr, it2->second);
1944}
1945
1946// Tests that changing the bundled MID in subsequent offer/answer exchange is
1947// not supported.
1948// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1949// fixed
1950TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1951 CreateJsepTransportController(JsepTransportController::Config());
1952 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1953 bundle_group.AddContentName(kAudioMid1);
1954 bundle_group.AddContentName(kVideoMid1);
1955
Mirko Bonadei317a1f02019-09-17 15:06:181956 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271957 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1958 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1959 nullptr);
1960 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1961 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1962 nullptr);
1963
Mirko Bonadei317a1f02019-09-17 15:06:181964 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271965 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1966 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1967 nullptr);
1968 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1969 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1970 nullptr);
1971
1972 local_offer->AddGroup(bundle_group);
1973 remote_answer->AddGroup(bundle_group);
1974 EXPECT_TRUE(transport_controller_
1975 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1976 .ok());
1977 EXPECT_TRUE(transport_controller_
1978 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1979 .ok());
1980 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1981 transport_controller_->GetRtpTransport(kVideoMid1));
1982
1983 // Reorder the bundle group.
1984 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1985 bundle_group.AddContentName(kAudioMid1);
1986 // The answerer uses the new bundle group and now the bundle mid is changed to
1987 // |kVideo1|.
1988 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1989 remote_answer->AddGroup(bundle_group);
1990 EXPECT_TRUE(transport_controller_
1991 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1992 .ok());
1993 EXPECT_FALSE(transport_controller_
1994 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1995 .ok());
1996}
Zhi Huange830e682018-03-30 17:48:351997// Test that rejecting only the first m= section of a BUNDLE group is treated as
1998// an error, but rejecting all of them works as expected.
1999TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
2000 CreateJsepTransportController(JsepTransportController::Config());
2001 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
2002 bundle_group.AddContentName(kAudioMid1);
2003 bundle_group.AddContentName(kVideoMid1);
2004 bundle_group.AddContentName(kDataMid1);
2005
Mirko Bonadei317a1f02019-09-17 15:06:182006 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:352007 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2008 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2009 nullptr);
2010 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
2011 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2012 nullptr);
2013 AddDataSection(local_offer.get(), kDataMid1,
2014 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
2015 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2016 nullptr);
2017
Mirko Bonadei317a1f02019-09-17 15:06:182018 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:352019 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2020 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
2021 nullptr);
2022 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
2023 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
2024 nullptr);
2025 AddDataSection(remote_answer.get(), kDataMid1,
2026 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
2027 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
2028 nullptr);
2029 // Reject audio content in answer.
2030 remote_answer->contents()[0].rejected = true;
2031
2032 local_offer->AddGroup(bundle_group);
2033 remote_answer->AddGroup(bundle_group);
2034
2035 EXPECT_TRUE(transport_controller_
2036 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2037 .ok());
2038 EXPECT_FALSE(transport_controller_
2039 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2040 .ok());
2041
2042 // Reject all the contents.
2043 remote_answer->contents()[1].rejected = true;
2044 remote_answer->contents()[2].rejected = true;
2045 EXPECT_TRUE(transport_controller_
2046 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2047 .ok());
2048 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
2049 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
2050 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
2051}
2052
2053// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
2054// is used.
2055TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
2056 JsepTransportController::Config config;
2057 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2058 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 15:06:182059 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:352060 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2061 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2062 nullptr);
2063
2064 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
2065 // Applying a non-RTCP-mux offer is expected to fail.
2066 EXPECT_FALSE(transport_controller_
2067 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2068 .ok());
2069}
2070
2071// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
2072// is used.
2073TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
2074 JsepTransportController::Config config;
2075 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2076 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 15:06:182077 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:352078 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2079 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2080 nullptr);
2081 EXPECT_TRUE(transport_controller_
2082 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2083 .ok());
2084
Mirko Bonadei317a1f02019-09-17 15:06:182085 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:352086 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2087 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
2088 nullptr);
2089 // Applying a non-RTCP-mux answer is expected to fail.
2090 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
2091 EXPECT_FALSE(transport_controller_
2092 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2093 .ok());
2094}
Zhi Huange818b6e2018-02-22 23:26:272095
Zhi Huangd2248f82018-04-10 21:41:032096// This tests that the BUNDLE group in answer should be a subset of the offered
2097// group.
2098TEST_F(JsepTransportControllerTest,
2099 AddContentToBundleGroupInAnswerNotSupported) {
2100 CreateJsepTransportController(JsepTransportController::Config());
2101 auto local_offer = CreateSessionDescriptionWithoutBundle();
2102 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2103
2104 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2105 offer_bundle_group.AddContentName(kAudioMid1);
2106 local_offer->AddGroup(offer_bundle_group);
2107
2108 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2109 answer_bundle_group.AddContentName(kAudioMid1);
2110 answer_bundle_group.AddContentName(kVideoMid1);
2111 remote_answer->AddGroup(answer_bundle_group);
2112 EXPECT_TRUE(transport_controller_
2113 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2114 .ok());
2115 EXPECT_FALSE(transport_controller_
2116 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2117 .ok());
2118}
2119
2120// This tests that the BUNDLE group with non-existing MID should be rejectd.
2121TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
2122 CreateJsepTransportController(JsepTransportController::Config());
2123 auto local_offer = CreateSessionDescriptionWithoutBundle();
2124 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2125
2126 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2127 // The BUNDLE group is invalid because there is no data section in the
2128 // description.
2129 invalid_bundle_group.AddContentName(kDataMid1);
2130 local_offer->AddGroup(invalid_bundle_group);
2131 remote_answer->AddGroup(invalid_bundle_group);
2132
2133 EXPECT_FALSE(transport_controller_
2134 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2135 .ok());
2136 EXPECT_FALSE(transport_controller_
2137 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2138 .ok());
2139}
2140
2141// This tests that an answer shouldn't be able to remove an m= section from an
2142// established group without rejecting it.
2143TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
2144 CreateJsepTransportController(JsepTransportController::Config());
2145
2146 auto local_offer = CreateSessionDescriptionWithBundleGroup();
2147 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
2148 EXPECT_TRUE(transport_controller_
2149 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2150 .ok());
2151 EXPECT_TRUE(transport_controller_
2152 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2153 .ok());
2154
2155 // Do an re-offer/answer.
2156 EXPECT_TRUE(transport_controller_
2157 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2158 .ok());
2159 auto new_answer = CreateSessionDescriptionWithoutBundle();
2160 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2161 // The answer removes video from the BUNDLE group without rejecting it is
2162 // invalid.
2163 new_bundle_group.AddContentName(kAudioMid1);
2164 new_answer->AddGroup(new_bundle_group);
2165
2166 // Applying invalid answer is expected to fail.
2167 EXPECT_FALSE(transport_controller_
2168 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2169 .ok());
2170
2171 // Rejected the video content.
2172 auto video_content = new_answer->GetContentByName(kVideoMid1);
2173 ASSERT_TRUE(video_content);
2174 video_content->rejected = true;
2175 EXPECT_TRUE(transport_controller_
2176 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2177 .ok());
2178}
2179
Steve Anton2bed3972019-01-05 01:04:302180// Test that the JsepTransportController can process a new local and remote
2181// description that changes the tagged BUNDLE group with the max-bundle policy
2182// specified.
2183// This is a regression test for bugs.webrtc.org/9954
2184TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
2185 CreateJsepTransportController(JsepTransportController::Config());
2186
Mirko Bonadei317a1f02019-09-17 15:06:182187 auto local_offer = std::make_unique<cricket::SessionDescription>();
Steve Anton2bed3972019-01-05 01:04:302188 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2189 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2190 nullptr);
2191 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
2192 bundle_group.AddContentName(kAudioMid1);
2193 local_offer->AddGroup(bundle_group);
2194 EXPECT_TRUE(transport_controller_
2195 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2196 .ok());
2197
2198 std::unique_ptr<cricket::SessionDescription> remote_answer(
Harald Alvestrand4d7160e2019-04-12 05:01:292199 local_offer->Clone());
Steve Anton2bed3972019-01-05 01:04:302200 EXPECT_TRUE(transport_controller_
2201 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2202 .ok());
2203
2204 std::unique_ptr<cricket::SessionDescription> local_reoffer(
Harald Alvestrand4d7160e2019-04-12 05:01:292205 local_offer->Clone());
Steve Anton2bed3972019-01-05 01:04:302206 local_reoffer->contents()[0].rejected = true;
2207 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
2208 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2209 nullptr);
2210 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
2211 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2212 new_bundle_group.AddContentName(kVideoMid1);
2213 local_reoffer->AddGroup(new_bundle_group);
2214
2215 EXPECT_TRUE(transport_controller_
2216 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
2217 .ok());
2218
2219 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
Harald Alvestrand4d7160e2019-04-12 05:01:292220 local_reoffer->Clone());
Steve Anton2bed3972019-01-05 01:04:302221 EXPECT_TRUE(
2222 transport_controller_
2223 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
2224 .ok());
2225}
2226
Bjorn A Mellemc85ebbe2019-06-07 17:28:062227constexpr char kFakeTransportParameters[] = "fake-params";
2228
2229// Test fixture that provides common setup and helpers for tests related to the
2230// datagram transport.
2231class JsepTransportControllerDatagramTest
2232 : public JsepTransportControllerTest,
2233 public testing::WithParamInterface<bool> {
2234 public:
2235 JsepTransportControllerDatagramTest()
2236 : JsepTransportControllerTest(),
2237 fake_media_transport_factory_(kFakeTransportParameters) {
2238 JsepTransportController::Config config;
2239 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2240 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2241 config.media_transport_factory = &fake_media_transport_factory_;
2242 config.use_datagram_transport = true;
2243 CreateJsepTransportController(config);
2244 }
2245
2246 // Whether the JsepTransportController under test acts as the offerer or
2247 // answerer in this test.
2248 bool IsOfferer() { return GetParam(); }
2249
2250 // Sets a description as local or remote based on type and current
2251 // perspective.
2252 RTCError SetDescription(SdpType type,
2253 const cricket::SessionDescription* description) {
2254 if (IsOfferer() == (type == SdpType::kOffer)) {
2255 return transport_controller_->SetLocalDescription(type, description);
2256 } else {
2257 return transport_controller_->SetRemoteDescription(type, description);
2258 }
2259 }
2260
2261 // Creates a session description with the settings necessary for datagram
2262 // transport (bundle + crypto) and the given |transport_params|.
2263 std::unique_ptr<cricket::SessionDescription>
2264 CreateSessionDescriptionForDatagramTransport(
2265 absl::optional<cricket::OpaqueTransportParameters> transport_params) {
2266 auto description = CreateSessionDescriptionWithBundleGroup();
2267 AddCryptoSettings(description.get());
2268
2269 for (auto& info : description->transport_infos()) {
2270 info.description.opaque_parameters = transport_params;
2271 }
Bjorn A Mellem8e1343a2019-09-30 22:12:472272 if (transport_params) {
2273 for (auto& content_info : description->contents()) {
2274 content_info.media_description()->set_alt_protocol(
2275 transport_params->protocol);
2276 }
2277 }
Bjorn A Mellemc85ebbe2019-06-07 17:28:062278 return description;
2279 }
2280
2281 // Creates transport parameters with |protocol| and |parameters|
2282 // matching what |fake_media_transport_factory_| provides.
2283 cricket::OpaqueTransportParameters CreateTransportParameters() {
2284 cricket::OpaqueTransportParameters params;
2285 params.protocol = fake_media_transport_factory_.GetTransportName();
2286 params.parameters = "fake-params";
2287 return params;
2288 }
2289
2290 protected:
2291 FakeMediaTransportFactory fake_media_transport_factory_;
2292};
2293
2294TEST_P(JsepTransportControllerDatagramTest, InitDatagramTransport) {
2295 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2296 if (IsOfferer()) {
2297 // Getting transport parameters is allowed before setting a description.
2298 // This is necessary so that the offerer can include these params.
2299 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2300 fake_params);
2301 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2302 fake_params);
2303 }
2304
2305 // Setting a description activates the datagram transport without changing
2306 // transport parameters.
2307 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2308 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2309
2310 // After setting an offer with transport parameters, those parameters are
2311 // reflected by the controller.
2312 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2313 fake_params);
2314 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2315 fake_params);
2316}
2317
2318TEST_P(JsepTransportControllerDatagramTest,
2319 OfferMissingDatagramTransportParams) {
2320 if (IsOfferer()) {
2321 // This test doesn't make sense from the offerer's perspective, as the offer
2322 // must contain datagram transport params if the offerer supports it.
2323 return;
2324 }
2325
2326 auto description =
2327 CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2328 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2329
2330 // The offer didn't contain any datagram transport parameters, so the answer
2331 // won't either.
2332 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2333 absl::nullopt);
2334 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2335 absl::nullopt);
2336}
2337
2338TEST_P(JsepTransportControllerDatagramTest, OfferHasWrongTransportName) {
2339 if (IsOfferer()) {
2340 // This test doesn't make sense from the offerer's perspective, as the
2341 // offerer cannot offer itself the wrong transport.
2342 return;
2343 }
2344
2345 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2346 fake_params.protocol = "wrong-name";
2347
2348 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2349 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2350
2351 // The offerer and answerer support different datagram transports, so the
2352 // answerer rejects the offered parameters.
2353 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2354 absl::nullopt);
2355 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2356 absl::nullopt);
2357}
2358
2359TEST_P(JsepTransportControllerDatagramTest, AnswerRejectsDatagram) {
2360 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2361 if (IsOfferer()) {
2362 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2363 fake_params);
2364 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2365 fake_params);
2366 }
2367
2368 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2369 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2370
2371 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2372 fake_params);
2373 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2374 fake_params);
2375
2376 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2377 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2378
2379 // The answer rejected datagram transport, so its parameters are empty.
2380 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2381 absl::nullopt);
2382 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2383 absl::nullopt);
2384}
2385
2386TEST_P(JsepTransportControllerDatagramTest, AnswerAcceptsDatagram) {
2387 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2388 if (IsOfferer()) {
2389 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2390 fake_params);
2391 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2392 fake_params);
2393 }
2394
2395 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2396 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2397
2398 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2399 fake_params);
2400 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2401 fake_params);
2402
2403 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2404 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2405
2406 // The answer accepted datagram transport, so it is present.
2407 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2408 fake_params);
2409 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2410 fake_params);
2411}
2412
2413TEST_P(JsepTransportControllerDatagramTest, PrAnswerRejectsDatagram) {
2414 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2415 if (IsOfferer()) {
2416 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2417 fake_params);
2418 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2419 fake_params);
2420 }
2421
2422 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2423 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2424
2425 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2426 fake_params);
2427 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2428 fake_params);
2429
2430 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2431 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2432
2433 // The answer rejected datagram transport, but it's provisional, so the
2434 // transport is kept around for now.
2435 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2436 fake_params);
2437 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2438 fake_params);
2439}
2440
2441TEST_P(JsepTransportControllerDatagramTest, PrAnswerAcceptsDatagram) {
2442 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2443 if (IsOfferer()) {
2444 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2445 fake_params);
2446 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2447 fake_params);
2448 }
2449
2450 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2451 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2452
2453 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2454 fake_params);
2455 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2456 fake_params);
2457
2458 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2459 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2460
2461 // The answer provisionally accepted datagram transport, so it's kept.
2462 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2463 fake_params);
2464 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2465 fake_params);
2466}
2467
2468TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotAddDatagram) {
2469 auto offer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2470 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2471
2472 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2473 absl::nullopt);
2474 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2475 absl::nullopt);
2476
2477 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2478 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2479
2480 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2481 absl::nullopt);
2482 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2483 absl::nullopt);
2484
2485 // Attempting to add a datagram transport on a re-offer does not cause an
2486 // error, but also does not add a datagram transport.
2487 auto reoffer =
2488 CreateSessionDescriptionForDatagramTransport(CreateTransportParameters());
2489 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2490
2491 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2492 absl::nullopt);
2493 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2494 absl::nullopt);
2495}
2496
2497TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotRemoveDatagram) {
2498 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2499 if (IsOfferer()) {
2500 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2501 fake_params);
2502 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2503 fake_params);
2504 }
2505
2506 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2507 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2508
2509 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2510 fake_params);
2511 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2512 fake_params);
2513
2514 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2515 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2516
2517 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2518 fake_params);
2519 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2520 fake_params);
2521
2522 // Attempting to remove a datagram transport on a re-offer does not cause an
2523 // error, but also does not remove the datagram transport.
2524 auto reoffer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2525 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2526
2527 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2528 fake_params);
2529 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2530 fake_params);
2531}
2532
2533TEST_P(JsepTransportControllerDatagramTest,
2534 RenegotiationKeepsDatagramTransport) {
2535 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2536 if (IsOfferer()) {
2537 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2538 fake_params);
2539 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2540 fake_params);
2541 }
2542
2543 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2544 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2545
2546 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2547 fake_params);
2548 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2549 fake_params);
2550
2551 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2552 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2553
2554 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2555 fake_params);
2556 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2557 fake_params);
2558
2559 // Attempting to remove a datagram transport on a re-offer does not cause an
2560 // error, but also does not remove the datagram transport.
2561 auto reoffer = CreateSessionDescriptionForDatagramTransport(fake_params);
2562 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2563
2564 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2565 fake_params);
2566 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2567 fake_params);
2568
2569 auto reanswer = CreateSessionDescriptionForDatagramTransport(fake_params);
2570 EXPECT_TRUE(SetDescription(SdpType::kAnswer, reanswer.get()).ok());
2571
2572 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2573 fake_params);
2574 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2575 fake_params);
2576}
2577
2578INSTANTIATE_TEST_SUITE_P(
2579 JsepTransportControllerDatagramTests,
2580 JsepTransportControllerDatagramTest,
2581 testing::Values(true, false),
2582 // The parameter value is the local perspective (offerer or answerer).
2583 [](const testing::TestParamInfo<bool>& info) {
2584 return info.param ? "Offerer" : "Answerer";
2585 });
2586
Zhi Huange818b6e2018-02-22 23:26:272587} // namespace webrtc