blob: 0bd55b53b76e9d86cbc55ca1d60eb17d0361bd32 [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,
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100308 rtc::scoped_refptr<DtlsTransport> dtls_transport,
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800309 MediaTransportInterface* media_transport) override {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700310 changed_rtp_transport_by_mid_[mid] = rtp_transport;
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100311 if (dtls_transport) {
312 changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
313 } else {
314 changed_dtls_transport_by_mid_[mid] = nullptr;
315 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800316 changed_media_transport_by_mid_[mid] = media_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700317 return true;
Zhi Huange818b6e2018-02-22 15:26:27 -0800318 }
319
320 // Information received from signals from transport controller.
Alex Loiko9289eda2018-11-23 16:18:59 +0000321 cricket::IceConnectionState connection_state_ =
322 cricket::kIceConnectionConnecting;
323 PeerConnectionInterface::IceConnectionState ice_connection_state_ =
Jonas Olsson635474e2018-10-18 15:58:17 +0200324 PeerConnectionInterface::kIceConnectionNew;
325 PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
326 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -0800327 bool receiving_ = false;
328 cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
329 // transport_name => candidates
330 std::map<std::string, Candidates> candidates_;
331 // Counts of each signal emitted.
332 int connection_state_signal_count_ = 0;
Alex Loiko9289eda2018-11-23 16:18:59 +0000333 int ice_connection_state_signal_count_ = 0;
Jonas Olsson635474e2018-10-18 15:58:17 +0200334 int combined_connection_state_signal_count_ = 0;
Zhi Huange818b6e2018-02-22 15:26:27 -0800335 int receiving_signal_count_ = 0;
336 int gathering_state_signal_count_ = 0;
337 int candidates_signal_count_ = 0;
338
339 // |network_thread_| should be destroyed after |transport_controller_|
340 std::unique_ptr<rtc::Thread> network_thread_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800341 std::unique_ptr<FakeTransportFactory> fake_transport_factory_;
342 rtc::Thread* const signaling_thread_ = nullptr;
343 bool signaled_on_non_signaling_thread_ = false;
344 // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
345 // signaled correctly.
346 std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
347 std::map<std::string, cricket::DtlsTransportInternal*>
348 changed_dtls_transport_by_mid_;
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800349 std::map<std::string, MediaTransportInterface*>
350 changed_media_transport_by_mid_;
351
352 // Transport controller needs to be destroyed first, because it may issue
353 // callbacks that modify the changed_*_by_mid in the destructor.
354 std::unique_ptr<JsepTransportController> transport_controller_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800355};
356
357TEST_F(JsepTransportControllerTest, GetRtpTransport) {
358 CreateJsepTransportController(JsepTransportController::Config());
359 auto description = CreateSessionDescriptionWithoutBundle();
360 EXPECT_TRUE(transport_controller_
361 ->SetLocalDescription(SdpType::kOffer, description.get())
362 .ok());
363 auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
364 auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
365 EXPECT_NE(nullptr, audio_rtp_transport);
366 EXPECT_NE(nullptr, video_rtp_transport);
367 EXPECT_NE(audio_rtp_transport, video_rtp_transport);
368 // Return nullptr for non-existing ones.
369 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
370}
371
372TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
373 JsepTransportController::Config config;
374 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
375 CreateJsepTransportController(config);
376 auto description = CreateSessionDescriptionWithoutBundle();
377 EXPECT_TRUE(transport_controller_
378 ->SetLocalDescription(SdpType::kOffer, description.get())
379 .ok());
380 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
381 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100382 EXPECT_NE(nullptr,
383 transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800384 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
385 EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100386 EXPECT_NE(nullptr,
387 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
388 // Lookup for all MIDs should return different transports (no bundle)
389 EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
390 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
Zhi Huange818b6e2018-02-22 15:26:27 -0800391 // Return nullptr for non-existing ones.
392 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
393 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
Harald Alvestrandad88c882018-11-28 16:47:46 +0100394 EXPECT_EQ(nullptr,
395 transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100396 // Take a pointer to a transport, shut down the transport controller,
397 // and verify that the resulting container is empty.
398 auto dtls_transport =
399 transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
400 webrtc::DtlsTransport* my_transport =
401 static_cast<DtlsTransport*>(dtls_transport.get());
402 EXPECT_NE(nullptr, my_transport->internal());
403 transport_controller_.reset();
404 EXPECT_EQ(nullptr, my_transport->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800405}
406
Zhi Huange830e682018-03-30 10:48:35 -0700407TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
408 JsepTransportController::Config config;
409 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
410 CreateJsepTransportController(config);
411 auto description = CreateSessionDescriptionWithoutBundle();
412 EXPECT_TRUE(transport_controller_
413 ->SetLocalDescription(SdpType::kOffer, description.get())
414 .ok());
415 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
416 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
417 EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
418 EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
Anton Sukhanov7940da02018-10-10 10:34:49 -0700419 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
420}
421
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800422TEST_F(JsepTransportControllerTest,
423 DtlsIsStillCreatedIfMediaTransportIsOnlyUsedForDataChannels) {
424 FakeMediaTransportFactory fake_media_transport_factory;
425 JsepTransportController::Config config;
426
427 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
428 config.media_transport_factory = &fake_media_transport_factory;
429 config.use_media_transport_for_data_channels = true;
430 CreateJsepTransportController(config);
431 auto description = CreateSessionDescriptionWithBundleGroup();
432 AddCryptoSettings(description.get());
433
434 EXPECT_TRUE(transport_controller_
435 ->SetLocalDescription(SdpType::kOffer, description.get())
436 .ok());
437
438 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
439 transport_controller_->GetMediaTransport(kAudioMid1));
440
441 ASSERT_NE(nullptr, media_transport);
442
443 // After SetLocalDescription, media transport should be created as caller.
444 EXPECT_TRUE(media_transport->is_caller());
445 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
446
447 // Return nullptr for non-existing mids.
448 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
449
450 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
451 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
452 << "Media transport for media was not enabled, and so DTLS transport "
453 "should be created.";
454}
455
Anton Sukhanov7940da02018-10-10 10:34:49 -0700456TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
457 FakeMediaTransportFactory fake_media_transport_factory;
458 JsepTransportController::Config config;
459
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800460 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700461 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800462 config.use_media_transport_for_data_channels = true;
463 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700464 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800465 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700466 AddCryptoSettings(description.get());
467
Anton Sukhanov7940da02018-10-10 10:34:49 -0700468 EXPECT_TRUE(transport_controller_
469 ->SetLocalDescription(SdpType::kOffer, description.get())
470 .ok());
471
472 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
473 transport_controller_->GetMediaTransport(kAudioMid1));
474
475 ASSERT_NE(nullptr, media_transport);
476
477 // After SetLocalDescription, media transport should be created as caller.
478 EXPECT_TRUE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700479 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700480
481 // Return nullptr for non-existing mids.
482 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800483
484 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
485 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
486 << "Because media transport is used, expected no-op DTLS transport.";
Anton Sukhanov7940da02018-10-10 10:34:49 -0700487}
488
489TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
490 FakeMediaTransportFactory fake_media_transport_factory;
491 JsepTransportController::Config config;
492
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800493 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700494 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800495 config.use_media_transport_for_data_channels = true;
496 config.use_media_transport_for_media = true;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700497 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800498 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700499 AddCryptoSettings(description.get());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700500 EXPECT_TRUE(transport_controller_
501 ->SetRemoteDescription(SdpType::kOffer, description.get())
502 .ok());
503
504 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
505 transport_controller_->GetMediaTransport(kAudioMid1));
506
507 ASSERT_NE(nullptr, media_transport);
508
509 // After SetRemoteDescription, media transport should be created as callee.
510 EXPECT_FALSE(media_transport->is_caller());
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700511 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
Anton Sukhanov7940da02018-10-10 10:34:49 -0700512
513 // Return nullptr for non-existing mids.
514 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800515
516 EXPECT_EQ(cricket::kNoOpDtlsTransportComponent,
517 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
518 << "Because media transport is used, expected no-op DTLS transport.";
Zhi Huange830e682018-03-30 10:48:35 -0700519}
520
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800521TEST_F(JsepTransportControllerTest, GetMediaTransportInCalleePassesSdp) {
522 FakeMediaTransportFactory fake_media_transport_factory;
523 JsepTransportController::Config config;
524
525 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
526 config.media_transport_factory = &fake_media_transport_factory;
527 config.use_media_transport_for_data_channels = true;
528 config.use_media_transport_for_media = true;
529 CreateJsepTransportController(config);
530 auto description = CreateSessionDescriptionWithBundleGroup();
531 AddCryptoSettings(description.get());
532 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
533 EXPECT_TRUE(transport_controller_
534 ->SetRemoteDescription(SdpType::kOffer, description.get())
535 .ok());
536
537 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
538 transport_controller_->GetMediaTransport(kAudioMid1));
539
540 ASSERT_NE(nullptr, media_transport);
541
542 EXPECT_EQ("this-is-a-test-setting",
543 media_transport->settings().remote_transport_parameters);
544}
545
546// Caller ignores its own outgoing parameters.
547TEST_F(JsepTransportControllerTest,
548 GetMediaTransportInCallerIgnoresXmtSection) {
549 FakeMediaTransportFactory fake_media_transport_factory;
550 JsepTransportController::Config config;
551
552 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
553 config.media_transport_factory = &fake_media_transport_factory;
554 config.use_media_transport_for_data_channels = true;
555 config.use_media_transport_for_media = true;
556 CreateJsepTransportController(config);
557 auto description = CreateSessionDescriptionWithBundleGroup();
558 AddCryptoSettings(description.get());
559 description->AddMediaTransportSetting("fake", "this-is-a-test-setting");
560 EXPECT_TRUE(transport_controller_
561 ->SetLocalDescription(SdpType::kOffer, description.get())
562 .ok());
563
564 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
565 transport_controller_->GetMediaTransport(kAudioMid1));
566
567 ASSERT_NE(nullptr, media_transport);
568
569 // Remote parameters are nullopt, because we are the offerer (we don't)
570 // have the remote transport parameters, only ours.
571 EXPECT_EQ(absl::nullopt,
572 media_transport->settings().remote_transport_parameters);
573}
574
575TEST_F(JsepTransportControllerTest,
576 GetMediaTransportInCalleeIgnoresDifferentTransport) {
577 FakeMediaTransportFactory fake_media_transport_factory;
578 JsepTransportController::Config config;
579
580 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
581 config.media_transport_factory = &fake_media_transport_factory;
582 config.use_media_transport_for_data_channels = true;
583 config.use_media_transport_for_media = true;
584 CreateJsepTransportController(config);
585 auto description = CreateSessionDescriptionWithBundleGroup();
586 AddCryptoSettings(description.get());
587 description->AddMediaTransportSetting("not-a-fake-transport",
588 "this-is-a-test-setting");
589 EXPECT_TRUE(transport_controller_
590 ->SetRemoteDescription(SdpType::kOffer, description.get())
591 .ok());
592
593 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
594 transport_controller_->GetMediaTransport(kAudioMid1));
595
596 ASSERT_NE(nullptr, media_transport);
597
598 EXPECT_EQ(absl::nullopt,
599 media_transport->settings().remote_transport_parameters);
600}
601
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700602TEST_F(JsepTransportControllerTest, GetMediaTransportIsNotSetIfNoSdes) {
603 FakeMediaTransportFactory fake_media_transport_factory;
604 JsepTransportController::Config config;
605
606 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
607 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800608 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700609 CreateJsepTransportController(config);
610 auto description = CreateSessionDescriptionWithoutBundle();
611 EXPECT_TRUE(transport_controller_
612 ->SetRemoteDescription(SdpType::kOffer, description.get())
613 .ok());
614
615 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
616
617 // Even if we set local description with crypto now (after the remote offer
618 // was set), media transport won't be provided.
619 auto description2 = CreateSessionDescriptionWithoutBundle();
620 AddCryptoSettings(description2.get());
621 EXPECT_TRUE(transport_controller_
622 ->SetLocalDescription(SdpType::kAnswer, description2.get())
623 .ok());
624
625 EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800626 EXPECT_EQ(cricket::ICE_CANDIDATE_COMPONENT_RTP,
627 transport_controller_->GetDtlsTransport(kAudioMid1)->component())
628 << "Because media transport is NOT used (fallback to RTP), expected "
629 "actual DTLS transport for RTP";
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700630}
631
632TEST_F(JsepTransportControllerTest,
633 AfterSettingAnswerTheSameMediaTransportIsReturned) {
634 FakeMediaTransportFactory fake_media_transport_factory;
635 JsepTransportController::Config config;
636
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800637 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700638 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800639 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700640 CreateJsepTransportController(config);
641 auto description = CreateSessionDescriptionWithoutBundle();
642 AddCryptoSettings(description.get());
643 EXPECT_TRUE(transport_controller_
644 ->SetRemoteDescription(SdpType::kOffer, description.get())
645 .ok());
646
647 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
648 transport_controller_->GetMediaTransport(kAudioMid1));
649 EXPECT_NE(nullptr, media_transport);
650 EXPECT_TRUE(media_transport->pre_shared_key().has_value());
651
652 // Even if we set local description with crypto now (after the remote offer
653 // was set), media transport won't be provided.
654 auto description2 = CreateSessionDescriptionWithoutBundle();
655 AddCryptoSettings(description2.get());
656
657 RTCError result = transport_controller_->SetLocalDescription(
658 SdpType::kAnswer, description2.get());
659 EXPECT_TRUE(result.ok()) << result.message();
660
661 // Media transport did not change.
662 EXPECT_EQ(media_transport,
663 transport_controller_->GetMediaTransport(kAudioMid1));
664}
665
Zhi Huange818b6e2018-02-22 15:26:27 -0800666TEST_F(JsepTransportControllerTest, SetIceConfig) {
667 CreateJsepTransportController(JsepTransportController::Config());
668 auto description = CreateSessionDescriptionWithoutBundle();
669 EXPECT_TRUE(transport_controller_
670 ->SetLocalDescription(SdpType::kOffer, description.get())
671 .ok());
672
673 transport_controller_->SetIceConfig(
674 CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
675 FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
676 transport_controller_->GetDtlsTransport(kAudioMid1));
677 ASSERT_NE(nullptr, fake_audio_dtls);
678 EXPECT_EQ(kTimeout,
679 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
680 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
681
682 // Test that value stored in controller is applied to new transports.
683 AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
684 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
685 nullptr);
686
687 EXPECT_TRUE(transport_controller_
688 ->SetLocalDescription(SdpType::kOffer, description.get())
689 .ok());
690 fake_audio_dtls = static_cast<FakeDtlsTransport*>(
691 transport_controller_->GetDtlsTransport(kAudioMid2));
692 ASSERT_NE(nullptr, fake_audio_dtls);
693 EXPECT_EQ(kTimeout,
694 fake_audio_dtls->fake_ice_transport()->receiving_timeout());
695 EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
696}
697
698// Tests the getter and setter of the ICE restart flag.
699TEST_F(JsepTransportControllerTest, NeedIceRestart) {
700 CreateJsepTransportController(JsepTransportController::Config());
701 auto description = CreateSessionDescriptionWithoutBundle();
702 EXPECT_TRUE(transport_controller_
703 ->SetLocalDescription(SdpType::kOffer, description.get())
704 .ok());
705 EXPECT_TRUE(transport_controller_
706 ->SetRemoteDescription(SdpType::kAnswer, description.get())
707 .ok());
708
709 // Initially NeedsIceRestart should return false.
710 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
711 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
712 // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
713 // true.
714 transport_controller_->SetNeedsIceRestartFlag();
715 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
716 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
717 // For a nonexistent transport, false should be returned.
718 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
719
720 // Reset the ice_ufrag/ice_pwd for audio.
721 auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
722 audio_transport_info->description.ice_ufrag = kIceUfrag2;
723 audio_transport_info->description.ice_pwd = kIcePwd2;
724 EXPECT_TRUE(transport_controller_
725 ->SetLocalDescription(SdpType::kOffer, description.get())
726 .ok());
727 // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
728 // return false for audio and true for video.
729 EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
730 EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
731}
732
733TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
734 CreateJsepTransportController(JsepTransportController::Config());
735 auto description = CreateSessionDescriptionWithBundleGroup();
736 EXPECT_TRUE(transport_controller_
737 ->SetLocalDescription(SdpType::kOffer, description.get())
738 .ok());
739 // After setting the local description, we should be able to start gathering
740 // candidates.
741 transport_controller_->MaybeStartGathering();
742 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
743 EXPECT_EQ(1, gathering_state_signal_count_);
744}
745
746TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
747 CreateJsepTransportController(JsepTransportController::Config());
748 auto description = CreateSessionDescriptionWithoutBundle();
749 transport_controller_->SetLocalDescription(SdpType::kOffer,
750 description.get());
751 transport_controller_->SetRemoteDescription(SdpType::kAnswer,
752 description.get());
753 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
754 transport_controller_->GetDtlsTransport(kAudioMid1));
755 ASSERT_NE(nullptr, fake_audio_dtls);
756 Candidates candidates;
757 candidates.push_back(
758 CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
759 EXPECT_TRUE(
760 transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
761 EXPECT_EQ(1U,
762 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
763
764 EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
765 EXPECT_EQ(0U,
766 fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
767}
768
769TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
770 CreateJsepTransportController(JsepTransportController::Config());
771
772 rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
773 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
774 rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)));
775 rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
776
Karl Wiberg918f50c2018-07-05 11:40:33 +0200777 auto description = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800778 AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
779 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
780 certificate1);
781
782 // Apply the local certificate.
783 EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
784 // Apply the local description.
785 EXPECT_TRUE(transport_controller_
786 ->SetLocalDescription(SdpType::kOffer, description.get())
787 .ok());
788 returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
789 EXPECT_TRUE(returned_certificate);
790 EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
791 returned_certificate->identity()->certificate().ToPEMString());
792
793 // Should fail if called for a nonexistant transport.
794 EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
795
796 // Shouldn't be able to change the identity once set.
797 rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
798 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
799 rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)));
800 EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
801}
802
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800803TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800804 CreateJsepTransportController(JsepTransportController::Config());
805 auto description = CreateSessionDescriptionWithBundleGroup();
806 EXPECT_TRUE(transport_controller_
807 ->SetLocalDescription(SdpType::kOffer, description.get())
808 .ok());
809 rtc::FakeSSLCertificate fake_certificate("fake_data");
810
811 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
812 transport_controller_->GetDtlsTransport(kAudioMid1));
813 fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800814 std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
815 transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
816 ASSERT_TRUE(returned_cert_chain);
817 ASSERT_EQ(1u, returned_cert_chain->GetSize());
Zhi Huange818b6e2018-02-22 15:26:27 -0800818 EXPECT_EQ(fake_certificate.ToPEMString(),
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800819 returned_cert_chain->Get(0).ToPEMString());
Zhi Huange818b6e2018-02-22 15:26:27 -0800820
821 // Should fail if called for a nonexistant transport.
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800822 EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
Zhi Huange818b6e2018-02-22 15:26:27 -0800823}
824
825TEST_F(JsepTransportControllerTest, GetDtlsRole) {
826 CreateJsepTransportController(JsepTransportController::Config());
827 auto offer_certificate =
828 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
829 rtc::SSLIdentity::Generate("offer", rtc::KT_DEFAULT)));
830 auto answer_certificate =
831 rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
832 rtc::SSLIdentity::Generate("answer", rtc::KT_DEFAULT)));
833 transport_controller_->SetLocalCertificate(offer_certificate);
834
Karl Wiberg918f50c2018-07-05 11:40:33 +0200835 auto offer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800836 AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
837 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
838 offer_certificate);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200839 auto answer_desc = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800840 AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
841 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
842 answer_certificate);
843
844 EXPECT_TRUE(transport_controller_
845 ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
846 .ok());
847
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200848 absl::optional<rtc::SSLRole> role =
Zhi Huange818b6e2018-02-22 15:26:27 -0800849 transport_controller_->GetDtlsRole(kAudioMid1);
850 // The DTLS role is not decided yet.
851 EXPECT_FALSE(role);
852 EXPECT_TRUE(transport_controller_
853 ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
854 .ok());
855 role = transport_controller_->GetDtlsRole(kAudioMid1);
856
857 ASSERT_TRUE(role);
858 EXPECT_EQ(rtc::SSL_CLIENT, *role);
859}
860
861TEST_F(JsepTransportControllerTest, GetStats) {
862 CreateJsepTransportController(JsepTransportController::Config());
863 auto description = CreateSessionDescriptionWithBundleGroup();
864 EXPECT_TRUE(transport_controller_
865 ->SetLocalDescription(SdpType::kOffer, description.get())
866 .ok());
867
868 cricket::TransportStats stats;
869 EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
870 EXPECT_EQ(kAudioMid1, stats.transport_name);
871 EXPECT_EQ(1u, stats.channel_stats.size());
872 // Return false for non-existing transport.
873 EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
874}
875
876TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
877 CreateJsepTransportController(JsepTransportController::Config());
878 auto description = CreateSessionDescriptionWithoutBundle();
879 EXPECT_TRUE(transport_controller_
880 ->SetLocalDescription(SdpType::kOffer, description.get())
881 .ok());
882
883 auto fake_ice = static_cast<cricket::FakeIceTransport*>(
884 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
885 fake_ice->SetCandidatesGatheringComplete();
886 fake_ice->SetConnectionCount(1);
887 // The connection stats will be failed if there is no active connection.
888 fake_ice->SetConnectionCount(0);
Alex Loiko9289eda2018-11-23 16:18:59 +0000889 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100890 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000891 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
892 ice_connection_state_, kTimeout);
893 EXPECT_EQ(1, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100894 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
895 combined_connection_state_, kTimeout);
Jonas Olsson635474e2018-10-18 15:58:17 +0200896 EXPECT_EQ(1, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800897}
898
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700899TEST_F(JsepTransportControllerTest,
900 SignalConnectionStateConnectedNoMediaTransport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800901 CreateJsepTransportController(JsepTransportController::Config());
902 auto description = CreateSessionDescriptionWithoutBundle();
903 EXPECT_TRUE(transport_controller_
904 ->SetLocalDescription(SdpType::kOffer, description.get())
905 .ok());
906
907 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
908 transport_controller_->GetDtlsTransport(kAudioMid1));
909 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
910 transport_controller_->GetDtlsTransport(kVideoMid1));
911
912 // First, have one transport connect, and another fail, to ensure that
913 // the first transport connecting didn't trigger a "connected" state signal.
914 // We should only get a signal when all are connected.
915 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
916 fake_audio_dtls->SetWritable(true);
917 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
918 // Decrease the number of the connection to trigger the signal.
919 fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
920 fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
921 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
922
Alex Loiko9289eda2018-11-23 16:18:59 +0000923 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100924 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000925 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
926 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100927 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100928 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
929 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100930 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800931
Jonas Olsson635474e2018-10-18 15:58:17 +0200932 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
933 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -0800934 // Set the connection count to be 2 and the cricket::FakeIceTransport will set
935 // the transport state to be STATE_CONNECTING.
936 fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
937 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +0000938 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +0100939 EXPECT_EQ(2, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +0000940 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
941 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100942 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +0100943 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
944 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +0100945 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -0800946}
947
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700948TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800949 SignalConnectionStateConnectedWithMediaTransportAndNoDtls) {
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700950 FakeMediaTransportFactory fake_media_transport_factory;
951 JsepTransportController::Config config;
952 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800953 config.use_media_transport_for_data_channels = true;
954 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700955 CreateJsepTransportController(config);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800956
957 // Media Transport is only used with bundle.
958 auto description = CreateSessionDescriptionWithBundleGroup();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700959 AddCryptoSettings(description.get());
960 EXPECT_TRUE(transport_controller_
961 ->SetLocalDescription(SdpType::kOffer, description.get())
962 .ok());
963
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800964 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
965 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
966 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
967 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
968 fake_audio_ice->SetConnectionCount(2);
969 fake_audio_ice->SetConnectionCount(1);
970 fake_video_ice->SetConnectionCount(2);
971 fake_video_ice->SetConnectionCount(1);
972 fake_audio_ice->SetWritable(true);
973 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700974
975 // Still not connected, because we are waiting for media transport.
Alex Loiko9289eda2018-11-23 16:18:59 +0000976 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
977 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700978
979 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
980 transport_controller_->GetMediaTransport(kAudioMid1));
981
982 media_transport->SetState(webrtc::MediaTransportState::kWritable);
Alex Loiko9289eda2018-11-23 16:18:59 +0000983 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
984 kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700985
986 // Still waiting for the second media transport.
987 media_transport = static_cast<FakeMediaTransport*>(
988 transport_controller_->GetMediaTransport(kVideoMid1));
989 media_transport->SetState(webrtc::MediaTransportState::kWritable);
990
Alex Loiko9289eda2018-11-23 16:18:59 +0000991 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700992}
993
994TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800995 SignalConnectionStateConnectedWithMediaTransport) {
996 FakeMediaTransportFactory fake_media_transport_factory;
997 JsepTransportController::Config config;
998 config.media_transport_factory = &fake_media_transport_factory;
999 config.use_media_transport_for_media = true;
1000 CreateJsepTransportController(config);
1001
1002 // Media Transport is only used with bundle.
1003 auto description = CreateSessionDescriptionWithBundleGroup();
1004 AddCryptoSettings(description.get());
1005 EXPECT_TRUE(transport_controller_
1006 ->SetLocalDescription(SdpType::kOffer, description.get())
1007 .ok());
1008
1009 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1010 transport_controller_->GetDtlsTransport(kAudioMid1));
1011 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1012 transport_controller_->GetDtlsTransport(kVideoMid1));
1013
1014 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1015 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1016 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1017 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1018 fake_audio_ice->SetConnectionCount(2);
1019 fake_audio_ice->SetConnectionCount(1);
1020 fake_video_ice->SetConnectionCount(2);
1021 fake_video_ice->SetConnectionCount(1);
1022 fake_audio_ice->SetWritable(true);
1023 fake_video_ice->SetWritable(true);
1024 fake_audio_dtls->SetWritable(true);
1025 fake_video_dtls->SetWritable(true);
1026
1027 // Still not connected, because we are waiting for media transport.
1028 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1029 kTimeout);
1030
1031 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1032 transport_controller_->GetMediaTransport(kAudioMid1));
1033
1034 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1035 EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
1036 kTimeout);
1037
1038 // Still waiting for the second media transport.
1039 media_transport = static_cast<FakeMediaTransport*>(
1040 transport_controller_->GetMediaTransport(kVideoMid1));
1041 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1042
1043 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
1044}
1045
1046TEST_F(JsepTransportControllerTest,
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001047 SignalConnectionStateFailedWhenMediaTransportClosed) {
1048 FakeMediaTransportFactory fake_media_transport_factory;
1049 JsepTransportController::Config config;
1050 config.media_transport_factory = &fake_media_transport_factory;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001051 config.use_media_transport_for_media = true;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001052 CreateJsepTransportController(config);
1053 auto description = CreateSessionDescriptionWithoutBundle();
1054 AddCryptoSettings(description.get());
1055 EXPECT_TRUE(transport_controller_
1056 ->SetLocalDescription(SdpType::kOffer, description.get())
1057 .ok());
1058
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001059 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1060 transport_controller_->GetDtlsTransport(kAudioMid1));
1061 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1062 transport_controller_->GetDtlsTransport(kVideoMid1));
1063
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001064 auto fake_audio_ice = static_cast<cricket::FakeIceTransport*>(
1065 transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
1066 auto fake_video_ice = static_cast<cricket::FakeIceTransport*>(
1067 transport_controller_->GetDtlsTransport(kVideoMid1)->ice_transport());
1068 fake_audio_ice->SetWritable(true);
1069 fake_video_ice->SetWritable(true);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001070 // Decreasing connection count from 2 to 1 triggers connection state event.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001071 fake_audio_ice->SetConnectionCount(2);
1072 fake_audio_ice->SetConnectionCount(1);
1073 fake_video_ice->SetConnectionCount(2);
1074 fake_video_ice->SetConnectionCount(1);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001075
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001076 fake_audio_dtls->SetWritable(true);
1077 fake_video_dtls->SetWritable(true);
1078
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001079 FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
1080 transport_controller_->GetMediaTransport(kAudioMid1));
1081
1082 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1083
1084 media_transport = static_cast<FakeMediaTransport*>(
1085 transport_controller_->GetMediaTransport(kVideoMid1));
1086
1087 media_transport->SetState(webrtc::MediaTransportState::kWritable);
1088
Alex Loiko9289eda2018-11-23 16:18:59 +00001089 EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001090
1091 media_transport->SetState(webrtc::MediaTransportState::kClosed);
Alex Loiko9289eda2018-11-23 16:18:59 +00001092 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001093}
1094
Zhi Huange818b6e2018-02-22 15:26:27 -08001095TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
1096 CreateJsepTransportController(JsepTransportController::Config());
1097 auto description = CreateSessionDescriptionWithoutBundle();
1098 EXPECT_TRUE(transport_controller_
1099 ->SetLocalDescription(SdpType::kOffer, description.get())
1100 .ok());
1101
1102 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1103 transport_controller_->GetDtlsTransport(kAudioMid1));
1104 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1105 transport_controller_->GetDtlsTransport(kVideoMid1));
1106
1107 // First, have one transport connect, and another fail, to ensure that
1108 // the first transport connecting didn't trigger a "connected" state signal.
1109 // We should only get a signal when all are connected.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001110 fake_audio_dtls->fake_ice_transport()->SetTransportState(
1111 IceTransportState::kCompleted,
1112 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001113 fake_audio_dtls->SetWritable(true);
1114 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001115
1116 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
1117 ice_connection_state_, kTimeout);
1118 EXPECT_EQ(1, ice_connection_state_signal_count_);
1119 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
1120 combined_connection_state_, kTimeout);
1121 EXPECT_EQ(1, combined_connection_state_signal_count_);
1122
1123 fake_video_dtls->fake_ice_transport()->SetTransportState(
1124 IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001125 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1126
Alex Loiko9289eda2018-11-23 16:18:59 +00001127 EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
Jonas Olsson1e87b4f2018-11-22 16:50:37 +01001128 EXPECT_EQ(1, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001129 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
1130 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001131 EXPECT_EQ(2, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001132 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
1133 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001134 EXPECT_EQ(2, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001135
Jonas Olsson635474e2018-10-18 15:58:17 +02001136 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
1137 fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001138 // Set the connection count to be 1 and the cricket::FakeIceTransport will set
1139 // the transport state to be STATE_COMPLETED.
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001140 fake_video_dtls->fake_ice_transport()->SetTransportState(
1141 IceTransportState::kCompleted,
1142 cricket::IceTransportState::STATE_COMPLETED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001143 fake_video_dtls->SetWritable(true);
Alex Loiko9289eda2018-11-23 16:18:59 +00001144 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Jonas Olsson7a6739e2019-01-15 16:31:55 +01001145 EXPECT_EQ(3, connection_state_signal_count_);
Alex Loiko9289eda2018-11-23 16:18:59 +00001146 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
1147 ice_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001148 EXPECT_EQ(3, ice_connection_state_signal_count_);
Jonas Olssond8aa9f92018-11-09 10:51:09 +01001149 EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
1150 combined_connection_state_, kTimeout);
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001151 EXPECT_EQ(3, combined_connection_state_signal_count_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001152}
1153
1154TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
1155 CreateJsepTransportController(JsepTransportController::Config());
1156 auto description = CreateSessionDescriptionWithoutBundle();
1157 EXPECT_TRUE(transport_controller_
1158 ->SetLocalDescription(SdpType::kOffer, description.get())
1159 .ok());
1160
1161 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1162 transport_controller_->GetDtlsTransport(kAudioMid1));
1163 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1164 // Should be in the gathering state as soon as any transport starts gathering.
1165 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1166 EXPECT_EQ(1, gathering_state_signal_count_);
1167}
1168
1169TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
1170 CreateJsepTransportController(JsepTransportController::Config());
1171 auto description = CreateSessionDescriptionWithoutBundle();
1172 EXPECT_TRUE(transport_controller_
1173 ->SetLocalDescription(SdpType::kOffer, description.get())
1174 .ok());
1175
1176 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1177 transport_controller_->GetDtlsTransport(kAudioMid1));
1178 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1179 transport_controller_->GetDtlsTransport(kVideoMid1));
1180
1181 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1182 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1183 EXPECT_EQ(1, gathering_state_signal_count_);
1184
1185 // Have one transport finish gathering, to make sure gathering
1186 // completion wasn't signalled if only one transport finished gathering.
1187 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1188 EXPECT_EQ(1, gathering_state_signal_count_);
1189
1190 fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
1191 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1192 EXPECT_EQ(1, gathering_state_signal_count_);
1193
1194 fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1195 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1196 EXPECT_EQ(2, gathering_state_signal_count_);
1197}
1198
1199// Test that when the last transport that hasn't finished connecting and/or
1200// gathering is destroyed, the aggregate state jumps to "completed". This can
1201// happen if, for example, we have an audio and video transport, the audio
1202// transport completes, then we start bundling video on the audio transport.
1203TEST_F(JsepTransportControllerTest,
1204 SignalingWhenLastIncompleteTransportDestroyed) {
1205 CreateJsepTransportController(JsepTransportController::Config());
1206 auto description = CreateSessionDescriptionWithBundleGroup();
1207 EXPECT_TRUE(transport_controller_
1208 ->SetLocalDescription(SdpType::kOffer, description.get())
1209 .ok());
1210
1211 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1212 transport_controller_->GetDtlsTransport(kAudioMid1));
1213 auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
1214 transport_controller_->GetDtlsTransport(kVideoMid1));
1215 EXPECT_NE(fake_audio_dtls, fake_video_dtls);
1216
1217 fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
1218 EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
1219 EXPECT_EQ(1, gathering_state_signal_count_);
1220
1221 // Let the audio transport complete.
1222 fake_audio_dtls->SetWritable(true);
1223 fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
1224 fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
Jonas Olsson635474e2018-10-18 15:58:17 +02001225 fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
Zhi Huange818b6e2018-02-22 15:26:27 -08001226 EXPECT_EQ(1, gathering_state_signal_count_);
1227
1228 // Set the remote description and enable the bundle.
1229 EXPECT_TRUE(transport_controller_
1230 ->SetRemoteDescription(SdpType::kAnswer, description.get())
1231 .ok());
1232 // The BUNDLE should be enabled, the incomplete video transport should be
1233 // deleted and the states shoud be updated.
1234 fake_video_dtls = static_cast<FakeDtlsTransport*>(
1235 transport_controller_->GetDtlsTransport(kVideoMid1));
1236 EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
Alex Loiko9289eda2018-11-23 16:18:59 +00001237 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
1238 EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
1239 ice_connection_state_);
Jonas Olsson635474e2018-10-18 15:58:17 +02001240 EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
1241 combined_connection_state_);
Zhi Huange818b6e2018-02-22 15:26:27 -08001242 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1243 EXPECT_EQ(2, gathering_state_signal_count_);
1244}
1245
1246TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
1247 CreateJsepTransportController(JsepTransportController::Config());
1248 auto description = CreateSessionDescriptionWithBundleGroup();
1249 EXPECT_TRUE(transport_controller_
1250 ->SetLocalDescription(SdpType::kOffer, description.get())
1251 .ok());
1252 transport_controller_->MaybeStartGathering();
1253
1254 auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
1255 transport_controller_->GetDtlsTransport(kAudioMid1));
1256 fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
1257 fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
1258 EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
1259 EXPECT_EQ(1u, candidates_[kAudioMid1].size());
1260}
1261
1262TEST_F(JsepTransportControllerTest, IceSignalingOccursOnSignalingThread) {
1263 network_thread_ = rtc::Thread::CreateWithSocketServer();
1264 network_thread_->Start();
1265 CreateJsepTransportController(JsepTransportController::Config(),
1266 signaling_thread_, network_thread_.get(),
Mirko Bonadei970f2f72019-02-28 14:57:52 +01001267 /*port_allocator=*/nullptr);
Zhi Huange818b6e2018-02-22 15:26:27 -08001268 CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
1269
1270 // connecting --> connected --> completed
Alex Loiko9289eda2018-11-23 16:18:59 +00001271 EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
Zhi Huange818b6e2018-02-22 15:26:27 -08001272 EXPECT_EQ(2, connection_state_signal_count_);
1273
1274 // new --> gathering --> complete
1275 EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
1276 EXPECT_EQ(2, gathering_state_signal_count_);
1277
1278 EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
1279 EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
1280 EXPECT_EQ(2, candidates_signal_count_);
1281
1282 EXPECT_TRUE(!signaled_on_non_signaling_thread_);
1283}
1284
1285// Older versions of Chrome expect the ICE role to be re-determined when an
1286// ICE restart occurs, and also don't perform conflict resolution correctly,
1287// so for now we can't safely stop doing this.
1288// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1289// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1290// enough population.
1291TEST_F(JsepTransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) {
1292 CreateJsepTransportController(JsepTransportController::Config());
1293 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001294 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001295 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1296 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1297 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001298 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001299 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1300 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1301 nullptr);
1302
1303 EXPECT_TRUE(transport_controller_
1304 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1305 .ok());
1306 EXPECT_TRUE(transport_controller_
1307 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1308 .ok());
1309
1310 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1311 transport_controller_->GetDtlsTransport(kAudioMid1));
1312 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1313 fake_dtls->fake_ice_transport()->GetIceRole());
1314
1315 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001316 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001317 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1318 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1319 nullptr);
1320 EXPECT_TRUE(
1321 transport_controller_
1322 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1323 .ok());
1324 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1325 fake_dtls->fake_ice_transport()->GetIceRole());
1326}
1327
1328// Test that if the TransportController was created with the
1329// |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
1330// redetermined on an ICE restart.
1331TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
1332 JsepTransportController::Config config;
1333 config.redetermine_role_on_ice_restart = false;
1334
1335 CreateJsepTransportController(config);
1336 // Let the |transport_controller_| be the controlled side initially.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001337 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001338 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1339 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1340 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001341 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001342 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1343 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1344 nullptr);
1345
1346 EXPECT_TRUE(transport_controller_
1347 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1348 .ok());
1349 EXPECT_TRUE(transport_controller_
1350 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1351 .ok());
1352
1353 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1354 transport_controller_->GetDtlsTransport(kAudioMid1));
1355 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1356 fake_dtls->fake_ice_transport()->GetIceRole());
1357
1358 // New offer will trigger the ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001359 auto restart_local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001360 AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
1361 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1362 nullptr);
1363 EXPECT_TRUE(
1364 transport_controller_
1365 ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
1366 .ok());
1367 EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
1368 fake_dtls->fake_ice_transport()->GetIceRole());
1369}
1370
1371// Tests ICE-Lite mode in remote answer.
1372TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
1373 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001374 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001375 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1376 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1377 nullptr);
1378 EXPECT_TRUE(transport_controller_
1379 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1380 .ok());
1381 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1382 transport_controller_->GetDtlsTransport(kAudioMid1));
1383 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1384 fake_dtls->fake_ice_transport()->GetIceRole());
1385 EXPECT_EQ(cricket::ICEMODE_FULL,
1386 fake_dtls->fake_ice_transport()->remote_ice_mode());
1387
Karl Wiberg918f50c2018-07-05 11:40:33 +02001388 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001389 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1390 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
1391 nullptr);
1392 EXPECT_TRUE(transport_controller_
1393 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1394 .ok());
1395 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1396 fake_dtls->fake_ice_transport()->GetIceRole());
1397 EXPECT_EQ(cricket::ICEMODE_LITE,
1398 fake_dtls->fake_ice_transport()->remote_ice_mode());
1399}
1400
1401// Tests that the ICE role remains "controlling" if a subsequent offer that
1402// does an ICE restart is received from an ICE lite endpoint. Regression test
1403// for: https://crbug.com/710760
1404TEST_F(JsepTransportControllerTest,
1405 IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
1406 CreateJsepTransportController(JsepTransportController::Config());
Karl Wiberg918f50c2018-07-05 11:40:33 +02001407 auto remote_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001408 AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1409 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1410 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001411 auto local_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001412 AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1413 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1414 nullptr);
1415 // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
1416 // local side is the controlling.
1417 EXPECT_TRUE(transport_controller_
1418 ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
1419 .ok());
1420 EXPECT_TRUE(transport_controller_
1421 ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
1422 .ok());
1423 auto fake_dtls = static_cast<FakeDtlsTransport*>(
1424 transport_controller_->GetDtlsTransport(kAudioMid1));
1425 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1426 fake_dtls->fake_ice_transport()->GetIceRole());
1427
1428 // In the subsequence remote offer triggers an ICE restart.
Karl Wiberg918f50c2018-07-05 11:40:33 +02001429 auto remote_offer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001430 AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1431 cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1432 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001433 auto local_answer2 = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001434 AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1435 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1436 nullptr);
1437 EXPECT_TRUE(transport_controller_
1438 ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1439 .ok());
1440 EXPECT_TRUE(transport_controller_
1441 ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1442 .ok());
1443 fake_dtls = static_cast<FakeDtlsTransport*>(
1444 transport_controller_->GetDtlsTransport(kAudioMid1));
1445 // The local side is still the controlling role since the remote side is using
1446 // ICE-Lite.
1447 EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1448 fake_dtls->fake_ice_transport()->GetIceRole());
1449}
1450
1451// Tests that the SDP has more than one audio/video m= sections.
1452TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1453 CreateJsepTransportController(JsepTransportController::Config());
1454 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1455 bundle_group.AddContentName(kAudioMid1);
1456 bundle_group.AddContentName(kAudioMid2);
1457 bundle_group.AddContentName(kVideoMid1);
1458 bundle_group.AddContentName(kDataMid1);
1459
Karl Wiberg918f50c2018-07-05 11:40:33 +02001460 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001461 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1462 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1463 nullptr);
1464 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1465 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1466 nullptr);
1467 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1468 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1469 nullptr);
1470 AddDataSection(local_offer.get(), kDataMid1,
1471 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1472 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1473 nullptr);
1474
Karl Wiberg918f50c2018-07-05 11:40:33 +02001475 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001476 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1477 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1478 nullptr);
1479 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1480 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1481 nullptr);
1482 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1483 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1484 nullptr);
1485 AddDataSection(remote_answer.get(), kDataMid1,
1486 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1487 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1488 nullptr);
1489
1490 local_offer->AddGroup(bundle_group);
1491 remote_answer->AddGroup(bundle_group);
1492
1493 EXPECT_TRUE(transport_controller_
1494 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1495 .ok());
1496 EXPECT_TRUE(transport_controller_
1497 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1498 .ok());
1499 // Verify that all the sections are bundled on kAudio1.
1500 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1501 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1502 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1503 auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1504 EXPECT_EQ(transport1, transport2);
1505 EXPECT_EQ(transport1, transport3);
1506 EXPECT_EQ(transport1, transport4);
1507
Harald Alvestrandad88c882018-11-28 16:47:46 +01001508 EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1509 transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1510
Zhi Huange818b6e2018-02-22 15:26:27 -08001511 // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1512 auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1513 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1514 EXPECT_EQ(transport1, it->second);
1515 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1516 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1517 EXPECT_EQ(transport1, it->second);
1518 it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1519 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1520 EXPECT_EQ(transport1, it->second);
1521 // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1522 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1523 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1524 EXPECT_EQ(transport1->rtp_packet_transport(), it2->second);
1525}
1526
1527// Tests that only a subset of all the m= sections are bundled.
1528TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1529 CreateJsepTransportController(JsepTransportController::Config());
1530 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1531 bundle_group.AddContentName(kAudioMid1);
1532 bundle_group.AddContentName(kVideoMid1);
1533
Karl Wiberg918f50c2018-07-05 11:40:33 +02001534 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001535 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1536 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1537 nullptr);
1538 AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1539 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1540 nullptr);
1541 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1542 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1543 nullptr);
1544
Karl Wiberg918f50c2018-07-05 11:40:33 +02001545 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001546 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1547 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1548 nullptr);
1549 AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1550 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1551 nullptr);
1552 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1553 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1554 nullptr);
1555
1556 local_offer->AddGroup(bundle_group);
1557 remote_answer->AddGroup(bundle_group);
1558 EXPECT_TRUE(transport_controller_
1559 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1560 .ok());
1561 EXPECT_TRUE(transport_controller_
1562 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1563 .ok());
1564
1565 // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1566 auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1567 auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1568 auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1569 EXPECT_NE(transport1, transport2);
1570 EXPECT_EQ(transport1, transport3);
1571
1572 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1573 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1574 EXPECT_EQ(transport1, it->second);
1575 it = changed_rtp_transport_by_mid_.find(kAudioMid2);
Zhi Huangd2248f82018-04-10 14:41:03 -07001576 EXPECT_TRUE(transport2 == it->second);
Zhi Huange818b6e2018-02-22 15:26:27 -08001577}
1578
1579// Tests that the initial offer/answer only have data section and audio/video
1580// sections are added in the subsequent offer.
1581TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1582 CreateJsepTransportController(JsepTransportController::Config());
1583 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1584 bundle_group.AddContentName(kDataMid1);
1585
Karl Wiberg918f50c2018-07-05 11:40:33 +02001586 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001587 AddDataSection(local_offer.get(), kDataMid1,
1588 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1589 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1590 nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001591 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001592 AddDataSection(remote_answer.get(), kDataMid1,
1593 cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1594 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1595 nullptr);
1596 local_offer->AddGroup(bundle_group);
1597 remote_answer->AddGroup(bundle_group);
1598
1599 EXPECT_TRUE(transport_controller_
1600 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1601 .ok());
1602 EXPECT_TRUE(transport_controller_
1603 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1604 .ok());
1605 auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1606
1607 // Add audio/video sections in subsequent offer.
1608 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1609 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1610 nullptr);
1611 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1612 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1613 nullptr);
1614 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1615 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1616 nullptr);
1617 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1618 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1619 nullptr);
1620
1621 // Reset the bundle group and do another offer/answer exchange.
1622 bundle_group.AddContentName(kAudioMid1);
1623 bundle_group.AddContentName(kVideoMid1);
1624 local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1625 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1626 local_offer->AddGroup(bundle_group);
1627 remote_answer->AddGroup(bundle_group);
1628
1629 EXPECT_TRUE(transport_controller_
1630 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1631 .ok());
1632 EXPECT_TRUE(transport_controller_
1633 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1634 .ok());
1635
1636 auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1637 auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1638 EXPECT_EQ(data_transport, audio_transport);
1639 EXPECT_EQ(data_transport, video_transport);
1640}
1641
1642TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1643 CreateJsepTransportController(JsepTransportController::Config());
1644 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1645 bundle_group.AddContentName(kAudioMid1);
1646 bundle_group.AddContentName(kVideoMid1);
1647 bundle_group.AddContentName(kDataMid1);
1648
Karl Wiberg918f50c2018-07-05 11:40:33 +02001649 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001650 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1651 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1652 nullptr);
1653 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1654 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1655 nullptr);
1656 AddDataSection(local_offer.get(), kDataMid1,
1657 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1658 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1659 nullptr);
1660
Karl Wiberg918f50c2018-07-05 11:40:33 +02001661 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001662 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1663 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1664 nullptr);
1665 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1666 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1667 nullptr);
1668 AddDataSection(remote_answer.get(), kDataMid1,
1669 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1670 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1671 nullptr);
1672 // Reject video and data section.
1673 remote_answer->contents()[1].rejected = true;
1674 remote_answer->contents()[2].rejected = true;
1675
1676 local_offer->AddGroup(bundle_group);
1677 remote_answer->AddGroup(bundle_group);
1678
1679 EXPECT_TRUE(transport_controller_
1680 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1681 .ok());
1682 EXPECT_TRUE(transport_controller_
1683 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1684 .ok());
1685
1686 // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1687 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1688 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1689 // Verify the signals are fired correctly.
1690 auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1691 ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1692 EXPECT_EQ(nullptr, it->second);
1693 auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1694 ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1695 EXPECT_EQ(nullptr, it2->second);
1696}
1697
1698// Tests that changing the bundled MID in subsequent offer/answer exchange is
1699// not supported.
1700// TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1701// fixed
1702TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1703 CreateJsepTransportController(JsepTransportController::Config());
1704 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1705 bundle_group.AddContentName(kAudioMid1);
1706 bundle_group.AddContentName(kVideoMid1);
1707
Karl Wiberg918f50c2018-07-05 11:40:33 +02001708 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001709 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1710 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1711 nullptr);
1712 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1713 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1714 nullptr);
1715
Karl Wiberg918f50c2018-07-05 11:40:33 +02001716 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange818b6e2018-02-22 15:26:27 -08001717 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1718 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1719 nullptr);
1720 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1721 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1722 nullptr);
1723
1724 local_offer->AddGroup(bundle_group);
1725 remote_answer->AddGroup(bundle_group);
1726 EXPECT_TRUE(transport_controller_
1727 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1728 .ok());
1729 EXPECT_TRUE(transport_controller_
1730 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1731 .ok());
1732 EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1733 transport_controller_->GetRtpTransport(kVideoMid1));
1734
1735 // Reorder the bundle group.
1736 EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1737 bundle_group.AddContentName(kAudioMid1);
1738 // The answerer uses the new bundle group and now the bundle mid is changed to
1739 // |kVideo1|.
1740 remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1741 remote_answer->AddGroup(bundle_group);
1742 EXPECT_TRUE(transport_controller_
1743 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1744 .ok());
1745 EXPECT_FALSE(transport_controller_
1746 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1747 .ok());
1748}
Zhi Huange830e682018-03-30 10:48:35 -07001749// Test that rejecting only the first m= section of a BUNDLE group is treated as
1750// an error, but rejecting all of them works as expected.
1751TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1752 CreateJsepTransportController(JsepTransportController::Config());
1753 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1754 bundle_group.AddContentName(kAudioMid1);
1755 bundle_group.AddContentName(kVideoMid1);
1756 bundle_group.AddContentName(kDataMid1);
1757
Karl Wiberg918f50c2018-07-05 11:40:33 +02001758 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001759 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1760 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1761 nullptr);
1762 AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1763 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1764 nullptr);
1765 AddDataSection(local_offer.get(), kDataMid1,
1766 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1767 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1768 nullptr);
1769
Karl Wiberg918f50c2018-07-05 11:40:33 +02001770 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001771 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1772 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1773 nullptr);
1774 AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1775 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1776 nullptr);
1777 AddDataSection(remote_answer.get(), kDataMid1,
1778 cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1779 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1780 nullptr);
1781 // Reject audio content in answer.
1782 remote_answer->contents()[0].rejected = true;
1783
1784 local_offer->AddGroup(bundle_group);
1785 remote_answer->AddGroup(bundle_group);
1786
1787 EXPECT_TRUE(transport_controller_
1788 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1789 .ok());
1790 EXPECT_FALSE(transport_controller_
1791 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1792 .ok());
1793
1794 // Reject all the contents.
1795 remote_answer->contents()[1].rejected = true;
1796 remote_answer->contents()[2].rejected = true;
1797 EXPECT_TRUE(transport_controller_
1798 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1799 .ok());
1800 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1801 EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1802 EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1803}
1804
1805// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1806// is used.
1807TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1808 JsepTransportController::Config config;
1809 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1810 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001811 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001812 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1813 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1814 nullptr);
1815
1816 local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1817 // Applying a non-RTCP-mux offer is expected to fail.
1818 EXPECT_FALSE(transport_controller_
1819 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1820 .ok());
1821}
1822
1823// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1824// is used.
1825TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1826 JsepTransportController::Config config;
1827 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1828 CreateJsepTransportController(config);
Karl Wiberg918f50c2018-07-05 11:40:33 +02001829 auto local_offer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001830 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1831 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1832 nullptr);
1833 EXPECT_TRUE(transport_controller_
1834 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1835 .ok());
1836
Karl Wiberg918f50c2018-07-05 11:40:33 +02001837 auto remote_answer = absl::make_unique<cricket::SessionDescription>();
Zhi Huange830e682018-03-30 10:48:35 -07001838 AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1839 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1840 nullptr);
1841 // Applying a non-RTCP-mux answer is expected to fail.
1842 remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1843 EXPECT_FALSE(transport_controller_
1844 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1845 .ok());
1846}
Zhi Huange818b6e2018-02-22 15:26:27 -08001847
Zhi Huangd2248f82018-04-10 14:41:03 -07001848// This tests that the BUNDLE group in answer should be a subset of the offered
1849// group.
1850TEST_F(JsepTransportControllerTest,
1851 AddContentToBundleGroupInAnswerNotSupported) {
1852 CreateJsepTransportController(JsepTransportController::Config());
1853 auto local_offer = CreateSessionDescriptionWithoutBundle();
1854 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1855
1856 cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1857 offer_bundle_group.AddContentName(kAudioMid1);
1858 local_offer->AddGroup(offer_bundle_group);
1859
1860 cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1861 answer_bundle_group.AddContentName(kAudioMid1);
1862 answer_bundle_group.AddContentName(kVideoMid1);
1863 remote_answer->AddGroup(answer_bundle_group);
1864 EXPECT_TRUE(transport_controller_
1865 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1866 .ok());
1867 EXPECT_FALSE(transport_controller_
1868 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1869 .ok());
1870}
1871
1872// This tests that the BUNDLE group with non-existing MID should be rejectd.
1873TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1874 CreateJsepTransportController(JsepTransportController::Config());
1875 auto local_offer = CreateSessionDescriptionWithoutBundle();
1876 auto remote_answer = CreateSessionDescriptionWithoutBundle();
1877
1878 cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1879 // The BUNDLE group is invalid because there is no data section in the
1880 // description.
1881 invalid_bundle_group.AddContentName(kDataMid1);
1882 local_offer->AddGroup(invalid_bundle_group);
1883 remote_answer->AddGroup(invalid_bundle_group);
1884
1885 EXPECT_FALSE(transport_controller_
1886 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1887 .ok());
1888 EXPECT_FALSE(transport_controller_
1889 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1890 .ok());
1891}
1892
1893// This tests that an answer shouldn't be able to remove an m= section from an
1894// established group without rejecting it.
1895TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1896 CreateJsepTransportController(JsepTransportController::Config());
1897
1898 auto local_offer = CreateSessionDescriptionWithBundleGroup();
1899 auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1900 EXPECT_TRUE(transport_controller_
1901 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1902 .ok());
1903 EXPECT_TRUE(transport_controller_
1904 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1905 .ok());
1906
1907 // Do an re-offer/answer.
1908 EXPECT_TRUE(transport_controller_
1909 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1910 .ok());
1911 auto new_answer = CreateSessionDescriptionWithoutBundle();
1912 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1913 // The answer removes video from the BUNDLE group without rejecting it is
1914 // invalid.
1915 new_bundle_group.AddContentName(kAudioMid1);
1916 new_answer->AddGroup(new_bundle_group);
1917
1918 // Applying invalid answer is expected to fail.
1919 EXPECT_FALSE(transport_controller_
1920 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1921 .ok());
1922
1923 // Rejected the video content.
1924 auto video_content = new_answer->GetContentByName(kVideoMid1);
1925 ASSERT_TRUE(video_content);
1926 video_content->rejected = true;
1927 EXPECT_TRUE(transport_controller_
1928 ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1929 .ok());
1930}
1931
Steve Anton2bed3972019-01-04 17:04:30 -08001932// Test that the JsepTransportController can process a new local and remote
1933// description that changes the tagged BUNDLE group with the max-bundle policy
1934// specified.
1935// This is a regression test for bugs.webrtc.org/9954
1936TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
1937 CreateJsepTransportController(JsepTransportController::Config());
1938
1939 auto local_offer = absl::make_unique<cricket::SessionDescription>();
1940 AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1941 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1942 nullptr);
1943 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1944 bundle_group.AddContentName(kAudioMid1);
1945 local_offer->AddGroup(bundle_group);
1946 EXPECT_TRUE(transport_controller_
1947 ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1948 .ok());
1949
1950 std::unique_ptr<cricket::SessionDescription> remote_answer(
1951 local_offer->Copy());
1952 EXPECT_TRUE(transport_controller_
1953 ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1954 .ok());
1955
1956 std::unique_ptr<cricket::SessionDescription> local_reoffer(
1957 local_offer->Copy());
1958 local_reoffer->contents()[0].rejected = true;
1959 AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
1960 cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1961 nullptr);
1962 local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1963 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1964 new_bundle_group.AddContentName(kVideoMid1);
1965 local_reoffer->AddGroup(new_bundle_group);
1966
1967 EXPECT_TRUE(transport_controller_
1968 ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
1969 .ok());
1970
1971 std::unique_ptr<cricket::SessionDescription> remote_reanswer(
1972 local_reoffer->Copy());
1973 EXPECT_TRUE(
1974 transport_controller_
1975 ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
1976 .ok());
1977}
1978
Zhi Huange818b6e2018-02-22 15:26:27 -08001979} // namespace webrtc