blob: 3fc6f8b7e55418c842e01ce8619367e505555cbf [file] [log] [blame]
Zhi Huange818b6e2018-02-22 23:26:271/*
2 * Copyright 2018 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Jonas Olssona4d87372019-07-05 17:08:3311#include "pc/jsep_transport_controller.h"
12
Zhi Huange818b6e2018-02-22 23:26:2713#include <map>
14#include <memory>
15
Anton Sukhanov7940da02018-10-10 17:34:4916#include "api/test/fake_media_transport.h"
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:0517#include "api/test/loopback_media_transport.h"
Niels Möller65f17ca2019-09-12 11:59:3618#include "api/transport/media/media_transport_interface.h"
Qingsi Wang25ec8882019-11-15 20:33:0519#include "p2p/base/dtls_transport_factory.h"
Steve Anton10542f22019-01-11 17:11:0020#include "p2p/base/fake_dtls_transport.h"
21#include "p2p/base/fake_ice_transport.h"
Steve Anton10542f22019-01-11 17:11:0022#include "p2p/base/transport_info.h"
Zhi Huange818b6e2018-02-22 23:26:2723#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 23:26:2724#include "rtc_base/thread.h"
25#include "test/gtest.h"
26
Zhi Huange818b6e2018-02-22 23:26:2727using cricket::Candidate;
28using cricket::Candidates;
Jonas Olssona4d87372019-07-05 17:08:3329using cricket::FakeDtlsTransport;
Zhi Huange818b6e2018-02-22 23:26:2730using 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 15:25:2647namespace {
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 20:33:0561class FakeIceTransportFactory : public webrtc::IceTransportFactory {
Zhi Huange818b6e2018-02-22 23:26:2762 public:
Qingsi Wang25ec8882019-11-15 20:33:0563 ~FakeIceTransportFactory() override = default;
64 rtc::scoped_refptr<IceTransportInterface> CreateIceTransport(
Zhi Huange818b6e2018-02-22 23:26:2765 const std::string& transport_name,
Qingsi Wang25ec8882019-11-15 20:33:0566 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 23:26:2770 }
Qingsi Wang25ec8882019-11-15 20:33:0571};
Zhi Huange818b6e2018-02-22 23:26:2772
Qingsi Wang25ec8882019-11-15 20:33:0573class FakeDtlsTransportFactory : public cricket::DtlsTransportFactory {
74 public:
Zhi Huange818b6e2018-02-22 23:26:2775 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-30 00:34:1376 cricket::IceTransportInternal* ice,
Benjamin Wrighta54daf12018-10-11 22:33:1777 const webrtc::CryptoOptions& crypto_options) override {
Mirko Bonadei317a1f02019-09-17 15:06:1878 return std::make_unique<FakeDtlsTransport>(
Bjorn A Mellem0c1c1b42019-05-30 00:34:1379 static_cast<cricket::FakeIceTransport*>(ice));
Zhi Huange818b6e2018-02-22 23:26:2780 }
81};
82
Zhi Huang365381f2018-04-13 23:44:3483class JsepTransportControllerTest : public JsepTransportController::Observer,
Mirko Bonadei6a489f22019-04-09 13:11:1284 public ::testing::Test,
Zhi Huange818b6e2018-02-22 23:26:2785 public sigslot::has_slots<> {
86 public:
87 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Qingsi Wang25ec8882019-11-15 20:33:0588 fake_ice_transport_factory_ = std::make_unique<FakeIceTransportFactory>();
89 fake_dtls_transport_factory_ = std::make_unique<FakeDtlsTransportFactory>();
Zhi Huange818b6e2018-02-22 23:26:2790 }
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 23:44:3497 config.transport_observer = this;
Sebastian Jansson1b83a9e2019-09-18 16:22:1298 config.rtcp_handler = [](const rtc::CopyOnWriteBuffer& packet,
99 int64_t packet_time_us) { RTC_NOTREACHED(); };
Qingsi Wang25ec8882019-11-15 20:33:05100 config.ice_transport_factory = fake_ice_transport_factory_.get();
101 config.dtls_transport_factory = fake_dtls_transport_factory_.get();
Mirko Bonadei317a1f02019-09-17 15:06:18102 transport_controller_ = std::make_unique<JsepTransportController>(
Qingsi Wange8d54b92020-01-06 22:31:57103 signaling_thread, network_thread, port_allocator,
104 nullptr /* async_resolver_factory */, config);
Zhi Huange818b6e2018-02-22 23:26:27105 ConnectTransportControllerSignals();
106 }
107
108 void ConnectTransportControllerSignals() {
109 transport_controller_->SignalIceConnectionState.connect(
110 this, &JsepTransportControllerTest::OnConnectionState);
Alex Loiko9289eda2018-11-23 16:18:59111 transport_controller_->SignalStandardizedIceConnectionState.connect(
112 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 13:58:17113 transport_controller_->SignalConnectionState.connect(
114 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 23:26:27115 transport_controller_->SignalIceGatheringState.connect(
116 this, &JsepTransportControllerTest::OnGatheringState);
117 transport_controller_->SignalIceCandidatesGathered.connect(
118 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 23:26:27119 }
120
121 std::unique_ptr<cricket::SessionDescription>
122 CreateSessionDescriptionWithoutBundle() {
Mirko Bonadei317a1f02019-09-17 15:06:18123 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27124 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 22:12:47144 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 23:26:27159 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 17:48:35168 // Set RTCP-mux to be true because the default policy is "mux required".
169 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 23:26:27170 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 18:35:45171 /*rejected=*/false, std::move(audio));
Zhi Huange818b6e2018-02-22 23:26:27172 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 17:48:35184 // Set RTCP-mux to be true because the default policy is "mux required".
185 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 23:26:27186 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 18:35:45187 /*rejected=*/false, std::move(video));
Zhi Huange818b6e2018-02-22 23:26:27188 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 11:36:16199 RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp);
200 std::unique_ptr<cricket::SctpDataContentDescription> data(
201 new cricket::SctpDataContentDescription());
Zhi Huange830e682018-03-30 17:48:35202 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 23:26:27203 description->AddContent(mid, protocol_type,
Harald Alvestrand1716d392019-06-03 18:35:45204 /*rejected=*/false, std::move(data));
Zhi Huange818b6e2018-02-22 23:26:27205 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-16 02:27:44217 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 23:26:27218 }
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:59282 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 23:26:27283 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:59290 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 13:58:17299 void OnCombinedConnectionState(
300 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 12:11:44301 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
302 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 13:58:17303 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 23:26:27310 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 23:44:34328 // JsepTransportController::Observer overrides.
Bjorn A Mellemb689af42019-08-21 17:44:59329 bool OnTransportChanged(
330 const std::string& mid,
331 RtpTransportInternal* rtp_transport,
332 rtc::scoped_refptr<DtlsTransport> dtls_transport,
Bjorn A Mellembc3eebc2019-09-23 21:53:54333 DataChannelTransportInterface* data_channel_transport) override {
Taylor Brandstettercbaa2542018-04-16 23:42:14334 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 06:51:00335 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 23:42:14340 return true;
Zhi Huange818b6e2018-02-22 23:26:27341 }
342
343 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59344 cricket::IceConnectionState connection_state_ =
345 cricket::kIceConnectionConnecting;
346 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 13:58:17347 PeerConnectionInterface::kIceConnectionNew;
348 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
349 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 23:26:27350 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:59356 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 13:58:17357 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 23:26:27358 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 20:33:05364 std::unique_ptr<FakeIceTransportFactory> fake_ice_transport_factory_;
365 std::unique_ptr<FakeDtlsTransportFactory> fake_dtls_transport_factory_;
Zhi Huange818b6e2018-02-22 23:26:27366 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 16:26:19373
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 23:26:27377};
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 15:47:46404 EXPECT_NE(nullptr,
405 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 23:26:27406 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
407 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 15:47:46408 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 23:26:27413 // 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 15:47:46416 EXPECT_EQ(nullptr,
417 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 09:55:20418 // 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 23:26:27427}
428
Zhi Huange830e682018-03-30 17:48:35429TEST_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 21:31:15441}
442
Bjorn A Mellem703ea952019-08-23 17:31:11443TEST_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 22:12:47454 auto description = CreateSessionDescriptionWithBundledData();
Bjorn A Mellem703ea952019-08-23 17:31:11455 AddCryptoSettings(description.get());
Bjorn A Mellem8e1343a2019-09-30 22:12:47456
Bjorn A Mellem703ea952019-08-23 17:31:11457 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 22:12:47462 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 17:31:11467
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 22:12:47499// 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 23:26:27533TEST_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 =
Harald Alvestrand8515d5a2020-03-20 21:51:32640 rtc::RTCCertificate::Create(
641 rtc::SSLIdentity::Create("session1", rtc::KT_DEFAULT));
Zhi Huange818b6e2018-02-22 23:26:27642 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
643
Mirko Bonadei317a1f02019-09-17 15:06:18644 auto description = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27645 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 =
Harald Alvestrand8515d5a2020-03-20 21:51:32665 rtc::RTCCertificate::Create(
666 rtc::SSLIdentity::Create("session2", rtc::KT_DEFAULT));
Zhi Huange818b6e2018-02-22 23:26:27667 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
668}
669
Taylor Brandstetterc3928662018-02-23 21:04:51670TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 23:26:27671 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 21:04:51681 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 23:26:27685 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 21:04:51686 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 23:26:27687
688 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 21:04:51689 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 23:26:27690}
691
692TEST_F(JsepTransportControllerTest, GetDtlsRole) {
693 CreateJsepTransportController(JsepTransportController::Config());
Harald Alvestrand8515d5a2020-03-20 21:51:32694 auto offer_certificate = rtc::RTCCertificate::Create(
695 rtc::SSLIdentity::Create("offer", rtc::KT_DEFAULT));
696 auto answer_certificate = rtc::RTCCertificate::Create(
697 rtc::SSLIdentity::Create("answer", rtc::KT_DEFAULT));
Zhi Huange818b6e2018-02-22 23:26:27698 transport_controller_->SetLocalCertificate(offer_certificate);
699
Mirko Bonadei317a1f02019-09-17 15:06:18700 auto offer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27701 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
702 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
703 offer_certificate);
Mirko Bonadei317a1f02019-09-17 15:06:18704 auto answer_desc = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:27705 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
706 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
707 answer_certificate);
708
709 EXPECT_TRUE(transport_controller_
710 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
711 .ok());
712
Danil Chapovalov66cadcc2018-06-19 14:47:43713 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 23:26:27714 transport_controller_->GetDtlsRole(kAudioMid1);
715 // The DTLS role is not decided yet.
716 EXPECT_FALSE(role);
717 EXPECT_TRUE(transport_controller_
718 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
719 .ok());
720 role = transport_controller_->GetDtlsRole(kAudioMid1);
721
722 ASSERT_TRUE(role);
723 EXPECT_EQ(rtc::SSL_CLIENT, *role);
724}
725
726TEST_F(JsepTransportControllerTest, GetStats) {
727 CreateJsepTransportController(JsepTransportController::Config());
728 auto description = CreateSessionDescriptionWithBundleGroup();
729 EXPECT_TRUE(transport_controller_
730 ->SetLocalDescription(SdpType::kOffer, description.get())
731 .ok());
732
733 cricket::TransportStats stats;
734 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
735 EXPECT_EQ(kAudioMid1, stats.transport_name);
736 EXPECT_EQ(1u, stats.channel_stats.size());
737 // Return false for non-existing transport.
738 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
739}
740
741TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
742 CreateJsepTransportController(JsepTransportController::Config());
743 auto description = CreateSessionDescriptionWithoutBundle();
744 EXPECT_TRUE(transport_controller_
745 ->SetLocalDescription(SdpType::kOffer, description.get())
746 .ok());
747
748 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
749 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
750 fake_ice->SetCandidatesGatheringComplete();
751 fake_ice->SetConnectionCount(1);
752 // The connection stats will be failed if there is no active connection.
753 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59754 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 15:50:37755 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59756 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
757 ice_connection_state_, kTimeout);
758 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 09:51:09759 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
760 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 13:58:17761 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 23:26:27762}
763
Piotr (Peter) Slatala4eb41122018-11-01 14:26:03764TEST_F(JsepTransportControllerTest,
765 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 23:26:27766 CreateJsepTransportController(JsepTransportController::Config());
767 auto description = CreateSessionDescriptionWithoutBundle();
768 EXPECT_TRUE(transport_controller_
769 ->SetLocalDescription(SdpType::kOffer, description.get())
770 .ok());
771
772 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
773 transport_controller_->GetDtlsTransport(kAudioMid1));
774 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
775 transport_controller_->GetDtlsTransport(kVideoMid1));
776
777 // First, have one transport connect, and another fail, to ensure that
778 // the first transport connecting didn't trigger a "connected" state signal.
779 // We should only get a signal when all are connected.
780 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
781 fake_audio_dtls->SetWritable(true);
782 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
783 // Decrease the number of the connection to trigger the signal.
784 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
785 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
786 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
787
Alex Loiko9289eda2018-11-23 16:18:59788 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 15:50:37789 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59790 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
791 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:44792 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 09:51:09793 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
794 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:44795 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 23:26:27796
Jonas Olsson635474e2018-10-18 13:58:17797 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
798 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 23:26:27799 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
800 // the transport state to be STATE_CONNECTING.
801 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
802 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59803 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 15:50:37804 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59805 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
806 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:44807 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 09:51:09808 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
809 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:44810 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 23:26:27811}
812
813TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
814 CreateJsepTransportController(JsepTransportController::Config());
815 auto description = CreateSessionDescriptionWithoutBundle();
816 EXPECT_TRUE(transport_controller_
817 ->SetLocalDescription(SdpType::kOffer, description.get())
818 .ok());
819
820 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
821 transport_controller_->GetDtlsTransport(kAudioMid1));
822 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
823 transport_controller_->GetDtlsTransport(kVideoMid1));
824
825 // First, have one transport connect, and another fail, to ensure that
826 // the first transport connecting didn't trigger a "connected" state signal.
827 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 12:11:44828 fake_audio_dtls->fake_ice_transport()->SetTransportState(
829 IceTransportState::kCompleted,
830 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 23:26:27831 fake_audio_dtls->SetWritable(true);
832 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 12:11:44833
834 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
835 ice_connection_state_, kTimeout);
836 EXPECT_EQ(1, ice_connection_state_signal_count_);
837 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
838 combined_connection_state_, kTimeout);
839 EXPECT_EQ(1, combined_connection_state_signal_count_);
840
841 fake_video_dtls->fake_ice_transport()->SetTransportState(
842 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 23:26:27843 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
844
Alex Loiko9289eda2018-11-23 16:18:59845 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 15:50:37846 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59847 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
848 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:44849 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 09:51:09850 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
851 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:44852 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 23:26:27853
Jonas Olsson635474e2018-10-18 13:58:17854 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
855 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 23:26:27856 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
857 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 12:11:44858 fake_video_dtls->fake_ice_transport()->SetTransportState(
859 IceTransportState::kCompleted,
860 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 23:26:27861 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59862 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 15:31:55863 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59864 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
865 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:44866 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 09:51:09867 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
868 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 12:11:44869 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 23:26:27870}
871
872TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
873 CreateJsepTransportController(JsepTransportController::Config());
874 auto description = CreateSessionDescriptionWithoutBundle();
875 EXPECT_TRUE(transport_controller_
876 ->SetLocalDescription(SdpType::kOffer, description.get())
877 .ok());
878
879 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
880 transport_controller_->GetDtlsTransport(kAudioMid1));
881 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
882 // Should be in the gathering state as soon as any transport starts gathering.
883 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
884 EXPECT_EQ(1, gathering_state_signal_count_);
885}
886
887TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
888 CreateJsepTransportController(JsepTransportController::Config());
889 auto description = CreateSessionDescriptionWithoutBundle();
890 EXPECT_TRUE(transport_controller_
891 ->SetLocalDescription(SdpType::kOffer, description.get())
892 .ok());
893
894 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
895 transport_controller_->GetDtlsTransport(kAudioMid1));
896 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
897 transport_controller_->GetDtlsTransport(kVideoMid1));
898
899 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
900 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
901 EXPECT_EQ(1, gathering_state_signal_count_);
902
903 // Have one transport finish gathering, to make sure gathering
904 // completion wasn't signalled if only one transport finished gathering.
905 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
906 EXPECT_EQ(1, gathering_state_signal_count_);
907
908 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
909 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
910 EXPECT_EQ(1, gathering_state_signal_count_);
911
912 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
913 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
914 EXPECT_EQ(2, gathering_state_signal_count_);
915}
916
917// Test that when the last transport that hasn't finished connecting and/or
918// gathering is destroyed, the aggregate state jumps to "completed". This can
919// happen if, for example, we have an audio and video transport, the audio
920// transport completes, then we start bundling video on the audio transport.
921TEST_F(JsepTransportControllerTest,
922 SignalingWhenLastIncompleteTransportDestroyed) {
923 CreateJsepTransportController(JsepTransportController::Config());
924 auto description = CreateSessionDescriptionWithBundleGroup();
925 EXPECT_TRUE(transport_controller_
926 ->SetLocalDescription(SdpType::kOffer, description.get())
927 .ok());
928
929 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
930 transport_controller_->GetDtlsTransport(kAudioMid1));
931 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
932 transport_controller_->GetDtlsTransport(kVideoMid1));
933 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
934
935 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
936 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
937 EXPECT_EQ(1, gathering_state_signal_count_);
938
939 // Let the audio transport complete.
940 fake_audio_dtls->SetWritable(true);
941 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
942 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 13:58:17943 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 23:26:27944 EXPECT_EQ(1, gathering_state_signal_count_);
945
946 // Set the remote description and enable the bundle.
947 EXPECT_TRUE(transport_controller_
948 ->SetRemoteDescription(SdpType::kAnswer, description.get())
949 .ok());
950 // The BUNDLE should be enabled, the incomplete video transport should be
951 // deleted and the states shoud be updated.
952 fake_video_dtls = static_cast<FakeDtlsTransport*>(
953 transport_controller_->GetDtlsTransport(kVideoMid1));
954 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59955 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
956 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
957 ice_connection_state_);
Jonas Olsson635474e2018-10-18 13:58:17958 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
959 combined_connection_state_);
Zhi Huange818b6e2018-02-22 23:26:27960 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
961 EXPECT_EQ(2, gathering_state_signal_count_);
962}
963
964TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
965 CreateJsepTransportController(JsepTransportController::Config());
966 auto description = CreateSessionDescriptionWithBundleGroup();
967 EXPECT_TRUE(transport_controller_
968 ->SetLocalDescription(SdpType::kOffer, description.get())
969 .ok());
970 transport_controller_->MaybeStartGathering();
971
972 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
973 transport_controller_->GetDtlsTransport(kAudioMid1));
974 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
975 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
976 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
977 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
978}
979
980TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
981 network_thread_ = rtc::Thread::CreateWithSocketServer();
982 network_thread_->Start();
983 CreateJsepTransportController(JsepTransportController::Config(),
984 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 13:57:52985 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 23:26:27986 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
987
988 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59989 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 23:26:27990 EXPECT_EQ(2, connection_state_signal_count_);
991
992 // new --> gathering --> complete
993 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
994 EXPECT_EQ(2, gathering_state_signal_count_);
995
996 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
997 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
998 EXPECT_EQ(2, candidates_signal_count_);
999
1000 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1001}
1002
Zhi Huange818b6e2018-02-22 23:26:271003// Test that if the TransportController was created with the
1004// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1005// redetermined on an ICE restart.
1006TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1007 JsepTransportController::Config config;
1008 config.redetermine_role_on_ice_restart = false;
1009
1010 CreateJsepTransportController(config);
1011 // Let the |transport_controller_| be the controlled side initially.
Mirko Bonadei317a1f02019-09-17 15:06:181012 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271013 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1014 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1015 nullptr);
Mirko Bonadei317a1f02019-09-17 15:06:181016 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271017 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1018 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1019 nullptr);
1020
1021 EXPECT_TRUE(transport_controller_
1022 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1023 .ok());
1024 EXPECT_TRUE(transport_controller_
1025 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1026 .ok());
1027
1028 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1029 transport_controller_->GetDtlsTransport(kAudioMid1));
1030 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1031 fake_dtls->fake_ice_transport()->GetIceRole());
1032
1033 // New offer will trigger the ICE restart.
Mirko Bonadei317a1f02019-09-17 15:06:181034 auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271035 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1036 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1037 nullptr);
1038 EXPECT_TRUE(
1039 transport_controller_
1040 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1041 .ok());
1042 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1043 fake_dtls->fake_ice_transport()->GetIceRole());
1044}
1045
1046// Tests ICE-Lite mode in remote answer.
1047TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1048 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 15:06:181049 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271050 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1051 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1052 nullptr);
1053 EXPECT_TRUE(transport_controller_
1054 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1055 .ok());
1056 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1057 transport_controller_->GetDtlsTransport(kAudioMid1));
1058 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1059 fake_dtls->fake_ice_transport()->GetIceRole());
1060 EXPECT_EQ(cricket::ICEMODE_FULL,
1061 fake_dtls->fake_ice_transport()->remote_ice_mode());
1062
Mirko Bonadei317a1f02019-09-17 15:06:181063 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271064 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1065 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1066 nullptr);
1067 EXPECT_TRUE(transport_controller_
1068 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1069 .ok());
1070 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1071 fake_dtls->fake_ice_transport()->GetIceRole());
1072 EXPECT_EQ(cricket::ICEMODE_LITE,
1073 fake_dtls->fake_ice_transport()->remote_ice_mode());
1074}
1075
1076// Tests that the ICE role remains "controlling" if a subsequent offer that
1077// does an ICE restart is received from an ICE lite endpoint. Regression test
1078// for: https://crbug.com/710760
1079TEST_F(JsepTransportControllerTest,
1080 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1081 CreateJsepTransportController(JsepTransportController::Config());
Mirko Bonadei317a1f02019-09-17 15:06:181082 auto remote_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271083 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1084 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1085 nullptr);
Mirko Bonadei317a1f02019-09-17 15:06:181086 auto local_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271087 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1088 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1089 nullptr);
1090 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1091 // local side is the controlling.
1092 EXPECT_TRUE(transport_controller_
1093 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1094 .ok());
1095 EXPECT_TRUE(transport_controller_
1096 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1097 .ok());
1098 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1099 transport_controller_->GetDtlsTransport(kAudioMid1));
1100 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1101 fake_dtls->fake_ice_transport()->GetIceRole());
1102
1103 // In the subsequence remote offer triggers an ICE restart.
Mirko Bonadei317a1f02019-09-17 15:06:181104 auto remote_offer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271105 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1106 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1107 nullptr);
Mirko Bonadei317a1f02019-09-17 15:06:181108 auto local_answer2 = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271109 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1110 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1111 nullptr);
1112 EXPECT_TRUE(transport_controller_
1113 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1114 .ok());
1115 EXPECT_TRUE(transport_controller_
1116 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1117 .ok());
1118 fake_dtls = static_cast<FakeDtlsTransport*>(
1119 transport_controller_->GetDtlsTransport(kAudioMid1));
1120 // The local side is still the controlling role since the remote side is using
1121 // ICE-Lite.
1122 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1123 fake_dtls->fake_ice_transport()->GetIceRole());
1124}
1125
1126// Tests that the SDP has more than one audio/video m= sections.
1127TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1128 CreateJsepTransportController(JsepTransportController::Config());
1129 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1130 bundle_group.AddContentName(kAudioMid1);
1131 bundle_group.AddContentName(kAudioMid2);
1132 bundle_group.AddContentName(kVideoMid1);
1133 bundle_group.AddContentName(kDataMid1);
1134
Mirko Bonadei317a1f02019-09-17 15:06:181135 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271136 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1137 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1138 nullptr);
1139 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1140 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1141 nullptr);
1142 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1143 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1144 nullptr);
1145 AddDataSection(local_offer.get(), kDataMid1,
1146 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1147 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1148 nullptr);
1149
Mirko Bonadei317a1f02019-09-17 15:06:181150 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271151 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1152 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1153 nullptr);
1154 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1155 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1156 nullptr);
1157 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1158 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1159 nullptr);
1160 AddDataSection(remote_answer.get(), kDataMid1,
1161 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1162 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1163 nullptr);
1164
1165 local_offer->AddGroup(bundle_group);
1166 remote_answer->AddGroup(bundle_group);
1167
1168 EXPECT_TRUE(transport_controller_
1169 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1170 .ok());
1171 EXPECT_TRUE(transport_controller_
1172 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1173 .ok());
1174 // Verify that all the sections are bundled on kAudio1.
1175 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1176 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1177 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1178 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1179 EXPECT_EQ(transport1, transport2);
1180 EXPECT_EQ(transport1, transport3);
1181 EXPECT_EQ(transport1, transport4);
1182
Harald Alvestrandad88c882018-11-28 15:47:461183 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1184 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1185
Zhi Huange818b6e2018-02-22 23:26:271186 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1187 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1188 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1189 EXPECT_EQ(transport1, it->second);
1190 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1191 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1192 EXPECT_EQ(transport1, it->second);
1193 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1194 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1195 EXPECT_EQ(transport1, it->second);
1196 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1197 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1198 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
Zhi Huange818b6e2018-02-22 23:26:271199}
1200
1201// Tests that only a subset of all the m= sections are bundled.
1202TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1203 CreateJsepTransportController(JsepTransportController::Config());
1204 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1205 bundle_group.AddContentName(kAudioMid1);
1206 bundle_group.AddContentName(kVideoMid1);
1207
Mirko Bonadei317a1f02019-09-17 15:06:181208 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271209 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1210 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1211 nullptr);
1212 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1213 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1214 nullptr);
1215 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1216 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1217 nullptr);
1218
Mirko Bonadei317a1f02019-09-17 15:06:181219 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271220 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1221 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1222 nullptr);
1223 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1224 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1225 nullptr);
1226 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1227 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1228 nullptr);
1229
1230 local_offer->AddGroup(bundle_group);
1231 remote_answer->AddGroup(bundle_group);
1232 EXPECT_TRUE(transport_controller_
1233 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1234 .ok());
1235 EXPECT_TRUE(transport_controller_
1236 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1237 .ok());
1238
1239 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1240 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1241 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1242 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1243 EXPECT_NE(transport1, transport2);
1244 EXPECT_EQ(transport1, transport3);
1245
1246 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1247 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1248 EXPECT_EQ(transport1, it->second);
1249 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 21:41:031250 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 23:26:271251}
1252
1253// Tests that the initial offer/answer only have data section and audio/video
1254// sections are added in the subsequent offer.
1255TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1256 CreateJsepTransportController(JsepTransportController::Config());
1257 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1258 bundle_group.AddContentName(kDataMid1);
1259
Mirko Bonadei317a1f02019-09-17 15:06:181260 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271261 AddDataSection(local_offer.get(), kDataMid1,
1262 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1263 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1264 nullptr);
Mirko Bonadei317a1f02019-09-17 15:06:181265 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271266 AddDataSection(remote_answer.get(), kDataMid1,
1267 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1268 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1269 nullptr);
1270 local_offer->AddGroup(bundle_group);
1271 remote_answer->AddGroup(bundle_group);
1272
1273 EXPECT_TRUE(transport_controller_
1274 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1275 .ok());
1276 EXPECT_TRUE(transport_controller_
1277 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1278 .ok());
1279 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1280
1281 // Add audio/video sections in subsequent offer.
1282 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1283 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1284 nullptr);
1285 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1286 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1287 nullptr);
1288 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1289 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1290 nullptr);
1291 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1292 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1293 nullptr);
1294
1295 // Reset the bundle group and do another offer/answer exchange.
1296 bundle_group.AddContentName(kAudioMid1);
1297 bundle_group.AddContentName(kVideoMid1);
1298 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1299 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1300 local_offer->AddGroup(bundle_group);
1301 remote_answer->AddGroup(bundle_group);
1302
1303 EXPECT_TRUE(transport_controller_
1304 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1305 .ok());
1306 EXPECT_TRUE(transport_controller_
1307 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1308 .ok());
1309
1310 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1311 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1312 EXPECT_EQ(data_transport, audio_transport);
1313 EXPECT_EQ(data_transport, video_transport);
1314}
1315
1316TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1317 CreateJsepTransportController(JsepTransportController::Config());
1318 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1319 bundle_group.AddContentName(kAudioMid1);
1320 bundle_group.AddContentName(kVideoMid1);
1321 bundle_group.AddContentName(kDataMid1);
1322
Mirko Bonadei317a1f02019-09-17 15:06:181323 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271324 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1325 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1326 nullptr);
1327 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1328 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1329 nullptr);
1330 AddDataSection(local_offer.get(), kDataMid1,
1331 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1332 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1333 nullptr);
1334
Mirko Bonadei317a1f02019-09-17 15:06:181335 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271336 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1337 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1338 nullptr);
1339 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1340 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1341 nullptr);
1342 AddDataSection(remote_answer.get(), kDataMid1,
1343 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1344 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1345 nullptr);
1346 // Reject video and data section.
1347 remote_answer->contents()[1].rejected = true;
1348 remote_answer->contents()[2].rejected = true;
1349
1350 local_offer->AddGroup(bundle_group);
1351 remote_answer->AddGroup(bundle_group);
1352
1353 EXPECT_TRUE(transport_controller_
1354 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1355 .ok());
1356 EXPECT_TRUE(transport_controller_
1357 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1358 .ok());
1359
1360 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1361 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1362 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1363 // Verify the signals are fired correctly.
1364 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1365 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1366 EXPECT_EQ(nullptr, it->second);
1367 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1368 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1369 EXPECT_EQ(nullptr, it2->second);
1370}
1371
1372// Tests that changing the bundled MID in subsequent offer/answer exchange is
1373// not supported.
1374// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1375// fixed
1376TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1377 CreateJsepTransportController(JsepTransportController::Config());
1378 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1379 bundle_group.AddContentName(kAudioMid1);
1380 bundle_group.AddContentName(kVideoMid1);
1381
Mirko Bonadei317a1f02019-09-17 15:06:181382 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271383 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1384 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1385 nullptr);
1386 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1387 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1388 nullptr);
1389
Mirko Bonadei317a1f02019-09-17 15:06:181390 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 23:26:271391 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1392 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1393 nullptr);
1394 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1395 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1396 nullptr);
1397
1398 local_offer->AddGroup(bundle_group);
1399 remote_answer->AddGroup(bundle_group);
1400 EXPECT_TRUE(transport_controller_
1401 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1402 .ok());
1403 EXPECT_TRUE(transport_controller_
1404 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1405 .ok());
1406 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1407 transport_controller_->GetRtpTransport(kVideoMid1));
1408
1409 // Reorder the bundle group.
1410 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1411 bundle_group.AddContentName(kAudioMid1);
1412 // The answerer uses the new bundle group and now the bundle mid is changed to
1413 // |kVideo1|.
1414 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1415 remote_answer->AddGroup(bundle_group);
1416 EXPECT_TRUE(transport_controller_
1417 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1418 .ok());
1419 EXPECT_FALSE(transport_controller_
1420 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1421 .ok());
1422}
Zhi Huange830e682018-03-30 17:48:351423// Test that rejecting only the first m= section of a BUNDLE group is treated as
1424// an error, but rejecting all of them works as expected.
1425TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1426 CreateJsepTransportController(JsepTransportController::Config());
1427 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1428 bundle_group.AddContentName(kAudioMid1);
1429 bundle_group.AddContentName(kVideoMid1);
1430 bundle_group.AddContentName(kDataMid1);
1431
Mirko Bonadei317a1f02019-09-17 15:06:181432 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:351433 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1434 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1435 nullptr);
1436 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1437 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1438 nullptr);
1439 AddDataSection(local_offer.get(), kDataMid1,
1440 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1441 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1442 nullptr);
1443
Mirko Bonadei317a1f02019-09-17 15:06:181444 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:351445 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1446 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1447 nullptr);
1448 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1449 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1450 nullptr);
1451 AddDataSection(remote_answer.get(), kDataMid1,
1452 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1453 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1454 nullptr);
1455 // Reject audio content in answer.
1456 remote_answer->contents()[0].rejected = true;
1457
1458 local_offer->AddGroup(bundle_group);
1459 remote_answer->AddGroup(bundle_group);
1460
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
1468 // Reject all the contents.
1469 remote_answer->contents()[1].rejected = true;
1470 remote_answer->contents()[2].rejected = true;
1471 EXPECT_TRUE(transport_controller_
1472 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1473 .ok());
1474 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1475 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1476 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1477}
1478
1479// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1480// is used.
1481TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1482 JsepTransportController::Config config;
1483 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1484 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 15:06:181485 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:351486 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1487 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1488 nullptr);
1489
1490 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1491 // Applying a non-RTCP-mux offer is expected to fail.
1492 EXPECT_FALSE(transport_controller_
1493 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1494 .ok());
1495}
1496
1497// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1498// is used.
1499TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1500 JsepTransportController::Config config;
1501 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1502 CreateJsepTransportController(config);
Mirko Bonadei317a1f02019-09-17 15:06:181503 auto local_offer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:351504 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1505 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1506 nullptr);
1507 EXPECT_TRUE(transport_controller_
1508 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1509 .ok());
1510
Mirko Bonadei317a1f02019-09-17 15:06:181511 auto remote_answer = std::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 17:48:351512 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1513 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1514 nullptr);
1515 // Applying a non-RTCP-mux answer is expected to fail.
1516 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1517 EXPECT_FALSE(transport_controller_
1518 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1519 .ok());
1520}
Zhi Huange818b6e2018-02-22 23:26:271521
Zhi Huangd2248f82018-04-10 21:41:031522// This tests that the BUNDLE group in answer should be a subset of the offered
1523// group.
1524TEST_F(JsepTransportControllerTest,
1525 AddContentToBundleGroupInAnswerNotSupported) {
1526 CreateJsepTransportController(JsepTransportController::Config());
1527 auto local_offer = CreateSessionDescriptionWithoutBundle();
1528 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1529
1530 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1531 offer_bundle_group.AddContentName(kAudioMid1);
1532 local_offer->AddGroup(offer_bundle_group);
1533
1534 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1535 answer_bundle_group.AddContentName(kAudioMid1);
1536 answer_bundle_group.AddContentName(kVideoMid1);
1537 remote_answer->AddGroup(answer_bundle_group);
1538 EXPECT_TRUE(transport_controller_
1539 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1540 .ok());
1541 EXPECT_FALSE(transport_controller_
1542 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1543 .ok());
1544}
1545
1546// This tests that the BUNDLE group with non-existing MID should be rejectd.
1547TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1548 CreateJsepTransportController(JsepTransportController::Config());
1549 auto local_offer = CreateSessionDescriptionWithoutBundle();
1550 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1551
1552 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1553 // The BUNDLE group is invalid because there is no data section in the
1554 // description.
1555 invalid_bundle_group.AddContentName(kDataMid1);
1556 local_offer->AddGroup(invalid_bundle_group);
1557 remote_answer->AddGroup(invalid_bundle_group);
1558
1559 EXPECT_FALSE(transport_controller_
1560 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1561 .ok());
1562 EXPECT_FALSE(transport_controller_
1563 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1564 .ok());
1565}
1566
1567// This tests that an answer shouldn't be able to remove an m= section from an
1568// established group without rejecting it.
1569TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1570 CreateJsepTransportController(JsepTransportController::Config());
1571
1572 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1573 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1574 EXPECT_TRUE(transport_controller_
1575 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1576 .ok());
1577 EXPECT_TRUE(transport_controller_
1578 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1579 .ok());
1580
1581 // Do an re-offer/answer.
1582 EXPECT_TRUE(transport_controller_
1583 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1584 .ok());
1585 auto new_answer = CreateSessionDescriptionWithoutBundle();
1586 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1587 // The answer removes video from the BUNDLE group without rejecting it is
1588 // invalid.
1589 new_bundle_group.AddContentName(kAudioMid1);
1590 new_answer->AddGroup(new_bundle_group);
1591
1592 // Applying invalid answer is expected to fail.
1593 EXPECT_FALSE(transport_controller_
1594 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1595 .ok());
1596
1597 // Rejected the video content.
1598 auto video_content = new_answer->GetContentByName(kVideoMid1);
1599 ASSERT_TRUE(video_content);
1600 video_content->rejected = true;
1601 EXPECT_TRUE(transport_controller_
1602 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1603 .ok());
1604}
1605
Steve Anton2bed3972019-01-05 01:04:301606// Test that the JsepTransportController can process a new local and remote
1607// description that changes the tagged BUNDLE group with the max-bundle policy
1608// specified.
1609// This is a regression test for bugs.webrtc.org/9954
1610TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
1611 CreateJsepTransportController(JsepTransportController::Config());
1612
Mirko Bonadei317a1f02019-09-17 15:06:181613 auto local_offer = std::make_unique<cricket::SessionDescription>();
Steve Anton2bed3972019-01-05 01:04:301614 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1615 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1616 nullptr);
1617 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1618 bundle_group.AddContentName(kAudioMid1);
1619 local_offer->AddGroup(bundle_group);
1620 EXPECT_TRUE(transport_controller_
1621 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1622 .ok());
1623
1624 std::unique_ptr<cricket::SessionDescription> remote_answer(
Harald Alvestrand4d7160e2019-04-12 05:01:291625 local_offer->Clone());
Steve Anton2bed3972019-01-05 01:04:301626 EXPECT_TRUE(transport_controller_
1627 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1628 .ok());
1629
1630 std::unique_ptr<cricket::SessionDescription> local_reoffer(
Harald Alvestrand4d7160e2019-04-12 05:01:291631 local_offer->Clone());
Steve Anton2bed3972019-01-05 01:04:301632 local_reoffer->contents()[0].rejected = true;
1633 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
1634 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1635 nullptr);
1636 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1637 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1638 new_bundle_group.AddContentName(kVideoMid1);
1639 local_reoffer->AddGroup(new_bundle_group);
1640
1641 EXPECT_TRUE(transport_controller_
1642 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
1643 .ok());
1644
1645 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
Harald Alvestrand4d7160e2019-04-12 05:01:291646 local_reoffer->Clone());
Steve Anton2bed3972019-01-05 01:04:301647 EXPECT_TRUE(
1648 transport_controller_
1649 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
1650 .ok());
1651}
1652
Bjorn A Mellemc85ebbe2019-06-07 17:28:061653constexpr char kFakeTransportParameters[] = "fake-params";
1654
1655// Test fixture that provides common setup and helpers for tests related to the
1656// datagram transport.
1657class JsepTransportControllerDatagramTest
1658 : public JsepTransportControllerTest,
1659 public testing::WithParamInterface<bool> {
1660 public:
1661 JsepTransportControllerDatagramTest()
1662 : JsepTransportControllerTest(),
1663 fake_media_transport_factory_(kFakeTransportParameters) {
1664 JsepTransportController::Config config;
1665 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1666 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
1667 config.media_transport_factory = &fake_media_transport_factory_;
1668 config.use_datagram_transport = true;
1669 CreateJsepTransportController(config);
1670 }
1671
1672 // Whether the JsepTransportController under test acts as the offerer or
1673 // answerer in this test.
1674 bool IsOfferer() { return GetParam(); }
1675
1676 // Sets a description as local or remote based on type and current
1677 // perspective.
1678 RTCError SetDescription(SdpType type,
1679 const cricket::SessionDescription* description) {
1680 if (IsOfferer() == (type == SdpType::kOffer)) {
1681 return transport_controller_->SetLocalDescription(type, description);
1682 } else {
1683 return transport_controller_->SetRemoteDescription(type, description);
1684 }
1685 }
1686
1687 // Creates a session description with the settings necessary for datagram
1688 // transport (bundle + crypto) and the given |transport_params|.
1689 std::unique_ptr<cricket::SessionDescription>
1690 CreateSessionDescriptionForDatagramTransport(
1691 absl::optional<cricket::OpaqueTransportParameters> transport_params) {
1692 auto description = CreateSessionDescriptionWithBundleGroup();
1693 AddCryptoSettings(description.get());
1694
1695 for (auto& info : description->transport_infos()) {
1696 info.description.opaque_parameters = transport_params;
1697 }
Bjorn A Mellem8e1343a2019-09-30 22:12:471698 if (transport_params) {
1699 for (auto& content_info : description->contents()) {
1700 content_info.media_description()->set_alt_protocol(
1701 transport_params->protocol);
1702 }
1703 }
Bjorn A Mellemc85ebbe2019-06-07 17:28:061704 return description;
1705 }
1706
1707 // Creates transport parameters with |protocol| and |parameters|
1708 // matching what |fake_media_transport_factory_| provides.
1709 cricket::OpaqueTransportParameters CreateTransportParameters() {
1710 cricket::OpaqueTransportParameters params;
1711 params.protocol = fake_media_transport_factory_.GetTransportName();
1712 params.parameters = "fake-params";
1713 return params;
1714 }
1715
1716 protected:
1717 FakeMediaTransportFactory fake_media_transport_factory_;
1718};
1719
1720TEST_P(JsepTransportControllerDatagramTest, InitDatagramTransport) {
1721 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1722 if (IsOfferer()) {
1723 // Getting transport parameters is allowed before setting a description.
1724 // This is necessary so that the offerer can include these params.
1725 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1726 fake_params);
1727 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1728 fake_params);
1729 }
1730
1731 // Setting a description activates the datagram transport without changing
1732 // transport parameters.
1733 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
1734 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
1735
1736 // After setting an offer with transport parameters, those parameters are
1737 // reflected by the controller.
1738 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1739 fake_params);
1740 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1741 fake_params);
1742}
1743
1744TEST_P(JsepTransportControllerDatagramTest,
1745 OfferMissingDatagramTransportParams) {
1746 if (IsOfferer()) {
1747 // This test doesn't make sense from the offerer's perspective, as the offer
1748 // must contain datagram transport params if the offerer supports it.
1749 return;
1750 }
1751
1752 auto description =
1753 CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1754 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
1755
1756 // The offer didn't contain any datagram transport parameters, so the answer
1757 // won't either.
1758 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1759 absl::nullopt);
1760 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1761 absl::nullopt);
1762}
1763
1764TEST_P(JsepTransportControllerDatagramTest, OfferHasWrongTransportName) {
1765 if (IsOfferer()) {
1766 // This test doesn't make sense from the offerer's perspective, as the
1767 // offerer cannot offer itself the wrong transport.
1768 return;
1769 }
1770
1771 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1772 fake_params.protocol = "wrong-name";
1773
1774 auto description = CreateSessionDescriptionForDatagramTransport(fake_params);
1775 EXPECT_TRUE(SetDescription(SdpType::kOffer, description.get()).ok());
1776
1777 // The offerer and answerer support different datagram transports, so the
1778 // answerer rejects the offered parameters.
1779 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1780 absl::nullopt);
1781 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1782 absl::nullopt);
1783}
1784
Bjorn A Mellem0cda7b82020-01-29 01:06:551785TEST_P(JsepTransportControllerDatagramTest, IncompatibleAnswer) {
1786 // Transport will claim that no parameters are compatible, even if they match
1787 // exactly.
1788 fake_media_transport_factory_.set_transport_parameters_comparison(
1789 [](absl::string_view, absl::string_view) { return false; });
1790
1791 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1792 if (IsOfferer()) {
1793 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1794 fake_params);
1795 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1796 fake_params);
1797 }
1798
1799 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1800 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1801
1802 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
1803 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1804
1805 // The offerer and answerer have incompatible parameters, so the answerer
1806 // rejects the offered parameters.
1807 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1808 absl::nullopt);
1809 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1810 absl::nullopt);
1811}
1812
1813TEST_P(JsepTransportControllerDatagramTest, CompatibleAnswer) {
1814 // Transport will claim that no parameters are compatible, even if they are
1815 // completely different.
1816 fake_media_transport_factory_.set_transport_parameters_comparison(
1817 [](absl::string_view, absl::string_view) { return true; });
1818
1819 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1820 if (IsOfferer()) {
1821 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1822 fake_params);
1823 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1824 fake_params);
1825 }
1826
1827 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1828 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1829
1830 cricket::OpaqueTransportParameters answer_params;
1831 answer_params.protocol = fake_params.protocol;
1832 answer_params.parameters = "something different from offer";
1833 auto answer = CreateSessionDescriptionForDatagramTransport(answer_params);
1834 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1835
1836 // The offerer and answerer have compatible parameters, so the answerer
1837 // accepts the offered parameters.
1838 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1839 fake_params);
1840 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1841 fake_params);
1842}
1843
Bjorn A Mellemc85ebbe2019-06-07 17:28:061844TEST_P(JsepTransportControllerDatagramTest, AnswerRejectsDatagram) {
1845 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1846 if (IsOfferer()) {
1847 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1848 fake_params);
1849 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1850 fake_params);
1851 }
1852
1853 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1854 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1855
1856 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1857 fake_params);
1858 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1859 fake_params);
1860
1861 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1862 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1863
1864 // The answer rejected datagram transport, so its parameters are empty.
1865 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1866 absl::nullopt);
1867 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1868 absl::nullopt);
1869}
1870
1871TEST_P(JsepTransportControllerDatagramTest, AnswerAcceptsDatagram) {
1872 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1873 if (IsOfferer()) {
1874 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1875 fake_params);
1876 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1877 fake_params);
1878 }
1879
1880 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1881 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1882
1883 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1884 fake_params);
1885 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1886 fake_params);
1887
1888 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
1889 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1890
1891 // The answer accepted datagram transport, so it is present.
1892 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1893 fake_params);
1894 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1895 fake_params);
1896}
1897
1898TEST_P(JsepTransportControllerDatagramTest, PrAnswerRejectsDatagram) {
1899 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1900 if (IsOfferer()) {
1901 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1902 fake_params);
1903 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1904 fake_params);
1905 }
1906
1907 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1908 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1909
1910 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1911 fake_params);
1912 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1913 fake_params);
1914
1915 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1916 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
1917
1918 // The answer rejected datagram transport, but it's provisional, so the
1919 // transport is kept around for now.
1920 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1921 fake_params);
1922 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1923 fake_params);
1924}
1925
1926TEST_P(JsepTransportControllerDatagramTest, PrAnswerAcceptsDatagram) {
1927 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1928 if (IsOfferer()) {
1929 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1930 fake_params);
1931 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1932 fake_params);
1933 }
1934
1935 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1936 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1937
1938 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1939 fake_params);
1940 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1941 fake_params);
1942
1943 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
1944 EXPECT_TRUE(SetDescription(SdpType::kPrAnswer, answer.get()).ok());
1945
1946 // The answer provisionally accepted datagram transport, so it's kept.
1947 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1948 fake_params);
1949 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1950 fake_params);
1951}
1952
1953TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotAddDatagram) {
1954 auto offer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1955 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1956
1957 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1958 absl::nullopt);
1959 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1960 absl::nullopt);
1961
1962 auto answer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
1963 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
1964
1965 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1966 absl::nullopt);
1967 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1968 absl::nullopt);
1969
1970 // Attempting to add a datagram transport on a re-offer does not cause an
1971 // error, but also does not add a datagram transport.
1972 auto reoffer =
1973 CreateSessionDescriptionForDatagramTransport(CreateTransportParameters());
1974 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
1975
1976 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1977 absl::nullopt);
1978 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1979 absl::nullopt);
1980}
1981
1982TEST_P(JsepTransportControllerDatagramTest, RenegotiationCannotRemoveDatagram) {
1983 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
1984 if (IsOfferer()) {
1985 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1986 fake_params);
1987 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1988 fake_params);
1989 }
1990
1991 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
1992 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
1993
1994 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
1995 fake_params);
1996 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
1997 fake_params);
1998
1999 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2000 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2001
2002 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2003 fake_params);
2004 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2005 fake_params);
2006
2007 // Attempting to remove a datagram transport on a re-offer does not cause an
2008 // error, but also does not remove the datagram transport.
2009 auto reoffer = CreateSessionDescriptionForDatagramTransport(absl::nullopt);
2010 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2011
2012 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2013 fake_params);
2014 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2015 fake_params);
2016}
2017
2018TEST_P(JsepTransportControllerDatagramTest,
2019 RenegotiationKeepsDatagramTransport) {
2020 cricket::OpaqueTransportParameters fake_params = CreateTransportParameters();
2021 if (IsOfferer()) {
2022 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2023 fake_params);
2024 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2025 fake_params);
2026 }
2027
2028 auto offer = CreateSessionDescriptionForDatagramTransport(fake_params);
2029 EXPECT_TRUE(SetDescription(SdpType::kOffer, offer.get()).ok());
2030
2031 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2032 fake_params);
2033 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2034 fake_params);
2035
2036 auto answer = CreateSessionDescriptionForDatagramTransport(fake_params);
2037 EXPECT_TRUE(SetDescription(SdpType::kAnswer, answer.get()).ok());
2038
2039 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2040 fake_params);
2041 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2042 fake_params);
2043
2044 // Attempting to remove a datagram transport on a re-offer does not cause an
2045 // error, but also does not remove the datagram transport.
2046 auto reoffer = CreateSessionDescriptionForDatagramTransport(fake_params);
2047 EXPECT_TRUE(SetDescription(SdpType::kOffer, reoffer.get()).ok());
2048
2049 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2050 fake_params);
2051 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2052 fake_params);
2053
2054 auto reanswer = CreateSessionDescriptionForDatagramTransport(fake_params);
2055 EXPECT_TRUE(SetDescription(SdpType::kAnswer, reanswer.get()).ok());
2056
2057 EXPECT_EQ(transport_controller_->GetTransportParameters(kAudioMid1),
2058 fake_params);
2059 EXPECT_EQ(transport_controller_->GetTransportParameters(kVideoMid1),
2060 fake_params);
2061}
2062
2063INSTANTIATE_TEST_SUITE_P(
2064 JsepTransportControllerDatagramTests,
2065 JsepTransportControllerDatagramTest,
2066 testing::Values(true, false),
2067 // The parameter value is the local perspective (offerer or answerer).
2068 [](const testing::TestParamInfo<bool>& info) {
2069 return info.param ? "Offerer" : "Answerer";
2070 });
2071
Zhi Huange818b6e2018-02-22 23:26:272072} // namespace webrtc