blob: fc0448bcef77b5f433796000d799bee1eb23db17 [file] [log] [blame]
Steve Antonf1c6db12017-10-13 11:13:35 -07001/*
2 * Copyright 2017 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
Harald Alvestrandc24a2182022-02-23 13:44:59 +000011#include <stddef.h>
12#include <stdint.h>
Mirko Bonadei317a1f02019-09-17 17:06:18 +020013
Harald Alvestrandc24a2182022-02-23 13:44:59 +000014#include <memory>
15#include <string>
16#include <tuple>
17#include <type_traits>
18#include <utility>
19#include <vector>
20
21#include "absl/types/optional.h"
22#include "api/audio/audio_mixer.h"
23#include "api/candidate.h"
24#include "api/ice_transport_interface.h"
25#include "api/jsep.h"
26#include "api/media_types.h"
27#include "api/peer_connection_interface.h"
28#include "api/rtc_error.h"
29#include "api/scoped_refptr.h"
30#include "modules/audio_device/include/audio_device.h"
31#include "modules/audio_processing/include/audio_processing.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "p2p/base/fake_port_allocator.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000033#include "p2p/base/ice_transport_internal.h"
34#include "p2p/base/p2p_constants.h"
35#include "p2p/base/port.h"
36#include "p2p/base/port_allocator.h"
37#include "p2p/base/transport_description.h"
38#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 09:11:00 -080039#include "p2p/client/basic_port_allocator.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000040#include "pc/channel_interface.h"
41#include "pc/dtls_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080042#include "pc/media_session.h"
43#include "pc/peer_connection.h"
44#include "pc/peer_connection_wrapper.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000045#include "pc/rtp_transceiver.h"
Steve Anton10542f22019-01-11 09:11:00 -080046#include "pc/sdp_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000047#include "pc/session_description.h"
48#include "rtc_base/checks.h"
Byoungchan Leed197e0b2022-05-30 23:59:55 +090049#include "rtc_base/internal/default_socket_server.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000050#include "rtc_base/ip_address.h"
51#include "rtc_base/logging.h"
52#include "rtc_base/net_helper.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000053#include "rtc_base/rtc_certificate_generator.h"
54#include "rtc_base/socket_address.h"
55#include "rtc_base/thread.h"
56#include "test/gtest.h"
Sameer Vijaykar0793ee72023-01-23 16:31:29 +010057#include "test/scoped_key_value_config.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070058#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080059#include "pc/test/android_test_initializer.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070060#endif
Karl Wiberg1b0eae32017-10-17 14:48:54 +020061#include "api/audio_codecs/builtin_audio_decoder_factory.h"
62#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Mirko Bonadei2ff3f492018-11-22 09:00:13 +010063#include "api/create_peerconnection_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080064#include "api/uma_metrics.h"
Anders Carlsson67537952018-05-03 11:28:29 +020065#include "api/video_codecs/builtin_video_decoder_factory.h"
66#include "api/video_codecs/builtin_video_encoder_factory.h"
Markus Handella1b82012021-05-26 18:56:30 +020067#include "pc/peer_connection_proxy.h"
Steve Anton10542f22019-01-11 09:11:00 -080068#include "pc/test/fake_audio_capture_module.h"
Henrik Boströmee6f4f62019-11-06 12:36:12 +010069#include "pc/test/mock_peer_connection_observers.h"
Steve Anton10542f22019-01-11 09:11:00 -080070#include "rtc_base/fake_network.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070071#include "rtc_base/gunit.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020072#include "rtc_base/strings/string_builder.h"
Steve Anton10542f22019-01-11 09:11:00 -080073#include "rtc_base/virtual_socket_server.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020074#include "system_wrappers/include/metrics.h"
Steve Antonb443dfe2019-03-05 14:09:49 -080075#include "test/gmock.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070076
77namespace webrtc {
78
79using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
80using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
81using rtc::SocketAddress;
Steve Anton46d926a2018-01-23 10:23:06 -080082using ::testing::Combine;
Steve Antonb443dfe2019-03-05 14:09:49 -080083using ::testing::ElementsAre;
84using ::testing::Pair;
Steve Antonf1c6db12017-10-13 11:13:35 -070085using ::testing::Values;
86
87constexpr int kIceCandidatesTimeout = 10000;
Henrik Boströmee6f4f62019-11-06 12:36:12 +010088constexpr int64_t kWaitTimeout = 10000;
Philipp Hanckefd91d022022-10-27 20:08:23 +020089constexpr uint64_t kTiebreakerDefault = 44444;
Steve Antonf1c6db12017-10-13 11:13:35 -070090
Steve Anton46d926a2018-01-23 10:23:06 -080091class PeerConnectionWrapperForIceTest : public PeerConnectionWrapper {
Steve Antonf1c6db12017-10-13 11:13:35 -070092 public:
93 using PeerConnectionWrapper::PeerConnectionWrapper;
94
Henrik Boströmee6f4f62019-11-06 12:36:12 +010095 std::unique_ptr<IceCandidateInterface> CreateJsepCandidateForFirstTransport(
96 cricket::Candidate* candidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -070097 RTC_DCHECK(pc()->remote_description());
98 const auto* desc = pc()->remote_description()->description();
99 RTC_DCHECK(desc->contents().size() > 0);
100 const auto& first_content = desc->contents()[0];
101 candidate->set_transport_name(first_content.name);
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100102 return CreateIceCandidate(first_content.name, -1, *candidate);
103 }
104
105 // Adds a new ICE candidate to the first transport.
106 bool AddIceCandidate(cricket::Candidate* candidate) {
107 return pc()->AddIceCandidate(
108 CreateJsepCandidateForFirstTransport(candidate).get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700109 }
110
111 // Returns ICE candidates from the remote session description.
112 std::vector<const IceCandidateInterface*>
113 GetIceCandidatesFromRemoteDescription() {
114 const SessionDescriptionInterface* sdesc = pc()->remote_description();
115 RTC_DCHECK(sdesc);
116 std::vector<const IceCandidateInterface*> candidates;
117 for (size_t mline_index = 0; mline_index < sdesc->number_of_mediasections();
118 mline_index++) {
119 const auto* candidate_collection = sdesc->candidates(mline_index);
120 for (size_t i = 0; i < candidate_collection->count(); i++) {
121 candidates.push_back(candidate_collection->at(i));
122 }
123 }
124 return candidates;
125 }
126
127 rtc::FakeNetworkManager* network() { return network_; }
128
129 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
130
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200131 // The port allocator used by this PC.
132 cricket::PortAllocator* port_allocator_;
133
Steve Antonf1c6db12017-10-13 11:13:35 -0700134 private:
135 rtc::FakeNetworkManager* network_;
136};
137
Steve Anton46d926a2018-01-23 10:23:06 -0800138class PeerConnectionIceBaseTest : public ::testing::Test {
Steve Antonf1c6db12017-10-13 11:13:35 -0700139 protected:
Steve Anton46d926a2018-01-23 10:23:06 -0800140 typedef std::unique_ptr<PeerConnectionWrapperForIceTest> WrapperPtr;
Steve Antonf1c6db12017-10-13 11:13:35 -0700141
Steve Anton46d926a2018-01-23 10:23:06 -0800142 explicit PeerConnectionIceBaseTest(SdpSemantics sdp_semantics)
143 : vss_(new rtc::VirtualSocketServer()),
144 main_(vss_.get()),
145 sdp_semantics_(sdp_semantics) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700146#ifdef WEBRTC_ANDROID
147 InitializeAndroidObjects();
148#endif
149 pc_factory_ = CreatePeerConnectionFactory(
150 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Anders Carlsson67537952018-05-03 11:28:29 +0200151 rtc::scoped_refptr<AudioDeviceModule>(FakeAudioCaptureModule::Create()),
152 CreateBuiltinAudioEncoderFactory(), CreateBuiltinAudioDecoderFactory(),
153 CreateBuiltinVideoEncoderFactory(), CreateBuiltinVideoDecoderFactory(),
154 nullptr /* audio_mixer */, nullptr /* audio_processing */);
Steve Antonf1c6db12017-10-13 11:13:35 -0700155 }
156
157 WrapperPtr CreatePeerConnection() {
158 return CreatePeerConnection(RTCConfiguration());
159 }
160
161 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
162 auto* fake_network = NewFakeNetwork();
Byoungchan Leed197e0b2022-05-30 23:59:55 +0900163 auto port_allocator = std::make_unique<cricket::BasicPortAllocator>(
164 fake_network,
165 std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700166 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
167 cricket::PORTALLOCATOR_DISABLE_RELAY);
168 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
Steve Anton46d926a2018-01-23 10:23:06 -0800169 RTCConfiguration modified_config = config;
170 modified_config.sdp_semantics = sdp_semantics_;
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200171 auto observer = std::make_unique<MockPeerConnectionObserver>();
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200172 auto port_allocator_copy = port_allocator.get();
Florent Castelli72424402022-04-06 03:45:10 +0200173 PeerConnectionDependencies pc_dependencies(observer.get());
174 pc_dependencies.allocator = std::move(port_allocator);
175 auto result = pc_factory_->CreatePeerConnectionOrError(
176 modified_config, std::move(pc_dependencies));
177 if (!result.ok()) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700178 return nullptr;
179 }
180
Niels Möllerafb246b2022-04-20 14:26:50 +0200181 observer->SetPeerConnectionInterface(result.value().get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200182 auto wrapper = std::make_unique<PeerConnectionWrapperForIceTest>(
Florent Castelli72424402022-04-06 03:45:10 +0200183 pc_factory_, result.MoveValue(), std::move(observer));
Steve Antonf1c6db12017-10-13 11:13:35 -0700184 wrapper->set_network(fake_network);
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200185 wrapper->port_allocator_ = port_allocator_copy;
Steve Antonf1c6db12017-10-13 11:13:35 -0700186 return wrapper;
187 }
188
189 // Accepts the same arguments as CreatePeerConnection and adds default audio
190 // and video tracks.
191 template <typename... Args>
192 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
193 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
194 if (!wrapper) {
195 return nullptr;
196 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700197 wrapper->AddAudioTrack("a");
198 wrapper->AddVideoTrack("v");
Steve Antonf1c6db12017-10-13 11:13:35 -0700199 return wrapper;
200 }
201
202 cricket::Candidate CreateLocalUdpCandidate(
203 const rtc::SocketAddress& address) {
204 cricket::Candidate candidate;
205 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
206 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
207 candidate.set_address(address);
208 candidate.set_type(cricket::LOCAL_PORT_TYPE);
209 return candidate;
210 }
211
212 // Remove all ICE ufrag/pwd lines from the given session description.
213 void RemoveIceUfragPwd(SessionDescriptionInterface* sdesc) {
214 SetIceUfragPwd(sdesc, "", "");
215 }
216
217 // Sets all ICE ufrag/pwds on the given session description.
218 void SetIceUfragPwd(SessionDescriptionInterface* sdesc,
219 const std::string& ufrag,
220 const std::string& pwd) {
221 auto* desc = sdesc->description();
222 for (const auto& content : desc->contents()) {
223 auto* transport_info = desc->GetTransportInfoByName(content.name);
224 transport_info->description.ice_ufrag = ufrag;
225 transport_info->description.ice_pwd = pwd;
226 }
227 }
228
Qingsi Wange1692722017-11-29 13:27:20 -0800229 // Set ICE mode on the given session description.
230 void SetIceMode(SessionDescriptionInterface* sdesc,
231 const cricket::IceMode ice_mode) {
232 auto* desc = sdesc->description();
233 for (const auto& content : desc->contents()) {
234 auto* transport_info = desc->GetTransportInfoByName(content.name);
235 transport_info->description.ice_mode = ice_mode;
236 }
237 }
238
Steve Antonf1c6db12017-10-13 11:13:35 -0700239 cricket::TransportDescription* GetFirstTransportDescription(
240 SessionDescriptionInterface* sdesc) {
241 auto* desc = sdesc->description();
242 RTC_DCHECK(desc->contents().size() > 0);
243 auto* transport_info =
244 desc->GetTransportInfoByName(desc->contents()[0].name);
245 RTC_DCHECK(transport_info);
246 return &transport_info->description;
247 }
248
249 const cricket::TransportDescription* GetFirstTransportDescription(
250 const SessionDescriptionInterface* sdesc) {
251 auto* desc = sdesc->description();
252 RTC_DCHECK(desc->contents().size() > 0);
253 auto* transport_info =
254 desc->GetTransportInfoByName(desc->contents()[0].name);
255 RTC_DCHECK(transport_info);
256 return &transport_info->description;
257 }
258
Qingsi Wange1692722017-11-29 13:27:20 -0800259 // TODO(qingsi): Rewrite this method in terms of the standard IceTransport
260 // after it is implemented.
261 cricket::IceRole GetIceRole(const WrapperPtr& pc_wrapper_ptr) {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100262 auto* pc_proxy =
263 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
264 pc_wrapper_ptr->pc());
265 PeerConnection* pc = static_cast<PeerConnection*>(pc_proxy->internal());
Mirko Bonadei739baf02019-01-27 17:29:42 +0100266 for (const auto& transceiver : pc->GetTransceiversInternal()) {
Steve Anton69470252018-02-09 11:43:08 -0800267 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700268 auto dtls_transport = pc->LookupDtlsTransportByMidInternal(
Tomas Gunnarsson5411b172022-01-24 08:45:26 +0100269 transceiver->internal()->channel()->mid());
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700270 return dtls_transport->ice_transport()->internal()->GetIceRole();
Steve Anton46d926a2018-01-23 10:23:06 -0800271 }
272 }
Artem Titovd3251962021-11-15 16:57:07 +0100273 RTC_DCHECK_NOTREACHED();
Steve Anton46d926a2018-01-23 10:23:06 -0800274 return cricket::ICEROLE_UNKNOWN;
Qingsi Wange1692722017-11-29 13:27:20 -0800275 }
276
Henrik Boström79b69802019-07-18 11:16:56 +0200277 // Returns a list of (ufrag, pwd) pairs in the order that they appear in
Artem Titov880fa812021-07-30 22:30:23 +0200278 // `description`, or the empty list if `description` is null.
Henrik Boström79b69802019-07-18 11:16:56 +0200279 std::vector<std::pair<std::string, std::string>> GetIceCredentials(
280 const SessionDescriptionInterface* description) {
281 std::vector<std::pair<std::string, std::string>> ice_credentials;
282 if (!description)
283 return ice_credentials;
284 const auto* desc = description->description();
285 for (const auto& content_info : desc->contents()) {
286 const auto* transport_info =
287 desc->GetTransportInfoByName(content_info.name);
288 if (transport_info) {
289 ice_credentials.push_back(
290 std::make_pair(transport_info->description.ice_ufrag,
291 transport_info->description.ice_pwd));
292 }
293 }
294 return ice_credentials;
295 }
296
Steve Antonf1c6db12017-10-13 11:13:35 -0700297 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
298 SessionDescriptionInterface* sdesc) {
299 auto* desc = sdesc->description();
300 RTC_DCHECK(desc->contents().size() > 0);
301 const auto& first_content = desc->contents()[0];
302 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -0700303 std::unique_ptr<IceCandidateInterface> jsep_candidate =
304 CreateIceCandidate(first_content.name, 0, *candidate);
305 return sdesc->AddCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700306 }
307
308 rtc::FakeNetworkManager* NewFakeNetwork() {
309 // The PeerConnection's port allocator is tied to the PeerConnection's
310 // lifetime and expects the underlying NetworkManager to outlive it. That
311 // prevents us from having the PeerConnectionWrapper own the fake network.
312 // Therefore, the test fixture will own all the fake networks even though
313 // tests should access the fake network through the PeerConnectionWrapper.
314 auto* fake_network = new rtc::FakeNetworkManager();
315 fake_networks_.emplace_back(fake_network);
316 return fake_network;
317 }
318
319 std::unique_ptr<rtc::VirtualSocketServer> vss_;
320 rtc::AutoSocketServerThread main_;
321 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
322 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton46d926a2018-01-23 10:23:06 -0800323 const SdpSemantics sdp_semantics_;
324};
325
326class PeerConnectionIceTest
327 : public PeerConnectionIceBaseTest,
328 public ::testing::WithParamInterface<SdpSemantics> {
329 protected:
Harald Alvestrand76829d72018-07-18 23:24:36 +0200330 PeerConnectionIceTest() : PeerConnectionIceBaseTest(GetParam()) {
331 webrtc::metrics::Reset();
332 }
Steve Antonf1c6db12017-10-13 11:13:35 -0700333};
334
335::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
336 const char* b_expr,
337 const cricket::Candidate& a,
338 const cricket::Candidate& b) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200339 rtc::StringBuilder failure_info;
Steve Antonf1c6db12017-10-13 11:13:35 -0700340 if (a.component() != b.component()) {
341 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
342 }
343 if (a.protocol() != b.protocol()) {
344 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
345 }
346 if (a.address() != b.address()) {
347 failure_info << "\naddress: " << a.address().ToString()
348 << " != " << b.address().ToString();
349 }
350 if (a.type() != b.type()) {
351 failure_info << "\ntype: " << a.type() << " != " << b.type();
352 }
353 std::string failure_info_str = failure_info.str();
354 if (failure_info_str.empty()) {
355 return ::testing::AssertionSuccess();
356 } else {
357 return ::testing::AssertionFailure()
358 << a_expr << " and " << b_expr << " are not equal"
359 << failure_info_str;
360 }
361}
362
Steve Anton46d926a2018-01-23 10:23:06 -0800363TEST_P(PeerConnectionIceTest, OfferContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700364 const SocketAddress kLocalAddress("1.1.1.1", 0);
365
366 auto caller = CreatePeerConnectionWithAudioVideo();
367 caller->network()->AddInterface(kLocalAddress);
368
369 // Start ICE candidate gathering by setting the local offer.
370 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
371
372 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
373
374 auto offer = caller->CreateOffer();
375 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
376 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
377 offer->candidates(0)->count());
378 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
379 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
380 offer->candidates(1)->count());
381}
382
Steve Anton46d926a2018-01-23 10:23:06 -0800383TEST_P(PeerConnectionIceTest, AnswerContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700384 const SocketAddress kCallerAddress("1.1.1.1", 0);
385
386 auto caller = CreatePeerConnectionWithAudioVideo();
387 auto callee = CreatePeerConnectionWithAudioVideo();
388 caller->network()->AddInterface(kCallerAddress);
389
390 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
391 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
392
393 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
394
Steve Antondffead82018-02-06 10:31:29 -0800395 auto* answer = callee->pc()->local_description();
Steve Antonf1c6db12017-10-13 11:13:35 -0700396 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
397 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
398 answer->candidates(0)->count());
399 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
400 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
401 answer->candidates(1)->count());
402}
403
Steve Anton46d926a2018-01-23 10:23:06 -0800404TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700405 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
406 const SocketAddress kCallerAddress("1.1.1.1", 1111);
407
408 auto caller = CreatePeerConnectionWithAudioVideo();
409 auto callee = CreatePeerConnectionWithAudioVideo();
410
411 auto offer = caller->CreateOfferAndSetAsLocal();
412 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
413 AddCandidateToFirstTransport(&candidate, offer.get());
414
415 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
416 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
417 ASSERT_EQ(1u, remote_candidates.size());
418 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
419 remote_candidates[0]->candidate());
420}
421
Steve Anton46d926a2018-01-23 10:23:06 -0800422TEST_P(PeerConnectionIceTest, SetLocalDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700423 auto caller = CreatePeerConnectionWithAudioVideo();
424
425 auto offer = caller->CreateOffer();
426 RemoveIceUfragPwd(offer.get());
427
428 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
429}
430
Steve Anton46d926a2018-01-23 10:23:06 -0800431TEST_P(PeerConnectionIceTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700432 auto caller = CreatePeerConnectionWithAudioVideo();
433 auto callee = CreatePeerConnectionWithAudioVideo();
434
435 auto offer = caller->CreateOfferAndSetAsLocal();
436 RemoveIceUfragPwd(offer.get());
437
438 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
439}
440
Steve Antonf764cf42018-05-01 14:32:17 -0700441// Test that doing an offer/answer exchange with no transport (i.e., no data
442// channel or media) results in the ICE connection state staying at New.
443TEST_P(PeerConnectionIceTest,
444 OfferAnswerWithNoTransportsDoesNotChangeIceConnectionState) {
445 auto caller = CreatePeerConnection();
446 auto callee = CreatePeerConnection();
447
448 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
449
450 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
451 caller->pc()->ice_connection_state());
452 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
453 callee->pc()->ice_connection_state());
454}
455
Steve Antonf1c6db12017-10-13 11:13:35 -0700456// The following group tests that ICE candidates are not generated before
457// SetLocalDescription is called on a PeerConnection.
458
Steve Anton46d926a2018-01-23 10:23:06 -0800459TEST_P(PeerConnectionIceTest, NoIceCandidatesBeforeSetLocalDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700460 const SocketAddress kLocalAddress("1.1.1.1", 0);
461
462 auto caller = CreatePeerConnectionWithAudioVideo();
463 caller->network()->AddInterface(kLocalAddress);
464
465 // Pump for 1 second and verify that no candidates are generated.
466 rtc::Thread::Current()->ProcessMessages(1000);
467
468 EXPECT_EQ(0u, caller->observer()->candidates_.size());
469}
Steve Anton46d926a2018-01-23 10:23:06 -0800470TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700471 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
472 const SocketAddress kCallerAddress("1.1.1.1", 1111);
473
474 auto caller = CreatePeerConnectionWithAudioVideo();
475 auto callee = CreatePeerConnectionWithAudioVideo();
476 caller->network()->AddInterface(kCallerAddress);
477
478 auto offer = caller->CreateOfferAndSetAsLocal();
479 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
480 AddCandidateToFirstTransport(&candidate, offer.get());
481 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
482
483 // Pump for 1 second and verify that no candidates are generated.
484 rtc::Thread::Current()->ProcessMessages(1000);
485
486 EXPECT_EQ(0u, callee->observer()->candidates_.size());
487}
488
Steve Anton46d926a2018-01-23 10:23:06 -0800489TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenRemoteDescriptionNotSet) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700490 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
491
492 auto caller = CreatePeerConnectionWithAudioVideo();
493 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton27ab0e52018-07-23 15:11:53 -0700494 std::unique_ptr<IceCandidateInterface> jsep_candidate =
495 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
Steve Antonf1c6db12017-10-13 11:13:35 -0700496
Steve Anton27ab0e52018-07-23 15:11:53 -0700497 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700498
499 caller->CreateOfferAndSetAsLocal();
500
Steve Anton27ab0e52018-07-23 15:11:53 -0700501 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Ying Wangef3998f2019-12-09 13:06:53 +0100502 EXPECT_METRIC_THAT(
503 webrtc::metrics::Samples("WebRTC.PeerConnection.AddIceCandidate"),
504 ElementsAre(Pair(kAddIceCandidateFailNoRemoteDescription, 2)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700505}
506
Steve Antonc79268f2018-04-24 09:54:10 -0700507TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenPeerConnectionClosed) {
508 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
509
510 auto caller = CreatePeerConnectionWithAudioVideo();
511 auto callee = CreatePeerConnectionWithAudioVideo();
512
513 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
514
515 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
516 auto* audio_content = cricket::GetFirstAudioContent(
517 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700518 std::unique_ptr<IceCandidateInterface> jsep_candidate =
519 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700520
521 caller->pc()->Close();
522
Steve Anton27ab0e52018-07-23 15:11:53 -0700523 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700524}
525
Steve Anton46d926a2018-01-23 10:23:06 -0800526TEST_P(PeerConnectionIceTest, DuplicateIceCandidateIgnoredWhenAdded) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700527 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
528
529 auto caller = CreatePeerConnectionWithAudioVideo();
530 auto callee = CreatePeerConnectionWithAudioVideo();
531
532 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
533 ASSERT_TRUE(
534 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
535
536 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
537 caller->AddIceCandidate(&candidate);
538 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
539 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
540}
541
Tomas Gunnarsson27bc6e22021-02-12 13:16:26 +0100542// TODO(tommi): Re-enable after updating RTCPeerConnection-blockedPorts.html in
543// Chromium (the test needs setRemoteDescription to succeed for an invalid
544// candidate).
545TEST_P(PeerConnectionIceTest, DISABLED_ErrorOnInvalidRemoteIceCandidateAdded) {
Tomas Gunnarsson8cb97062021-02-08 18:57:04 +0100546 auto caller = CreatePeerConnectionWithAudioVideo();
547 auto callee = CreatePeerConnectionWithAudioVideo();
548 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
549 // Add a candidate to the remote description with a candidate that has an
550 // invalid address (port number == 2).
551 auto answer = callee->CreateAnswerAndSetAsLocal();
552 cricket::Candidate bad_candidate =
553 CreateLocalUdpCandidate(SocketAddress("2.2.2.2", 2));
554 RTC_LOG(LS_INFO) << "Bad candidate: " << bad_candidate.ToString();
555 AddCandidateToFirstTransport(&bad_candidate, answer.get());
556 // Now the call to SetRemoteDescription should fail.
557 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
558}
559
Steve Anton46d926a2018-01-23 10:23:06 -0800560TEST_P(PeerConnectionIceTest,
Steve Antonc79268f2018-04-24 09:54:10 -0700561 CannotRemoveIceCandidatesWhenPeerConnectionClosed) {
562 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
563
564 auto caller = CreatePeerConnectionWithAudioVideo();
565 auto callee = CreatePeerConnectionWithAudioVideo();
566
567 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
568
569 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
570 auto* audio_content = cricket::GetFirstAudioContent(
571 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700572 std::unique_ptr<IceCandidateInterface> ice_candidate =
573 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700574
Steve Anton27ab0e52018-07-23 15:11:53 -0700575 ASSERT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700576
577 caller->pc()->Close();
578
579 EXPECT_FALSE(caller->pc()->RemoveIceCandidates({candidate}));
580}
581
582TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700583 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
584 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
585
586 auto caller = CreatePeerConnectionWithAudioVideo();
587 auto callee = CreatePeerConnectionWithAudioVideo();
588
589 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
590 ASSERT_TRUE(
591 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
592
Artem Titovcfea2182021-08-10 01:22:31 +0200593 // `candidate.transport_name()` is empty.
Steve Antonf1c6db12017-10-13 11:13:35 -0700594 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton46d926a2018-01-23 10:23:06 -0800595 auto* audio_content = cricket::GetFirstAudioContent(
596 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700597 std::unique_ptr<IceCandidateInterface> ice_candidate =
598 CreateIceCandidate(audio_content->name, 0, candidate);
599 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700600 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
601}
602
Steve Anton46d926a2018-01-23 10:23:06 -0800603TEST_P(PeerConnectionIceTest, RemoveCandidateRemovesFromRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700604 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
605
606 auto caller = CreatePeerConnectionWithAudioVideo();
607 auto callee = CreatePeerConnectionWithAudioVideo();
608
609 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
610 ASSERT_TRUE(
611 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
612
613 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
614 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
615 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
616 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
617}
618
619// Test that if a candidate is added via AddIceCandidate and via an updated
620// remote description, then both candidates appear in the stored remote
621// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800622TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700623 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
624 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
625 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
626
627 auto caller = CreatePeerConnectionWithAudioVideo();
628 auto callee = CreatePeerConnectionWithAudioVideo();
629
630 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
631 ASSERT_TRUE(
632 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
633
Artem Titov880fa812021-07-30 22:30:23 +0200634 // Add one candidate via `AddIceCandidate`.
Steve Antonf1c6db12017-10-13 11:13:35 -0700635 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
636 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
637
638 // Add the second candidate via a reoffer.
639 auto offer = caller->CreateOffer();
640 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
641 AddCandidateToFirstTransport(&candidate2, offer.get());
642
643 // Expect both candidates to appear in the callee's remote description.
644 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
645 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
646}
647
648// The follow test verifies that SetLocal/RemoteDescription fails when an offer
649// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
650// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
651// pwd must be 22-256 characters and ufrag must be 4-256 characters.
Steve Anton46d926a2018-01-23 10:23:06 -0800652TEST_P(PeerConnectionIceTest, VerifyUfragPwdLength) {
Yves Gerey665174f2018-06-19 15:03:05 +0200653 auto set_local_description_with_ufrag_pwd_length = [this](int ufrag_len,
654 int pwd_len) {
655 auto pc = CreatePeerConnectionWithAudioVideo();
656 auto offer = pc->CreateOffer();
657 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
658 std::string(pwd_len, 'x'));
659 return pc->SetLocalDescription(std::move(offer));
660 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700661
Yves Gerey665174f2018-06-19 15:03:05 +0200662 auto set_remote_description_with_ufrag_pwd_length = [this](int ufrag_len,
663 int pwd_len) {
664 auto pc = CreatePeerConnectionWithAudioVideo();
665 auto offer = pc->CreateOffer();
666 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
667 std::string(pwd_len, 'x'));
668 return pc->SetRemoteDescription(std::move(offer));
669 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700670
671 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
672 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
673 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
674 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
675 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
676 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
677 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
678 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
679 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
680 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
681 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
682 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
683}
684
685::testing::AssertionResult AssertIpInCandidates(
686 const char* address_expr,
687 const char* candidates_expr,
688 const SocketAddress& address,
689 const std::vector<IceCandidateInterface*> candidates) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200690 rtc::StringBuilder candidate_hosts;
Steve Antonf1c6db12017-10-13 11:13:35 -0700691 for (const auto* candidate : candidates) {
692 const auto& candidate_ip = candidate->candidate().address().ipaddr();
693 if (candidate_ip == address.ipaddr()) {
694 return ::testing::AssertionSuccess();
695 }
Jonas Olssonabbe8412018-04-03 13:40:05 +0200696 candidate_hosts << "\n" << candidate_ip.ToString();
Steve Antonf1c6db12017-10-13 11:13:35 -0700697 }
698 return ::testing::AssertionFailure()
699 << address_expr << " (host " << address.HostAsURIString()
700 << ") not in " << candidates_expr
701 << " which have the following address hosts:" << candidate_hosts.str();
702}
703
Steve Anton46d926a2018-01-23 10:23:06 -0800704TEST_P(PeerConnectionIceTest, CandidatesGeneratedForEachLocalInterface) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700705 const SocketAddress kLocalAddress1("1.1.1.1", 0);
706 const SocketAddress kLocalAddress2("2.2.2.2", 0);
707
708 auto caller = CreatePeerConnectionWithAudioVideo();
709 caller->network()->AddInterface(kLocalAddress1);
710 caller->network()->AddInterface(kLocalAddress2);
711
712 caller->CreateOfferAndSetAsLocal();
713 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
714
715 auto candidates = caller->observer()->GetCandidatesByMline(0);
716 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
717 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
718}
719
Steve Anton46d926a2018-01-23 10:23:06 -0800720TEST_P(PeerConnectionIceTest, TrickledSingleCandidateAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700721 const SocketAddress kCallerAddress("1.1.1.1", 1111);
722
723 auto caller = CreatePeerConnectionWithAudioVideo();
724 auto callee = CreatePeerConnectionWithAudioVideo();
725
726 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
727
728 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
729 callee->AddIceCandidate(&candidate);
730 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
731 ASSERT_EQ(1u, candidates.size());
732 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
733 candidates[0]->candidate());
734}
735
Steve Anton46d926a2018-01-23 10:23:06 -0800736TEST_P(PeerConnectionIceTest, TwoTrickledCandidatesAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700737 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
738 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
739
740 auto caller = CreatePeerConnectionWithAudioVideo();
741 auto callee = CreatePeerConnectionWithAudioVideo();
742
743 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
744 ASSERT_TRUE(
745 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
746
747 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
748 caller->AddIceCandidate(&candidate1);
749
750 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
751 caller->AddIceCandidate(&candidate2);
752
753 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
754 ASSERT_EQ(2u, candidates.size());
755 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
756 candidates[0]->candidate());
757 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
758 candidates[1]->candidate());
759}
760
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100761TEST_P(PeerConnectionIceTest, AsyncAddIceCandidateIsAddedToRemoteDescription) {
762 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
763
764 auto caller = CreatePeerConnectionWithAudioVideo();
765 auto callee = CreatePeerConnectionWithAudioVideo();
766
767 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
768
769 auto jsep_candidate =
770 callee->CreateJsepCandidateForFirstTransport(&candidate);
771 bool operation_completed = false;
772 callee->pc()->AddIceCandidate(std::move(jsep_candidate),
773 [&operation_completed](RTCError result) {
774 EXPECT_TRUE(result.ok());
775 operation_completed = true;
776 });
777 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
778
779 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
780 ASSERT_EQ(1u, candidates.size());
781 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
782 candidates[0]->candidate());
783}
784
785TEST_P(PeerConnectionIceTest,
786 AsyncAddIceCandidateCompletesImmediatelyIfNoPendingOperation) {
787 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
788
789 auto caller = CreatePeerConnectionWithAudioVideo();
790 auto callee = CreatePeerConnectionWithAudioVideo();
791
792 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
793
794 auto jsep_candidate =
795 callee->CreateJsepCandidateForFirstTransport(&candidate);
796 bool operation_completed = false;
797 callee->pc()->AddIceCandidate(
798 std::move(jsep_candidate),
799 [&operation_completed](RTCError result) { operation_completed = true; });
800 EXPECT_TRUE(operation_completed);
801}
802
803TEST_P(PeerConnectionIceTest,
804 AsyncAddIceCandidateCompletesWhenPendingOperationCompletes) {
805 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
806
807 auto caller = CreatePeerConnectionWithAudioVideo();
808 auto callee = CreatePeerConnectionWithAudioVideo();
809
810 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
811
812 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200813 auto answer_observer =
814 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Niels Möllerafb246b2022-04-20 14:26:50 +0200815 callee->pc()->CreateAnswer(answer_observer.get(), RTCOfferAnswerOptions());
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100816
817 auto jsep_candidate =
818 callee->CreateJsepCandidateForFirstTransport(&candidate);
819 bool operation_completed = false;
820 callee->pc()->AddIceCandidate(
821 std::move(jsep_candidate),
822 [&operation_completed](RTCError result) { operation_completed = true; });
823 // The operation will not be able to complete until we EXPECT_TRUE_WAIT()
824 // allowing CreateAnswer() to complete.
825 EXPECT_FALSE(operation_completed);
826 EXPECT_TRUE_WAIT(answer_observer->called(), kWaitTimeout);
827 // As soon as it does, AddIceCandidate() will execute without delay, so it
828 // must also have completed.
829 EXPECT_TRUE(operation_completed);
830}
831
832TEST_P(PeerConnectionIceTest,
833 AsyncAddIceCandidateFailsBeforeSetRemoteDescription) {
834 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
835
836 auto caller = CreatePeerConnectionWithAudioVideo();
837 std::unique_ptr<IceCandidateInterface> jsep_candidate =
838 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
839
840 bool operation_completed = false;
841 caller->pc()->AddIceCandidate(
842 std::move(jsep_candidate), [&operation_completed](RTCError result) {
843 EXPECT_FALSE(result.ok());
844 EXPECT_EQ(result.message(),
Henrik Boström347488e2022-01-21 15:18:08 +0100845 std::string("The remote description was null"));
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100846 operation_completed = true;
847 });
848 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
849}
850
851TEST_P(PeerConnectionIceTest,
852 AsyncAddIceCandidateFailsIfPeerConnectionDestroyed) {
853 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
854
855 auto caller = CreatePeerConnectionWithAudioVideo();
856 auto callee = CreatePeerConnectionWithAudioVideo();
857
858 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
859
860 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200861 auto answer_observer =
862 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Niels Möllerafb246b2022-04-20 14:26:50 +0200863 callee->pc()->CreateAnswer(answer_observer.get(), RTCOfferAnswerOptions());
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100864
865 auto jsep_candidate =
866 callee->CreateJsepCandidateForFirstTransport(&candidate);
867 bool operation_completed = false;
868 callee->pc()->AddIceCandidate(
869 std::move(jsep_candidate), [&operation_completed](RTCError result) {
870 EXPECT_FALSE(result.ok());
871 EXPECT_EQ(
872 result.message(),
873 std::string(
874 "AddIceCandidate failed because the session was shut down"));
875 operation_completed = true;
876 });
877 // The operation will not be able to run until EXPECT_TRUE_WAIT(), giving us
878 // time to remove all references to the PeerConnection.
879 EXPECT_FALSE(operation_completed);
880 // This should delete the callee PC.
881 callee = nullptr;
882 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
883}
884
Steve Anton46d926a2018-01-23 10:23:06 -0800885TEST_P(PeerConnectionIceTest, LocalDescriptionUpdatedWhenContinualGathering) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700886 const SocketAddress kLocalAddress("1.1.1.1", 0);
887
888 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100889 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700890 config.continual_gathering_policy =
891 PeerConnectionInterface::GATHER_CONTINUALLY;
892 auto caller = CreatePeerConnectionWithAudioVideo(config);
893 caller->network()->AddInterface(kLocalAddress);
894
895 // Start ICE candidate gathering by setting the local offer.
896 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
897
898 // Since we're using continual gathering, we won't get "gathering done".
899 EXPECT_TRUE_WAIT(
900 caller->pc()->local_description()->candidates(0)->count() > 0,
901 kIceCandidatesTimeout);
902}
903
904// Test that when continual gathering is enabled, and a network interface goes
905// down, the candidate is signaled as removed and removed from the local
906// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800907TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700908 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
909 const SocketAddress kLocalAddress("1.1.1.1", 0);
910
911 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100912 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700913 config.continual_gathering_policy =
914 PeerConnectionInterface::GATHER_CONTINUALLY;
915 auto caller = CreatePeerConnectionWithAudioVideo(config);
916 caller->network()->AddInterface(kLocalAddress);
917
918 // Start ICE candidate gathering by setting the local offer.
919 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
920
921 EXPECT_TRUE_WAIT(
922 caller->pc()->local_description()->candidates(0)->count() > 0,
923 kIceCandidatesTimeout);
924
925 // Remove the only network interface, causing the PeerConnection to signal
926 // the removal of all candidates derived from this interface.
927 caller->network()->RemoveInterface(kLocalAddress);
928
929 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
930 kIceCandidatesTimeout);
931 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
932}
933
Steve Anton46d926a2018-01-23 10:23:06 -0800934TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700935 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
936 const SocketAddress kLocalAddress("1.1.1.1", 0);
937
938 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100939 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700940 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
941 auto caller = CreatePeerConnectionWithAudioVideo(config);
942 caller->network()->AddInterface(kLocalAddress);
943
944 // Start ICE candidate gathering by setting the local offer.
945 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
946
947 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
948
949 caller->network()->RemoveInterface(kLocalAddress);
950
951 // Verify that the local candidates are not removed;
952 rtc::Thread::Current()->ProcessMessages(1000);
953 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
954}
955
956// The following group tests that when an offer includes a new ufrag or pwd
957// (indicating an ICE restart) the old candidates are removed and new candidates
958// added to the remote description.
959
Steve Anton46d926a2018-01-23 10:23:06 -0800960TEST_P(PeerConnectionIceTest, IceRestartOfferClearsExistingCandidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700961 const SocketAddress kCallerAddress("1.1.1.1", 1111);
962
963 auto caller = CreatePeerConnectionWithAudioVideo();
964 auto callee = CreatePeerConnectionWithAudioVideo();
965
Amit Hilbuchae3df542019-01-07 12:13:08 -0800966 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700967 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
968 AddCandidateToFirstTransport(&candidate, offer.get());
969
970 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
971
972 RTCOfferAnswerOptions options;
973 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800974 ASSERT_TRUE(
975 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700976
977 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
978}
Steve Anton46d926a2018-01-23 10:23:06 -0800979TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700980 IceRestartOfferCandidateReplacesExistingCandidate) {
981 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
982 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
983
984 auto caller = CreatePeerConnectionWithAudioVideo();
985 auto callee = CreatePeerConnectionWithAudioVideo();
986
Amit Hilbuchae3df542019-01-07 12:13:08 -0800987 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700988 cricket::Candidate old_candidate =
989 CreateLocalUdpCandidate(kFirstCallerAddress);
990 AddCandidateToFirstTransport(&old_candidate, offer.get());
991
992 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
993
994 RTCOfferAnswerOptions options;
995 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800996 auto restart_offer = caller->CreateOfferAndSetAsLocal(options);
Steve Antonf1c6db12017-10-13 11:13:35 -0700997 cricket::Candidate new_candidate =
998 CreateLocalUdpCandidate(kRestartedCallerAddress);
999 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
1000
1001 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
1002
1003 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
1004 ASSERT_EQ(1u, remote_candidates.size());
1005 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
1006 remote_candidates[0]->candidate());
1007}
1008
1009// Test that if there is not an ICE restart (i.e., nothing changes), then the
1010// answer to a later offer should have the same ufrag/pwd as the first answer.
Steve Anton46d926a2018-01-23 10:23:06 -08001011TEST_P(PeerConnectionIceTest, LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
Steve Antonf1c6db12017-10-13 11:13:35 -07001012 auto caller = CreatePeerConnectionWithAudioVideo();
1013 auto callee = CreatePeerConnectionWithAudioVideo();
1014
1015 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1016 ASSERT_TRUE(
1017 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1018
1019 // Re-offer.
1020 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1021
1022 auto answer = callee->CreateAnswer();
1023 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
1024 auto* local_transport_desc =
1025 GetFirstTransportDescription(callee->pc()->local_description());
1026
1027 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
1028 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
1029}
1030
Henrik Boström79b69802019-07-18 11:16:56 +02001031TEST_P(PeerConnectionIceTest, RestartIceGeneratesNewCredentials) {
1032 auto caller = CreatePeerConnectionWithAudioVideo();
1033 auto callee = CreatePeerConnectionWithAudioVideo();
1034
1035 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1036 auto initial_ice_credentials =
1037 GetIceCredentials(caller->pc()->local_description());
1038 caller->pc()->RestartIce();
1039 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1040 auto restarted_ice_credentials =
1041 GetIceCredentials(caller->pc()->local_description());
1042 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1043}
1044
1045TEST_P(PeerConnectionIceTest,
1046 RestartIceWhileLocalOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1047 auto caller = CreatePeerConnectionWithAudioVideo();
1048 auto callee = CreatePeerConnectionWithAudioVideo();
1049
1050 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1051 auto initial_ice_credentials =
1052 GetIceCredentials(caller->pc()->local_description());
Artem Titov880fa812021-07-30 22:30:23 +02001053 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001054 // offerer.
1055 caller->pc()->RestartIce();
1056 ASSERT_TRUE(
1057 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1058 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1059 auto restarted_ice_credentials =
1060 GetIceCredentials(caller->pc()->local_description());
1061 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1062}
1063
1064TEST_P(PeerConnectionIceTest,
1065 RestartIceWhileRemoteOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1066 auto caller = CreatePeerConnectionWithAudioVideo();
1067 auto callee = CreatePeerConnectionWithAudioVideo();
1068
1069 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1070 auto initial_ice_credentials =
1071 GetIceCredentials(caller->pc()->local_description());
1072 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001073 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001074 // answerer.
1075 caller->pc()->RestartIce();
1076 ASSERT_TRUE(
1077 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
1078 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1079 auto restarted_ice_credentials =
1080 GetIceCredentials(caller->pc()->local_description());
1081 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1082}
1083
1084TEST_P(PeerConnectionIceTest, RestartIceTriggeredByRemoteSide) {
1085 auto caller = CreatePeerConnectionWithAudioVideo();
1086 auto callee = CreatePeerConnectionWithAudioVideo();
1087
1088 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1089 auto initial_ice_credentials =
1090 GetIceCredentials(caller->pc()->local_description());
1091
Artem Titov880fa812021-07-30 22:30:23 +02001092 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001093 // restart ICE locally as well.
1094 callee->pc()->RestartIce();
1095 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1096
1097 auto restarted_ice_credentials =
1098 GetIceCredentials(caller->pc()->local_description());
1099 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1100}
1101
1102TEST_P(PeerConnectionIceTest, RestartIceCausesNegotiationNeeded) {
1103 auto caller = CreatePeerConnectionWithAudioVideo();
1104 auto callee = CreatePeerConnectionWithAudioVideo();
1105
1106 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001107 caller->observer()->clear_legacy_renegotiation_needed();
1108 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001109 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001110 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1111 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001112}
1113
1114// In Unified Plan, "onnegotiationneeded" is spec-compliant, including not
1115// firing multipe times in a row, or firing when returning to the stable
1116// signaling state if negotiation is still needed. In Plan B it fires any time
1117// something changes. As such, some tests are SdpSemantics-specific.
1118class PeerConnectionIceTestUnifiedPlan : public PeerConnectionIceBaseTest {
1119 protected:
1120 PeerConnectionIceTestUnifiedPlan()
1121 : PeerConnectionIceBaseTest(SdpSemantics::kUnifiedPlan) {}
1122};
1123
1124TEST_F(PeerConnectionIceTestUnifiedPlan,
1125 RestartIceWhileLocalOfferIsPendingCausesNegotiationNeededWhenStable) {
1126 auto caller = CreatePeerConnectionWithAudioVideo();
1127 auto callee = CreatePeerConnectionWithAudioVideo();
1128
1129 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001130 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001131 // offerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001132 caller->observer()->clear_legacy_renegotiation_needed();
1133 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001134 caller->pc()->RestartIce();
1135 // In Unified Plan, the event should not fire until we are back in the stable
1136 // signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001137 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1138 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001139 ASSERT_TRUE(
1140 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001141 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1142 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001143}
1144
1145TEST_F(PeerConnectionIceTestUnifiedPlan,
1146 RestartIceWhileRemoteOfferIsPendingCausesNegotiationNeededWhenStable) {
1147 auto caller = CreatePeerConnectionWithAudioVideo();
1148 auto callee = CreatePeerConnectionWithAudioVideo();
1149
1150 // Establish initial credentials as the caller.
1151 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1152 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001153 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001154 // answerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001155 caller->observer()->clear_legacy_renegotiation_needed();
1156 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001157 caller->pc()->RestartIce();
1158 // In Unified Plan, the event should not fire until we are back in the stable
1159 // signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001160 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1161 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001162 ASSERT_TRUE(
1163 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001164 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1165 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001166}
1167
1168TEST_F(PeerConnectionIceTestUnifiedPlan,
1169 RestartIceTriggeredByRemoteSideCauseNegotiationNotNeeded) {
1170 auto caller = CreatePeerConnectionWithAudioVideo();
1171 auto callee = CreatePeerConnectionWithAudioVideo();
1172
1173 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1174 // Local restart.
1175 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001176 caller->observer()->clear_legacy_renegotiation_needed();
1177 caller->observer()->clear_latest_negotiation_needed_event();
Artem Titov880fa812021-07-30 22:30:23 +02001178 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001179 // restart ICE locally as well.
1180 callee->pc()->RestartIce();
1181 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1182 // Having restarted ICE by the remote offer, we do not need to renegotiate ICE
1183 // credentials when back in the stable signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001184 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1185 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001186}
1187
1188TEST_F(PeerConnectionIceTestUnifiedPlan,
1189 RestartIceTwiceDoesNotFireNegotiationNeededTwice) {
1190 auto caller = CreatePeerConnectionWithAudioVideo();
1191 auto callee = CreatePeerConnectionWithAudioVideo();
1192
1193 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1194 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001195 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1196 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1197 caller->observer()->clear_legacy_renegotiation_needed();
1198 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001199 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001200 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1201 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001202}
1203
1204// In Plan B, "onnegotiationneeded" is not spec-compliant, firing based on if
1205// something changed rather than if negotiation is needed. In Unified Plan it
1206// fires according to spec. As such, some tests are SdpSemantics-specific.
1207class PeerConnectionIceTestPlanB : public PeerConnectionIceBaseTest {
1208 protected:
1209 PeerConnectionIceTestPlanB()
Florent Castelli15a38de2022-04-06 00:38:21 +02001210 : PeerConnectionIceBaseTest(SdpSemantics::kPlanB_DEPRECATED) {}
Henrik Boström79b69802019-07-18 11:16:56 +02001211};
1212
1213TEST_F(PeerConnectionIceTestPlanB,
1214 RestartIceWhileOfferIsPendingCausesNegotiationNeededImmediately) {
1215 auto caller = CreatePeerConnectionWithAudioVideo();
1216 auto callee = CreatePeerConnectionWithAudioVideo();
1217
1218 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001219 caller->observer()->clear_legacy_renegotiation_needed();
1220 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001221 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001222 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1223 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1224 caller->observer()->clear_legacy_renegotiation_needed();
1225 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001226 ASSERT_TRUE(
1227 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1228 // In Plan B, the event fired early so we don't expect it to fire now. This is
1229 // not spec-compliant but follows the pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001230 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1231 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001232}
1233
1234TEST_F(PeerConnectionIceTestPlanB,
1235 RestartIceTwiceDoesFireNegotiationNeededTwice) {
1236 auto caller = CreatePeerConnectionWithAudioVideo();
1237 auto callee = CreatePeerConnectionWithAudioVideo();
1238
1239 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001240 caller->observer()->clear_legacy_renegotiation_needed();
1241 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001242 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001243 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1244 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1245 caller->observer()->clear_legacy_renegotiation_needed();
1246 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001247 caller->pc()->RestartIce();
1248 // In Plan B, the event fires every time something changed, even if we have
1249 // already fired the event. This is not spec-compliant but follows the same
1250 // pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001251 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1252 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001253}
1254
Steve Antonf1c6db12017-10-13 11:13:35 -07001255// The following parameterized test verifies that if an offer is sent with a
1256// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
1257// other side has initiated an ICE restart and generate a new ufrag and pwd.
1258// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
1259// a=ice-pwd attributes compared to the previous SDP from the peer, it
1260// indicates that ICE is restarting for this media stream."
1261
Steve Anton46d926a2018-01-23 10:23:06 -08001262class PeerConnectionIceUfragPwdAnswerTest
1263 : public PeerConnectionIceBaseTest,
1264 public ::testing::WithParamInterface<
1265 std::tuple<SdpSemantics, std::tuple<bool, bool>>> {
Steve Antonf1c6db12017-10-13 11:13:35 -07001266 protected:
Steve Anton46d926a2018-01-23 10:23:06 -08001267 PeerConnectionIceUfragPwdAnswerTest()
1268 : PeerConnectionIceBaseTest(std::get<0>(GetParam())) {
1269 auto param = std::get<1>(GetParam());
1270 offer_new_ufrag_ = std::get<0>(param);
1271 offer_new_pwd_ = std::get<1>(param);
Steve Antonf1c6db12017-10-13 11:13:35 -07001272 }
1273
1274 bool offer_new_ufrag_;
1275 bool offer_new_pwd_;
1276};
1277
Steve Anton46d926a2018-01-23 10:23:06 -08001278TEST_P(PeerConnectionIceUfragPwdAnswerTest, TestIncludedInAnswer) {
Steve Antonf1c6db12017-10-13 11:13:35 -07001279 auto caller = CreatePeerConnectionWithAudioVideo();
1280 auto callee = CreatePeerConnectionWithAudioVideo();
1281
1282 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1283 ASSERT_TRUE(
1284 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1285
1286 auto offer = caller->CreateOffer();
1287 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
1288 if (offer_new_ufrag_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001289 offer_transport_desc->ice_ufrag += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001290 }
1291 if (offer_new_pwd_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001292 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001293 }
1294
1295 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1296
1297 auto answer = callee->CreateAnswer();
1298 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
1299 auto* local_transport_desc =
1300 GetFirstTransportDescription(callee->pc()->local_description());
1301
1302 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
1303 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
1304}
1305
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001306INSTANTIATE_TEST_SUITE_P(
Steve Anton46d926a2018-01-23 10:23:06 -08001307 PeerConnectionIceTest,
1308 PeerConnectionIceUfragPwdAnswerTest,
Florent Castelli15a38de2022-04-06 00:38:21 +02001309 Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Anton46d926a2018-01-23 10:23:06 -08001310 Values(std::make_pair(true, true), // Both changed.
1311 std::make_pair(true, false), // Only ufrag changed.
1312 std::make_pair(false, true)))); // Only pwd changed.
Steve Antonf1c6db12017-10-13 11:13:35 -07001313
1314// Test that if an ICE restart is offered on one media section, then the answer
1315// will only change ICE ufrag/pwd for that section and keep the other sections
1316// the same.
1317// Note that this only works if we have disabled BUNDLE, otherwise all media
1318// sections will share the same transport.
Steve Anton46d926a2018-01-23 10:23:06 -08001319TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -07001320 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
1321 auto caller = CreatePeerConnectionWithAudioVideo();
1322 auto callee = CreatePeerConnectionWithAudioVideo();
1323
1324 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1325 ASSERT_TRUE(
1326 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1327
1328 RTCOfferAnswerOptions disable_bundle_options;
1329 disable_bundle_options.use_rtp_mux = false;
1330
1331 auto offer = caller->CreateOffer(disable_bundle_options);
1332
1333 // Signal ICE restart on the first media section.
1334 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
Steve Anton71ff0732020-01-24 16:28:15 -08001335 offer_transport_desc->ice_ufrag += "+new";
1336 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001337
1338 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1339
1340 auto answer = callee->CreateAnswer(disable_bundle_options);
1341 const auto& answer_transports = answer->description()->transport_infos();
1342 const auto& local_transports =
1343 callee->pc()->local_description()->description()->transport_infos();
1344
1345 EXPECT_NE(answer_transports[0].description.ice_ufrag,
1346 local_transports[0].description.ice_ufrag);
1347 EXPECT_NE(answer_transports[0].description.ice_pwd,
1348 local_transports[0].description.ice_pwd);
1349 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
1350 local_transports[1].description.ice_ufrag);
1351 EXPECT_EQ(answer_transports[1].description.ice_pwd,
1352 local_transports[1].description.ice_pwd);
1353}
1354
Qingsi Wange1692722017-11-29 13:27:20 -08001355// Test that when the initial offerer (caller) uses the lite implementation of
1356// ICE and the callee uses the full implementation, the caller takes the
1357// CONTROLLED role and the callee takes the CONTROLLING role. This is specified
1358// in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001359TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001360 OfferFromLiteIceControlledAndAnswerFromFullIceControlling) {
1361 auto caller = CreatePeerConnectionWithAudioVideo();
1362 auto callee = CreatePeerConnectionWithAudioVideo();
1363
1364 auto offer = caller->CreateOffer();
1365 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1366 ASSERT_TRUE(
1367 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1368 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1369
1370 auto answer = callee->CreateAnswer();
1371 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_FULL);
1372 ASSERT_TRUE(
1373 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1374 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1375
1376 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(caller));
1377 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(callee));
1378}
1379
1380// Test that when the caller and the callee both use the lite implementation of
1381// ICE, the initial offerer (caller) takes the CONTROLLING role and the callee
1382// takes the CONTROLLED role. This is specified in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001383TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001384 OfferFromLiteIceControllingAndAnswerFromLiteIceControlled) {
1385 auto caller = CreatePeerConnectionWithAudioVideo();
1386 auto callee = CreatePeerConnectionWithAudioVideo();
1387
1388 auto offer = caller->CreateOffer();
1389 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1390 ASSERT_TRUE(
1391 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1392 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1393
1394 auto answer = callee->CreateAnswer();
1395 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_LITE);
1396 ASSERT_TRUE(
1397 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1398 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1399
1400 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(caller));
1401 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(callee));
1402}
1403
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001404INSTANTIATE_TEST_SUITE_P(PeerConnectionIceTest,
1405 PeerConnectionIceTest,
Florent Castelli15a38de2022-04-06 00:38:21 +02001406 Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001407 SdpSemantics::kUnifiedPlan));
Steve Anton46d926a2018-01-23 10:23:06 -08001408
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001409class PeerConnectionIceConfigTest : public ::testing::Test {
Byoungchan Leed58f5262022-06-27 18:05:22 +09001410 public:
1411 PeerConnectionIceConfigTest()
1412 : socket_server_(rtc::CreateDefaultSocketServer()),
1413 main_thread_(socket_server_.get()) {}
1414
Qingsi Wang4ff54432018-03-01 18:25:20 -08001415 protected:
1416 void SetUp() override {
1417 pc_factory_ = CreatePeerConnectionFactory(
1418 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
1419 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
Anders Carlsson67537952018-05-03 11:28:29 +02001420 CreateBuiltinAudioDecoderFactory(), CreateBuiltinVideoEncoderFactory(),
1421 CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
1422 nullptr /* audio_processing */);
Qingsi Wang4ff54432018-03-01 18:25:20 -08001423 }
1424 void CreatePeerConnection(const RTCConfiguration& config) {
Byoungchan Leed58f5262022-06-27 18:05:22 +09001425 packet_socket_factory_.reset(
1426 new rtc::BasicPacketSocketFactory(socket_server_.get()));
Qingsi Wang4ff54432018-03-01 18:25:20 -08001427 std::unique_ptr<cricket::FakePortAllocator> port_allocator(
Byoungchan Leed58f5262022-06-27 18:05:22 +09001428 new cricket::FakePortAllocator(rtc::Thread::Current(),
Sameer Vijaykar0793ee72023-01-23 16:31:29 +01001429 packet_socket_factory_.get(),
1430 &field_trials_));
Qingsi Wang4ff54432018-03-01 18:25:20 -08001431 port_allocator_ = port_allocator.get();
Philipp Hanckefd91d022022-10-27 20:08:23 +02001432 port_allocator_->SetIceTiebreaker(kTiebreakerDefault);
Florent Castelli72424402022-04-06 03:45:10 +02001433 PeerConnectionDependencies pc_dependencies(&observer_);
1434 pc_dependencies.allocator = std::move(port_allocator);
1435 auto result = pc_factory_->CreatePeerConnectionOrError(
1436 config, std::move(pc_dependencies));
1437 EXPECT_TRUE(result.ok());
1438 pc_ = result.MoveValue();
Qingsi Wang4ff54432018-03-01 18:25:20 -08001439 }
1440
Sameer Vijaykar0793ee72023-01-23 16:31:29 +01001441 webrtc::test::ScopedKeyValueConfig field_trials_;
Byoungchan Leed58f5262022-06-27 18:05:22 +09001442 std::unique_ptr<rtc::SocketServer> socket_server_;
1443 rtc::AutoSocketServerThread main_thread_;
Qingsi Wang4ff54432018-03-01 18:25:20 -08001444 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_ = nullptr;
1445 rtc::scoped_refptr<PeerConnectionInterface> pc_ = nullptr;
Byoungchan Leed58f5262022-06-27 18:05:22 +09001446 std::unique_ptr<rtc::PacketSocketFactory> packet_socket_factory_;
Qingsi Wang4ff54432018-03-01 18:25:20 -08001447 cricket::FakePortAllocator* port_allocator_ = nullptr;
1448
1449 MockPeerConnectionObserver observer_;
1450};
1451
1452TEST_F(PeerConnectionIceConfigTest, SetStunCandidateKeepaliveInterval) {
1453 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001454 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Qingsi Wang4ff54432018-03-01 18:25:20 -08001455 config.stun_candidate_keepalive_interval = 123;
1456 config.ice_candidate_pool_size = 1;
1457 CreatePeerConnection(config);
1458 ASSERT_NE(port_allocator_, nullptr);
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001459 absl::optional<int> actual_stun_keepalive_interval =
Qingsi Wang4ff54432018-03-01 18:25:20 -08001460 port_allocator_->stun_candidate_keepalive_interval();
1461 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 123);
1462 config.stun_candidate_keepalive_interval = 321;
Niels Möller2579f0c2019-08-19 09:58:17 +02001463 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
Qingsi Wang4ff54432018-03-01 18:25:20 -08001464 actual_stun_keepalive_interval =
1465 port_allocator_->stun_candidate_keepalive_interval();
1466 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 321);
1467}
1468
Derek Bailey6c127a12021-04-15 12:42:41 -07001469TEST_F(PeerConnectionIceConfigTest, SetStableWritableConnectionInterval) {
1470 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001471 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001472 config.stable_writable_connection_ping_interval_ms = 3500;
1473 CreatePeerConnection(config);
1474 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1475 EXPECT_EQ(pc_->GetConfiguration().stable_writable_connection_ping_interval_ms,
1476 config.stable_writable_connection_ping_interval_ms);
1477}
1478
1479TEST_F(PeerConnectionIceConfigTest,
1480 SetStableWritableConnectionInterval_FailsValidation) {
1481 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001482 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001483 CreatePeerConnection(config);
1484 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1485 config.stable_writable_connection_ping_interval_ms = 5000;
1486 config.ice_check_interval_strong_connectivity = 7500;
1487 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1488}
1489
1490TEST_F(PeerConnectionIceConfigTest,
1491 SetStableWritableConnectionInterval_DefaultValue_FailsValidation) {
1492 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001493 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001494 CreatePeerConnection(config);
1495 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1496 config.ice_check_interval_strong_connectivity = 2500;
1497 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1498 config.ice_check_interval_strong_connectivity = 2501;
1499 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1500}
1501
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001502TEST_P(PeerConnectionIceTest, IceCredentialsCreateOffer) {
1503 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001504 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001505 config.ice_candidate_pool_size = 1;
1506 auto pc = CreatePeerConnectionWithAudioVideo(config);
1507 ASSERT_NE(pc->port_allocator_, nullptr);
1508 auto offer = pc->CreateOffer();
1509 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1510 ASSERT_EQ(1u, credentials.size());
1511
1512 auto* desc = offer->description();
1513 for (const auto& content : desc->contents()) {
1514 auto* transport_info = desc->GetTransportInfoByName(content.name);
1515 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1516 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1517 }
1518}
1519
1520TEST_P(PeerConnectionIceTest, IceCredentialsCreateAnswer) {
1521 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001522 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001523 config.ice_candidate_pool_size = 1;
1524 auto pc = CreatePeerConnectionWithAudioVideo(config);
1525 ASSERT_NE(pc->port_allocator_, nullptr);
1526 auto offer = pc->CreateOffer();
1527 ASSERT_TRUE(pc->SetRemoteDescription(std::move(offer)));
1528 auto answer = pc->CreateAnswer();
1529
1530 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1531 ASSERT_EQ(1u, credentials.size());
1532
1533 auto* desc = answer->description();
1534 for (const auto& content : desc->contents()) {
1535 auto* transport_info = desc->GetTransportInfoByName(content.name);
1536 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1537 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1538 }
1539}
1540
Steve Antonec47b572020-01-24 14:53:37 -08001541// Regression test for https://bugs.chromium.org/p/webrtc/issues/detail?id=4728
1542TEST_P(PeerConnectionIceTest, CloseDoesNotTransitionGatheringStateToComplete) {
1543 auto pc = CreatePeerConnectionWithAudioVideo();
1544 pc->pc()->Close();
1545 EXPECT_FALSE(pc->IsIceGatheringDone());
1546 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
1547 pc->pc()->ice_gathering_state());
1548}
1549
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001550TEST_P(PeerConnectionIceTest, PrefersMidOverMLineIndex) {
1551 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
1552
1553 auto caller = CreatePeerConnectionWithAudioVideo();
1554 auto callee = CreatePeerConnectionWithAudioVideo();
1555
1556 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1557 ASSERT_TRUE(
1558 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1559
Artem Titovcfea2182021-08-10 01:22:31 +02001560 // `candidate.transport_name()` is empty.
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001561 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
1562 auto* audio_content = cricket::GetFirstAudioContent(
1563 caller->pc()->local_description()->description());
1564 std::unique_ptr<IceCandidateInterface> ice_candidate =
1565 CreateIceCandidate(audio_content->name, 65535, candidate);
1566 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
1567 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
1568}
1569
Steve Antonf1c6db12017-10-13 11:13:35 -07001570} // namespace webrtc