blob: 590f57dab2b9fe29265765cd2312e240d16c9ebc [file] [log] [blame]
Zhi Huange818b6e2018-02-22 15:26:27 -08001/*
2 * Copyright 2018 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include <map>
12#include <memory>
13
Steve Anton2bed3972019-01-04 17:04:30 -080014#include "absl/memory/memory.h"
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -080015#include "api/media_transport_interface.h"
Anton Sukhanov7940da02018-10-10 10:34:49 -070016#include "api/test/fake_media_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "p2p/base/fake_dtls_transport.h"
18#include "p2p/base/fake_ice_transport.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080019#include "p2p/base/no_op_dtls_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "p2p/base/transport_factory_interface.h"
21#include "p2p/base/transport_info.h"
22#include "pc/jsep_transport_controller.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080023#include "rtc_base/gunit.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/thread.h"
25#include "test/gtest.h"
26
27using cricket::FakeDtlsTransport;
28using cricket::Candidate;
29using cricket::Candidates;
30using webrtc::SdpType;
31
32static const int kTimeout = 100;
33static const char kIceUfrag1[] = "u0001";
34static const char kIcePwd1[] = "TESTICEPWD00000000000001";
35static const char kIceUfrag2[] = "u0002";
36static const char kIcePwd2[] = "TESTICEPWD00000000000002";
37static const char kIceUfrag3[] = "u0003";
38static const char kIcePwd3[] = "TESTICEPWD00000000000003";
39static const char kAudioMid1[] = "audio1";
40static const char kAudioMid2[] = "audio2";
41static const char kVideoMid1[] = "video1";
42static const char kVideoMid2[] = "video2";
43static const char kDataMid1[] = "data1";
44
45namespace webrtc {
46
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070047namespace {
48
49// Media transport factory requires crypto settings to be present in order to
50// create media transport.
51void AddCryptoSettings(cricket::SessionDescription* description) {
52 for (auto& content : description->contents()) {
53 content.media_description()->AddCrypto(cricket::CryptoParams(
54 /*t=*/0, std::string(rtc::CS_AES_CM_128_HMAC_SHA1_80),
55 "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2", ""));
56 }
57}
58
59} // namespace
60
Zhi Huange818b6e2018-02-22 15:26:27 -080061class FakeTransportFactory : public cricket::TransportFactoryInterface {
62 public:
63 std::unique_ptr<cricket::IceTransportInternal> CreateIceTransport(
64 const std::string& transport_name,
65 int component) override {
Karl Wiberg918f50c2018-07-05 11:40:33 +020066 return absl::make_unique<cricket::FakeIceTransport>(transport_name,
67 component);
Zhi Huange818b6e2018-02-22 15:26:27 -080068 }
69
70 std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
71 std::unique_ptr<cricket::IceTransportInternal> ice,
Benjamin Wrighta54daf12018-10-11 15:33:17 -070072 const webrtc::CryptoOptions& crypto_options) override {
Zhi Huange818b6e2018-02-22 15:26:27 -080073 std::unique_ptr<cricket::FakeIceTransport> fake_ice(
74 static_cast<cricket::FakeIceTransport*>(ice.release()));
Karl Wiberg918f50c2018-07-05 11:40:33 +020075 return absl::make_unique<FakeDtlsTransport>(std::move(fake_ice));
Zhi Huange818b6e2018-02-22 15:26:27 -080076 }
77};
78
Zhi Huang365381f2018-04-13 16:44:34 -070079class JsepTransportControllerTest : public JsepTransportController::Observer,
80 public testing::Test,
Zhi Huange818b6e2018-02-22 15:26:27 -080081 public sigslot::has_slots<> {
82 public:
83 JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
Karl Wiberg918f50c2018-07-05 11:40:33 +020084 fake_transport_factory_ = absl::make_unique<FakeTransportFactory>();
Zhi Huange818b6e2018-02-22 15:26:27 -080085 }
86
87 void CreateJsepTransportController(
88 JsepTransportController::Config config,
89 rtc::Thread* signaling_thread = rtc::Thread::Current(),
90 rtc::Thread* network_thread = rtc::Thread::Current(),
91 cricket::PortAllocator* port_allocator = nullptr) {
Zhi Huang365381f2018-04-13 16:44:34 -070092 config.transport_observer = this;
Zhi Huange818b6e2018-02-22 15:26:27 -080093 // The tests only works with |fake_transport_factory|;
94 config.external_transport_factory = fake_transport_factory_.get();
Zach Steine20867f2018-08-02 13:20:15 -070095 // TODO(zstein): Provide an AsyncResolverFactory once it is required.
Karl Wiberg918f50c2018-07-05 11:40:33 +020096 transport_controller_ = absl::make_unique<JsepTransportController>(
Zach Steine20867f2018-08-02 13:20:15 -070097 signaling_thread, network_thread, port_allocator, nullptr, config);
Zhi Huange818b6e2018-02-22 15:26:27 -080098 ConnectTransportControllerSignals();
99 }
100
101 void ConnectTransportControllerSignals() {
102 transport_controller_->SignalIceConnectionState.connect(
103 this, &JsepTransportControllerTest::OnConnectionState);
Alex Loiko9289eda2018-11-23 16:18:59 +0000104 transport_controller_->SignalStandardizedIceConnectionState.connect(
105 this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
Jonas Olsson635474e2018-10-18 15:58:17 +0200106 transport_controller_->SignalConnectionState.connect(
107 this, &JsepTransportControllerTest::OnCombinedConnectionState);
Zhi Huange818b6e2018-02-22 15:26:27 -0800108 transport_controller_->SignalIceGatheringState.connect(
109 this, &JsepTransportControllerTest::OnGatheringState);
110 transport_controller_->SignalIceCandidatesGathered.connect(
111 this, &JsepTransportControllerTest::OnCandidatesGathered);
Zhi Huange818b6e2018-02-22 15:26:27 -0800112 }
113
114 std::unique_ptr<cricket::SessionDescription>
115 CreateSessionDescriptionWithoutBundle() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200116 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800117 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
118 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
119 nullptr);
120 AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
121 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
122 nullptr);
123 return description;
124 }
125
126 std::unique_ptr<cricket::SessionDescription>
127 CreateSessionDescriptionWithBundleGroup() {
128 auto description = CreateSessionDescriptionWithoutBundle();
129 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
130 bundle_group.AddContentName(kAudioMid1);
131 bundle_group.AddContentName(kVideoMid1);
132 description->AddGroup(bundle_group);
133
134 return description;
135 }
136
137 void AddAudioSection(cricket::SessionDescription* description,
138 const std::string& mid,
139 const std::string& ufrag,
140 const std::string& pwd,
141 cricket::IceMode ice_mode,
142 cricket::ConnectionRole conn_role,
143 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
144 std::unique_ptr<cricket::AudioContentDescription> audio(
145 new cricket::AudioContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700146 // Set RTCP-mux to be true because the default policy is "mux required".
147 audio->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800148 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
149 /*rejected=*/false, audio.release());
150 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
151 }
152
153 void AddVideoSection(cricket::SessionDescription* description,
154 const std::string& mid,
155 const std::string& ufrag,
156 const std::string& pwd,
157 cricket::IceMode ice_mode,
158 cricket::ConnectionRole conn_role,
159 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
160 std::unique_ptr<cricket::VideoContentDescription> video(
161 new cricket::VideoContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700162 // Set RTCP-mux to be true because the default policy is "mux required".
163 video->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800164 description->AddContent(mid, cricket::MediaProtocolType::kRtp,
165 /*rejected=*/false, video.release());
166 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
167 }
168
169 void AddDataSection(cricket::SessionDescription* description,
170 const std::string& mid,
171 cricket::MediaProtocolType protocol_type,
172 const std::string& ufrag,
173 const std::string& pwd,
174 cricket::IceMode ice_mode,
175 cricket::ConnectionRole conn_role,
176 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
177 std::unique_ptr<cricket::DataContentDescription> data(
178 new cricket::DataContentDescription());
Zhi Huange830e682018-03-30 10:48:35 -0700179 data->set_rtcp_mux(true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800180 description->AddContent(mid, protocol_type,
181 /*rejected=*/false, data.release());
182 AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
183 }
184
185 void AddTransportInfo(cricket::SessionDescription* description,
186 const std::string& mid,
187 const std::string& ufrag,
188 const std::string& pwd,
189 cricket::IceMode ice_mode,
190 cricket::ConnectionRole conn_role,
191 rtc::scoped_refptr<rtc::RTCCertificate> cert) {
192 std::unique_ptr<rtc::SSLFingerprint> fingerprint;
193 if (cert) {
Steve Anton4905edb2018-10-15 19:27:44 -0700194 fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
Zhi Huange818b6e2018-02-22 15:26:27 -0800195 }
196
197 cricket::TransportDescription transport_desc(std::vector<std::string>(),
198 ufrag, pwd, ice_mode,
199 conn_role, fingerprint.get());
200 description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
201 }
202
203 cricket::IceConfig CreateIceConfig(
204 int receiving_timeout,
205 cricket::ContinualGatheringPolicy continual_gathering_policy) {
206 cricket::IceConfig config;
207 config.receiving_timeout = receiving_timeout;
208 config.continual_gathering_policy = continual_gathering_policy;
209 return config;
210 }
211
212 Candidate CreateCandidate(const std::string& transport_name, int component) {
213 Candidate c;
214 c.set_transport_name(transport_name);
215 c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
216 c.set_component(component);
217 c.set_protocol(cricket::UDP_PROTOCOL_NAME);
218 c.set_priority(1);
219 return c;
220 }
221
222 void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
223 if (!network_thread_->IsCurrent()) {
224 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
225 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
226 });
227 return;
228 }
229
230 auto description = CreateSessionDescriptionWithBundleGroup();
231 EXPECT_TRUE(transport_controller_
232 ->SetLocalDescription(SdpType::kOffer, description.get())
233 .ok());
234
235 transport_controller_->MaybeStartGathering();
236 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
237 transport_controller_->GetDtlsTransport(kAudioMid1));
238 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
239 transport_controller_->GetDtlsTransport(kVideoMid1));
240 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
241 fake_audio_dtls->fake_ice_transport(),
242 CreateCandidate(kAudioMid1, /*component=*/1));
243 fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
244 fake_video_dtls->fake_ice_transport(),
245 CreateCandidate(kVideoMid1, /*component=*/1));
246 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
247 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
248 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
249 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
250 fake_audio_dtls->SetReceiving(true);
251 fake_video_dtls->SetReceiving(true);
252 fake_audio_dtls->SetWritable(true);
253 fake_video_dtls->SetWritable(true);
254 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
255 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
256 }
257
258 protected:
Alex Loiko9289eda2018-11-23 16:18:59 +0000259 void OnConnectionState(cricket::IceConnectionState state) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800260 if (!signaling_thread_->IsCurrent()) {
261 signaled_on_non_signaling_thread_ = true;
262 }
263 connection_state_ = state;
264 ++connection_state_signal_count_;
265 }
266
Alex Loiko9289eda2018-11-23 16:18:59 +0000267 void OnStandardizedIceConnectionState(
268 PeerConnectionInterface::IceConnectionState state) {
269 if (!signaling_thread_->IsCurrent()) {
270 signaled_on_non_signaling_thread_ = true;
271 }
272 ice_connection_state_ = state;
273 ++ice_connection_state_signal_count_;
274 }
275
Jonas Olsson635474e2018-10-18 15:58:17 +0200276 void OnCombinedConnectionState(
277 PeerConnectionInterface::PeerConnectionState state) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100278 RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
279 << static_cast<int>(state);
Jonas Olsson635474e2018-10-18 15:58:17 +0200280 if (!signaling_thread_->IsCurrent()) {
281 signaled_on_non_signaling_thread_ = true;
282 }
283 combined_connection_state_ = state;
284 ++combined_connection_state_signal_count_;
285 }
286
Zhi Huange818b6e2018-02-22 15:26:27 -0800287 void OnGatheringState(cricket::IceGatheringState state) {
288 if (!signaling_thread_->IsCurrent()) {
289 signaled_on_non_signaling_thread_ = true;
290 }
291 gathering_state_ = state;
292 ++gathering_state_signal_count_;
293 }
294
295 void OnCandidatesGathered(const std::string& transport_name,
296 const Candidates& candidates) {
297 if (!signaling_thread_->IsCurrent()) {
298 signaled_on_non_signaling_thread_ = true;
299 }
300 candidates_[transport_name].insert(candidates_[transport_name].end(),
301 candidates.begin(), candidates.end());
302 ++candidates_signal_count_;
303 }
304
Zhi Huang365381f2018-04-13 16:44:34 -0700305 // JsepTransportController::Observer overrides.
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800306 bool OnTransportChanged(const std::string& mid,
307 RtpTransportInternal* rtp_transport,
308 cricket::DtlsTransportInternal* dtls_transport,
309 MediaTransportInterface* media_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700310 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800311 changed_dtls_transport_by_mid_[mid] = dtls_transport;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800312 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700313 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800314 }
315
316 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000317 cricket::IceConnectionState connection_state_ =
318 cricket::kIceConnectionConnecting;
319 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200320 PeerConnectionInterface::kIceConnectionNew;
321 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
322 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800323 bool receiving_ = false;
324 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
325 // transport_name => candidates
326 std::map<std::string, Candidates> candidates_;
327 // Counts of each signal emitted.
328 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000329 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200330 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800331 int receiving_signal_count_ = 0;
332 int gathering_state_signal_count_ = 0;
333 int candidates_signal_count_ = 0;
334
335 // |network_thread_| should be destroyed after |transport_controller_|
336 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800337 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
338 rtc::Thread* const signaling_thread_ = nullptr;
339 bool signaled_on_non_signaling_thread_ = false;
340 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
341 // signaled correctly.
342 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
343 std::map<std::string, cricket::DtlsTransportInternal*>
344 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800345 std::map<std::string, MediaTransportInterface*>
346 changed_media_transport_by_mid_;
347
348 // Transport controller needs to be destroyed first, because it may issue
349 // callbacks that modify the changed_*_by_mid in the destructor.
350 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800351};
352
353TEST_F(JsepTransportControllerTest, GetRtpTransport) {
354 CreateJsepTransportController(JsepTransportController::Config());
355 auto description = CreateSessionDescriptionWithoutBundle();
356 EXPECT_TRUE(transport_controller_
357 ->SetLocalDescription(SdpType::kOffer, description.get())
358 .ok());
359 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
360 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
361 EXPECT_NE(nullptr, audio_rtp_transport);
362 EXPECT_NE(nullptr, video_rtp_transport);
363 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
364 // Return nullptr for non-existing ones.
365 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
366}
367
368TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
369 JsepTransportController::Config config;
370 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
371 CreateJsepTransportController(config);
372 auto description = CreateSessionDescriptionWithoutBundle();
373 EXPECT_TRUE(transport_controller_
374 ->SetLocalDescription(SdpType::kOffer, description.get())
375 .ok());
376 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
377 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100378 EXPECT_NE(nullptr,
379 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800380 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
381 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100382 EXPECT_NE(nullptr,
383 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
384 // Lookup for all MIDs should return different transports (no bundle)
385 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
386 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800387 // Return nullptr for non-existing ones.
388 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
389 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100390 EXPECT_EQ(nullptr,
391 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100392 // Take a pointer to a transport, shut down the transport controller,
393 // and verify that the resulting container is empty.
394 auto dtls_transport =
395 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
396 webrtc::DtlsTransport* my_transport =
397 static_cast<DtlsTransport*>(dtls_transport.get());
398 EXPECT_NE(nullptr, my_transport->internal());
399 transport_controller_.reset();
400 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800401}
402
Zhi Huange830e682018-03-30 10:48:35 -0700403TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
404 JsepTransportController::Config config;
405 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
406 CreateJsepTransportController(config);
407 auto description = CreateSessionDescriptionWithoutBundle();
408 EXPECT_TRUE(transport_controller_
409 ->SetLocalDescription(SdpType::kOffer, description.get())
410 .ok());
411 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
412 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
413 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
414 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700415 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
416}
417
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800418TEST_F(JsepTransportControllerTest,
419 DtlsIsStillCreatedIfMediaTransportIsOnlyUsedForDataChannels) {
420 FakeMediaTransportFactory fake_media_transport_factory;
421 JsepTransportController::Config config;
422
423 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
424 config.media_transport_factory = &fake_media_transport_factory;
425 config.use_media_transport_for_data_channels = true;
426 CreateJsepTransportController(config);
427 auto description = CreateSessionDescriptionWithBundleGroup();
428 AddCryptoSettings(description.get());
429
430 EXPECT_TRUE(transport_controller_
431 ->SetLocalDescription(SdpType::kOffer, description.get())
432 .ok());
433
434 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
435 transport_controller_->GetMediaTransport(kAudioMid1));
436
437 ASSERT_NE(nullptr, media_transport);
438
439 // After SetLocalDescription, media transport should be created as caller.
440 EXPECT_TRUE(media_transport->is_caller());
441 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
442
443 // Return nullptr for non-existing mids.
444 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
445
446 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
447 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
448 << "Media transport for media was not enabled, and so DTLS transport "
449 "should be created.";
450}
451
Anton Sukhanov7940da02018-10-10 10:34:49 -0700452TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
453 FakeMediaTransportFactory fake_media_transport_factory;
454 JsepTransportController::Config config;
455
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800456 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700457 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800458 config.use_media_transport_for_data_channels = true;
459 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700460 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800461 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700462 AddCryptoSettings(description.get());
463
Anton Sukhanov7940da02018-10-10 10:34:49 -0700464 EXPECT_TRUE(transport_controller_
465 ->SetLocalDescription(SdpType::kOffer, description.get())
466 .ok());
467
468 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
469 transport_controller_->GetMediaTransport(kAudioMid1));
470
471 ASSERT_NE(nullptr, media_transport);
472
473 // After SetLocalDescription, media transport should be created as caller.
474 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700475 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700476
477 // Return nullptr for non-existing mids.
478 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800479
480 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
481 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
482 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700483}
484
485TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
486 FakeMediaTransportFactory fake_media_transport_factory;
487 JsepTransportController::Config config;
488
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800489 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700490 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800491 config.use_media_transport_for_data_channels = true;
492 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700493 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800494 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700495 AddCryptoSettings(description.get());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700496 EXPECT_TRUE(transport_controller_
497 ->SetRemoteDescription(SdpType::kOffer, description.get())
498 .ok());
499
500 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
501 transport_controller_->GetMediaTransport(kAudioMid1));
502
503 ASSERT_NE(nullptr, media_transport);
504
505 // After SetRemoteDescription, media transport should be created as callee.
506 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700507 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700508
509 // Return nullptr for non-existing mids.
510 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800511
512 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
513 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
514 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700515}
516
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800517TEST_F(JsepTransportControllerTest, GetMediaTransportInCalleePassesSdp) {
518 FakeMediaTransportFactory fake_media_transport_factory;
519 JsepTransportController::Config config;
520
521 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
522 config.media_transport_factory = &fake_media_transport_factory;
523 config.use_media_transport_for_data_channels = true;
524 config.use_media_transport_for_media = true;
525 CreateJsepTransportController(config);
526 auto description = CreateSessionDescriptionWithBundleGroup();
527 AddCryptoSettings(description.get());
528 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
529 EXPECT_TRUE(transport_controller_
530 ->SetRemoteDescription(SdpType::kOffer, description.get())
531 .ok());
532
533 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
534 transport_controller_->GetMediaTransport(kAudioMid1));
535
536 ASSERT_NE(nullptr, media_transport);
537
538 EXPECT_EQ("this-is-a-test-setting",
539 media_transport->settings().remote_transport_parameters);
540}
541
542// Caller ignores its own outgoing parameters.
543TEST_F(JsepTransportControllerTest,
544 GetMediaTransportInCallerIgnoresXmtSection) {
545 FakeMediaTransportFactory fake_media_transport_factory;
546 JsepTransportController::Config config;
547
548 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
549 config.media_transport_factory = &fake_media_transport_factory;
550 config.use_media_transport_for_data_channels = true;
551 config.use_media_transport_for_media = true;
552 CreateJsepTransportController(config);
553 auto description = CreateSessionDescriptionWithBundleGroup();
554 AddCryptoSettings(description.get());
555 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
556 EXPECT_TRUE(transport_controller_
557 ->SetLocalDescription(SdpType::kOffer, description.get())
558 .ok());
559
560 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
561 transport_controller_->GetMediaTransport(kAudioMid1));
562
563 ASSERT_NE(nullptr, media_transport);
564
565 // Remote parameters are nullopt, because we are the offerer (we don't)
566 // have the remote transport parameters, only ours.
567 EXPECT_EQ(absl::nullopt,
568 media_transport->settings().remote_transport_parameters);
569}
570
571TEST_F(JsepTransportControllerTest,
572 GetMediaTransportInCalleeIgnoresDifferentTransport) {
573 FakeMediaTransportFactory fake_media_transport_factory;
574 JsepTransportController::Config config;
575
576 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
577 config.media_transport_factory = &fake_media_transport_factory;
578 config.use_media_transport_for_data_channels = true;
579 config.use_media_transport_for_media = true;
580 CreateJsepTransportController(config);
581 auto description = CreateSessionDescriptionWithBundleGroup();
582 AddCryptoSettings(description.get());
583 description->AddMediaTransportSetting("not-a-fake-transport",
584 "this-is-a-test-setting");
585 EXPECT_TRUE(transport_controller_
586 ->SetRemoteDescription(SdpType::kOffer, description.get())
587 .ok());
588
589 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
590 transport_controller_->GetMediaTransport(kAudioMid1));
591
592 ASSERT_NE(nullptr, media_transport);
593
594 EXPECT_EQ(absl::nullopt,
595 media_transport->settings().remote_transport_parameters);
596}
597
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700598TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
599 FakeMediaTransportFactory fake_media_transport_factory;
600 JsepTransportController::Config config;
601
602 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
603 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800604 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700605 CreateJsepTransportController(config);
606 auto description = CreateSessionDescriptionWithoutBundle();
607 EXPECT_TRUE(transport_controller_
608 ->SetRemoteDescription(SdpType::kOffer, description.get())
609 .ok());
610
611 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
612
613 // Even if we set local description with crypto now (after the remote offer
614 // was set), media transport won't be provided.
615 auto description2 = CreateSessionDescriptionWithoutBundle();
616 AddCryptoSettings(description2.get());
617 EXPECT_TRUE(transport_controller_
618 ->SetLocalDescription(SdpType::kAnswer, description2.get())
619 .ok());
620
621 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800622 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
623 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
624 << "Because media transport is NOT used (fallback to RTP), expected "
625 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700626}
627
628TEST_F(JsepTransportControllerTest,
629 AfterSettingAnswerTheSameMediaTransportIsReturned) {
630 FakeMediaTransportFactory fake_media_transport_factory;
631 JsepTransportController::Config config;
632
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800633 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700634 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800635 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700636 CreateJsepTransportController(config);
637 auto description = CreateSessionDescriptionWithoutBundle();
638 AddCryptoSettings(description.get());
639 EXPECT_TRUE(transport_controller_
640 ->SetRemoteDescription(SdpType::kOffer, description.get())
641 .ok());
642
643 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
644 transport_controller_->GetMediaTransport(kAudioMid1));
645 EXPECT_NE(nullptr, media_transport);
646 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
647
648 // Even if we set local description with crypto now (after the remote offer
649 // was set), media transport won't be provided.
650 auto description2 = CreateSessionDescriptionWithoutBundle();
651 AddCryptoSettings(description2.get());
652
653 RTCError result = transport_controller_->SetLocalDescription(
654 SdpType::kAnswer, description2.get());
655 EXPECT_TRUE(result.ok()) << result.message();
656
657 // Media transport did not change.
658 EXPECT_EQ(media_transport,
659 transport_controller_->GetMediaTransport(kAudioMid1));
660}
661
Zhi Huange818b6e2018-02-22 15:26:27 -0800662TEST_F(JsepTransportControllerTest, SetIceConfig) {
663 CreateJsepTransportController(JsepTransportController::Config());
664 auto description = CreateSessionDescriptionWithoutBundle();
665 EXPECT_TRUE(transport_controller_
666 ->SetLocalDescription(SdpType::kOffer, description.get())
667 .ok());
668
669 transport_controller_->SetIceConfig(
670 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
671 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
672 transport_controller_->GetDtlsTransport(kAudioMid1));
673 ASSERT_NE(nullptr, fake_audio_dtls);
674 EXPECT_EQ(kTimeout,
675 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
676 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
677
678 // Test that value stored in controller is applied to new transports.
679 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
680 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
681 nullptr);
682
683 EXPECT_TRUE(transport_controller_
684 ->SetLocalDescription(SdpType::kOffer, description.get())
685 .ok());
686 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
687 transport_controller_->GetDtlsTransport(kAudioMid2));
688 ASSERT_NE(nullptr, fake_audio_dtls);
689 EXPECT_EQ(kTimeout,
690 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
691 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
692}
693
694// Tests the getter and setter of the ICE restart flag.
695TEST_F(JsepTransportControllerTest, NeedIceRestart) {
696 CreateJsepTransportController(JsepTransportController::Config());
697 auto description = CreateSessionDescriptionWithoutBundle();
698 EXPECT_TRUE(transport_controller_
699 ->SetLocalDescription(SdpType::kOffer, description.get())
700 .ok());
701 EXPECT_TRUE(transport_controller_
702 ->SetRemoteDescription(SdpType::kAnswer, description.get())
703 .ok());
704
705 // Initially NeedsIceRestart should return false.
706 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
707 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
708 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
709 // true.
710 transport_controller_->SetNeedsIceRestartFlag();
711 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
712 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
713 // For a nonexistent transport, false should be returned.
714 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
715
716 // Reset the ice_ufrag/ice_pwd for audio.
717 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
718 audio_transport_info->description.ice_ufrag = kIceUfrag2;
719 audio_transport_info->description.ice_pwd = kIcePwd2;
720 EXPECT_TRUE(transport_controller_
721 ->SetLocalDescription(SdpType::kOffer, description.get())
722 .ok());
723 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
724 // return false for audio and true for video.
725 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
726 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
727}
728
729TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
730 CreateJsepTransportController(JsepTransportController::Config());
731 auto description = CreateSessionDescriptionWithBundleGroup();
732 EXPECT_TRUE(transport_controller_
733 ->SetLocalDescription(SdpType::kOffer, description.get())
734 .ok());
735 // After setting the local description, we should be able to start gathering
736 // candidates.
737 transport_controller_->MaybeStartGathering();
738 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
739 EXPECT_EQ(1, gathering_state_signal_count_);
740}
741
742TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
743 CreateJsepTransportController(JsepTransportController::Config());
744 auto description = CreateSessionDescriptionWithoutBundle();
745 transport_controller_->SetLocalDescription(SdpType::kOffer,
746 description.get());
747 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
748 description.get());
749 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
750 transport_controller_->GetDtlsTransport(kAudioMid1));
751 ASSERT_NE(nullptr, fake_audio_dtls);
752 Candidates candidates;
753 candidates.push_back(
754 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
755 EXPECT_TRUE(
756 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
757 EXPECT_EQ(1U,
758 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
759
760 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
761 EXPECT_EQ(0U,
762 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
763}
764
765TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
766 CreateJsepTransportController(JsepTransportController::Config());
767
768 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
769 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
770 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
771 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
772
Karl Wiberg918f50c2018-07-05 11:40:33 +0200773 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800774 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
775 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
776 certificate1);
777
778 // Apply the local certificate.
779 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
780 // Apply the local description.
781 EXPECT_TRUE(transport_controller_
782 ->SetLocalDescription(SdpType::kOffer, description.get())
783 .ok());
784 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
785 EXPECT_TRUE(returned_certificate);
786 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
787 returned_certificate->identity()->certificate().ToPEMString());
788
789 // Should fail if called for a nonexistant transport.
790 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
791
792 // Shouldn't be able to change the identity once set.
793 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
794 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
795 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
796 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
797}
798
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800799TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800800 CreateJsepTransportController(JsepTransportController::Config());
801 auto description = CreateSessionDescriptionWithBundleGroup();
802 EXPECT_TRUE(transport_controller_
803 ->SetLocalDescription(SdpType::kOffer, description.get())
804 .ok());
805 rtc::FakeSSLCertificate fake_certificate("fake_data");
806
807 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
808 transport_controller_->GetDtlsTransport(kAudioMid1));
809 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800810 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
811 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
812 ASSERT_TRUE(returned_cert_chain);
813 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800814 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800815 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800816
817 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800818 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800819}
820
821TEST_F(JsepTransportControllerTest, GetDtlsRole) {
822 CreateJsepTransportController(JsepTransportController::Config());
823 auto offer_certificate =
824 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
825 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
826 auto answer_certificate =
827 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
828 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
829 transport_controller_->SetLocalCertificate(offer_certificate);
830
Karl Wiberg918f50c2018-07-05 11:40:33 +0200831 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800832 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
833 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
834 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200835 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800836 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
837 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
838 answer_certificate);
839
840 EXPECT_TRUE(transport_controller_
841 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
842 .ok());
843
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200844 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800845 transport_controller_->GetDtlsRole(kAudioMid1);
846 // The DTLS role is not decided yet.
847 EXPECT_FALSE(role);
848 EXPECT_TRUE(transport_controller_
849 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
850 .ok());
851 role = transport_controller_->GetDtlsRole(kAudioMid1);
852
853 ASSERT_TRUE(role);
854 EXPECT_EQ(rtc::SSL_CLIENT, *role);
855}
856
857TEST_F(JsepTransportControllerTest, GetStats) {
858 CreateJsepTransportController(JsepTransportController::Config());
859 auto description = CreateSessionDescriptionWithBundleGroup();
860 EXPECT_TRUE(transport_controller_
861 ->SetLocalDescription(SdpType::kOffer, description.get())
862 .ok());
863
864 cricket::TransportStats stats;
865 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
866 EXPECT_EQ(kAudioMid1, stats.transport_name);
867 EXPECT_EQ(1u, stats.channel_stats.size());
868 // Return false for non-existing transport.
869 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
870}
871
872TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
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_ice = static_cast<cricket::FakeIceTransport*>(
880 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
881 fake_ice->SetCandidatesGatheringComplete();
882 fake_ice->SetConnectionCount(1);
883 // The connection stats will be failed if there is no active connection.
884 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +0000885 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100886 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000887 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
888 ice_connection_state_, kTimeout);
889 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100890 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
891 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200892 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800893}
894
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700895TEST_F(JsepTransportControllerTest,
896 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800897 CreateJsepTransportController(JsepTransportController::Config());
898 auto description = CreateSessionDescriptionWithoutBundle();
899 EXPECT_TRUE(transport_controller_
900 ->SetLocalDescription(SdpType::kOffer, description.get())
901 .ok());
902
903 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
904 transport_controller_->GetDtlsTransport(kAudioMid1));
905 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
906 transport_controller_->GetDtlsTransport(kVideoMid1));
907
908 // First, have one transport connect, and another fail, to ensure that
909 // the first transport connecting didn't trigger a "connected" state signal.
910 // We should only get a signal when all are connected.
911 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
912 fake_audio_dtls->SetWritable(true);
913 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
914 // Decrease the number of the connection to trigger the signal.
915 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
916 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
917 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
918
Alex Loiko9289eda2018-11-23 16:18:59 +0000919 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100920 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000921 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
922 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100923 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100924 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
925 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100926 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800927
Jonas Olsson635474e2018-10-18 15:58:17 +0200928 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
929 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800930 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
931 // the transport state to be STATE_CONNECTING.
932 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
933 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000934 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100935 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000936 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
937 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100938 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100939 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
940 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100941 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800942}
943
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700944TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800945 SignalConnectionStateConnectedWithMediaTransportAndNoDtls) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700946 FakeMediaTransportFactory fake_media_transport_factory;
947 JsepTransportController::Config config;
948 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800949 config.use_media_transport_for_data_channels = true;
950 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700951 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800952
953 // Media Transport is only used with bundle.
954 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700955 AddCryptoSettings(description.get());
956 EXPECT_TRUE(transport_controller_
957 ->SetLocalDescription(SdpType::kOffer, description.get())
958 .ok());
959
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800960 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
961 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
962 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
963 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
964 fake_audio_ice->SetConnectionCount(2);
965 fake_audio_ice->SetConnectionCount(1);
966 fake_video_ice->SetConnectionCount(2);
967 fake_video_ice->SetConnectionCount(1);
968 fake_audio_ice->SetWritable(true);
969 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700970
971 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +0000972 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
973 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700974
975 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
976 transport_controller_->GetMediaTransport(kAudioMid1));
977
978 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Alex Loiko9289eda2018-11-23 16:18:59 +0000979 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
980 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700981
982 // Still waiting for the second media transport.
983 media_transport = static_cast<FakeMediaTransport*>(
984 transport_controller_->GetMediaTransport(kVideoMid1));
985 media_transport->SetState(webrtc::MediaTransportState::kWritable);
986
Alex Loiko9289eda2018-11-23 16:18:59 +0000987 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700988}
989
990TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800991 SignalConnectionStateConnectedWithMediaTransport) {
992 FakeMediaTransportFactory fake_media_transport_factory;
993 JsepTransportController::Config config;
994 config.media_transport_factory = &fake_media_transport_factory;
995 config.use_media_transport_for_media = true;
996 CreateJsepTransportController(config);
997
998 // Media Transport is only used with bundle.
999 auto description = CreateSessionDescriptionWithBundleGroup();
1000 AddCryptoSettings(description.get());
1001 EXPECT_TRUE(transport_controller_
1002 ->SetLocalDescription(SdpType::kOffer, description.get())
1003 .ok());
1004
1005 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1006 transport_controller_->GetDtlsTransport(kAudioMid1));
1007 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1008 transport_controller_->GetDtlsTransport(kVideoMid1));
1009
1010 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1011 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1012 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1013 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1014 fake_audio_ice->SetConnectionCount(2);
1015 fake_audio_ice->SetConnectionCount(1);
1016 fake_video_ice->SetConnectionCount(2);
1017 fake_video_ice->SetConnectionCount(1);
1018 fake_audio_ice->SetWritable(true);
1019 fake_video_ice->SetWritable(true);
1020 fake_audio_dtls->SetWritable(true);
1021 fake_video_dtls->SetWritable(true);
1022
1023 // Still not connected, because we are waiting for media transport.
1024 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1025 kTimeout);
1026
1027 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1028 transport_controller_->GetMediaTransport(kAudioMid1));
1029
1030 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1031 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1032 kTimeout);
1033
1034 // Still waiting for the second media transport.
1035 media_transport = static_cast<FakeMediaTransport*>(
1036 transport_controller_->GetMediaTransport(kVideoMid1));
1037 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1038
1039 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
1040}
1041
1042TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001043 SignalConnectionStateFailedWhenMediaTransportClosed) {
1044 FakeMediaTransportFactory fake_media_transport_factory;
1045 JsepTransportController::Config config;
1046 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001047 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001048 CreateJsepTransportController(config);
1049 auto description = CreateSessionDescriptionWithoutBundle();
1050 AddCryptoSettings(description.get());
1051 EXPECT_TRUE(transport_controller_
1052 ->SetLocalDescription(SdpType::kOffer, description.get())
1053 .ok());
1054
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001055 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1056 transport_controller_->GetDtlsTransport(kAudioMid1));
1057 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1058 transport_controller_->GetDtlsTransport(kVideoMid1));
1059
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001060 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1061 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1062 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1063 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1064 fake_audio_ice->SetWritable(true);
1065 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001066 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001067 fake_audio_ice->SetConnectionCount(2);
1068 fake_audio_ice->SetConnectionCount(1);
1069 fake_video_ice->SetConnectionCount(2);
1070 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001071
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001072 fake_audio_dtls->SetWritable(true);
1073 fake_video_dtls->SetWritable(true);
1074
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001075 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1076 transport_controller_->GetMediaTransport(kAudioMid1));
1077
1078 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1079
1080 media_transport = static_cast<FakeMediaTransport*>(
1081 transport_controller_->GetMediaTransport(kVideoMid1));
1082
1083 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1084
Alex Loiko9289eda2018-11-23 16:18:59 +00001085 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001086
1087 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +00001088 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001089}
1090
Zhi Huange818b6e2018-02-22 15:26:27 -08001091TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1092 CreateJsepTransportController(JsepTransportController::Config());
1093 auto description = CreateSessionDescriptionWithoutBundle();
1094 EXPECT_TRUE(transport_controller_
1095 ->SetLocalDescription(SdpType::kOffer, description.get())
1096 .ok());
1097
1098 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1099 transport_controller_->GetDtlsTransport(kAudioMid1));
1100 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1101 transport_controller_->GetDtlsTransport(kVideoMid1));
1102
1103 // First, have one transport connect, and another fail, to ensure that
1104 // the first transport connecting didn't trigger a "connected" state signal.
1105 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001106 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1107 IceTransportState::kCompleted,
1108 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001109 fake_audio_dtls->SetWritable(true);
1110 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001111
1112 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1113 ice_connection_state_, kTimeout);
1114 EXPECT_EQ(1, ice_connection_state_signal_count_);
1115 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1116 combined_connection_state_, kTimeout);
1117 EXPECT_EQ(1, combined_connection_state_signal_count_);
1118
1119 fake_video_dtls->fake_ice_transport()->SetTransportState(
1120 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001121 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1122
Alex Loiko9289eda2018-11-23 16:18:59 +00001123 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001124 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001125 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1126 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001127 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001128 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1129 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001130 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001131
Jonas Olsson635474e2018-10-18 15:58:17 +02001132 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1133 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001134 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1135 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001136 fake_video_dtls->fake_ice_transport()->SetTransportState(
1137 IceTransportState::kCompleted,
1138 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001139 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001140 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +01001141 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001142 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1143 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001144 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001145 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1146 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001147 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001148}
1149
1150TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1151 CreateJsepTransportController(JsepTransportController::Config());
1152 auto description = CreateSessionDescriptionWithoutBundle();
1153 EXPECT_TRUE(transport_controller_
1154 ->SetLocalDescription(SdpType::kOffer, description.get())
1155 .ok());
1156
1157 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1158 transport_controller_->GetDtlsTransport(kAudioMid1));
1159 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1160 // Should be in the gathering state as soon as any transport starts gathering.
1161 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1162 EXPECT_EQ(1, gathering_state_signal_count_);
1163}
1164
1165TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1166 CreateJsepTransportController(JsepTransportController::Config());
1167 auto description = CreateSessionDescriptionWithoutBundle();
1168 EXPECT_TRUE(transport_controller_
1169 ->SetLocalDescription(SdpType::kOffer, description.get())
1170 .ok());
1171
1172 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1173 transport_controller_->GetDtlsTransport(kAudioMid1));
1174 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1175 transport_controller_->GetDtlsTransport(kVideoMid1));
1176
1177 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1178 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1179 EXPECT_EQ(1, gathering_state_signal_count_);
1180
1181 // Have one transport finish gathering, to make sure gathering
1182 // completion wasn't signalled if only one transport finished gathering.
1183 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1184 EXPECT_EQ(1, gathering_state_signal_count_);
1185
1186 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1187 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1188 EXPECT_EQ(1, gathering_state_signal_count_);
1189
1190 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1191 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1192 EXPECT_EQ(2, gathering_state_signal_count_);
1193}
1194
1195// Test that when the last transport that hasn't finished connecting and/or
1196// gathering is destroyed, the aggregate state jumps to "completed". This can
1197// happen if, for example, we have an audio and video transport, the audio
1198// transport completes, then we start bundling video on the audio transport.
1199TEST_F(JsepTransportControllerTest,
1200 SignalingWhenLastIncompleteTransportDestroyed) {
1201 CreateJsepTransportController(JsepTransportController::Config());
1202 auto description = CreateSessionDescriptionWithBundleGroup();
1203 EXPECT_TRUE(transport_controller_
1204 ->SetLocalDescription(SdpType::kOffer, description.get())
1205 .ok());
1206
1207 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1208 transport_controller_->GetDtlsTransport(kAudioMid1));
1209 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1210 transport_controller_->GetDtlsTransport(kVideoMid1));
1211 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1212
1213 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1214 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1215 EXPECT_EQ(1, gathering_state_signal_count_);
1216
1217 // Let the audio transport complete.
1218 fake_audio_dtls->SetWritable(true);
1219 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1220 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001221 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001222 EXPECT_EQ(1, gathering_state_signal_count_);
1223
1224 // Set the remote description and enable the bundle.
1225 EXPECT_TRUE(transport_controller_
1226 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1227 .ok());
1228 // The BUNDLE should be enabled, the incomplete video transport should be
1229 // deleted and the states shoud be updated.
1230 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1231 transport_controller_->GetDtlsTransport(kVideoMid1));
1232 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001233 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1234 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1235 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001236 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1237 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001238 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1239 EXPECT_EQ(2, gathering_state_signal_count_);
1240}
1241
1242TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1243 CreateJsepTransportController(JsepTransportController::Config());
1244 auto description = CreateSessionDescriptionWithBundleGroup();
1245 EXPECT_TRUE(transport_controller_
1246 ->SetLocalDescription(SdpType::kOffer, description.get())
1247 .ok());
1248 transport_controller_->MaybeStartGathering();
1249
1250 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1251 transport_controller_->GetDtlsTransport(kAudioMid1));
1252 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1253 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1254 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1255 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1256}
1257
1258TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1259 network_thread_ = rtc::Thread::CreateWithSocketServer();
1260 network_thread_->Start();
1261 CreateJsepTransportController(JsepTransportController::Config(),
1262 signaling_thread_, network_thread_.get(),
1263 /*PortAllocator=*/nullptr);
1264 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1265
1266 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001267 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001268 EXPECT_EQ(2, connection_state_signal_count_);
1269
1270 // new --> gathering --> complete
1271 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1272 EXPECT_EQ(2, gathering_state_signal_count_);
1273
1274 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1275 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1276 EXPECT_EQ(2, candidates_signal_count_);
1277
1278 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1279}
1280
1281// Older versions of Chrome expect the ICE role to be re-determined when an
1282// ICE restart occurs, and also don't perform conflict resolution correctly,
1283// so for now we can't safely stop doing this.
1284// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1285// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1286// enough population.
1287TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1288 CreateJsepTransportController(JsepTransportController::Config());
1289 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001290 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001291 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1292 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1293 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001294 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001295 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1296 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1297 nullptr);
1298
1299 EXPECT_TRUE(transport_controller_
1300 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1301 .ok());
1302 EXPECT_TRUE(transport_controller_
1303 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1304 .ok());
1305
1306 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1307 transport_controller_->GetDtlsTransport(kAudioMid1));
1308 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1309 fake_dtls->fake_ice_transport()->GetIceRole());
1310
1311 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001312 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001313 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1314 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1315 nullptr);
1316 EXPECT_TRUE(
1317 transport_controller_
1318 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1319 .ok());
1320 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1321 fake_dtls->fake_ice_transport()->GetIceRole());
1322}
1323
1324// Test that if the TransportController was created with the
1325// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1326// redetermined on an ICE restart.
1327TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1328 JsepTransportController::Config config;
1329 config.redetermine_role_on_ice_restart = false;
1330
1331 CreateJsepTransportController(config);
1332 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001333 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001334 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1335 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1336 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001337 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001338 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1339 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1340 nullptr);
1341
1342 EXPECT_TRUE(transport_controller_
1343 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1344 .ok());
1345 EXPECT_TRUE(transport_controller_
1346 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1347 .ok());
1348
1349 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1350 transport_controller_->GetDtlsTransport(kAudioMid1));
1351 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1352 fake_dtls->fake_ice_transport()->GetIceRole());
1353
1354 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001355 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001356 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1357 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1358 nullptr);
1359 EXPECT_TRUE(
1360 transport_controller_
1361 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1362 .ok());
1363 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1364 fake_dtls->fake_ice_transport()->GetIceRole());
1365}
1366
1367// Tests ICE-Lite mode in remote answer.
1368TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1369 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001370 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001371 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1372 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1373 nullptr);
1374 EXPECT_TRUE(transport_controller_
1375 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1376 .ok());
1377 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1378 transport_controller_->GetDtlsTransport(kAudioMid1));
1379 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1380 fake_dtls->fake_ice_transport()->GetIceRole());
1381 EXPECT_EQ(cricket::ICEMODE_FULL,
1382 fake_dtls->fake_ice_transport()->remote_ice_mode());
1383
Karl Wiberg918f50c2018-07-05 11:40:33 +02001384 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001385 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1386 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1387 nullptr);
1388 EXPECT_TRUE(transport_controller_
1389 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1390 .ok());
1391 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1392 fake_dtls->fake_ice_transport()->GetIceRole());
1393 EXPECT_EQ(cricket::ICEMODE_LITE,
1394 fake_dtls->fake_ice_transport()->remote_ice_mode());
1395}
1396
1397// Tests that the ICE role remains "controlling" if a subsequent offer that
1398// does an ICE restart is received from an ICE lite endpoint. Regression test
1399// for: https://crbug.com/710760
1400TEST_F(JsepTransportControllerTest,
1401 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1402 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001403 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001404 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1405 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1406 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001407 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001408 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1409 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1410 nullptr);
1411 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1412 // local side is the controlling.
1413 EXPECT_TRUE(transport_controller_
1414 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1415 .ok());
1416 EXPECT_TRUE(transport_controller_
1417 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1418 .ok());
1419 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1420 transport_controller_->GetDtlsTransport(kAudioMid1));
1421 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1422 fake_dtls->fake_ice_transport()->GetIceRole());
1423
1424 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001425 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001426 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1427 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1428 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001429 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001430 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1431 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1432 nullptr);
1433 EXPECT_TRUE(transport_controller_
1434 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1435 .ok());
1436 EXPECT_TRUE(transport_controller_
1437 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1438 .ok());
1439 fake_dtls = static_cast<FakeDtlsTransport*>(
1440 transport_controller_->GetDtlsTransport(kAudioMid1));
1441 // The local side is still the controlling role since the remote side is using
1442 // ICE-Lite.
1443 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1444 fake_dtls->fake_ice_transport()->GetIceRole());
1445}
1446
1447// Tests that the SDP has more than one audio/video m= sections.
1448TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1449 CreateJsepTransportController(JsepTransportController::Config());
1450 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1451 bundle_group.AddContentName(kAudioMid1);
1452 bundle_group.AddContentName(kAudioMid2);
1453 bundle_group.AddContentName(kVideoMid1);
1454 bundle_group.AddContentName(kDataMid1);
1455
Karl Wiberg918f50c2018-07-05 11:40:33 +02001456 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001457 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1458 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1459 nullptr);
1460 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1461 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1462 nullptr);
1463 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1464 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1465 nullptr);
1466 AddDataSection(local_offer.get(), kDataMid1,
1467 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1468 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1469 nullptr);
1470
Karl Wiberg918f50c2018-07-05 11:40:33 +02001471 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001472 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1473 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1474 nullptr);
1475 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1476 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1477 nullptr);
1478 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1479 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1480 nullptr);
1481 AddDataSection(remote_answer.get(), kDataMid1,
1482 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1483 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1484 nullptr);
1485
1486 local_offer->AddGroup(bundle_group);
1487 remote_answer->AddGroup(bundle_group);
1488
1489 EXPECT_TRUE(transport_controller_
1490 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1491 .ok());
1492 EXPECT_TRUE(transport_controller_
1493 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1494 .ok());
1495 // Verify that all the sections are bundled on kAudio1.
1496 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1497 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1498 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1499 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1500 EXPECT_EQ(transport1, transport2);
1501 EXPECT_EQ(transport1, transport3);
1502 EXPECT_EQ(transport1, transport4);
1503
Harald Alvestrandad88c882018-11-28 16:47:46 +01001504 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1505 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1506
Zhi Huange818b6e2018-02-22 15:26:27 -08001507 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1508 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1509 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1510 EXPECT_EQ(transport1, it->second);
1511 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1512 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1513 EXPECT_EQ(transport1, it->second);
1514 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1515 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1516 EXPECT_EQ(transport1, it->second);
1517 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1518 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1519 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1520 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1521}
1522
1523// Tests that only a subset of all the m= sections are bundled.
1524TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1525 CreateJsepTransportController(JsepTransportController::Config());
1526 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1527 bundle_group.AddContentName(kAudioMid1);
1528 bundle_group.AddContentName(kVideoMid1);
1529
Karl Wiberg918f50c2018-07-05 11:40:33 +02001530 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001531 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1532 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1533 nullptr);
1534 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1535 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1536 nullptr);
1537 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1538 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1539 nullptr);
1540
Karl Wiberg918f50c2018-07-05 11:40:33 +02001541 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001542 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1543 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1544 nullptr);
1545 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1546 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1547 nullptr);
1548 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1549 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1550 nullptr);
1551
1552 local_offer->AddGroup(bundle_group);
1553 remote_answer->AddGroup(bundle_group);
1554 EXPECT_TRUE(transport_controller_
1555 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1556 .ok());
1557 EXPECT_TRUE(transport_controller_
1558 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1559 .ok());
1560
1561 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1562 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1563 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1564 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1565 EXPECT_NE(transport1, transport2);
1566 EXPECT_EQ(transport1, transport3);
1567
1568 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1569 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1570 EXPECT_EQ(transport1, it->second);
1571 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001572 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001573}
1574
1575// Tests that the initial offer/answer only have data section and audio/video
1576// sections are added in the subsequent offer.
1577TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1578 CreateJsepTransportController(JsepTransportController::Config());
1579 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1580 bundle_group.AddContentName(kDataMid1);
1581
Karl Wiberg918f50c2018-07-05 11:40:33 +02001582 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001583 AddDataSection(local_offer.get(), kDataMid1,
1584 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1585 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1586 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001587 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001588 AddDataSection(remote_answer.get(), kDataMid1,
1589 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1590 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1591 nullptr);
1592 local_offer->AddGroup(bundle_group);
1593 remote_answer->AddGroup(bundle_group);
1594
1595 EXPECT_TRUE(transport_controller_
1596 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1597 .ok());
1598 EXPECT_TRUE(transport_controller_
1599 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1600 .ok());
1601 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1602
1603 // Add audio/video sections in subsequent offer.
1604 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1605 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1606 nullptr);
1607 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1608 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1609 nullptr);
1610 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1611 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1612 nullptr);
1613 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1614 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1615 nullptr);
1616
1617 // Reset the bundle group and do another offer/answer exchange.
1618 bundle_group.AddContentName(kAudioMid1);
1619 bundle_group.AddContentName(kVideoMid1);
1620 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1621 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1622 local_offer->AddGroup(bundle_group);
1623 remote_answer->AddGroup(bundle_group);
1624
1625 EXPECT_TRUE(transport_controller_
1626 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1627 .ok());
1628 EXPECT_TRUE(transport_controller_
1629 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1630 .ok());
1631
1632 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1633 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1634 EXPECT_EQ(data_transport, audio_transport);
1635 EXPECT_EQ(data_transport, video_transport);
1636}
1637
1638TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1639 CreateJsepTransportController(JsepTransportController::Config());
1640 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1641 bundle_group.AddContentName(kAudioMid1);
1642 bundle_group.AddContentName(kVideoMid1);
1643 bundle_group.AddContentName(kDataMid1);
1644
Karl Wiberg918f50c2018-07-05 11:40:33 +02001645 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001646 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1647 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1648 nullptr);
1649 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1650 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1651 nullptr);
1652 AddDataSection(local_offer.get(), kDataMid1,
1653 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1654 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1655 nullptr);
1656
Karl Wiberg918f50c2018-07-05 11:40:33 +02001657 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001658 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1659 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1660 nullptr);
1661 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1662 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1663 nullptr);
1664 AddDataSection(remote_answer.get(), kDataMid1,
1665 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1666 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1667 nullptr);
1668 // Reject video and data section.
1669 remote_answer->contents()[1].rejected = true;
1670 remote_answer->contents()[2].rejected = true;
1671
1672 local_offer->AddGroup(bundle_group);
1673 remote_answer->AddGroup(bundle_group);
1674
1675 EXPECT_TRUE(transport_controller_
1676 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1677 .ok());
1678 EXPECT_TRUE(transport_controller_
1679 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1680 .ok());
1681
1682 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1683 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1684 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1685 // Verify the signals are fired correctly.
1686 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1687 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1688 EXPECT_EQ(nullptr, it->second);
1689 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1690 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1691 EXPECT_EQ(nullptr, it2->second);
1692}
1693
1694// Tests that changing the bundled MID in subsequent offer/answer exchange is
1695// not supported.
1696// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1697// fixed
1698TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1699 CreateJsepTransportController(JsepTransportController::Config());
1700 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1701 bundle_group.AddContentName(kAudioMid1);
1702 bundle_group.AddContentName(kVideoMid1);
1703
Karl Wiberg918f50c2018-07-05 11:40:33 +02001704 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001705 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1706 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1707 nullptr);
1708 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1709 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1710 nullptr);
1711
Karl Wiberg918f50c2018-07-05 11:40:33 +02001712 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001713 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1714 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1715 nullptr);
1716 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1717 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1718 nullptr);
1719
1720 local_offer->AddGroup(bundle_group);
1721 remote_answer->AddGroup(bundle_group);
1722 EXPECT_TRUE(transport_controller_
1723 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1724 .ok());
1725 EXPECT_TRUE(transport_controller_
1726 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1727 .ok());
1728 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1729 transport_controller_->GetRtpTransport(kVideoMid1));
1730
1731 // Reorder the bundle group.
1732 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1733 bundle_group.AddContentName(kAudioMid1);
1734 // The answerer uses the new bundle group and now the bundle mid is changed to
1735 // |kVideo1|.
1736 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1737 remote_answer->AddGroup(bundle_group);
1738 EXPECT_TRUE(transport_controller_
1739 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1740 .ok());
1741 EXPECT_FALSE(transport_controller_
1742 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1743 .ok());
1744}
Zhi Huange830e682018-03-30 10:48:35 -07001745// Test that rejecting only the first m= section of a BUNDLE group is treated as
1746// an error, but rejecting all of them works as expected.
1747TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1748 CreateJsepTransportController(JsepTransportController::Config());
1749 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1750 bundle_group.AddContentName(kAudioMid1);
1751 bundle_group.AddContentName(kVideoMid1);
1752 bundle_group.AddContentName(kDataMid1);
1753
Karl Wiberg918f50c2018-07-05 11:40:33 +02001754 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001755 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1756 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1757 nullptr);
1758 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1759 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1760 nullptr);
1761 AddDataSection(local_offer.get(), kDataMid1,
1762 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1763 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1764 nullptr);
1765
Karl Wiberg918f50c2018-07-05 11:40:33 +02001766 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001767 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1768 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1769 nullptr);
1770 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1771 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1772 nullptr);
1773 AddDataSection(remote_answer.get(), kDataMid1,
1774 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1775 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1776 nullptr);
1777 // Reject audio content in answer.
1778 remote_answer->contents()[0].rejected = true;
1779
1780 local_offer->AddGroup(bundle_group);
1781 remote_answer->AddGroup(bundle_group);
1782
1783 EXPECT_TRUE(transport_controller_
1784 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1785 .ok());
1786 EXPECT_FALSE(transport_controller_
1787 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1788 .ok());
1789
1790 // Reject all the contents.
1791 remote_answer->contents()[1].rejected = true;
1792 remote_answer->contents()[2].rejected = true;
1793 EXPECT_TRUE(transport_controller_
1794 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1795 .ok());
1796 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1797 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1798 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1799}
1800
1801// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1802// is used.
1803TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1804 JsepTransportController::Config config;
1805 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1806 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001807 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001808 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1809 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1810 nullptr);
1811
1812 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1813 // Applying a non-RTCP-mux offer is expected to fail.
1814 EXPECT_FALSE(transport_controller_
1815 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1816 .ok());
1817}
1818
1819// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1820// is used.
1821TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1822 JsepTransportController::Config config;
1823 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1824 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001825 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001826 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1827 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1828 nullptr);
1829 EXPECT_TRUE(transport_controller_
1830 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1831 .ok());
1832
Karl Wiberg918f50c2018-07-05 11:40:33 +02001833 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001834 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1835 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1836 nullptr);
1837 // Applying a non-RTCP-mux answer is expected to fail.
1838 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1839 EXPECT_FALSE(transport_controller_
1840 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1841 .ok());
1842}
Zhi Huange818b6e2018-02-22 15:26:27 -08001843
Zhi Huangd2248f82018-04-10 14:41:03 -07001844// This tests that the BUNDLE group in answer should be a subset of the offered
1845// group.
1846TEST_F(JsepTransportControllerTest,
1847 AddContentToBundleGroupInAnswerNotSupported) {
1848 CreateJsepTransportController(JsepTransportController::Config());
1849 auto local_offer = CreateSessionDescriptionWithoutBundle();
1850 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1851
1852 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1853 offer_bundle_group.AddContentName(kAudioMid1);
1854 local_offer->AddGroup(offer_bundle_group);
1855
1856 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1857 answer_bundle_group.AddContentName(kAudioMid1);
1858 answer_bundle_group.AddContentName(kVideoMid1);
1859 remote_answer->AddGroup(answer_bundle_group);
1860 EXPECT_TRUE(transport_controller_
1861 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1862 .ok());
1863 EXPECT_FALSE(transport_controller_
1864 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1865 .ok());
1866}
1867
1868// This tests that the BUNDLE group with non-existing MID should be rejectd.
1869TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1870 CreateJsepTransportController(JsepTransportController::Config());
1871 auto local_offer = CreateSessionDescriptionWithoutBundle();
1872 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1873
1874 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1875 // The BUNDLE group is invalid because there is no data section in the
1876 // description.
1877 invalid_bundle_group.AddContentName(kDataMid1);
1878 local_offer->AddGroup(invalid_bundle_group);
1879 remote_answer->AddGroup(invalid_bundle_group);
1880
1881 EXPECT_FALSE(transport_controller_
1882 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1883 .ok());
1884 EXPECT_FALSE(transport_controller_
1885 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1886 .ok());
1887}
1888
1889// This tests that an answer shouldn't be able to remove an m= section from an
1890// established group without rejecting it.
1891TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1892 CreateJsepTransportController(JsepTransportController::Config());
1893
1894 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1895 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1896 EXPECT_TRUE(transport_controller_
1897 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1898 .ok());
1899 EXPECT_TRUE(transport_controller_
1900 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1901 .ok());
1902
1903 // Do an re-offer/answer.
1904 EXPECT_TRUE(transport_controller_
1905 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1906 .ok());
1907 auto new_answer = CreateSessionDescriptionWithoutBundle();
1908 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1909 // The answer removes video from the BUNDLE group without rejecting it is
1910 // invalid.
1911 new_bundle_group.AddContentName(kAudioMid1);
1912 new_answer->AddGroup(new_bundle_group);
1913
1914 // Applying invalid answer is expected to fail.
1915 EXPECT_FALSE(transport_controller_
1916 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1917 .ok());
1918
1919 // Rejected the video content.
1920 auto video_content = new_answer->GetContentByName(kVideoMid1);
1921 ASSERT_TRUE(video_content);
1922 video_content->rejected = true;
1923 EXPECT_TRUE(transport_controller_
1924 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1925 .ok());
1926}
1927
Steve Anton2bed3972019-01-04 17:04:30 -08001928// Test that the JsepTransportController can process a new local and remote
1929// description that changes the tagged BUNDLE group with the max-bundle policy
1930// specified.
1931// This is a regression test for bugs.webrtc.org/9954
1932TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
1933 CreateJsepTransportController(JsepTransportController::Config());
1934
1935 auto local_offer = absl::make_unique<cricket::SessionDescription>();
1936 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1937 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1938 nullptr);
1939 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1940 bundle_group.AddContentName(kAudioMid1);
1941 local_offer->AddGroup(bundle_group);
1942 EXPECT_TRUE(transport_controller_
1943 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1944 .ok());
1945
1946 std::unique_ptr<cricket::SessionDescription> remote_answer(
1947 local_offer->Copy());
1948 EXPECT_TRUE(transport_controller_
1949 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1950 .ok());
1951
1952 std::unique_ptr<cricket::SessionDescription> local_reoffer(
1953 local_offer->Copy());
1954 local_reoffer->contents()[0].rejected = true;
1955 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
1956 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1957 nullptr);
1958 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1959 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1960 new_bundle_group.AddContentName(kVideoMid1);
1961 local_reoffer->AddGroup(new_bundle_group);
1962
1963 EXPECT_TRUE(transport_controller_
1964 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
1965 .ok());
1966
1967 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
1968 local_reoffer->Copy());
1969 EXPECT_TRUE(
1970 transport_controller_
1971 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
1972 .ok());
1973}
1974
Zhi Huange818b6e2018-02-22 15:26:27 -08001975} // namespace webrtc