blob: ef938980922445e6e047e33200f8e9c0d1b3a459 [file] [log] [blame]
Zhi Huange818b6e2018-02-22 15:26:27 -08001/*
2 * Copyright 2018 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/jsep_transport_controller.h"
12
Zhi Huange818b6e2018-02-22 15:26:27 -080013#include <map>
14#include <memory>
15
Anton Sukhanov7940da02018-10-10 10:34:49 -070016#include "api/test/fake_media_transport.h"
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -080017#include "api/test/loopback_media_transport.h"
Niels Möller65f17ca2019-09-12 13:59:36 +020018#include "api/transport/media/media_transport_interface.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "p2p/base/fake_dtls_transport.h"
20#include "p2p/base/fake_ice_transport.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080021#include "p2p/base/no_op_dtls_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "p2p/base/transport_factory_interface.h"
23#include "p2p/base/transport_info.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080025#include "rtc_base/thread.h"
26#include "test/gtest.h"
27
Zhi Huange818b6e2018-02-22 15:26:27 -080028using cricket::Candidate;
29using cricket::Candidates;
Jonas Olssona4d87372019-07-05 19:08:33 +020030using cricket::FakeDtlsTransport;
Zhi Huange818b6e2018-02-22 15:26:27 -080031using webrtc::SdpType;
32
33static const int kTimeout = 100;
34static const char kIceUfrag1[] = "u0001";
35static const char kIcePwd1[] = "TESTICEPWD00000000000001";
36static const char kIceUfrag2[] = "u0002";
37static const char kIcePwd2[] = "TESTICEPWD00000000000002";
38static const char kIceUfrag3[] = "u0003";
39static const char kIcePwd3[] = "TESTICEPWD00000000000003";
40static const char kAudioMid1[] = "audio1";
41static const char kAudioMid2[] = "audio2";
42static const char kVideoMid1[] = "video1";
43static const char kVideoMid2[] = "video2";
44static const char kDataMid1[] = "data1";
45
46namespace webrtc {
47
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070048namespace {
49
50// Media transport factory requires crypto settings to be present in order to
51// create media transport.
52void AddCryptoSettings(cricket::SessionDescription* description) {
53 for (auto& content : description->contents()) {
54 content.media_description()->AddCrypto(cricket::CryptoParams(
55 /*t=*/0, std::string(rtc::CS_AES_CM_128_HMAC_SHA1_80),
56 "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2", ""));
57 }
58}
59
60} // namespace
61
Zhi Huange818b6e2018-02-22 15:26:27 -080062class FakeTransportFactory : public cricket::TransportFactoryInterface {
63 public:
64 std::unique_ptr<cricket::IceTransportInternal> CreateIceTransport(
65 const std::string& transport_name,
66 int component) override {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020067 return std::make_unique<cricket::FakeIceTransport>(transport_name,
68 component);
Zhi Huange818b6e2018-02-22 15:26:27 -080069 }
70
71 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070072 cricket::IceTransportInternal* ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070073 const webrtc::CryptoOptions& crypto_options) override {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020074 return std::make_unique<FakeDtlsTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070075 static_cast<cricket::FakeIceTransport*>(ice));
Zhi Huange818b6e2018-02-22 15:26:27 -080076 }
77};
78
Zhi Huang365381f2018-04-13 16:44:34 -070079class JsepTransportControllerTest : public JsepTransportController::Observer,
Mirko Bonadei6a489f22019-04-09 15:11:12 +020080 public ::testing::Test,
Zhi Huange818b6e2018-02-22 15:26:27 -080081 public sigslot::has_slots<> {
82 public:
83 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020084 fake_transport_factory_ = std::make_unique<FakeTransportFactory>();
Zhi Huange818b6e2018-02-22 15:26:27 -080085 }
86
87 void CreateJsepTransportController(
88 JsepTransportController::Config config,
89 rtc::Thread* signaling_thread = rtc::Thread::Current(),
90 rtc::Thread* network_thread = rtc::Thread::Current(),
91 cricket::PortAllocator* port_allocator = nullptr) {
Zhi Huang365381f2018-04-13 16:44:34 -070092 config.transport_observer = this;
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +020093 config.rtcp_handler = [](const rtc::CopyOnWriteBuffer& packet,
94 int64_t packet_time_us) { RTC_NOTREACHED(); };
Zhi Huange818b6e2018-02-22 15:26:27 -080095 // The tests only works with |fake_transport_factory|;
96 config.external_transport_factory = fake_transport_factory_.get();
Zach Steine20867f2018-08-02 13:20:15 -070097 // TODO(zstein): Provide an AsyncResolverFactory once it is required.
Mirko Bonadei317a1f02019-09-17 17:06:18 +020098 transport_controller_ = std::make_unique<JsepTransportController>(
Zach Steine20867f2018-08-02 13:20:15 -070099 signaling_thread, network_thread, port_allocator, nullptr, config);
Zhi Huange818b6e2018-02-22 15:26:27 -0800100 ConnectTransportControllerSignals();
101 }
102
103 void ConnectTransportControllerSignals() {
104 transport_controller_->SignalIceConnectionState.connect(
105 this, &JsepTransportControllerTest::OnConnectionState);
Alex Loiko9289eda2018-11-23 16:18:59 +0000106 transport_controller_->SignalStandardizedIceConnectionState.connect(
107 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200108 transport_controller_->SignalConnectionState.connect(
109 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800110 transport_controller_->SignalIceGatheringState.connect(
111 this, &JsepTransportControllerTest::OnGatheringState);
112 transport_controller_->SignalIceCandidatesGathered.connect(
113 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800114 }
115
116 std::unique_ptr<cricket::SessionDescription>
117 CreateSessionDescriptionWithoutBundle() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200118 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800119 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
120 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
121 nullptr);
122 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
123 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
124 nullptr);
125 return description;
126 }
127
128 std::unique_ptr<cricket::SessionDescription>
129 CreateSessionDescriptionWithBundleGroup() {
130 auto description = CreateSessionDescriptionWithoutBundle();
131 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
132 bundle_group.AddContentName(kAudioMid1);
133 bundle_group.AddContentName(kVideoMid1);
134 description->AddGroup(bundle_group);
135
136 return description;
137 }
138
139 void AddAudioSection(cricket::SessionDescription* description,
140 const std::string& mid,
141 const std::string& ufrag,
142 const std::string& pwd,
143 cricket::IceMode ice_mode,
144 cricket::ConnectionRole conn_role,
145 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
146 std::unique_ptr<cricket::AudioContentDescription> audio(
147 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700148 // Set RTCP-mux to be true because the default policy is "mux required".
149 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800150 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200151 /*rejected=*/false, std::move(audio));
Zhi Huange818b6e2018-02-22 15:26:27 -0800152 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
153 }
154
155 void AddVideoSection(cricket::SessionDescription* description,
156 const std::string& mid,
157 const std::string& ufrag,
158 const std::string& pwd,
159 cricket::IceMode ice_mode,
160 cricket::ConnectionRole conn_role,
161 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
162 std::unique_ptr<cricket::VideoContentDescription> video(
163 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700164 // Set RTCP-mux to be true because the default policy is "mux required".
165 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800166 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200167 /*rejected=*/false, std::move(video));
Zhi Huange818b6e2018-02-22 15:26:27 -0800168 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
169 }
170
171 void AddDataSection(cricket::SessionDescription* description,
172 const std::string& mid,
173 cricket::MediaProtocolType protocol_type,
174 const std::string& ufrag,
175 const std::string& pwd,
176 cricket::IceMode ice_mode,
177 cricket::ConnectionRole conn_role,
178 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200179 RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp);
180 std::unique_ptr<cricket::SctpDataContentDescription> data(
181 new cricket::SctpDataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700182 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800183 description->AddContent(mid, protocol_type,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200184 /*rejected=*/false, std::move(data));
Zhi Huange818b6e2018-02-22 15:26:27 -0800185 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
186 }
187
188 void AddTransportInfo(cricket::SessionDescription* description,
189 const std::string& mid,
190 const std::string& ufrag,
191 const std::string& pwd,
192 cricket::IceMode ice_mode,
193 cricket::ConnectionRole conn_role,
194 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
195 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
196 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700197 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800198 }
199
200 cricket::TransportDescription transport_desc(std::vector<std::string>(),
201 ufrag, pwd, ice_mode,
202 conn_role, fingerprint.get());
203 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
204 }
205
206 cricket::IceConfig CreateIceConfig(
207 int receiving_timeout,
208 cricket::ContinualGatheringPolicy continual_gathering_policy) {
209 cricket::IceConfig config;
210 config.receiving_timeout = receiving_timeout;
211 config.continual_gathering_policy = continual_gathering_policy;
212 return config;
213 }
214
215 Candidate CreateCandidate(const std::string& transport_name, int component) {
216 Candidate c;
217 c.set_transport_name(transport_name);
218 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
219 c.set_component(component);
220 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
221 c.set_priority(1);
222 return c;
223 }
224
225 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
226 if (!network_thread_->IsCurrent()) {
227 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
228 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
229 });
230 return;
231 }
232
233 auto description = CreateSessionDescriptionWithBundleGroup();
234 EXPECT_TRUE(transport_controller_
235 ->SetLocalDescription(SdpType::kOffer, description.get())
236 .ok());
237
238 transport_controller_->MaybeStartGathering();
239 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
240 transport_controller_->GetDtlsTransport(kAudioMid1));
241 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
242 transport_controller_->GetDtlsTransport(kVideoMid1));
243 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
244 fake_audio_dtls->fake_ice_transport(),
245 CreateCandidate(kAudioMid1, /*component=*/1));
246 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
247 fake_video_dtls->fake_ice_transport(),
248 CreateCandidate(kVideoMid1, /*component=*/1));
249 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
250 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
251 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
252 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
253 fake_audio_dtls->SetReceiving(true);
254 fake_video_dtls->SetReceiving(true);
255 fake_audio_dtls->SetWritable(true);
256 fake_video_dtls->SetWritable(true);
257 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
258 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
259 }
260
261 protected:
Alex Loiko9289eda2018-11-23 16:18:59 +0000262 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800263 if (!signaling_thread_->IsCurrent()) {
264 signaled_on_non_signaling_thread_ = true;
265 }
266 connection_state_ = state;
267 ++connection_state_signal_count_;
268 }
269
Alex Loiko9289eda2018-11-23 16:18:59 +0000270 void OnStandardizedIceConnectionState(
271 PeerConnectionInterface::IceConnectionState state) {
272 if (!signaling_thread_->IsCurrent()) {
273 signaled_on_non_signaling_thread_ = true;
274 }
275 ice_connection_state_ = state;
276 ++ice_connection_state_signal_count_;
277 }
278
Jonas Olsson635474e2018-10-18 15:58:17 +0200279 void OnCombinedConnectionState(
280 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100281 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
282 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 15:58:17 +0200283 if (!signaling_thread_->IsCurrent()) {
284 signaled_on_non_signaling_thread_ = true;
285 }
286 combined_connection_state_ = state;
287 ++combined_connection_state_signal_count_;
288 }
289
Zhi Huange818b6e2018-02-22 15:26:27 -0800290 void OnGatheringState(cricket::IceGatheringState state) {
291 if (!signaling_thread_->IsCurrent()) {
292 signaled_on_non_signaling_thread_ = true;
293 }
294 gathering_state_ = state;
295 ++gathering_state_signal_count_;
296 }
297
298 void OnCandidatesGathered(const std::string& transport_name,
299 const Candidates& candidates) {
300 if (!signaling_thread_->IsCurrent()) {
301 signaled_on_non_signaling_thread_ = true;
302 }
303 candidates_[transport_name].insert(candidates_[transport_name].end(),
304 candidates.begin(), candidates.end());
305 ++candidates_signal_count_;
306 }
307
Zhi Huang365381f2018-04-13 16:44:34 -0700308 // JsepTransportController::Observer overrides.
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700309 bool OnTransportChanged(
310 const std::string& mid,
311 RtpTransportInternal* rtp_transport,
312 rtc::scoped_refptr<DtlsTransport> dtls_transport,
313 MediaTransportInterface* media_transport,
Qingsi Wang437077d2019-09-10 17:52:26 +0000314 DataChannelTransportInterface* data_channel_transport,
315 JsepTransportController::NegotiationState negotiation_state) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700316 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100317 if (dtls_transport) {
318 changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
319 } else {
320 changed_dtls_transport_by_mid_[mid] = nullptr;
321 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800322 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700323 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800324 }
325
326 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000327 cricket::IceConnectionState connection_state_ =
328 cricket::kIceConnectionConnecting;
329 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200330 PeerConnectionInterface::kIceConnectionNew;
331 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
332 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800333 bool receiving_ = false;
334 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
335 // transport_name => candidates
336 std::map<std::string, Candidates> candidates_;
337 // Counts of each signal emitted.
338 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000339 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200340 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800341 int receiving_signal_count_ = 0;
342 int gathering_state_signal_count_ = 0;
343 int candidates_signal_count_ = 0;
344
345 // |network_thread_| should be destroyed after |transport_controller_|
346 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800347 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
348 rtc::Thread* const signaling_thread_ = nullptr;
349 bool signaled_on_non_signaling_thread_ = false;
350 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
351 // signaled correctly.
352 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
353 std::map<std::string, cricket::DtlsTransportInternal*>
354 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800355 std::map<std::string, MediaTransportInterface*>
356 changed_media_transport_by_mid_;
357
358 // Transport controller needs to be destroyed first, because it may issue
359 // callbacks that modify the changed_*_by_mid in the destructor.
360 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800361};
362
363TEST_F(JsepTransportControllerTest, GetRtpTransport) {
364 CreateJsepTransportController(JsepTransportController::Config());
365 auto description = CreateSessionDescriptionWithoutBundle();
366 EXPECT_TRUE(transport_controller_
367 ->SetLocalDescription(SdpType::kOffer, description.get())
368 .ok());
369 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
370 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
371 EXPECT_NE(nullptr, audio_rtp_transport);
372 EXPECT_NE(nullptr, video_rtp_transport);
373 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
374 // Return nullptr for non-existing ones.
375 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
376}
377
378TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
379 JsepTransportController::Config config;
380 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
381 CreateJsepTransportController(config);
382 auto description = CreateSessionDescriptionWithoutBundle();
383 EXPECT_TRUE(transport_controller_
384 ->SetLocalDescription(SdpType::kOffer, description.get())
385 .ok());
386 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
387 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100388 EXPECT_NE(nullptr,
389 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800390 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
391 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100392 EXPECT_NE(nullptr,
393 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
394 // Lookup for all MIDs should return different transports (no bundle)
395 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
396 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800397 // Return nullptr for non-existing ones.
398 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
399 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100400 EXPECT_EQ(nullptr,
401 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100402 // Take a pointer to a transport, shut down the transport controller,
403 // and verify that the resulting container is empty.
404 auto dtls_transport =
405 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
406 webrtc::DtlsTransport* my_transport =
407 static_cast<DtlsTransport*>(dtls_transport.get());
408 EXPECT_NE(nullptr, my_transport->internal());
409 transport_controller_.reset();
410 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800411}
412
Zhi Huange830e682018-03-30 10:48:35 -0700413TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
414 JsepTransportController::Config config;
415 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
416 CreateJsepTransportController(config);
417 auto description = CreateSessionDescriptionWithoutBundle();
418 EXPECT_TRUE(transport_controller_
419 ->SetLocalDescription(SdpType::kOffer, description.get())
420 .ok());
421 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
422 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
423 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
424 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700425 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
426}
427
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800428TEST_F(JsepTransportControllerTest,
429 DtlsIsStillCreatedIfMediaTransportIsOnlyUsedForDataChannels) {
430 FakeMediaTransportFactory fake_media_transport_factory;
431 JsepTransportController::Config config;
432
433 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800434 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800435 config.media_transport_factory = &fake_media_transport_factory;
436 config.use_media_transport_for_data_channels = true;
437 CreateJsepTransportController(config);
438 auto description = CreateSessionDescriptionWithBundleGroup();
439 AddCryptoSettings(description.get());
440
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800441 EXPECT_NE(absl::nullopt,
442 transport_controller_->GenerateOrGetLastMediaTransportOffer());
443
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800444 EXPECT_TRUE(transport_controller_
445 ->SetLocalDescription(SdpType::kOffer, description.get())
446 .ok());
447
448 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700449 transport_controller_->GetDataChannelTransport(kAudioMid1));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800450
451 ASSERT_NE(nullptr, media_transport);
452
453 // After SetLocalDescription, media transport should be created as caller.
454 EXPECT_TRUE(media_transport->is_caller());
455 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
456
457 // Return nullptr for non-existing mids.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700458 EXPECT_EQ(nullptr,
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700459 transport_controller_->GetDataChannelTransport(kVideoMid2));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800460
461 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
462 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
463 << "Media transport for media was not enabled, and so DTLS transport "
464 "should be created.";
465}
466
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700467TEST_F(JsepTransportControllerTest,
468 DtlsIsStillCreatedIfDatagramTransportIsOnlyUsedForDataChannels) {
469 FakeMediaTransportFactory fake_media_transport_factory("transport_params");
470 JsepTransportController::Config config;
471
472 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
473 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
474 config.media_transport_factory = &fake_media_transport_factory;
475 config.use_datagram_transport_for_data_channels = true;
476 CreateJsepTransportController(config);
477
478 auto description = CreateSessionDescriptionWithBundleGroup();
479 AddCryptoSettings(description.get());
480 absl::optional<cricket::OpaqueTransportParameters> params =
481 transport_controller_->GetTransportParameters(kAudioMid1);
482 for (auto& info : description->transport_infos()) {
483 info.description.opaque_parameters = params;
484 }
485
486 EXPECT_TRUE(transport_controller_
487 ->SetLocalDescription(SdpType::kOffer, description.get())
488 .ok());
489 EXPECT_TRUE(transport_controller_
490 ->SetRemoteDescription(SdpType::kAnswer, description.get())
491 .ok());
492
493 FakeDatagramTransport* datagram_transport =
494 static_cast<FakeDatagramTransport*>(
495 transport_controller_->GetDataChannelTransport(kAudioMid1));
496
497 ASSERT_NE(nullptr, datagram_transport);
498
499 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
500 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
501 << "Datagram transport for media was not enabled, and so DTLS transport "
502 "should be created.";
503
504 // Datagram transport is not used for media, so no max packet size is
505 // specified.
506 EXPECT_EQ(transport_controller_->GetMediaTransportConfig(kAudioMid1)
507 .rtp_max_packet_size,
508 absl::nullopt);
509
510 // Since datagram transport is not used for RTP, setting it to writable should
511 // not make the RTP transport writable.
512 datagram_transport->set_state(MediaTransportState::kWritable);
513 EXPECT_FALSE(transport_controller_->GetRtpTransport(kAudioMid1)
514 ->IsWritable(/*rtcp=*/false));
515}
516
Anton Sukhanov7940da02018-10-10 10:34:49 -0700517TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
518 FakeMediaTransportFactory fake_media_transport_factory;
519 JsepTransportController::Config config;
520
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800521 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800522 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700523 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800524 config.use_media_transport_for_data_channels = true;
525 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700526 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800527 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700528 AddCryptoSettings(description.get());
529
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800530 EXPECT_NE(absl::nullopt,
531 transport_controller_->GenerateOrGetLastMediaTransportOffer());
532
Anton Sukhanov7940da02018-10-10 10:34:49 -0700533 EXPECT_TRUE(transport_controller_
534 ->SetLocalDescription(SdpType::kOffer, description.get())
535 .ok());
536
537 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
538 transport_controller_->GetMediaTransport(kAudioMid1));
539
540 ASSERT_NE(nullptr, media_transport);
541
542 // After SetLocalDescription, media transport should be created as caller.
543 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800544 // We set the pre-shared key on the caller.
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700545 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800546 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700547
548 // Return nullptr for non-existing mids.
549 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800550
551 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
552 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
553 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700554}
555
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800556TEST_F(JsepTransportControllerTest,
557 GetMediaTransportOfferInTheConfigOnSubsequentCalls) {
558 FakeMediaTransportFactory fake_media_transport_factory;
559 WrapperMediaTransportFactory wrapping_factory(&fake_media_transport_factory);
560 JsepTransportController::Config config;
561
562 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
563 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
564 config.media_transport_factory = &wrapping_factory;
565 config.use_media_transport_for_data_channels = true;
566 config.use_media_transport_for_media = true;
567 CreateJsepTransportController(config);
568 auto description = CreateSessionDescriptionWithBundleGroup();
569 AddCryptoSettings(description.get());
570
571 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
572 transport_controller_->GenerateOrGetLastMediaTransportOffer();
573 ASSERT_NE(absl::nullopt, settings);
574
575 EXPECT_TRUE(transport_controller_
576 ->SetLocalDescription(SdpType::kOffer, description.get())
577 .ok());
578
579 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
580 transport_controller_->GetMediaTransport(kAudioMid1));
581
582 ASSERT_NE(nullptr, media_transport);
583
584 absl::optional<cricket::SessionDescription::MediaTransportSetting>
585 new_settings =
586 transport_controller_->GenerateOrGetLastMediaTransportOffer();
587 ASSERT_NE(absl::nullopt, new_settings);
588 EXPECT_EQ(settings->transport_name, new_settings->transport_name);
589 EXPECT_EQ(settings->transport_setting, new_settings->transport_setting);
590 EXPECT_EQ(1, wrapping_factory.created_transport_count());
591}
592
Anton Sukhanov7940da02018-10-10 10:34:49 -0700593TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
594 FakeMediaTransportFactory fake_media_transport_factory;
595 JsepTransportController::Config config;
596
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800597 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700598 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800599 config.use_media_transport_for_data_channels = true;
600 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700601 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800602 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700603 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800604 description->AddMediaTransportSetting("fake", "fake-remote-settings");
Anton Sukhanov7940da02018-10-10 10:34:49 -0700605 EXPECT_TRUE(transport_controller_
606 ->SetRemoteDescription(SdpType::kOffer, description.get())
607 .ok());
608
609 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
610 transport_controller_->GetMediaTransport(kAudioMid1));
611
612 ASSERT_NE(nullptr, media_transport);
613
614 // After SetRemoteDescription, media transport should be created as callee.
615 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800616 // We do not set pre-shared key on the callee, it comes in media transport
617 // settings.
618 EXPECT_EQ(absl::nullopt, media_transport->settings().pre_shared_key);
619 EXPECT_TRUE(media_transport->is_connected());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700620
621 // Return nullptr for non-existing mids.
622 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800623
624 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
625 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
626 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700627}
628
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800629TEST_F(JsepTransportControllerTest, GetMediaTransportInCalleePassesSdp) {
630 FakeMediaTransportFactory fake_media_transport_factory;
631 JsepTransportController::Config config;
632
633 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
634 config.media_transport_factory = &fake_media_transport_factory;
635 config.use_media_transport_for_data_channels = true;
636 config.use_media_transport_for_media = true;
637 CreateJsepTransportController(config);
638 auto description = CreateSessionDescriptionWithBundleGroup();
639 AddCryptoSettings(description.get());
640 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
641 EXPECT_TRUE(transport_controller_
642 ->SetRemoteDescription(SdpType::kOffer, description.get())
643 .ok());
644
645 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
646 transport_controller_->GetMediaTransport(kAudioMid1));
647
648 ASSERT_NE(nullptr, media_transport);
649
650 EXPECT_EQ("this-is-a-test-setting",
651 media_transport->settings().remote_transport_parameters);
652}
653
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800654// Caller generates the offer if media transport returns empty offer (no
655// parameters).
656TEST_F(JsepTransportControllerTest, MediaTransportGeneratesSessionDescription) {
657 FakeMediaTransportFactory fake_media_transport_factory(
658 /*transport_offer=*/"");
659 JsepTransportController::Config config;
660
661 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
662 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
663 config.media_transport_factory = &fake_media_transport_factory;
664 config.use_media_transport_for_data_channels = true;
665 config.use_media_transport_for_media = true;
666 CreateJsepTransportController(config);
667 auto description = CreateSessionDescriptionWithBundleGroup();
668 AddCryptoSettings(description.get());
669 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
670 transport_controller_->GenerateOrGetLastMediaTransportOffer();
671
672 ASSERT_TRUE(settings.has_value());
673 EXPECT_EQ("fake", settings->transport_name);
674 // Fake media transport returns empty settings (but not nullopt settings!)
675 EXPECT_EQ("", settings->transport_setting);
676}
677
678// Caller generates the offer if media transport returns offer with parameters.
679TEST_F(JsepTransportControllerTest,
680 MediaTransportGeneratesSessionDescriptionWithOfferParams) {
681 FakeMediaTransportFactory fake_media_transport_factory(
682 /*transport_offer=*/"offer-params");
683 JsepTransportController::Config config;
684
685 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
686 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
687 config.media_transport_factory = &fake_media_transport_factory;
688 config.use_media_transport_for_data_channels = true;
689 config.use_media_transport_for_media = true;
690 CreateJsepTransportController(config);
691 auto description = CreateSessionDescriptionWithBundleGroup();
692 AddCryptoSettings(description.get());
693 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
694 transport_controller_->GenerateOrGetLastMediaTransportOffer();
695
696 ASSERT_TRUE(settings.has_value());
697 EXPECT_EQ("fake", settings->transport_name);
698 EXPECT_EQ("offer-params", settings->transport_setting);
699}
700
701// Caller skips the offer if media transport requests it.
702TEST_F(JsepTransportControllerTest,
703 MediaTransportGeneratesSkipsSessionDescription) {
704 FakeMediaTransportFactory fake_media_transport_factory(
705 /*transport_offer=*/absl::nullopt);
706 JsepTransportController::Config config;
707
708 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
709 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
710 config.media_transport_factory = &fake_media_transport_factory;
711 config.use_media_transport_for_data_channels = true;
712 config.use_media_transport_for_media = true;
713 CreateJsepTransportController(config);
714 auto description = CreateSessionDescriptionWithBundleGroup();
715 AddCryptoSettings(description.get());
716 absl::optional<cricket::SessionDescription::MediaTransportSetting> settings =
717 transport_controller_->GenerateOrGetLastMediaTransportOffer();
718
719 // Fake media transport returns nullopt settings
720 ASSERT_EQ(absl::nullopt, settings);
721}
722
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800723// Caller ignores its own outgoing parameters.
724TEST_F(JsepTransportControllerTest,
725 GetMediaTransportInCallerIgnoresXmtSection) {
726 FakeMediaTransportFactory fake_media_transport_factory;
727 JsepTransportController::Config config;
728
729 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800730 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800731 config.media_transport_factory = &fake_media_transport_factory;
732 config.use_media_transport_for_data_channels = true;
733 config.use_media_transport_for_media = true;
734 CreateJsepTransportController(config);
735 auto description = CreateSessionDescriptionWithBundleGroup();
736 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800737 EXPECT_NE(absl::nullopt,
738 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800739 EXPECT_TRUE(transport_controller_
740 ->SetLocalDescription(SdpType::kOffer, description.get())
741 .ok());
742
743 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
744 transport_controller_->GetMediaTransport(kAudioMid1));
745
746 ASSERT_NE(nullptr, media_transport);
747
748 // Remote parameters are nullopt, because we are the offerer (we don't)
749 // have the remote transport parameters, only ours.
750 EXPECT_EQ(absl::nullopt,
751 media_transport->settings().remote_transport_parameters);
752}
753
754TEST_F(JsepTransportControllerTest,
755 GetMediaTransportInCalleeIgnoresDifferentTransport) {
756 FakeMediaTransportFactory fake_media_transport_factory;
757 JsepTransportController::Config config;
758
759 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800760 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800761 config.media_transport_factory = &fake_media_transport_factory;
762 config.use_media_transport_for_data_channels = true;
763 config.use_media_transport_for_media = true;
764 CreateJsepTransportController(config);
765 auto description = CreateSessionDescriptionWithBundleGroup();
766 AddCryptoSettings(description.get());
767 description->AddMediaTransportSetting("not-a-fake-transport",
768 "this-is-a-test-setting");
769 EXPECT_TRUE(transport_controller_
770 ->SetRemoteDescription(SdpType::kOffer, description.get())
771 .ok());
772
773 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
774 transport_controller_->GetMediaTransport(kAudioMid1));
775
776 ASSERT_NE(nullptr, media_transport);
777
778 EXPECT_EQ(absl::nullopt,
779 media_transport->settings().remote_transport_parameters);
780}
781
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700782TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
783 FakeMediaTransportFactory fake_media_transport_factory;
784 JsepTransportController::Config config;
785
786 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800787 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700788 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800789 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700790 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800791 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700792 EXPECT_TRUE(transport_controller_
793 ->SetRemoteDescription(SdpType::kOffer, description.get())
794 .ok());
795
796 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
797
798 // Even if we set local description with crypto now (after the remote offer
799 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800800 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700801 AddCryptoSettings(description2.get());
802 EXPECT_TRUE(transport_controller_
803 ->SetLocalDescription(SdpType::kAnswer, description2.get())
804 .ok());
805
806 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800807 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
808 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
809 << "Because media transport is NOT used (fallback to RTP), expected "
810 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700811}
812
813TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800814 AfterSettingAnswerTheSameMediaTransportIsReturnedCallee) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700815 FakeMediaTransportFactory fake_media_transport_factory;
816 JsepTransportController::Config config;
817
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800818 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800819 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700820 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800821 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700822 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800823 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700824 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800825 description->AddMediaTransportSetting("fake", "fake-settings");
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700826 EXPECT_TRUE(transport_controller_
827 ->SetRemoteDescription(SdpType::kOffer, description.get())
828 .ok());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700829 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
830 transport_controller_->GetMediaTransport(kAudioMid1));
831 EXPECT_NE(nullptr, media_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800832 EXPECT_FALSE(media_transport->pre_shared_key().has_value())
833 << "On the callee, preshared key is passed through the media-transport "
834 "settings (x-mt)";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700835
836 // Even if we set local description with crypto now (after the remote offer
837 // was set), media transport won't be provided.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800838 auto description2 = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700839 AddCryptoSettings(description2.get());
840
841 RTCError result = transport_controller_->SetLocalDescription(
842 SdpType::kAnswer, description2.get());
843 EXPECT_TRUE(result.ok()) << result.message();
844
845 // Media transport did not change.
846 EXPECT_EQ(media_transport,
847 transport_controller_->GetMediaTransport(kAudioMid1));
848}
849
Zhi Huange818b6e2018-02-22 15:26:27 -0800850TEST_F(JsepTransportControllerTest, SetIceConfig) {
851 CreateJsepTransportController(JsepTransportController::Config());
852 auto description = CreateSessionDescriptionWithoutBundle();
853 EXPECT_TRUE(transport_controller_
854 ->SetLocalDescription(SdpType::kOffer, description.get())
855 .ok());
856
857 transport_controller_->SetIceConfig(
858 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
859 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
860 transport_controller_->GetDtlsTransport(kAudioMid1));
861 ASSERT_NE(nullptr, fake_audio_dtls);
862 EXPECT_EQ(kTimeout,
863 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
864 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
865
866 // Test that value stored in controller is applied to new transports.
867 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
868 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
869 nullptr);
870
871 EXPECT_TRUE(transport_controller_
872 ->SetLocalDescription(SdpType::kOffer, description.get())
873 .ok());
874 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
875 transport_controller_->GetDtlsTransport(kAudioMid2));
876 ASSERT_NE(nullptr, fake_audio_dtls);
877 EXPECT_EQ(kTimeout,
878 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
879 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
880}
881
882// Tests the getter and setter of the ICE restart flag.
883TEST_F(JsepTransportControllerTest, NeedIceRestart) {
884 CreateJsepTransportController(JsepTransportController::Config());
885 auto description = CreateSessionDescriptionWithoutBundle();
886 EXPECT_TRUE(transport_controller_
887 ->SetLocalDescription(SdpType::kOffer, description.get())
888 .ok());
889 EXPECT_TRUE(transport_controller_
890 ->SetRemoteDescription(SdpType::kAnswer, description.get())
891 .ok());
892
893 // Initially NeedsIceRestart should return false.
894 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
895 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
896 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
897 // true.
898 transport_controller_->SetNeedsIceRestartFlag();
899 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
900 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
901 // For a nonexistent transport, false should be returned.
902 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
903
904 // Reset the ice_ufrag/ice_pwd for audio.
905 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
906 audio_transport_info->description.ice_ufrag = kIceUfrag2;
907 audio_transport_info->description.ice_pwd = kIcePwd2;
908 EXPECT_TRUE(transport_controller_
909 ->SetLocalDescription(SdpType::kOffer, description.get())
910 .ok());
911 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
912 // return false for audio and true for video.
913 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
914 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
915}
916
917TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
918 CreateJsepTransportController(JsepTransportController::Config());
919 auto description = CreateSessionDescriptionWithBundleGroup();
920 EXPECT_TRUE(transport_controller_
921 ->SetLocalDescription(SdpType::kOffer, description.get())
922 .ok());
923 // After setting the local description, we should be able to start gathering
924 // candidates.
925 transport_controller_->MaybeStartGathering();
926 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
927 EXPECT_EQ(1, gathering_state_signal_count_);
928}
929
930TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
931 CreateJsepTransportController(JsepTransportController::Config());
932 auto description = CreateSessionDescriptionWithoutBundle();
933 transport_controller_->SetLocalDescription(SdpType::kOffer,
934 description.get());
935 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
936 description.get());
937 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
938 transport_controller_->GetDtlsTransport(kAudioMid1));
939 ASSERT_NE(nullptr, fake_audio_dtls);
940 Candidates candidates;
941 candidates.push_back(
942 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
943 EXPECT_TRUE(
944 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
945 EXPECT_EQ(1U,
946 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
947
948 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
949 EXPECT_EQ(0U,
950 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
951}
952
953TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
954 CreateJsepTransportController(JsepTransportController::Config());
955
956 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
957 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
958 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
959 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
960
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200961 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800962 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
963 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
964 certificate1);
965
966 // Apply the local certificate.
967 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
968 // Apply the local description.
969 EXPECT_TRUE(transport_controller_
970 ->SetLocalDescription(SdpType::kOffer, description.get())
971 .ok());
972 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
973 EXPECT_TRUE(returned_certificate);
974 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
975 returned_certificate->identity()->certificate().ToPEMString());
976
977 // Should fail if called for a nonexistant transport.
978 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
979
980 // Shouldn't be able to change the identity once set.
981 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
982 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
983 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
984 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
985}
986
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800987TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800988 CreateJsepTransportController(JsepTransportController::Config());
989 auto description = CreateSessionDescriptionWithBundleGroup();
990 EXPECT_TRUE(transport_controller_
991 ->SetLocalDescription(SdpType::kOffer, description.get())
992 .ok());
993 rtc::FakeSSLCertificate fake_certificate("fake_data");
994
995 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
996 transport_controller_->GetDtlsTransport(kAudioMid1));
997 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800998 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
999 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
1000 ASSERT_TRUE(returned_cert_chain);
1001 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -08001002 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001003 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -08001004
1005 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001006 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -08001007}
1008
1009TEST_F(JsepTransportControllerTest, GetDtlsRole) {
1010 CreateJsepTransportController(JsepTransportController::Config());
1011 auto offer_certificate =
1012 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1013 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
1014 auto answer_certificate =
1015 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
1016 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
1017 transport_controller_->SetLocalCertificate(offer_certificate);
1018
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001019 auto offer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001020 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1021 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1022 offer_certificate);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001023 auto answer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001024 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1025 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1026 answer_certificate);
1027
1028 EXPECT_TRUE(transport_controller_
1029 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
1030 .ok());
1031
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001032 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -08001033 transport_controller_->GetDtlsRole(kAudioMid1);
1034 // The DTLS role is not decided yet.
1035 EXPECT_FALSE(role);
1036 EXPECT_TRUE(transport_controller_
1037 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
1038 .ok());
1039 role = transport_controller_->GetDtlsRole(kAudioMid1);
1040
1041 ASSERT_TRUE(role);
1042 EXPECT_EQ(rtc::SSL_CLIENT, *role);
1043}
1044
1045TEST_F(JsepTransportControllerTest, GetStats) {
1046 CreateJsepTransportController(JsepTransportController::Config());
1047 auto description = CreateSessionDescriptionWithBundleGroup();
1048 EXPECT_TRUE(transport_controller_
1049 ->SetLocalDescription(SdpType::kOffer, description.get())
1050 .ok());
1051
1052 cricket::TransportStats stats;
1053 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
1054 EXPECT_EQ(kAudioMid1, stats.transport_name);
1055 EXPECT_EQ(1u, stats.channel_stats.size());
1056 // Return false for non-existing transport.
1057 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
1058}
1059
1060TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
1061 CreateJsepTransportController(JsepTransportController::Config());
1062 auto description = CreateSessionDescriptionWithoutBundle();
1063 EXPECT_TRUE(transport_controller_
1064 ->SetLocalDescription(SdpType::kOffer, description.get())
1065 .ok());
1066
1067 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
1068 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1069 fake_ice->SetCandidatesGatheringComplete();
1070 fake_ice->SetConnectionCount(1);
1071 // The connection stats will be failed if there is no active connection.
1072 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +00001073 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001074 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001075 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1076 ice_connection_state_, kTimeout);
1077 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001078 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1079 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +02001080 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001081}
1082
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001083TEST_F(JsepTransportControllerTest,
1084 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001085 CreateJsepTransportController(JsepTransportController::Config());
1086 auto description = CreateSessionDescriptionWithoutBundle();
1087 EXPECT_TRUE(transport_controller_
1088 ->SetLocalDescription(SdpType::kOffer, description.get())
1089 .ok());
1090
1091 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1092 transport_controller_->GetDtlsTransport(kAudioMid1));
1093 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1094 transport_controller_->GetDtlsTransport(kVideoMid1));
1095
1096 // First, have one transport connect, and another fail, to ensure that
1097 // the first transport connecting didn't trigger a "connected" state signal.
1098 // We should only get a signal when all are connected.
1099 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
1100 fake_audio_dtls->SetWritable(true);
1101 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1102 // Decrease the number of the connection to trigger the signal.
1103 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
1104 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
1105 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1106
Alex Loiko9289eda2018-11-23 16:18:59 +00001107 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001108 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001109 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1110 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001111 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001112 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1113 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001114 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001115
Jonas Olsson635474e2018-10-18 15:58:17 +02001116 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1117 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001118 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
1119 // the transport state to be STATE_CONNECTING.
1120 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
1121 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001122 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001123 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001124 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
1125 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001126 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001127 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1128 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001129 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001130}
1131
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001132TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001133 SignalConnectionStateConnectedWithMediaTransportAndNoDtlsCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001134 FakeMediaTransportFactory fake_media_transport_factory;
1135 JsepTransportController::Config config;
1136 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001137 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1138 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001139 config.use_media_transport_for_data_channels = true;
1140 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001141 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001142
1143 // Media Transport is only used with bundle.
1144 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001145 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001146 EXPECT_NE(absl::nullopt,
1147 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001148 EXPECT_TRUE(transport_controller_
1149 ->SetLocalDescription(SdpType::kOffer, description.get())
1150 .ok());
1151
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001152 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1153 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1154 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1155 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001156 EXPECT_EQ(fake_audio_ice, fake_video_ice);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001157 fake_audio_ice->SetConnectionCount(2);
1158 fake_audio_ice->SetConnectionCount(1);
1159 fake_video_ice->SetConnectionCount(2);
1160 fake_video_ice->SetConnectionCount(1);
1161 fake_audio_ice->SetWritable(true);
1162 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001163
1164 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001165 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1166 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001167
1168 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1169 transport_controller_->GetMediaTransport(kAudioMid1));
1170
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001171 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001172
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001173 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001174 // Only one media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +00001175 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001176}
1177
1178TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001179 SignalConnectionStateConnectedWithMediaTransportCaller) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001180 FakeMediaTransportFactory fake_media_transport_factory;
1181 JsepTransportController::Config config;
1182 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001183 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1184 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001185 config.use_media_transport_for_media = true;
1186 CreateJsepTransportController(config);
1187
1188 // Media Transport is only used with bundle.
1189 auto description = CreateSessionDescriptionWithBundleGroup();
1190 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001191 EXPECT_NE(absl::nullopt,
1192 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001193 EXPECT_TRUE(transport_controller_
1194 ->SetLocalDescription(SdpType::kOffer, description.get())
1195 .ok());
1196
1197 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1198 transport_controller_->GetDtlsTransport(kAudioMid1));
1199 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1200 transport_controller_->GetDtlsTransport(kVideoMid1));
1201
1202 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1203 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1204 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1205 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1206 fake_audio_ice->SetConnectionCount(2);
1207 fake_audio_ice->SetConnectionCount(1);
1208 fake_video_ice->SetConnectionCount(2);
1209 fake_video_ice->SetConnectionCount(1);
1210 fake_audio_ice->SetWritable(true);
1211 fake_video_ice->SetWritable(true);
1212 fake_audio_dtls->SetWritable(true);
1213 fake_video_dtls->SetWritable(true);
1214
1215 // Still not connected, because we are waiting for media transport.
1216 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1217 kTimeout);
1218
1219 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1220 transport_controller_->GetMediaTransport(kAudioMid1));
1221
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001222 ASSERT_NE(nullptr, media_transport);
1223
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001224 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1225 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1226 kTimeout);
1227
1228 // Still waiting for the second media transport.
1229 media_transport = static_cast<FakeMediaTransport*>(
1230 transport_controller_->GetMediaTransport(kVideoMid1));
1231 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1232
1233 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
1234}
1235
1236TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001237 SignalConnectionStateFailedWhenMediaTransportClosedCaller) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001238 FakeMediaTransportFactory fake_media_transport_factory;
1239 JsepTransportController::Config config;
1240 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001241 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1242 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001243 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001244 CreateJsepTransportController(config);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001245 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001246 AddCryptoSettings(description.get());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001247 EXPECT_NE(absl::nullopt,
1248 transport_controller_->GenerateOrGetLastMediaTransportOffer());
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001249 EXPECT_TRUE(transport_controller_
1250 ->SetLocalDescription(SdpType::kOffer, description.get())
1251 .ok());
1252
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001253 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1254 transport_controller_->GetDtlsTransport(kAudioMid1));
1255 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1256 transport_controller_->GetDtlsTransport(kVideoMid1));
1257
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001258 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1259 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1260 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1261 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1262 fake_audio_ice->SetWritable(true);
1263 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001264 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001265 fake_audio_ice->SetConnectionCount(2);
1266 fake_audio_ice->SetConnectionCount(1);
1267 fake_video_ice->SetConnectionCount(2);
1268 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001269
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001270 fake_audio_dtls->SetWritable(true);
1271 fake_video_dtls->SetWritable(true);
1272
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001273 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1274 transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001275 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001276 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1277
1278 media_transport = static_cast<FakeMediaTransport*>(
1279 transport_controller_->GetMediaTransport(kVideoMid1));
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001280 ASSERT_NE(nullptr, media_transport);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001281
1282 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1283
Alex Loiko9289eda2018-11-23 16:18:59 +00001284 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001285
1286 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +00001287 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001288}
1289
Zhi Huange818b6e2018-02-22 15:26:27 -08001290TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1291 CreateJsepTransportController(JsepTransportController::Config());
1292 auto description = CreateSessionDescriptionWithoutBundle();
1293 EXPECT_TRUE(transport_controller_
1294 ->SetLocalDescription(SdpType::kOffer, description.get())
1295 .ok());
1296
1297 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1298 transport_controller_->GetDtlsTransport(kAudioMid1));
1299 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1300 transport_controller_->GetDtlsTransport(kVideoMid1));
1301
1302 // First, have one transport connect, and another fail, to ensure that
1303 // the first transport connecting didn't trigger a "connected" state signal.
1304 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001305 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1306 IceTransportState::kCompleted,
1307 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001308 fake_audio_dtls->SetWritable(true);
1309 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001310
1311 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1312 ice_connection_state_, kTimeout);
1313 EXPECT_EQ(1, ice_connection_state_signal_count_);
1314 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1315 combined_connection_state_, kTimeout);
1316 EXPECT_EQ(1, combined_connection_state_signal_count_);
1317
1318 fake_video_dtls->fake_ice_transport()->SetTransportState(
1319 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001320 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1321
Alex Loiko9289eda2018-11-23 16:18:59 +00001322 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001323 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001324 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1325 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001326 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001327 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1328 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001329 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001330
Jonas Olsson635474e2018-10-18 15:58:17 +02001331 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1332 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001333 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1334 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001335 fake_video_dtls->fake_ice_transport()->SetTransportState(
1336 IceTransportState::kCompleted,
1337 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001338 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001339 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +01001340 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001341 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1342 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001343 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001344 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1345 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001346 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001347}
1348
1349TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1350 CreateJsepTransportController(JsepTransportController::Config());
1351 auto description = CreateSessionDescriptionWithoutBundle();
1352 EXPECT_TRUE(transport_controller_
1353 ->SetLocalDescription(SdpType::kOffer, description.get())
1354 .ok());
1355
1356 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1357 transport_controller_->GetDtlsTransport(kAudioMid1));
1358 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1359 // Should be in the gathering state as soon as any transport starts gathering.
1360 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1361 EXPECT_EQ(1, gathering_state_signal_count_);
1362}
1363
1364TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1365 CreateJsepTransportController(JsepTransportController::Config());
1366 auto description = CreateSessionDescriptionWithoutBundle();
1367 EXPECT_TRUE(transport_controller_
1368 ->SetLocalDescription(SdpType::kOffer, description.get())
1369 .ok());
1370
1371 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1372 transport_controller_->GetDtlsTransport(kAudioMid1));
1373 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1374 transport_controller_->GetDtlsTransport(kVideoMid1));
1375
1376 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1377 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1378 EXPECT_EQ(1, gathering_state_signal_count_);
1379
1380 // Have one transport finish gathering, to make sure gathering
1381 // completion wasn't signalled if only one transport finished gathering.
1382 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1383 EXPECT_EQ(1, gathering_state_signal_count_);
1384
1385 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1386 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1387 EXPECT_EQ(1, gathering_state_signal_count_);
1388
1389 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1390 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1391 EXPECT_EQ(2, gathering_state_signal_count_);
1392}
1393
1394// Test that when the last transport that hasn't finished connecting and/or
1395// gathering is destroyed, the aggregate state jumps to "completed". This can
1396// happen if, for example, we have an audio and video transport, the audio
1397// transport completes, then we start bundling video on the audio transport.
1398TEST_F(JsepTransportControllerTest,
1399 SignalingWhenLastIncompleteTransportDestroyed) {
1400 CreateJsepTransportController(JsepTransportController::Config());
1401 auto description = CreateSessionDescriptionWithBundleGroup();
1402 EXPECT_TRUE(transport_controller_
1403 ->SetLocalDescription(SdpType::kOffer, description.get())
1404 .ok());
1405
1406 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1407 transport_controller_->GetDtlsTransport(kAudioMid1));
1408 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1409 transport_controller_->GetDtlsTransport(kVideoMid1));
1410 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1411
1412 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1413 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1414 EXPECT_EQ(1, gathering_state_signal_count_);
1415
1416 // Let the audio transport complete.
1417 fake_audio_dtls->SetWritable(true);
1418 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1419 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001420 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001421 EXPECT_EQ(1, gathering_state_signal_count_);
1422
1423 // Set the remote description and enable the bundle.
1424 EXPECT_TRUE(transport_controller_
1425 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1426 .ok());
1427 // The BUNDLE should be enabled, the incomplete video transport should be
1428 // deleted and the states shoud be updated.
1429 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1430 transport_controller_->GetDtlsTransport(kVideoMid1));
1431 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001432 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1433 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1434 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001435 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1436 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001437 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1438 EXPECT_EQ(2, gathering_state_signal_count_);
1439}
1440
1441TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1442 CreateJsepTransportController(JsepTransportController::Config());
1443 auto description = CreateSessionDescriptionWithBundleGroup();
1444 EXPECT_TRUE(transport_controller_
1445 ->SetLocalDescription(SdpType::kOffer, description.get())
1446 .ok());
1447 transport_controller_->MaybeStartGathering();
1448
1449 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1450 transport_controller_->GetDtlsTransport(kAudioMid1));
1451 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1452 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1453 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1454 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1455}
1456
1457TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1458 network_thread_ = rtc::Thread::CreateWithSocketServer();
1459 network_thread_->Start();
1460 CreateJsepTransportController(JsepTransportController::Config(),
1461 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 14:57:52 +01001462 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 15:26:27 -08001463 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1464
1465 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001466 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001467 EXPECT_EQ(2, connection_state_signal_count_);
1468
1469 // new --> gathering --> complete
1470 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1471 EXPECT_EQ(2, gathering_state_signal_count_);
1472
1473 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1474 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1475 EXPECT_EQ(2, candidates_signal_count_);
1476
1477 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1478}
1479
1480// Older versions of Chrome expect the ICE role to be re-determined when an
1481// ICE restart occurs, and also don't perform conflict resolution correctly,
1482// so for now we can't safely stop doing this.
1483// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1484// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1485// enough population.
1486TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1487 CreateJsepTransportController(JsepTransportController::Config());
1488 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001489 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001490 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1491 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1492 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001493 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001494 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1495 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1496 nullptr);
1497
1498 EXPECT_TRUE(transport_controller_
1499 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1500 .ok());
1501 EXPECT_TRUE(transport_controller_
1502 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1503 .ok());
1504
1505 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1506 transport_controller_->GetDtlsTransport(kAudioMid1));
1507 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1508 fake_dtls->fake_ice_transport()->GetIceRole());
1509
1510 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001511 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001512 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1513 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1514 nullptr);
1515 EXPECT_TRUE(
1516 transport_controller_
1517 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1518 .ok());
1519 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1520 fake_dtls->fake_ice_transport()->GetIceRole());
1521}
1522
1523// Test that if the TransportController was created with the
1524// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1525// redetermined on an ICE restart.
1526TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1527 JsepTransportController::Config config;
1528 config.redetermine_role_on_ice_restart = false;
1529
1530 CreateJsepTransportController(config);
1531 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001532 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001533 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1534 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1535 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001536 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001537 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1538 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1539 nullptr);
1540
1541 EXPECT_TRUE(transport_controller_
1542 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1543 .ok());
1544 EXPECT_TRUE(transport_controller_
1545 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1546 .ok());
1547
1548 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1549 transport_controller_->GetDtlsTransport(kAudioMid1));
1550 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1551 fake_dtls->fake_ice_transport()->GetIceRole());
1552
1553 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001554 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001555 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1556 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1557 nullptr);
1558 EXPECT_TRUE(
1559 transport_controller_
1560 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1561 .ok());
1562 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1563 fake_dtls->fake_ice_transport()->GetIceRole());
1564}
1565
1566// Tests ICE-Lite mode in remote answer.
1567TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1568 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001569 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001570 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1571 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1572 nullptr);
1573 EXPECT_TRUE(transport_controller_
1574 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1575 .ok());
1576 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1577 transport_controller_->GetDtlsTransport(kAudioMid1));
1578 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1579 fake_dtls->fake_ice_transport()->GetIceRole());
1580 EXPECT_EQ(cricket::ICEMODE_FULL,
1581 fake_dtls->fake_ice_transport()->remote_ice_mode());
1582
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001583 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001584 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1585 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1586 nullptr);
1587 EXPECT_TRUE(transport_controller_
1588 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1589 .ok());
1590 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1591 fake_dtls->fake_ice_transport()->GetIceRole());
1592 EXPECT_EQ(cricket::ICEMODE_LITE,
1593 fake_dtls->fake_ice_transport()->remote_ice_mode());
1594}
1595
1596// Tests that the ICE role remains "controlling" if a subsequent offer that
1597// does an ICE restart is received from an ICE lite endpoint. Regression test
1598// for: https://crbug.com/710760
1599TEST_F(JsepTransportControllerTest,
1600 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1601 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001602 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001603 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1604 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1605 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001606 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001607 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1608 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1609 nullptr);
1610 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1611 // local side is the controlling.
1612 EXPECT_TRUE(transport_controller_
1613 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1614 .ok());
1615 EXPECT_TRUE(transport_controller_
1616 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1617 .ok());
1618 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1619 transport_controller_->GetDtlsTransport(kAudioMid1));
1620 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1621 fake_dtls->fake_ice_transport()->GetIceRole());
1622
1623 // In the subsequence remote offer triggers an ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001624 auto remote_offer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001625 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1626 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1627 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001628 auto local_answer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001629 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1630 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1631 nullptr);
1632 EXPECT_TRUE(transport_controller_
1633 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1634 .ok());
1635 EXPECT_TRUE(transport_controller_
1636 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1637 .ok());
1638 fake_dtls = static_cast<FakeDtlsTransport*>(
1639 transport_controller_->GetDtlsTransport(kAudioMid1));
1640 // The local side is still the controlling role since the remote side is using
1641 // ICE-Lite.
1642 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1643 fake_dtls->fake_ice_transport()->GetIceRole());
1644}
1645
1646// Tests that the SDP has more than one audio/video m= sections.
1647TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1648 CreateJsepTransportController(JsepTransportController::Config());
1649 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1650 bundle_group.AddContentName(kAudioMid1);
1651 bundle_group.AddContentName(kAudioMid2);
1652 bundle_group.AddContentName(kVideoMid1);
1653 bundle_group.AddContentName(kDataMid1);
1654
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001655 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001656 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1657 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1658 nullptr);
1659 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1660 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1661 nullptr);
1662 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1663 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1664 nullptr);
1665 AddDataSection(local_offer.get(), kDataMid1,
1666 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1667 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1668 nullptr);
1669
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001670 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001671 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1672 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1673 nullptr);
1674 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1675 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1676 nullptr);
1677 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1678 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1679 nullptr);
1680 AddDataSection(remote_answer.get(), kDataMid1,
1681 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1682 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1683 nullptr);
1684
1685 local_offer->AddGroup(bundle_group);
1686 remote_answer->AddGroup(bundle_group);
1687
1688 EXPECT_TRUE(transport_controller_
1689 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1690 .ok());
1691 EXPECT_TRUE(transport_controller_
1692 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1693 .ok());
1694 // Verify that all the sections are bundled on kAudio1.
1695 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1696 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1697 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1698 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1699 EXPECT_EQ(transport1, transport2);
1700 EXPECT_EQ(transport1, transport3);
1701 EXPECT_EQ(transport1, transport4);
1702
Harald Alvestrandad88c882018-11-28 16:47:46 +01001703 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1704 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1705
Zhi Huange818b6e2018-02-22 15:26:27 -08001706 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1707 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1708 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1709 EXPECT_EQ(transport1, it->second);
1710 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1711 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1712 EXPECT_EQ(transport1, it->second);
1713 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1714 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1715 EXPECT_EQ(transport1, it->second);
1716 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1717 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1718 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
Zhi Huange818b6e2018-02-22 15:26:27 -08001719}
1720
1721// Tests that only a subset of all the m= sections are bundled.
1722TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1723 CreateJsepTransportController(JsepTransportController::Config());
1724 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1725 bundle_group.AddContentName(kAudioMid1);
1726 bundle_group.AddContentName(kVideoMid1);
1727
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001728 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001729 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1730 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1731 nullptr);
1732 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1733 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1734 nullptr);
1735 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1736 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1737 nullptr);
1738
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001739 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001740 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1741 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1742 nullptr);
1743 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1744 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1745 nullptr);
1746 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1747 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1748 nullptr);
1749
1750 local_offer->AddGroup(bundle_group);
1751 remote_answer->AddGroup(bundle_group);
1752 EXPECT_TRUE(transport_controller_
1753 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1754 .ok());
1755 EXPECT_TRUE(transport_controller_
1756 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1757 .ok());
1758
1759 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1760 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1761 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1762 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1763 EXPECT_NE(transport1, transport2);
1764 EXPECT_EQ(transport1, transport3);
1765
1766 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1767 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1768 EXPECT_EQ(transport1, it->second);
1769 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001770 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001771}
1772
1773// Tests that the initial offer/answer only have data section and audio/video
1774// sections are added in the subsequent offer.
1775TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1776 CreateJsepTransportController(JsepTransportController::Config());
1777 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1778 bundle_group.AddContentName(kDataMid1);
1779
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001780 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001781 AddDataSection(local_offer.get(), kDataMid1,
1782 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1783 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1784 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001785 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001786 AddDataSection(remote_answer.get(), kDataMid1,
1787 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1788 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1789 nullptr);
1790 local_offer->AddGroup(bundle_group);
1791 remote_answer->AddGroup(bundle_group);
1792
1793 EXPECT_TRUE(transport_controller_
1794 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1795 .ok());
1796 EXPECT_TRUE(transport_controller_
1797 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1798 .ok());
1799 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1800
1801 // Add audio/video sections in subsequent offer.
1802 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1803 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1804 nullptr);
1805 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1806 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1807 nullptr);
1808 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1809 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1810 nullptr);
1811 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1812 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1813 nullptr);
1814
1815 // Reset the bundle group and do another offer/answer exchange.
1816 bundle_group.AddContentName(kAudioMid1);
1817 bundle_group.AddContentName(kVideoMid1);
1818 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1819 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1820 local_offer->AddGroup(bundle_group);
1821 remote_answer->AddGroup(bundle_group);
1822
1823 EXPECT_TRUE(transport_controller_
1824 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1825 .ok());
1826 EXPECT_TRUE(transport_controller_
1827 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1828 .ok());
1829
1830 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1831 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1832 EXPECT_EQ(data_transport, audio_transport);
1833 EXPECT_EQ(data_transport, video_transport);
1834}
1835
1836TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1837 CreateJsepTransportController(JsepTransportController::Config());
1838 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1839 bundle_group.AddContentName(kAudioMid1);
1840 bundle_group.AddContentName(kVideoMid1);
1841 bundle_group.AddContentName(kDataMid1);
1842
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001843 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001844 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1845 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1846 nullptr);
1847 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1848 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1849 nullptr);
1850 AddDataSection(local_offer.get(), kDataMid1,
1851 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1852 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1853 nullptr);
1854
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001855 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001856 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1857 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1858 nullptr);
1859 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1860 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1861 nullptr);
1862 AddDataSection(remote_answer.get(), kDataMid1,
1863 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1864 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1865 nullptr);
1866 // Reject video and data section.
1867 remote_answer->contents()[1].rejected = true;
1868 remote_answer->contents()[2].rejected = true;
1869
1870 local_offer->AddGroup(bundle_group);
1871 remote_answer->AddGroup(bundle_group);
1872
1873 EXPECT_TRUE(transport_controller_
1874 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1875 .ok());
1876 EXPECT_TRUE(transport_controller_
1877 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1878 .ok());
1879
1880 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1881 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1882 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1883 // Verify the signals are fired correctly.
1884 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1885 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1886 EXPECT_EQ(nullptr, it->second);
1887 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1888 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1889 EXPECT_EQ(nullptr, it2->second);
1890}
1891
1892// Tests that changing the bundled MID in subsequent offer/answer exchange is
1893// not supported.
1894// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1895// fixed
1896TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1897 CreateJsepTransportController(JsepTransportController::Config());
1898 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1899 bundle_group.AddContentName(kAudioMid1);
1900 bundle_group.AddContentName(kVideoMid1);
1901
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001902 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001903 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1904 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1905 nullptr);
1906 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1907 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1908 nullptr);
1909
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001910 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001911 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1912 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1913 nullptr);
1914 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1915 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1916 nullptr);
1917
1918 local_offer->AddGroup(bundle_group);
1919 remote_answer->AddGroup(bundle_group);
1920 EXPECT_TRUE(transport_controller_
1921 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1922 .ok());
1923 EXPECT_TRUE(transport_controller_
1924 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1925 .ok());
1926 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1927 transport_controller_->GetRtpTransport(kVideoMid1));
1928
1929 // Reorder the bundle group.
1930 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1931 bundle_group.AddContentName(kAudioMid1);
1932 // The answerer uses the new bundle group and now the bundle mid is changed to
1933 // |kVideo1|.
1934 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1935 remote_answer->AddGroup(bundle_group);
1936 EXPECT_TRUE(transport_controller_
1937 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1938 .ok());
1939 EXPECT_FALSE(transport_controller_
1940 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1941 .ok());
1942}
Zhi Huange830e682018-03-30 10:48:35 -07001943// Test that rejecting only the first m= section of a BUNDLE group is treated as
1944// an error, but rejecting all of them works as expected.
1945TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1946 CreateJsepTransportController(JsepTransportController::Config());
1947 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1948 bundle_group.AddContentName(kAudioMid1);
1949 bundle_group.AddContentName(kVideoMid1);
1950 bundle_group.AddContentName(kDataMid1);
1951
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001952 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001953 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1954 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1955 nullptr);
1956 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1957 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1958 nullptr);
1959 AddDataSection(local_offer.get(), kDataMid1,
1960 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1961 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1962 nullptr);
1963
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001964 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001965 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 AddDataSection(remote_answer.get(), kDataMid1,
1972 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1973 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1974 nullptr);
1975 // Reject audio content in answer.
1976 remote_answer->contents()[0].rejected = true;
1977
1978 local_offer->AddGroup(bundle_group);
1979 remote_answer->AddGroup(bundle_group);
1980
1981 EXPECT_TRUE(transport_controller_
1982 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1983 .ok());
1984 EXPECT_FALSE(transport_controller_
1985 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1986 .ok());
1987
1988 // Reject all the contents.
1989 remote_answer->contents()[1].rejected = true;
1990 remote_answer->contents()[2].rejected = true;
1991 EXPECT_TRUE(transport_controller_
1992 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1993 .ok());
1994 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1995 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1996 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1997}
1998
1999// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
2000// is used.
2001TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
2002 JsepTransportController::Config config;
2003 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2004 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002005 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002006 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2007 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2008 nullptr);
2009
2010 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
2011 // Applying a non-RTCP-mux offer is expected to fail.
2012 EXPECT_FALSE(transport_controller_
2013 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2014 .ok());
2015}
2016
2017// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
2018// is used.
2019TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
2020 JsepTransportController::Config config;
2021 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2022 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002023 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002024 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2025 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2026 nullptr);
2027 EXPECT_TRUE(transport_controller_
2028 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2029 .ok());
2030
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002031 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07002032 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2033 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
2034 nullptr);
2035 // Applying a non-RTCP-mux answer is expected to fail.
2036 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
2037 EXPECT_FALSE(transport_controller_
2038 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2039 .ok());
2040}
Zhi Huange818b6e2018-02-22 15:26:27 -08002041
Zhi Huangd2248f82018-04-10 14:41:03 -07002042// This tests that the BUNDLE group in answer should be a subset of the offered
2043// group.
2044TEST_F(JsepTransportControllerTest,
2045 AddContentToBundleGroupInAnswerNotSupported) {
2046 CreateJsepTransportController(JsepTransportController::Config());
2047 auto local_offer = CreateSessionDescriptionWithoutBundle();
2048 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2049
2050 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2051 offer_bundle_group.AddContentName(kAudioMid1);
2052 local_offer->AddGroup(offer_bundle_group);
2053
2054 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2055 answer_bundle_group.AddContentName(kAudioMid1);
2056 answer_bundle_group.AddContentName(kVideoMid1);
2057 remote_answer->AddGroup(answer_bundle_group);
2058 EXPECT_TRUE(transport_controller_
2059 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2060 .ok());
2061 EXPECT_FALSE(transport_controller_
2062 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2063 .ok());
2064}
2065
2066// This tests that the BUNDLE group with non-existing MID should be rejectd.
2067TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
2068 CreateJsepTransportController(JsepTransportController::Config());
2069 auto local_offer = CreateSessionDescriptionWithoutBundle();
2070 auto remote_answer = CreateSessionDescriptionWithoutBundle();
2071
2072 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2073 // The BUNDLE group is invalid because there is no data section in the
2074 // description.
2075 invalid_bundle_group.AddContentName(kDataMid1);
2076 local_offer->AddGroup(invalid_bundle_group);
2077 remote_answer->AddGroup(invalid_bundle_group);
2078
2079 EXPECT_FALSE(transport_controller_
2080 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2081 .ok());
2082 EXPECT_FALSE(transport_controller_
2083 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2084 .ok());
2085}
2086
2087// This tests that an answer shouldn't be able to remove an m= section from an
2088// established group without rejecting it.
2089TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
2090 CreateJsepTransportController(JsepTransportController::Config());
2091
2092 auto local_offer = CreateSessionDescriptionWithBundleGroup();
2093 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
2094 EXPECT_TRUE(transport_controller_
2095 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2096 .ok());
2097 EXPECT_TRUE(transport_controller_
2098 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2099 .ok());
2100
2101 // Do an re-offer/answer.
2102 EXPECT_TRUE(transport_controller_
2103 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2104 .ok());
2105 auto new_answer = CreateSessionDescriptionWithoutBundle();
2106 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2107 // The answer removes video from the BUNDLE group without rejecting it is
2108 // invalid.
2109 new_bundle_group.AddContentName(kAudioMid1);
2110 new_answer->AddGroup(new_bundle_group);
2111
2112 // Applying invalid answer is expected to fail.
2113 EXPECT_FALSE(transport_controller_
2114 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2115 .ok());
2116
2117 // Rejected the video content.
2118 auto video_content = new_answer->GetContentByName(kVideoMid1);
2119 ASSERT_TRUE(video_content);
2120 video_content->rejected = true;
2121 EXPECT_TRUE(transport_controller_
2122 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
2123 .ok());
2124}
2125
Steve Anton2bed3972019-01-04 17:04:30 -08002126// Test that the JsepTransportController can process a new local and remote
2127// description that changes the tagged BUNDLE group with the max-bundle policy
2128// specified.
2129// This is a regression test for bugs.webrtc.org/9954
2130TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
2131 CreateJsepTransportController(JsepTransportController::Config());
2132
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002133 auto local_offer = std::make_unique<cricket::SessionDescription>();
Steve Anton2bed3972019-01-04 17:04:30 -08002134 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
2135 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2136 nullptr);
2137 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
2138 bundle_group.AddContentName(kAudioMid1);
2139 local_offer->AddGroup(bundle_group);
2140 EXPECT_TRUE(transport_controller_
2141 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
2142 .ok());
2143
2144 std::unique_ptr<cricket::SessionDescription> remote_answer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002145 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002146 EXPECT_TRUE(transport_controller_
2147 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
2148 .ok());
2149
2150 std::unique_ptr<cricket::SessionDescription> local_reoffer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002151 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002152 local_reoffer->contents()[0].rejected = true;
2153 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
2154 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
2155 nullptr);
2156 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
2157 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
2158 new_bundle_group.AddContentName(kVideoMid1);
2159 local_reoffer->AddGroup(new_bundle_group);
2160
2161 EXPECT_TRUE(transport_controller_
2162 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
2163 .ok());
2164
2165 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002166 local_reoffer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08002167 EXPECT_TRUE(
2168 transport_controller_
2169 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
2170 .ok());
2171}
2172
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07002173constexpr char kFakeTransportParameters[] = "fake-params";
2174
2175// Test fixture that provides common setup and helpers for tests related to the
2176// datagram transport.
2177class JsepTransportControllerDatagramTest
2178 : public JsepTransportControllerTest,
2179 public testing::WithParamInterface<bool> {
2180 public:
2181 JsepTransportControllerDatagramTest()
2182 : JsepTransportControllerTest(),
2183 fake_media_transport_factory_(kFakeTransportParameters) {
2184 JsepTransportController::Config config;
2185 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
2186 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2187 config.media_transport_factory = &fake_media_transport_factory_;
2188 config.use_datagram_transport = true;
2189 CreateJsepTransportController(config);
2190 }
2191
2192 // Whether the JsepTransportController under test acts as the offerer or
2193 // answerer in this test.
2194 bool IsOfferer() { return GetParam(); }
2195
2196 // Sets a description as local or remote based on type and current
2197 // perspective.
2198 RTCError SetDescription(SdpType type,
2199 const cricket::SessionDescription* description) {
2200 if (IsOfferer() == (type == SdpType::kOffer)) {
2201 return transport_controller_->SetLocalDescription(type, description);
2202 } else {
2203 return transport_controller_->SetRemoteDescription(type, description);
2204 }
2205 }
2206
2207 // Creates a session description with the settings necessary for datagram
2208 // transport (bundle + crypto) and the given |transport_params|.
2209 std::unique_ptr<cricket::SessionDescription>
2210 CreateSessionDescriptionForDatagramTransport(
2211 absl::optional<cricket::OpaqueTransportParameters> transport_params) {
2212 auto description = CreateSessionDescriptionWithBundleGroup();
2213 AddCryptoSettings(description.get());
2214
2215 for (auto& info : description->transport_infos()) {
2216 info.description.opaque_parameters = transport_params;
2217 }
2218 return description;
2219 }
2220
2221 // Creates transport parameters with |protocol| and |parameters|
2222 // matching what |fake_media_transport_factory_| provides.
2223 cricket::OpaqueTransportParameters CreateTransportParameters() {
2224 cricket::OpaqueTransportParameters params;
2225 params.protocol = fake_media_transport_factory_.GetTransportName();
2226 params.parameters = "fake-params";
2227 return params;
2228 }
2229
2230 protected:
2231 FakeMediaTransportFactory fake_media_transport_factory_;
2232};
2233
2234TEST_P(JsepTransportControllerDatagramTest, InitDatagramTransport) {
2235 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2236 if (IsOfferer()) {
2237 // Getting transport parameters is allowed before setting a description.
2238 // This is necessary so that the offerer can include these params.
2239 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2240 fake_params);
2241 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2242 fake_params);
2243 }
2244
2245 // Setting a description activates the datagram transport without changing
2246 // transport parameters.
2247 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2248 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2249
2250 // After setting an offer with transport parameters, those parameters are
2251 // reflected by the controller.
2252 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2253 fake_params);
2254 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2255 fake_params);
2256}
2257
2258TEST_P(JsepTransportControllerDatagramTest,
2259 OfferMissingDatagramTransportParams) {
2260 if (IsOfferer()) {
2261 // This test doesn't make sense from the offerer's perspective, as the offer
2262 // must contain datagram transport params if the offerer supports it.
2263 return;
2264 }
2265
2266 auto description =
2267 CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2268 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2269
2270 // The offer didn't contain any datagram transport parameters, so the answer
2271 // won't either.
2272 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2273 absl::nullopt);
2274 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2275 absl::nullopt);
2276}
2277
2278TEST_P(JsepTransportControllerDatagramTest, OfferHasWrongTransportName) {
2279 if (IsOfferer()) {
2280 // This test doesn't make sense from the offerer's perspective, as the
2281 // offerer cannot offer itself the wrong transport.
2282 return;
2283 }
2284
2285 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2286 fake_params.protocol = "wrong-name";
2287
2288 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
2289 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
2290
2291 // The offerer and answerer support different datagram transports, so the
2292 // answerer rejects the offered parameters.
2293 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2294 absl::nullopt);
2295 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2296 absl::nullopt);
2297}
2298
2299TEST_P(JsepTransportControllerDatagramTest, AnswerRejectsDatagram) {
2300 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2301 if (IsOfferer()) {
2302 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2303 fake_params);
2304 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2305 fake_params);
2306 }
2307
2308 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2309 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2310
2311 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2312 fake_params);
2313 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2314 fake_params);
2315
2316 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2317 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2318
2319 // The answer rejected datagram transport, so its parameters are empty.
2320 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2321 absl::nullopt);
2322 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2323 absl::nullopt);
2324}
2325
2326TEST_P(JsepTransportControllerDatagramTest, AnswerAcceptsDatagram) {
2327 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2328 if (IsOfferer()) {
2329 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2330 fake_params);
2331 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2332 fake_params);
2333 }
2334
2335 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2336 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2337
2338 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2339 fake_params);
2340 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2341 fake_params);
2342
2343 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2344 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2345
2346 // The answer accepted datagram transport, so it is present.
2347 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2348 fake_params);
2349 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2350 fake_params);
2351}
2352
2353TEST_P(JsepTransportControllerDatagramTest, PrAnswerRejectsDatagram) {
2354 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2355 if (IsOfferer()) {
2356 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2357 fake_params);
2358 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2359 fake_params);
2360 }
2361
2362 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2363 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2364
2365 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2366 fake_params);
2367 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2368 fake_params);
2369
2370 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2371 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2372
2373 // The answer rejected datagram transport, but it's provisional, so the
2374 // transport is kept around for now.
2375 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2376 fake_params);
2377 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2378 fake_params);
2379}
2380
2381TEST_P(JsepTransportControllerDatagramTest, PrAnswerAcceptsDatagram) {
2382 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2383 if (IsOfferer()) {
2384 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2385 fake_params);
2386 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2387 fake_params);
2388 }
2389
2390 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2391 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2392
2393 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2394 fake_params);
2395 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2396 fake_params);
2397
2398 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2399 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
2400
2401 // The answer provisionally accepted datagram transport, so it's kept.
2402 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2403 fake_params);
2404 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2405 fake_params);
2406}
2407
2408TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotAddDatagram) {
2409 auto offer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2410 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2411
2412 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2413 absl::nullopt);
2414 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2415 absl::nullopt);
2416
2417 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2418 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2419
2420 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2421 absl::nullopt);
2422 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2423 absl::nullopt);
2424
2425 // Attempting to add a datagram transport on a re-offer does not cause an
2426 // error, but also does not add a datagram transport.
2427 auto reoffer =
2428 CreateSessionDescriptionForDatagramTransport(CreateTransportParameters());
2429 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2430
2431 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2432 absl::nullopt);
2433 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2434 absl::nullopt);
2435}
2436
2437TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotRemoveDatagram) {
2438 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2439 if (IsOfferer()) {
2440 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2441 fake_params);
2442 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2443 fake_params);
2444 }
2445
2446 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2447 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2448
2449 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2450 fake_params);
2451 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2452 fake_params);
2453
2454 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2455 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2456
2457 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2458 fake_params);
2459 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2460 fake_params);
2461
2462 // Attempting to remove a datagram transport on a re-offer does not cause an
2463 // error, but also does not remove the datagram transport.
2464 auto reoffer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2465 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2466
2467 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2468 fake_params);
2469 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2470 fake_params);
2471}
2472
2473TEST_P(JsepTransportControllerDatagramTest,
2474 RenegotiationKeepsDatagramTransport) {
2475 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2476 if (IsOfferer()) {
2477 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2478 fake_params);
2479 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2480 fake_params);
2481 }
2482
2483 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2484 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2485
2486 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2487 fake_params);
2488 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2489 fake_params);
2490
2491 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2492 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2493
2494 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2495 fake_params);
2496 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2497 fake_params);
2498
2499 // Attempting to remove a datagram transport on a re-offer does not cause an
2500 // error, but also does not remove the datagram transport.
2501 auto reoffer = CreateSessionDescriptionForDatagramTransport(fake_params);
2502 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2503
2504 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2505 fake_params);
2506 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2507 fake_params);
2508
2509 auto reanswer = CreateSessionDescriptionForDatagramTransport(fake_params);
2510 EXPECT_TRUE(SetDescription(SdpType::kAnswer, reanswer.get()).ok());
2511
2512 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2513 fake_params);
2514 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2515 fake_params);
2516}
2517
2518INSTANTIATE_TEST_SUITE_P(
2519 JsepTransportControllerDatagramTests,
2520 JsepTransportControllerDatagramTest,
2521 testing::Values(true, false),
2522 // The parameter value is the local perspective (offerer or answerer).
2523 [](const testing::TestParamInfo<bool>& info) {
2524 return info.param ? "Offerer" : "Answerer";
2525 });
2526
Zhi Huange818b6e2018-02-22 15:26:27 -08002527} // namespace webrtc