blob: d78597ccf1cf20ce54a772861a2baadec97173ef [file] [log] [blame]
Zhi Huange818b6e2018-02-22 15:26:27 -08001/*
2 * Copyright 2018 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/jsep_transport_controller.h"
12
Zhi Huange818b6e2018-02-22 15:26:27 -080013#include <map>
14#include <memory>
15
Anton Sukhanov7940da02018-10-10 10:34:49 -070016#include "api/test/fake_media_transport.h"
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -080017#include "api/test/loopback_media_transport.h"
Niels Möller65f17ca2019-09-12 13:59:36 +020018#include "api/transport/media/media_transport_interface.h"
Qingsi Wang25ec8882019-11-15 12:33:05 -080019#include "p2p/base/dtls_transport_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "p2p/base/fake_dtls_transport.h"
21#include "p2p/base/fake_ice_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "p2p/base/transport_info.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080023#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/thread.h"
25#include "test/gtest.h"
26
Zhi Huange818b6e2018-02-22 15:26:27 -080027using cricket::Candidate;
28using cricket::Candidates;
Jonas Olssona4d87372019-07-05 19:08:33 +020029using cricket::FakeDtlsTransport;
Zhi Huange818b6e2018-02-22 15:26:27 -080030using webrtc::SdpType;
31
32static const int kTimeout = 100;
33static const char kIceUfrag1[] = "u0001";
34static const char kIcePwd1[] = "TESTICEPWD00000000000001";
35static const char kIceUfrag2[] = "u0002";
36static const char kIcePwd2[] = "TESTICEPWD00000000000002";
37static const char kIceUfrag3[] = "u0003";
38static const char kIcePwd3[] = "TESTICEPWD00000000000003";
39static const char kAudioMid1[] = "audio1";
40static const char kAudioMid2[] = "audio2";
41static const char kVideoMid1[] = "video1";
42static const char kVideoMid2[] = "video2";
43static const char kDataMid1[] = "data1";
44
45namespace webrtc {
46
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070047namespace {
48
49// Media transport factory requires crypto settings to be present in order to
50// create media transport.
51void AddCryptoSettings(cricket::SessionDescription* description) {
52 for (auto& content : description->contents()) {
53 content.media_description()->AddCrypto(cricket::CryptoParams(
54 /*t=*/0, std::string(rtc::CS_AES_CM_128_HMAC_SHA1_80),
55 "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2", ""));
56 }
57}
58
59} // namespace
60
Qingsi Wang25ec8882019-11-15 12:33:05 -080061class FakeIceTransportFactory : public webrtc::IceTransportFactory {
Zhi Huange818b6e2018-02-22 15:26:27 -080062 public:
Qingsi Wang25ec8882019-11-15 12:33:05 -080063 ~FakeIceTransportFactory() override = default;
64 rtc::scoped_refptr<IceTransportInterface> CreateIceTransport(
Zhi Huange818b6e2018-02-22 15:26:27 -080065 const std::string& transport_name,
Qingsi Wang25ec8882019-11-15 12:33:05 -080066 int component,
67 IceTransportInit init) override {
68 return new rtc::RefCountedObject<cricket::FakeIceTransportWrapper>(
69 std::make_unique<cricket::FakeIceTransport>(transport_name, component));
Zhi Huange818b6e2018-02-22 15:26:27 -080070 }
Qingsi Wang25ec8882019-11-15 12:33:05 -080071};
Zhi Huange818b6e2018-02-22 15:26:27 -080072
Qingsi Wang25ec8882019-11-15 12:33:05 -080073class FakeDtlsTransportFactory : public cricket::DtlsTransportFactory {
74 public:
Zhi Huange818b6e2018-02-22 15:26:27 -080075 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070076 cricket::IceTransportInternal* ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070077 const webrtc::CryptoOptions& crypto_options) override {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020078 return std::make_unique<FakeDtlsTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -070079 static_cast<cricket::FakeIceTransport*>(ice));
Zhi Huange818b6e2018-02-22 15:26:27 -080080 }
81};
82
Zhi Huang365381f2018-04-13 16:44:34 -070083class JsepTransportControllerTest : public JsepTransportController::Observer,
Mirko Bonadei6a489f22019-04-09 15:11:12 +020084 public ::testing::Test,
Zhi Huange818b6e2018-02-22 15:26:27 -080085 public sigslot::has_slots<> {
86 public:
87 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Qingsi Wang25ec8882019-11-15 12:33:05 -080088 fake_ice_transport_factory_ = std::make_unique<FakeIceTransportFactory>();
89 fake_dtls_transport_factory_ = std::make_unique<FakeDtlsTransportFactory>();
Zhi Huange818b6e2018-02-22 15:26:27 -080090 }
91
92 void CreateJsepTransportController(
93 JsepTransportController::Config config,
94 rtc::Thread* signaling_thread = rtc::Thread::Current(),
95 rtc::Thread* network_thread = rtc::Thread::Current(),
96 cricket::PortAllocator* port_allocator = nullptr) {
Zhi Huang365381f2018-04-13 16:44:34 -070097 config.transport_observer = this;
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +020098 config.rtcp_handler = [](const rtc::CopyOnWriteBuffer& packet,
99 int64_t packet_time_us) { RTC_NOTREACHED(); };
Qingsi Wang25ec8882019-11-15 12:33:05 -0800100 config.ice_transport_factory = fake_ice_transport_factory_.get();
101 config.dtls_transport_factory = fake_dtls_transport_factory_.get();
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200102 transport_controller_ = std::make_unique<JsepTransportController>(
Qingsi Wange8d54b92020-01-06 14:31:57 -0800103 signaling_thread, network_thread, port_allocator,
104 nullptr /* async_resolver_factory */, config);
Zhi Huange818b6e2018-02-22 15:26:27 -0800105 ConnectTransportControllerSignals();
106 }
107
108 void ConnectTransportControllerSignals() {
109 transport_controller_->SignalIceConnectionState.connect(
110 this, &JsepTransportControllerTest::OnConnectionState);
Alex Loiko9289eda2018-11-23 16:18:59 +0000111 transport_controller_->SignalStandardizedIceConnectionState.connect(
112 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200113 transport_controller_->SignalConnectionState.connect(
114 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800115 transport_controller_->SignalIceGatheringState.connect(
116 this, &JsepTransportControllerTest::OnGatheringState);
117 transport_controller_->SignalIceCandidatesGathered.connect(
118 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800119 }
120
121 std::unique_ptr<cricket::SessionDescription>
122 CreateSessionDescriptionWithoutBundle() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200123 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800124 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
125 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
126 nullptr);
127 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
128 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
129 nullptr);
130 return description;
131 }
132
133 std::unique_ptr<cricket::SessionDescription>
134 CreateSessionDescriptionWithBundleGroup() {
135 auto description = CreateSessionDescriptionWithoutBundle();
136 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
137 bundle_group.AddContentName(kAudioMid1);
138 bundle_group.AddContentName(kVideoMid1);
139 description->AddGroup(bundle_group);
140
141 return description;
142 }
143
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700144 std::unique_ptr<cricket::SessionDescription>
145 CreateSessionDescriptionWithBundledData() {
146 auto description = CreateSessionDescriptionWithoutBundle();
147 AddDataSection(description.get(), kDataMid1,
148 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
149 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
150 nullptr);
151 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
152 bundle_group.AddContentName(kAudioMid1);
153 bundle_group.AddContentName(kVideoMid1);
154 bundle_group.AddContentName(kDataMid1);
155 description->AddGroup(bundle_group);
156 return description;
157 }
158
Zhi Huange818b6e2018-02-22 15:26:27 -0800159 void AddAudioSection(cricket::SessionDescription* description,
160 const std::string& mid,
161 const std::string& ufrag,
162 const std::string& pwd,
163 cricket::IceMode ice_mode,
164 cricket::ConnectionRole conn_role,
165 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
166 std::unique_ptr<cricket::AudioContentDescription> audio(
167 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700168 // Set RTCP-mux to be true because the default policy is "mux required".
169 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800170 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200171 /*rejected=*/false, std::move(audio));
Zhi Huange818b6e2018-02-22 15:26:27 -0800172 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
173 }
174
175 void AddVideoSection(cricket::SessionDescription* description,
176 const std::string& mid,
177 const std::string& ufrag,
178 const std::string& pwd,
179 cricket::IceMode ice_mode,
180 cricket::ConnectionRole conn_role,
181 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
182 std::unique_ptr<cricket::VideoContentDescription> video(
183 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700184 // Set RTCP-mux to be true because the default policy is "mux required".
185 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800186 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200187 /*rejected=*/false, std::move(video));
Zhi Huange818b6e2018-02-22 15:26:27 -0800188 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
189 }
190
191 void AddDataSection(cricket::SessionDescription* description,
192 const std::string& mid,
193 cricket::MediaProtocolType protocol_type,
194 const std::string& ufrag,
195 const std::string& pwd,
196 cricket::IceMode ice_mode,
197 cricket::ConnectionRole conn_role,
198 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200199 RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp);
200 std::unique_ptr<cricket::SctpDataContentDescription> data(
201 new cricket::SctpDataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700202 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800203 description->AddContent(mid, protocol_type,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200204 /*rejected=*/false, std::move(data));
Zhi Huange818b6e2018-02-22 15:26:27 -0800205 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
206 }
207
208 void AddTransportInfo(cricket::SessionDescription* description,
209 const std::string& mid,
210 const std::string& ufrag,
211 const std::string& pwd,
212 cricket::IceMode ice_mode,
213 cricket::ConnectionRole conn_role,
214 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
215 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
216 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700217 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800218 }
219
220 cricket::TransportDescription transport_desc(std::vector<std::string>(),
221 ufrag, pwd, ice_mode,
222 conn_role, fingerprint.get());
223 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
224 }
225
226 cricket::IceConfig CreateIceConfig(
227 int receiving_timeout,
228 cricket::ContinualGatheringPolicy continual_gathering_policy) {
229 cricket::IceConfig config;
230 config.receiving_timeout = receiving_timeout;
231 config.continual_gathering_policy = continual_gathering_policy;
232 return config;
233 }
234
235 Candidate CreateCandidate(const std::string& transport_name, int component) {
236 Candidate c;
237 c.set_transport_name(transport_name);
238 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
239 c.set_component(component);
240 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
241 c.set_priority(1);
242 return c;
243 }
244
245 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
246 if (!network_thread_->IsCurrent()) {
247 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
248 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
249 });
250 return;
251 }
252
253 auto description = CreateSessionDescriptionWithBundleGroup();
254 EXPECT_TRUE(transport_controller_
255 ->SetLocalDescription(SdpType::kOffer, description.get())
256 .ok());
257
258 transport_controller_->MaybeStartGathering();
259 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
260 transport_controller_->GetDtlsTransport(kAudioMid1));
261 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
262 transport_controller_->GetDtlsTransport(kVideoMid1));
263 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
264 fake_audio_dtls->fake_ice_transport(),
265 CreateCandidate(kAudioMid1, /*component=*/1));
266 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
267 fake_video_dtls->fake_ice_transport(),
268 CreateCandidate(kVideoMid1, /*component=*/1));
269 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
270 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
271 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
272 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
273 fake_audio_dtls->SetReceiving(true);
274 fake_video_dtls->SetReceiving(true);
275 fake_audio_dtls->SetWritable(true);
276 fake_video_dtls->SetWritable(true);
277 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
278 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
279 }
280
281 protected:
Alex Loiko9289eda2018-11-23 16:18:59 +0000282 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800283 if (!signaling_thread_->IsCurrent()) {
284 signaled_on_non_signaling_thread_ = true;
285 }
286 connection_state_ = state;
287 ++connection_state_signal_count_;
288 }
289
Alex Loiko9289eda2018-11-23 16:18:59 +0000290 void OnStandardizedIceConnectionState(
291 PeerConnectionInterface::IceConnectionState state) {
292 if (!signaling_thread_->IsCurrent()) {
293 signaled_on_non_signaling_thread_ = true;
294 }
295 ice_connection_state_ = state;
296 ++ice_connection_state_signal_count_;
297 }
298
Jonas Olsson635474e2018-10-18 15:58:17 +0200299 void OnCombinedConnectionState(
300 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100301 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
302 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 15:58:17 +0200303 if (!signaling_thread_->IsCurrent()) {
304 signaled_on_non_signaling_thread_ = true;
305 }
306 combined_connection_state_ = state;
307 ++combined_connection_state_signal_count_;
308 }
309
Zhi Huange818b6e2018-02-22 15:26:27 -0800310 void OnGatheringState(cricket::IceGatheringState state) {
311 if (!signaling_thread_->IsCurrent()) {
312 signaled_on_non_signaling_thread_ = true;
313 }
314 gathering_state_ = state;
315 ++gathering_state_signal_count_;
316 }
317
318 void OnCandidatesGathered(const std::string& transport_name,
319 const Candidates& candidates) {
320 if (!signaling_thread_->IsCurrent()) {
321 signaled_on_non_signaling_thread_ = true;
322 }
323 candidates_[transport_name].insert(candidates_[transport_name].end(),
324 candidates.begin(), candidates.end());
325 ++candidates_signal_count_;
326 }
327
Zhi Huang365381f2018-04-13 16:44:34 -0700328 // JsepTransportController::Observer overrides.
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700329 bool OnTransportChanged(
330 const std::string& mid,
331 RtpTransportInternal* rtp_transport,
332 rtc::scoped_refptr<DtlsTransport> dtls_transport,
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700333 DataChannelTransportInterface* data_channel_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700334 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100335 if (dtls_transport) {
336 changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
337 } else {
338 changed_dtls_transport_by_mid_[mid] = nullptr;
339 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700340 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800341 }
342
343 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000344 cricket::IceConnectionState connection_state_ =
345 cricket::kIceConnectionConnecting;
346 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200347 PeerConnectionInterface::kIceConnectionNew;
348 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
349 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800350 bool receiving_ = false;
351 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
352 // transport_name => candidates
353 std::map<std::string, Candidates> candidates_;
354 // Counts of each signal emitted.
355 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000356 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200357 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800358 int receiving_signal_count_ = 0;
359 int gathering_state_signal_count_ = 0;
360 int candidates_signal_count_ = 0;
361
362 // |network_thread_| should be destroyed after |transport_controller_|
363 std::unique_ptr<rtc::Thread> network_thread_;
Qingsi Wang25ec8882019-11-15 12:33:05 -0800364 std::unique_ptr<FakeIceTransportFactory> fake_ice_transport_factory_;
365 std::unique_ptr<FakeDtlsTransportFactory> fake_dtls_transport_factory_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800366 rtc::Thread* const signaling_thread_ = nullptr;
367 bool signaled_on_non_signaling_thread_ = false;
368 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
369 // signaled correctly.
370 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
371 std::map<std::string, cricket::DtlsTransportInternal*>
372 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800373
374 // Transport controller needs to be destroyed first, because it may issue
375 // callbacks that modify the changed_*_by_mid in the destructor.
376 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800377};
378
379TEST_F(JsepTransportControllerTest, GetRtpTransport) {
380 CreateJsepTransportController(JsepTransportController::Config());
381 auto description = CreateSessionDescriptionWithoutBundle();
382 EXPECT_TRUE(transport_controller_
383 ->SetLocalDescription(SdpType::kOffer, description.get())
384 .ok());
385 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
386 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
387 EXPECT_NE(nullptr, audio_rtp_transport);
388 EXPECT_NE(nullptr, video_rtp_transport);
389 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
390 // Return nullptr for non-existing ones.
391 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
392}
393
394TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
395 JsepTransportController::Config config;
396 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
397 CreateJsepTransportController(config);
398 auto description = CreateSessionDescriptionWithoutBundle();
399 EXPECT_TRUE(transport_controller_
400 ->SetLocalDescription(SdpType::kOffer, description.get())
401 .ok());
402 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
403 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100404 EXPECT_NE(nullptr,
405 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800406 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
407 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100408 EXPECT_NE(nullptr,
409 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
410 // Lookup for all MIDs should return different transports (no bundle)
411 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
412 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800413 // Return nullptr for non-existing ones.
414 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
415 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100416 EXPECT_EQ(nullptr,
417 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100418 // Take a pointer to a transport, shut down the transport controller,
419 // and verify that the resulting container is empty.
420 auto dtls_transport =
421 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
422 webrtc::DtlsTransport* my_transport =
423 static_cast<DtlsTransport*>(dtls_transport.get());
424 EXPECT_NE(nullptr, my_transport->internal());
425 transport_controller_.reset();
426 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800427}
428
Zhi Huange830e682018-03-30 10:48:35 -0700429TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
430 JsepTransportController::Config config;
431 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
432 CreateJsepTransportController(config);
433 auto description = CreateSessionDescriptionWithoutBundle();
434 EXPECT_TRUE(transport_controller_
435 ->SetLocalDescription(SdpType::kOffer, description.get())
436 .ok());
437 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
438 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
439 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
440 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800441}
442
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700443TEST_F(JsepTransportControllerTest,
444 DtlsIsStillCreatedIfDatagramTransportIsOnlyUsedForDataChannels) {
445 FakeMediaTransportFactory fake_media_transport_factory("transport_params");
446 JsepTransportController::Config config;
447
448 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
449 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
450 config.media_transport_factory = &fake_media_transport_factory;
451 config.use_datagram_transport_for_data_channels = true;
452 CreateJsepTransportController(config);
453
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700454 auto description = CreateSessionDescriptionWithBundledData();
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700455 AddCryptoSettings(description.get());
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700456
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700457 absl::optional<cricket::OpaqueTransportParameters> params =
458 transport_controller_->GetTransportParameters(kAudioMid1);
459 for (auto& info : description->transport_infos()) {
460 info.description.opaque_parameters = params;
461 }
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700462 for (cricket::ContentInfo& content_info : description->contents()) {
463 if (content_info.media_description()->type() == cricket::MEDIA_TYPE_DATA) {
464 content_info.media_description()->set_alt_protocol(params->protocol);
465 }
466 }
Bjorn A Mellem703ea952019-08-23 10:31:11 -0700467
468 EXPECT_TRUE(transport_controller_
469 ->SetLocalDescription(SdpType::kOffer, description.get())
470 .ok());
471 EXPECT_TRUE(transport_controller_
472 ->SetRemoteDescription(SdpType::kAnswer, description.get())
473 .ok());
474
475 FakeDatagramTransport* datagram_transport =
476 static_cast<FakeDatagramTransport*>(
477 transport_controller_->GetDataChannelTransport(kAudioMid1));
478
479 ASSERT_NE(nullptr, datagram_transport);
480
481 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
482 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
483 << "Datagram transport for media was not enabled, and so DTLS transport "
484 "should be created.";
485
486 // Datagram transport is not used for media, so no max packet size is
487 // specified.
488 EXPECT_EQ(transport_controller_->GetMediaTransportConfig(kAudioMid1)
489 .rtp_max_packet_size,
490 absl::nullopt);
491
492 // Since datagram transport is not used for RTP, setting it to writable should
493 // not make the RTP transport writable.
494 datagram_transport->set_state(MediaTransportState::kWritable);
495 EXPECT_FALSE(transport_controller_->GetRtpTransport(kAudioMid1)
496 ->IsWritable(/*rtcp=*/false));
497}
498
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700499// An offer that bundles different alt-protocols should be rejected.
500TEST_F(JsepTransportControllerTest, CannotBundleDifferentAltProtocols) {
501 FakeMediaTransportFactory fake_media_transport_factory("transport_params");
502 JsepTransportController::Config config;
503 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
504 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
505 config.media_transport_factory = &fake_media_transport_factory;
506 config.use_datagram_transport = true;
507 config.use_datagram_transport_for_data_channels = true;
508 CreateJsepTransportController(config);
509
510 auto description = CreateSessionDescriptionWithBundledData();
511 AddCryptoSettings(description.get());
512
513 absl::optional<cricket::OpaqueTransportParameters> params =
514 transport_controller_->GetTransportParameters(kAudioMid1);
515 for (auto& info : description->transport_infos()) {
516 info.description.opaque_parameters = params;
517 }
518
519 // Append a different alt-protocol to each of the sections.
520 for (cricket::ContentInfo& content_info : description->contents()) {
521 content_info.media_description()->set_alt_protocol(params->protocol + "-" +
522 content_info.name);
523 }
524
525 EXPECT_FALSE(transport_controller_
526 ->SetLocalDescription(SdpType::kOffer, description.get())
527 .ok());
528 EXPECT_FALSE(transport_controller_
529 ->SetRemoteDescription(SdpType::kAnswer, description.get())
530 .ok());
531}
532
Zhi Huange818b6e2018-02-22 15:26:27 -0800533TEST_F(JsepTransportControllerTest, SetIceConfig) {
534 CreateJsepTransportController(JsepTransportController::Config());
535 auto description = CreateSessionDescriptionWithoutBundle();
536 EXPECT_TRUE(transport_controller_
537 ->SetLocalDescription(SdpType::kOffer, description.get())
538 .ok());
539
540 transport_controller_->SetIceConfig(
541 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
542 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
543 transport_controller_->GetDtlsTransport(kAudioMid1));
544 ASSERT_NE(nullptr, fake_audio_dtls);
545 EXPECT_EQ(kTimeout,
546 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
547 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
548
549 // Test that value stored in controller is applied to new transports.
550 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
551 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
552 nullptr);
553
554 EXPECT_TRUE(transport_controller_
555 ->SetLocalDescription(SdpType::kOffer, description.get())
556 .ok());
557 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
558 transport_controller_->GetDtlsTransport(kAudioMid2));
559 ASSERT_NE(nullptr, fake_audio_dtls);
560 EXPECT_EQ(kTimeout,
561 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
562 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
563}
564
565// Tests the getter and setter of the ICE restart flag.
566TEST_F(JsepTransportControllerTest, NeedIceRestart) {
567 CreateJsepTransportController(JsepTransportController::Config());
568 auto description = CreateSessionDescriptionWithoutBundle();
569 EXPECT_TRUE(transport_controller_
570 ->SetLocalDescription(SdpType::kOffer, description.get())
571 .ok());
572 EXPECT_TRUE(transport_controller_
573 ->SetRemoteDescription(SdpType::kAnswer, description.get())
574 .ok());
575
576 // Initially NeedsIceRestart should return false.
577 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
578 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
579 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
580 // true.
581 transport_controller_->SetNeedsIceRestartFlag();
582 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
583 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
584 // For a nonexistent transport, false should be returned.
585 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
586
587 // Reset the ice_ufrag/ice_pwd for audio.
588 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
589 audio_transport_info->description.ice_ufrag = kIceUfrag2;
590 audio_transport_info->description.ice_pwd = kIcePwd2;
591 EXPECT_TRUE(transport_controller_
592 ->SetLocalDescription(SdpType::kOffer, description.get())
593 .ok());
594 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
595 // return false for audio and true for video.
596 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
597 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
598}
599
600TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
601 CreateJsepTransportController(JsepTransportController::Config());
602 auto description = CreateSessionDescriptionWithBundleGroup();
603 EXPECT_TRUE(transport_controller_
604 ->SetLocalDescription(SdpType::kOffer, description.get())
605 .ok());
606 // After setting the local description, we should be able to start gathering
607 // candidates.
608 transport_controller_->MaybeStartGathering();
609 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
610 EXPECT_EQ(1, gathering_state_signal_count_);
611}
612
613TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
614 CreateJsepTransportController(JsepTransportController::Config());
615 auto description = CreateSessionDescriptionWithoutBundle();
616 transport_controller_->SetLocalDescription(SdpType::kOffer,
617 description.get());
618 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
619 description.get());
620 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
621 transport_controller_->GetDtlsTransport(kAudioMid1));
622 ASSERT_NE(nullptr, fake_audio_dtls);
623 Candidates candidates;
624 candidates.push_back(
625 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
626 EXPECT_TRUE(
627 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
628 EXPECT_EQ(1U,
629 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
630
631 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
632 EXPECT_EQ(0U,
633 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
634}
635
636TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
637 CreateJsepTransportController(JsepTransportController::Config());
638
639 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
640 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
641 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
642 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
643
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200644 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800645 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
646 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
647 certificate1);
648
649 // Apply the local certificate.
650 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
651 // Apply the local description.
652 EXPECT_TRUE(transport_controller_
653 ->SetLocalDescription(SdpType::kOffer, description.get())
654 .ok());
655 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
656 EXPECT_TRUE(returned_certificate);
657 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
658 returned_certificate->identity()->certificate().ToPEMString());
659
660 // Should fail if called for a nonexistant transport.
661 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
662
663 // Shouldn't be able to change the identity once set.
664 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
665 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
666 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
667 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
668}
669
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800670TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800671 CreateJsepTransportController(JsepTransportController::Config());
672 auto description = CreateSessionDescriptionWithBundleGroup();
673 EXPECT_TRUE(transport_controller_
674 ->SetLocalDescription(SdpType::kOffer, description.get())
675 .ok());
676 rtc::FakeSSLCertificate fake_certificate("fake_data");
677
678 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
679 transport_controller_->GetDtlsTransport(kAudioMid1));
680 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800681 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
682 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
683 ASSERT_TRUE(returned_cert_chain);
684 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800685 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800686 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800687
688 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800689 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800690}
691
692TEST_F(JsepTransportControllerTest, GetDtlsRole) {
693 CreateJsepTransportController(JsepTransportController::Config());
694 auto offer_certificate =
695 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
696 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
697 auto answer_certificate =
698 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
699 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
700 transport_controller_->SetLocalCertificate(offer_certificate);
701
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200702 auto offer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800703 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
704 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
705 offer_certificate);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200706 auto answer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800707 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
708 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
709 answer_certificate);
710
711 EXPECT_TRUE(transport_controller_
712 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
713 .ok());
714
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200715 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800716 transport_controller_->GetDtlsRole(kAudioMid1);
717 // The DTLS role is not decided yet.
718 EXPECT_FALSE(role);
719 EXPECT_TRUE(transport_controller_
720 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
721 .ok());
722 role = transport_controller_->GetDtlsRole(kAudioMid1);
723
724 ASSERT_TRUE(role);
725 EXPECT_EQ(rtc::SSL_CLIENT, *role);
726}
727
728TEST_F(JsepTransportControllerTest, GetStats) {
729 CreateJsepTransportController(JsepTransportController::Config());
730 auto description = CreateSessionDescriptionWithBundleGroup();
731 EXPECT_TRUE(transport_controller_
732 ->SetLocalDescription(SdpType::kOffer, description.get())
733 .ok());
734
735 cricket::TransportStats stats;
736 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
737 EXPECT_EQ(kAudioMid1, stats.transport_name);
738 EXPECT_EQ(1u, stats.channel_stats.size());
739 // Return false for non-existing transport.
740 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
741}
742
743TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
744 CreateJsepTransportController(JsepTransportController::Config());
745 auto description = CreateSessionDescriptionWithoutBundle();
746 EXPECT_TRUE(transport_controller_
747 ->SetLocalDescription(SdpType::kOffer, description.get())
748 .ok());
749
750 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
751 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
752 fake_ice->SetCandidatesGatheringComplete();
753 fake_ice->SetConnectionCount(1);
754 // The connection stats will be failed if there is no active connection.
755 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +0000756 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100757 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000758 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
759 ice_connection_state_, kTimeout);
760 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100761 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
762 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200763 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800764}
765
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700766TEST_F(JsepTransportControllerTest,
767 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800768 CreateJsepTransportController(JsepTransportController::Config());
769 auto description = CreateSessionDescriptionWithoutBundle();
770 EXPECT_TRUE(transport_controller_
771 ->SetLocalDescription(SdpType::kOffer, description.get())
772 .ok());
773
774 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
775 transport_controller_->GetDtlsTransport(kAudioMid1));
776 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
777 transport_controller_->GetDtlsTransport(kVideoMid1));
778
779 // First, have one transport connect, and another fail, to ensure that
780 // the first transport connecting didn't trigger a "connected" state signal.
781 // We should only get a signal when all are connected.
782 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
783 fake_audio_dtls->SetWritable(true);
784 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
785 // Decrease the number of the connection to trigger the signal.
786 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
787 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
788 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
789
Alex Loiko9289eda2018-11-23 16:18:59 +0000790 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100791 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000792 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
793 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100794 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100795 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
796 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100797 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800798
Jonas Olsson635474e2018-10-18 15:58:17 +0200799 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
800 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800801 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
802 // the transport state to be STATE_CONNECTING.
803 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
804 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000805 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100806 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000807 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
808 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100809 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100810 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
811 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100812 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800813}
814
815TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
816 CreateJsepTransportController(JsepTransportController::Config());
817 auto description = CreateSessionDescriptionWithoutBundle();
818 EXPECT_TRUE(transport_controller_
819 ->SetLocalDescription(SdpType::kOffer, description.get())
820 .ok());
821
822 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
823 transport_controller_->GetDtlsTransport(kAudioMid1));
824 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
825 transport_controller_->GetDtlsTransport(kVideoMid1));
826
827 // First, have one transport connect, and another fail, to ensure that
828 // the first transport connecting didn't trigger a "connected" state signal.
829 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100830 fake_audio_dtls->fake_ice_transport()->SetTransportState(
831 IceTransportState::kCompleted,
832 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800833 fake_audio_dtls->SetWritable(true);
834 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100835
836 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
837 ice_connection_state_, kTimeout);
838 EXPECT_EQ(1, ice_connection_state_signal_count_);
839 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
840 combined_connection_state_, kTimeout);
841 EXPECT_EQ(1, combined_connection_state_signal_count_);
842
843 fake_video_dtls->fake_ice_transport()->SetTransportState(
844 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800845 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
846
Alex Loiko9289eda2018-11-23 16:18:59 +0000847 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100848 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000849 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
850 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100851 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100852 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
853 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100854 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800855
Jonas Olsson635474e2018-10-18 15:58:17 +0200856 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
857 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800858 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
859 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100860 fake_video_dtls->fake_ice_transport()->SetTransportState(
861 IceTransportState::kCompleted,
862 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800863 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000864 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +0100865 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000866 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
867 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100868 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100869 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
870 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100871 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800872}
873
874TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
875 CreateJsepTransportController(JsepTransportController::Config());
876 auto description = CreateSessionDescriptionWithoutBundle();
877 EXPECT_TRUE(transport_controller_
878 ->SetLocalDescription(SdpType::kOffer, description.get())
879 .ok());
880
881 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
882 transport_controller_->GetDtlsTransport(kAudioMid1));
883 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
884 // Should be in the gathering state as soon as any transport starts gathering.
885 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
886 EXPECT_EQ(1, gathering_state_signal_count_);
887}
888
889TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
890 CreateJsepTransportController(JsepTransportController::Config());
891 auto description = CreateSessionDescriptionWithoutBundle();
892 EXPECT_TRUE(transport_controller_
893 ->SetLocalDescription(SdpType::kOffer, description.get())
894 .ok());
895
896 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
897 transport_controller_->GetDtlsTransport(kAudioMid1));
898 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
899 transport_controller_->GetDtlsTransport(kVideoMid1));
900
901 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
902 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
903 EXPECT_EQ(1, gathering_state_signal_count_);
904
905 // Have one transport finish gathering, to make sure gathering
906 // completion wasn't signalled if only one transport finished gathering.
907 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
908 EXPECT_EQ(1, gathering_state_signal_count_);
909
910 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
911 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
912 EXPECT_EQ(1, gathering_state_signal_count_);
913
914 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
915 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
916 EXPECT_EQ(2, gathering_state_signal_count_);
917}
918
919// Test that when the last transport that hasn't finished connecting and/or
920// gathering is destroyed, the aggregate state jumps to "completed". This can
921// happen if, for example, we have an audio and video transport, the audio
922// transport completes, then we start bundling video on the audio transport.
923TEST_F(JsepTransportControllerTest,
924 SignalingWhenLastIncompleteTransportDestroyed) {
925 CreateJsepTransportController(JsepTransportController::Config());
926 auto description = CreateSessionDescriptionWithBundleGroup();
927 EXPECT_TRUE(transport_controller_
928 ->SetLocalDescription(SdpType::kOffer, description.get())
929 .ok());
930
931 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
932 transport_controller_->GetDtlsTransport(kAudioMid1));
933 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
934 transport_controller_->GetDtlsTransport(kVideoMid1));
935 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
936
937 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
938 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
939 EXPECT_EQ(1, gathering_state_signal_count_);
940
941 // Let the audio transport complete.
942 fake_audio_dtls->SetWritable(true);
943 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
944 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +0200945 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800946 EXPECT_EQ(1, gathering_state_signal_count_);
947
948 // Set the remote description and enable the bundle.
949 EXPECT_TRUE(transport_controller_
950 ->SetRemoteDescription(SdpType::kAnswer, description.get())
951 .ok());
952 // The BUNDLE should be enabled, the incomplete video transport should be
953 // deleted and the states shoud be updated.
954 fake_video_dtls = static_cast<FakeDtlsTransport*>(
955 transport_controller_->GetDtlsTransport(kVideoMid1));
956 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +0000957 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
958 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
959 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +0200960 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
961 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800962 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
963 EXPECT_EQ(2, gathering_state_signal_count_);
964}
965
966TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
967 CreateJsepTransportController(JsepTransportController::Config());
968 auto description = CreateSessionDescriptionWithBundleGroup();
969 EXPECT_TRUE(transport_controller_
970 ->SetLocalDescription(SdpType::kOffer, description.get())
971 .ok());
972 transport_controller_->MaybeStartGathering();
973
974 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
975 transport_controller_->GetDtlsTransport(kAudioMid1));
976 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
977 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
978 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
979 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
980}
981
982TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
983 network_thread_ = rtc::Thread::CreateWithSocketServer();
984 network_thread_->Start();
985 CreateJsepTransportController(JsepTransportController::Config(),
986 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 14:57:52 +0100987 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 15:26:27 -0800988 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
989
990 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +0000991 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -0800992 EXPECT_EQ(2, connection_state_signal_count_);
993
994 // new --> gathering --> complete
995 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
996 EXPECT_EQ(2, gathering_state_signal_count_);
997
998 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
999 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1000 EXPECT_EQ(2, candidates_signal_count_);
1001
1002 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1003}
1004
1005// Older versions of Chrome expect the ICE role to be re-determined when an
1006// ICE restart occurs, and also don't perform conflict resolution correctly,
1007// so for now we can't safely stop doing this.
1008// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1009// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1010// enough population.
1011TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1012 CreateJsepTransportController(JsepTransportController::Config());
1013 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001014 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001015 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1016 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1017 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001018 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001019 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1020 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1021 nullptr);
1022
1023 EXPECT_TRUE(transport_controller_
1024 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1025 .ok());
1026 EXPECT_TRUE(transport_controller_
1027 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1028 .ok());
1029
1030 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1031 transport_controller_->GetDtlsTransport(kAudioMid1));
1032 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1033 fake_dtls->fake_ice_transport()->GetIceRole());
1034
1035 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001036 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001037 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1038 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1039 nullptr);
1040 EXPECT_TRUE(
1041 transport_controller_
1042 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1043 .ok());
1044 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1045 fake_dtls->fake_ice_transport()->GetIceRole());
1046}
1047
1048// Test that if the TransportController was created with the
1049// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1050// redetermined on an ICE restart.
1051TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1052 JsepTransportController::Config config;
1053 config.redetermine_role_on_ice_restart = false;
1054
1055 CreateJsepTransportController(config);
1056 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001057 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001058 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1059 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1060 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001061 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001062 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1063 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1064 nullptr);
1065
1066 EXPECT_TRUE(transport_controller_
1067 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1068 .ok());
1069 EXPECT_TRUE(transport_controller_
1070 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1071 .ok());
1072
1073 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1074 transport_controller_->GetDtlsTransport(kAudioMid1));
1075 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1076 fake_dtls->fake_ice_transport()->GetIceRole());
1077
1078 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001079 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001080 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1081 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1082 nullptr);
1083 EXPECT_TRUE(
1084 transport_controller_
1085 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1086 .ok());
1087 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1088 fake_dtls->fake_ice_transport()->GetIceRole());
1089}
1090
1091// Tests ICE-Lite mode in remote answer.
1092TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1093 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001094 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001095 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1096 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1097 nullptr);
1098 EXPECT_TRUE(transport_controller_
1099 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1100 .ok());
1101 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1102 transport_controller_->GetDtlsTransport(kAudioMid1));
1103 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1104 fake_dtls->fake_ice_transport()->GetIceRole());
1105 EXPECT_EQ(cricket::ICEMODE_FULL,
1106 fake_dtls->fake_ice_transport()->remote_ice_mode());
1107
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001108 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001109 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1110 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1111 nullptr);
1112 EXPECT_TRUE(transport_controller_
1113 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1114 .ok());
1115 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1116 fake_dtls->fake_ice_transport()->GetIceRole());
1117 EXPECT_EQ(cricket::ICEMODE_LITE,
1118 fake_dtls->fake_ice_transport()->remote_ice_mode());
1119}
1120
1121// Tests that the ICE role remains "controlling" if a subsequent offer that
1122// does an ICE restart is received from an ICE lite endpoint. Regression test
1123// for: https://crbug.com/710760
1124TEST_F(JsepTransportControllerTest,
1125 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1126 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001127 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001128 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1129 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1130 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001131 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001132 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1133 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1134 nullptr);
1135 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1136 // local side is the controlling.
1137 EXPECT_TRUE(transport_controller_
1138 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1139 .ok());
1140 EXPECT_TRUE(transport_controller_
1141 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1142 .ok());
1143 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1144 transport_controller_->GetDtlsTransport(kAudioMid1));
1145 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1146 fake_dtls->fake_ice_transport()->GetIceRole());
1147
1148 // In the subsequence remote offer triggers an ICE restart.
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001149 auto remote_offer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001150 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1151 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1152 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001153 auto local_answer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001154 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1155 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1156 nullptr);
1157 EXPECT_TRUE(transport_controller_
1158 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1159 .ok());
1160 EXPECT_TRUE(transport_controller_
1161 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1162 .ok());
1163 fake_dtls = static_cast<FakeDtlsTransport*>(
1164 transport_controller_->GetDtlsTransport(kAudioMid1));
1165 // The local side is still the controlling role since the remote side is using
1166 // ICE-Lite.
1167 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1168 fake_dtls->fake_ice_transport()->GetIceRole());
1169}
1170
1171// Tests that the SDP has more than one audio/video m= sections.
1172TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1173 CreateJsepTransportController(JsepTransportController::Config());
1174 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1175 bundle_group.AddContentName(kAudioMid1);
1176 bundle_group.AddContentName(kAudioMid2);
1177 bundle_group.AddContentName(kVideoMid1);
1178 bundle_group.AddContentName(kDataMid1);
1179
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001180 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001181 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1182 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1183 nullptr);
1184 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1185 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1186 nullptr);
1187 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1188 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1189 nullptr);
1190 AddDataSection(local_offer.get(), kDataMid1,
1191 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1192 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1193 nullptr);
1194
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001195 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001196 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1197 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1198 nullptr);
1199 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1200 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1201 nullptr);
1202 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1203 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1204 nullptr);
1205 AddDataSection(remote_answer.get(), kDataMid1,
1206 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1207 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1208 nullptr);
1209
1210 local_offer->AddGroup(bundle_group);
1211 remote_answer->AddGroup(bundle_group);
1212
1213 EXPECT_TRUE(transport_controller_
1214 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1215 .ok());
1216 EXPECT_TRUE(transport_controller_
1217 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1218 .ok());
1219 // Verify that all the sections are bundled on kAudio1.
1220 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1221 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1222 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1223 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1224 EXPECT_EQ(transport1, transport2);
1225 EXPECT_EQ(transport1, transport3);
1226 EXPECT_EQ(transport1, transport4);
1227
Harald Alvestrandad88c882018-11-28 16:47:46 +01001228 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1229 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1230
Zhi Huange818b6e2018-02-22 15:26:27 -08001231 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1232 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1233 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1234 EXPECT_EQ(transport1, it->second);
1235 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1236 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1237 EXPECT_EQ(transport1, it->second);
1238 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1239 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1240 EXPECT_EQ(transport1, it->second);
1241 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1242 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1243 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
Zhi Huange818b6e2018-02-22 15:26:27 -08001244}
1245
1246// Tests that only a subset of all the m= sections are bundled.
1247TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1248 CreateJsepTransportController(JsepTransportController::Config());
1249 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1250 bundle_group.AddContentName(kAudioMid1);
1251 bundle_group.AddContentName(kVideoMid1);
1252
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001253 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001254 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1255 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1256 nullptr);
1257 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1258 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1259 nullptr);
1260 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1261 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1262 nullptr);
1263
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001264 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001265 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1266 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1267 nullptr);
1268 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1269 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1270 nullptr);
1271 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1272 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1273 nullptr);
1274
1275 local_offer->AddGroup(bundle_group);
1276 remote_answer->AddGroup(bundle_group);
1277 EXPECT_TRUE(transport_controller_
1278 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1279 .ok());
1280 EXPECT_TRUE(transport_controller_
1281 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1282 .ok());
1283
1284 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1285 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1286 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1287 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1288 EXPECT_NE(transport1, transport2);
1289 EXPECT_EQ(transport1, transport3);
1290
1291 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1292 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1293 EXPECT_EQ(transport1, it->second);
1294 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001295 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001296}
1297
1298// Tests that the initial offer/answer only have data section and audio/video
1299// sections are added in the subsequent offer.
1300TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1301 CreateJsepTransportController(JsepTransportController::Config());
1302 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1303 bundle_group.AddContentName(kDataMid1);
1304
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001305 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001306 AddDataSection(local_offer.get(), kDataMid1,
1307 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1308 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1309 nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001310 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001311 AddDataSection(remote_answer.get(), kDataMid1,
1312 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1313 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1314 nullptr);
1315 local_offer->AddGroup(bundle_group);
1316 remote_answer->AddGroup(bundle_group);
1317
1318 EXPECT_TRUE(transport_controller_
1319 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1320 .ok());
1321 EXPECT_TRUE(transport_controller_
1322 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1323 .ok());
1324 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1325
1326 // Add audio/video sections in subsequent offer.
1327 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1328 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1329 nullptr);
1330 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1331 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1332 nullptr);
1333 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1334 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1335 nullptr);
1336 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1337 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1338 nullptr);
1339
1340 // Reset the bundle group and do another offer/answer exchange.
1341 bundle_group.AddContentName(kAudioMid1);
1342 bundle_group.AddContentName(kVideoMid1);
1343 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1344 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1345 local_offer->AddGroup(bundle_group);
1346 remote_answer->AddGroup(bundle_group);
1347
1348 EXPECT_TRUE(transport_controller_
1349 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1350 .ok());
1351 EXPECT_TRUE(transport_controller_
1352 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1353 .ok());
1354
1355 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1356 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1357 EXPECT_EQ(data_transport, audio_transport);
1358 EXPECT_EQ(data_transport, video_transport);
1359}
1360
1361TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1362 CreateJsepTransportController(JsepTransportController::Config());
1363 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1364 bundle_group.AddContentName(kAudioMid1);
1365 bundle_group.AddContentName(kVideoMid1);
1366 bundle_group.AddContentName(kDataMid1);
1367
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001368 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001369 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1370 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1371 nullptr);
1372 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1373 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1374 nullptr);
1375 AddDataSection(local_offer.get(), kDataMid1,
1376 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1377 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1378 nullptr);
1379
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001380 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001381 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1382 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1383 nullptr);
1384 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1385 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1386 nullptr);
1387 AddDataSection(remote_answer.get(), kDataMid1,
1388 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1389 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1390 nullptr);
1391 // Reject video and data section.
1392 remote_answer->contents()[1].rejected = true;
1393 remote_answer->contents()[2].rejected = true;
1394
1395 local_offer->AddGroup(bundle_group);
1396 remote_answer->AddGroup(bundle_group);
1397
1398 EXPECT_TRUE(transport_controller_
1399 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1400 .ok());
1401 EXPECT_TRUE(transport_controller_
1402 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1403 .ok());
1404
1405 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1406 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1407 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1408 // Verify the signals are fired correctly.
1409 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1410 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1411 EXPECT_EQ(nullptr, it->second);
1412 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1413 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1414 EXPECT_EQ(nullptr, it2->second);
1415}
1416
1417// Tests that changing the bundled MID in subsequent offer/answer exchange is
1418// not supported.
1419// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1420// fixed
1421TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1422 CreateJsepTransportController(JsepTransportController::Config());
1423 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1424 bundle_group.AddContentName(kAudioMid1);
1425 bundle_group.AddContentName(kVideoMid1);
1426
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001427 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001428 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1429 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1430 nullptr);
1431 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1432 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1433 nullptr);
1434
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001435 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001436 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1437 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1438 nullptr);
1439 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1440 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1441 nullptr);
1442
1443 local_offer->AddGroup(bundle_group);
1444 remote_answer->AddGroup(bundle_group);
1445 EXPECT_TRUE(transport_controller_
1446 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1447 .ok());
1448 EXPECT_TRUE(transport_controller_
1449 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1450 .ok());
1451 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1452 transport_controller_->GetRtpTransport(kVideoMid1));
1453
1454 // Reorder the bundle group.
1455 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1456 bundle_group.AddContentName(kAudioMid1);
1457 // The answerer uses the new bundle group and now the bundle mid is changed to
1458 // |kVideo1|.
1459 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1460 remote_answer->AddGroup(bundle_group);
1461 EXPECT_TRUE(transport_controller_
1462 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1463 .ok());
1464 EXPECT_FALSE(transport_controller_
1465 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1466 .ok());
1467}
Zhi Huange830e682018-03-30 10:48:35 -07001468// Test that rejecting only the first m= section of a BUNDLE group is treated as
1469// an error, but rejecting all of them works as expected.
1470TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1471 CreateJsepTransportController(JsepTransportController::Config());
1472 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1473 bundle_group.AddContentName(kAudioMid1);
1474 bundle_group.AddContentName(kVideoMid1);
1475 bundle_group.AddContentName(kDataMid1);
1476
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001477 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001478 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1479 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1480 nullptr);
1481 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1482 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1483 nullptr);
1484 AddDataSection(local_offer.get(), kDataMid1,
1485 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1486 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1487 nullptr);
1488
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001489 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001490 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1491 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1492 nullptr);
1493 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1494 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1495 nullptr);
1496 AddDataSection(remote_answer.get(), kDataMid1,
1497 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1498 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1499 nullptr);
1500 // Reject audio content in answer.
1501 remote_answer->contents()[0].rejected = true;
1502
1503 local_offer->AddGroup(bundle_group);
1504 remote_answer->AddGroup(bundle_group);
1505
1506 EXPECT_TRUE(transport_controller_
1507 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1508 .ok());
1509 EXPECT_FALSE(transport_controller_
1510 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1511 .ok());
1512
1513 // Reject all the contents.
1514 remote_answer->contents()[1].rejected = true;
1515 remote_answer->contents()[2].rejected = true;
1516 EXPECT_TRUE(transport_controller_
1517 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1518 .ok());
1519 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1520 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1521 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1522}
1523
1524// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1525// is used.
1526TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1527 JsepTransportController::Config config;
1528 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1529 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001530 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001531 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1532 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1533 nullptr);
1534
1535 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1536 // Applying a non-RTCP-mux offer is expected to fail.
1537 EXPECT_FALSE(transport_controller_
1538 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1539 .ok());
1540}
1541
1542// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1543// is used.
1544TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1545 JsepTransportController::Config config;
1546 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1547 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001548 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001549 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1550 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1551 nullptr);
1552 EXPECT_TRUE(transport_controller_
1553 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1554 .ok());
1555
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001556 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001557 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1558 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1559 nullptr);
1560 // Applying a non-RTCP-mux answer is expected to fail.
1561 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1562 EXPECT_FALSE(transport_controller_
1563 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1564 .ok());
1565}
Zhi Huange818b6e2018-02-22 15:26:27 -08001566
Zhi Huangd2248f82018-04-10 14:41:03 -07001567// This tests that the BUNDLE group in answer should be a subset of the offered
1568// group.
1569TEST_F(JsepTransportControllerTest,
1570 AddContentToBundleGroupInAnswerNotSupported) {
1571 CreateJsepTransportController(JsepTransportController::Config());
1572 auto local_offer = CreateSessionDescriptionWithoutBundle();
1573 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1574
1575 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1576 offer_bundle_group.AddContentName(kAudioMid1);
1577 local_offer->AddGroup(offer_bundle_group);
1578
1579 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1580 answer_bundle_group.AddContentName(kAudioMid1);
1581 answer_bundle_group.AddContentName(kVideoMid1);
1582 remote_answer->AddGroup(answer_bundle_group);
1583 EXPECT_TRUE(transport_controller_
1584 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1585 .ok());
1586 EXPECT_FALSE(transport_controller_
1587 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1588 .ok());
1589}
1590
1591// This tests that the BUNDLE group with non-existing MID should be rejectd.
1592TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1593 CreateJsepTransportController(JsepTransportController::Config());
1594 auto local_offer = CreateSessionDescriptionWithoutBundle();
1595 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1596
1597 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1598 // The BUNDLE group is invalid because there is no data section in the
1599 // description.
1600 invalid_bundle_group.AddContentName(kDataMid1);
1601 local_offer->AddGroup(invalid_bundle_group);
1602 remote_answer->AddGroup(invalid_bundle_group);
1603
1604 EXPECT_FALSE(transport_controller_
1605 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1606 .ok());
1607 EXPECT_FALSE(transport_controller_
1608 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1609 .ok());
1610}
1611
1612// This tests that an answer shouldn't be able to remove an m= section from an
1613// established group without rejecting it.
1614TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1615 CreateJsepTransportController(JsepTransportController::Config());
1616
1617 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1618 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1619 EXPECT_TRUE(transport_controller_
1620 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1621 .ok());
1622 EXPECT_TRUE(transport_controller_
1623 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1624 .ok());
1625
1626 // Do an re-offer/answer.
1627 EXPECT_TRUE(transport_controller_
1628 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1629 .ok());
1630 auto new_answer = CreateSessionDescriptionWithoutBundle();
1631 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1632 // The answer removes video from the BUNDLE group without rejecting it is
1633 // invalid.
1634 new_bundle_group.AddContentName(kAudioMid1);
1635 new_answer->AddGroup(new_bundle_group);
1636
1637 // Applying invalid answer is expected to fail.
1638 EXPECT_FALSE(transport_controller_
1639 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1640 .ok());
1641
1642 // Rejected the video content.
1643 auto video_content = new_answer->GetContentByName(kVideoMid1);
1644 ASSERT_TRUE(video_content);
1645 video_content->rejected = true;
1646 EXPECT_TRUE(transport_controller_
1647 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1648 .ok());
1649}
1650
Steve Anton2bed3972019-01-04 17:04:30 -08001651// Test that the JsepTransportController can process a new local and remote
1652// description that changes the tagged BUNDLE group with the max-bundle policy
1653// specified.
1654// This is a regression test for bugs.webrtc.org/9954
1655TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
1656 CreateJsepTransportController(JsepTransportController::Config());
1657
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001658 auto local_offer = std::make_unique<cricket::SessionDescription>();
Steve Anton2bed3972019-01-04 17:04:30 -08001659 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1660 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1661 nullptr);
1662 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1663 bundle_group.AddContentName(kAudioMid1);
1664 local_offer->AddGroup(bundle_group);
1665 EXPECT_TRUE(transport_controller_
1666 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1667 .ok());
1668
1669 std::unique_ptr<cricket::SessionDescription> remote_answer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001670 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08001671 EXPECT_TRUE(transport_controller_
1672 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1673 .ok());
1674
1675 std::unique_ptr<cricket::SessionDescription> local_reoffer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001676 local_offer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08001677 local_reoffer->contents()[0].rejected = true;
1678 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
1679 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1680 nullptr);
1681 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1682 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1683 new_bundle_group.AddContentName(kVideoMid1);
1684 local_reoffer->AddGroup(new_bundle_group);
1685
1686 EXPECT_TRUE(transport_controller_
1687 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
1688 .ok());
1689
1690 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001691 local_reoffer->Clone());
Steve Anton2bed3972019-01-04 17:04:30 -08001692 EXPECT_TRUE(
1693 transport_controller_
1694 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
1695 .ok());
1696}
1697
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001698constexpr char kFakeTransportParameters[] = "fake-params";
1699
1700// Test fixture that provides common setup and helpers for tests related to the
1701// datagram transport.
1702class JsepTransportControllerDatagramTest
1703 : public JsepTransportControllerTest,
1704 public testing::WithParamInterface<bool> {
1705 public:
1706 JsepTransportControllerDatagramTest()
1707 : JsepTransportControllerTest(),
1708 fake_media_transport_factory_(kFakeTransportParameters) {
1709 JsepTransportController::Config config;
1710 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1711 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
1712 config.media_transport_factory = &fake_media_transport_factory_;
1713 config.use_datagram_transport = true;
1714 CreateJsepTransportController(config);
1715 }
1716
1717 // Whether the JsepTransportController under test acts as the offerer or
1718 // answerer in this test.
1719 bool IsOfferer() { return GetParam(); }
1720
1721 // Sets a description as local or remote based on type and current
1722 // perspective.
1723 RTCError SetDescription(SdpType type,
1724 const cricket::SessionDescription* description) {
1725 if (IsOfferer() == (type == SdpType::kOffer)) {
1726 return transport_controller_->SetLocalDescription(type, description);
1727 } else {
1728 return transport_controller_->SetRemoteDescription(type, description);
1729 }
1730 }
1731
1732 // Creates a session description with the settings necessary for datagram
1733 // transport (bundle + crypto) and the given |transport_params|.
1734 std::unique_ptr<cricket::SessionDescription>
1735 CreateSessionDescriptionForDatagramTransport(
1736 absl::optional<cricket::OpaqueTransportParameters> transport_params) {
1737 auto description = CreateSessionDescriptionWithBundleGroup();
1738 AddCryptoSettings(description.get());
1739
1740 for (auto& info : description->transport_infos()) {
1741 info.description.opaque_parameters = transport_params;
1742 }
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07001743 if (transport_params) {
1744 for (auto& content_info : description->contents()) {
1745 content_info.media_description()->set_alt_protocol(
1746 transport_params->protocol);
1747 }
1748 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001749 return description;
1750 }
1751
1752 // Creates transport parameters with |protocol| and |parameters|
1753 // matching what |fake_media_transport_factory_| provides.
1754 cricket::OpaqueTransportParameters CreateTransportParameters() {
1755 cricket::OpaqueTransportParameters params;
1756 params.protocol = fake_media_transport_factory_.GetTransportName();
1757 params.parameters = "fake-params";
1758 return params;
1759 }
1760
1761 protected:
1762 FakeMediaTransportFactory fake_media_transport_factory_;
1763};
1764
1765TEST_P(JsepTransportControllerDatagramTest, InitDatagramTransport) {
1766 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1767 if (IsOfferer()) {
1768 // Getting transport parameters is allowed before setting a description.
1769 // This is necessary so that the offerer can include these params.
1770 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1771 fake_params);
1772 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1773 fake_params);
1774 }
1775
1776 // Setting a description activates the datagram transport without changing
1777 // transport parameters.
1778 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
1779 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
1780
1781 // After setting an offer with transport parameters, those parameters are
1782 // reflected by the controller.
1783 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1784 fake_params);
1785 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1786 fake_params);
1787}
1788
1789TEST_P(JsepTransportControllerDatagramTest,
1790 OfferMissingDatagramTransportParams) {
1791 if (IsOfferer()) {
1792 // This test doesn't make sense from the offerer's perspective, as the offer
1793 // must contain datagram transport params if the offerer supports it.
1794 return;
1795 }
1796
1797 auto description =
1798 CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1799 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
1800
1801 // The offer didn't contain any datagram transport parameters, so the answer
1802 // won't either.
1803 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1804 absl::nullopt);
1805 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1806 absl::nullopt);
1807}
1808
1809TEST_P(JsepTransportControllerDatagramTest, OfferHasWrongTransportName) {
1810 if (IsOfferer()) {
1811 // This test doesn't make sense from the offerer's perspective, as the
1812 // offerer cannot offer itself the wrong transport.
1813 return;
1814 }
1815
1816 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1817 fake_params.protocol = "wrong-name";
1818
1819 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
1820 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
1821
1822 // The offerer and answerer support different datagram transports, so the
1823 // answerer rejects the offered parameters.
1824 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1825 absl::nullopt);
1826 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1827 absl::nullopt);
1828}
1829
1830TEST_P(JsepTransportControllerDatagramTest, AnswerRejectsDatagram) {
1831 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1832 if (IsOfferer()) {
1833 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1834 fake_params);
1835 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1836 fake_params);
1837 }
1838
1839 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1840 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1841
1842 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1843 fake_params);
1844 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1845 fake_params);
1846
1847 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1848 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1849
1850 // The answer rejected datagram transport, so its parameters are empty.
1851 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1852 absl::nullopt);
1853 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1854 absl::nullopt);
1855}
1856
1857TEST_P(JsepTransportControllerDatagramTest, AnswerAcceptsDatagram) {
1858 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1859 if (IsOfferer()) {
1860 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1861 fake_params);
1862 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1863 fake_params);
1864 }
1865
1866 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1867 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1868
1869 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1870 fake_params);
1871 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1872 fake_params);
1873
1874 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
1875 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1876
1877 // The answer accepted datagram transport, so it is present.
1878 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1879 fake_params);
1880 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1881 fake_params);
1882}
1883
1884TEST_P(JsepTransportControllerDatagramTest, PrAnswerRejectsDatagram) {
1885 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1886 if (IsOfferer()) {
1887 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1888 fake_params);
1889 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1890 fake_params);
1891 }
1892
1893 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1894 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1895
1896 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1897 fake_params);
1898 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1899 fake_params);
1900
1901 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1902 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
1903
1904 // The answer rejected datagram transport, but it's provisional, so the
1905 // transport is kept around for now.
1906 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1907 fake_params);
1908 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1909 fake_params);
1910}
1911
1912TEST_P(JsepTransportControllerDatagramTest, PrAnswerAcceptsDatagram) {
1913 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1914 if (IsOfferer()) {
1915 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1916 fake_params);
1917 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1918 fake_params);
1919 }
1920
1921 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1922 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1923
1924 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1925 fake_params);
1926 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1927 fake_params);
1928
1929 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
1930 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
1931
1932 // The answer provisionally accepted datagram transport, so it's kept.
1933 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1934 fake_params);
1935 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1936 fake_params);
1937}
1938
1939TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotAddDatagram) {
1940 auto offer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1941 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1942
1943 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1944 absl::nullopt);
1945 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1946 absl::nullopt);
1947
1948 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1949 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1950
1951 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1952 absl::nullopt);
1953 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1954 absl::nullopt);
1955
1956 // Attempting to add a datagram transport on a re-offer does not cause an
1957 // error, but also does not add a datagram transport.
1958 auto reoffer =
1959 CreateSessionDescriptionForDatagramTransport(CreateTransportParameters());
1960 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
1961
1962 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1963 absl::nullopt);
1964 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1965 absl::nullopt);
1966}
1967
1968TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotRemoveDatagram) {
1969 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1970 if (IsOfferer()) {
1971 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1972 fake_params);
1973 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1974 fake_params);
1975 }
1976
1977 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1978 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1979
1980 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1981 fake_params);
1982 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1983 fake_params);
1984
1985 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
1986 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1987
1988 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1989 fake_params);
1990 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1991 fake_params);
1992
1993 // Attempting to remove a datagram transport on a re-offer does not cause an
1994 // error, but also does not remove the datagram transport.
1995 auto reoffer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1996 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
1997
1998 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1999 fake_params);
2000 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2001 fake_params);
2002}
2003
2004TEST_P(JsepTransportControllerDatagramTest,
2005 RenegotiationKeepsDatagramTransport) {
2006 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2007 if (IsOfferer()) {
2008 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2009 fake_params);
2010 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2011 fake_params);
2012 }
2013
2014 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2015 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2016
2017 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2018 fake_params);
2019 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2020 fake_params);
2021
2022 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2023 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2024
2025 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2026 fake_params);
2027 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2028 fake_params);
2029
2030 // Attempting to remove a datagram transport on a re-offer does not cause an
2031 // error, but also does not remove the datagram transport.
2032 auto reoffer = CreateSessionDescriptionForDatagramTransport(fake_params);
2033 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2034
2035 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2036 fake_params);
2037 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2038 fake_params);
2039
2040 auto reanswer = CreateSessionDescriptionForDatagramTransport(fake_params);
2041 EXPECT_TRUE(SetDescription(SdpType::kAnswer, reanswer.get()).ok());
2042
2043 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2044 fake_params);
2045 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2046 fake_params);
2047}
2048
2049INSTANTIATE_TEST_SUITE_P(
2050 JsepTransportControllerDatagramTests,
2051 JsepTransportControllerDatagramTest,
2052 testing::Values(true, false),
2053 // The parameter value is the local perspective (offerer or answerer).
2054 [](const testing::TestParamInfo<bool>& info) {
2055 return info.param ? "Offerer" : "Answerer";
2056 });
2057
Zhi Huange818b6e2018-02-22 15:26:27 -08002058} // namespace webrtc