blob: b0d56fcb97daea8aadb25a7cd01c097e9f6dec59 [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"
Steve Antonf1c6db12017-10-13 11:13:35 -070057#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080058#include "pc/test/android_test_initializer.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070059#endif
Karl Wiberg1b0eae32017-10-17 14:48:54 +020060#include "api/audio_codecs/builtin_audio_decoder_factory.h"
61#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Mirko Bonadei2ff3f492018-11-22 09:00:13 +010062#include "api/create_peerconnection_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080063#include "api/uma_metrics.h"
Anders Carlsson67537952018-05-03 11:28:29 +020064#include "api/video_codecs/builtin_video_decoder_factory.h"
65#include "api/video_codecs/builtin_video_encoder_factory.h"
Markus Handella1b82012021-05-26 18:56:30 +020066#include "pc/peer_connection_proxy.h"
Steve Anton10542f22019-01-11 09:11:00 -080067#include "pc/test/fake_audio_capture_module.h"
Henrik Boströmee6f4f62019-11-06 12:36:12 +010068#include "pc/test/mock_peer_connection_observers.h"
Steve Anton10542f22019-01-11 09:11:00 -080069#include "rtc_base/fake_network.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070070#include "rtc_base/gunit.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020071#include "rtc_base/strings/string_builder.h"
Steve Anton10542f22019-01-11 09:11:00 -080072#include "rtc_base/virtual_socket_server.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020073#include "system_wrappers/include/metrics.h"
Steve Antonb443dfe2019-03-05 14:09:49 -080074#include "test/gmock.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070075
76namespace webrtc {
77
78using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
79using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
80using rtc::SocketAddress;
Steve Anton46d926a2018-01-23 10:23:06 -080081using ::testing::Combine;
Steve Antonb443dfe2019-03-05 14:09:49 -080082using ::testing::ElementsAre;
83using ::testing::Pair;
Steve Antonf1c6db12017-10-13 11:13:35 -070084using ::testing::Values;
85
86constexpr int kIceCandidatesTimeout = 10000;
Henrik Boströmee6f4f62019-11-06 12:36:12 +010087constexpr int64_t kWaitTimeout = 10000;
Philipp Hanckefd91d022022-10-27 20:08:23 +020088constexpr uint64_t kTiebreakerDefault = 44444;
Steve Antonf1c6db12017-10-13 11:13:35 -070089
Steve Anton46d926a2018-01-23 10:23:06 -080090class PeerConnectionWrapperForIceTest : public PeerConnectionWrapper {
Steve Antonf1c6db12017-10-13 11:13:35 -070091 public:
92 using PeerConnectionWrapper::PeerConnectionWrapper;
93
Henrik Boströmee6f4f62019-11-06 12:36:12 +010094 std::unique_ptr<IceCandidateInterface> CreateJsepCandidateForFirstTransport(
95 cricket::Candidate* candidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -070096 RTC_DCHECK(pc()->remote_description());
97 const auto* desc = pc()->remote_description()->description();
98 RTC_DCHECK(desc->contents().size() > 0);
99 const auto& first_content = desc->contents()[0];
100 candidate->set_transport_name(first_content.name);
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100101 return CreateIceCandidate(first_content.name, -1, *candidate);
102 }
103
104 // Adds a new ICE candidate to the first transport.
105 bool AddIceCandidate(cricket::Candidate* candidate) {
106 return pc()->AddIceCandidate(
107 CreateJsepCandidateForFirstTransport(candidate).get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700108 }
109
110 // Returns ICE candidates from the remote session description.
111 std::vector<const IceCandidateInterface*>
112 GetIceCandidatesFromRemoteDescription() {
113 const SessionDescriptionInterface* sdesc = pc()->remote_description();
114 RTC_DCHECK(sdesc);
115 std::vector<const IceCandidateInterface*> candidates;
116 for (size_t mline_index = 0; mline_index < sdesc->number_of_mediasections();
117 mline_index++) {
118 const auto* candidate_collection = sdesc->candidates(mline_index);
119 for (size_t i = 0; i < candidate_collection->count(); i++) {
120 candidates.push_back(candidate_collection->at(i));
121 }
122 }
123 return candidates;
124 }
125
126 rtc::FakeNetworkManager* network() { return network_; }
127
128 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
129
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200130 // The port allocator used by this PC.
131 cricket::PortAllocator* port_allocator_;
132
Steve Antonf1c6db12017-10-13 11:13:35 -0700133 private:
134 rtc::FakeNetworkManager* network_;
135};
136
Steve Anton46d926a2018-01-23 10:23:06 -0800137class PeerConnectionIceBaseTest : public ::testing::Test {
Steve Antonf1c6db12017-10-13 11:13:35 -0700138 protected:
Steve Anton46d926a2018-01-23 10:23:06 -0800139 typedef std::unique_ptr<PeerConnectionWrapperForIceTest> WrapperPtr;
Steve Antonf1c6db12017-10-13 11:13:35 -0700140
Steve Anton46d926a2018-01-23 10:23:06 -0800141 explicit PeerConnectionIceBaseTest(SdpSemantics sdp_semantics)
142 : vss_(new rtc::VirtualSocketServer()),
143 main_(vss_.get()),
144 sdp_semantics_(sdp_semantics) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700145#ifdef WEBRTC_ANDROID
146 InitializeAndroidObjects();
147#endif
148 pc_factory_ = CreatePeerConnectionFactory(
149 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Anders Carlsson67537952018-05-03 11:28:29 +0200150 rtc::scoped_refptr<AudioDeviceModule>(FakeAudioCaptureModule::Create()),
151 CreateBuiltinAudioEncoderFactory(), CreateBuiltinAudioDecoderFactory(),
152 CreateBuiltinVideoEncoderFactory(), CreateBuiltinVideoDecoderFactory(),
153 nullptr /* audio_mixer */, nullptr /* audio_processing */);
Steve Antonf1c6db12017-10-13 11:13:35 -0700154 }
155
156 WrapperPtr CreatePeerConnection() {
157 return CreatePeerConnection(RTCConfiguration());
158 }
159
160 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
161 auto* fake_network = NewFakeNetwork();
Byoungchan Leed197e0b2022-05-30 23:59:55 +0900162 auto port_allocator = std::make_unique<cricket::BasicPortAllocator>(
163 fake_network,
164 std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700165 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
166 cricket::PORTALLOCATOR_DISABLE_RELAY);
167 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
Steve Anton46d926a2018-01-23 10:23:06 -0800168 RTCConfiguration modified_config = config;
169 modified_config.sdp_semantics = sdp_semantics_;
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200170 auto observer = std::make_unique<MockPeerConnectionObserver>();
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200171 auto port_allocator_copy = port_allocator.get();
Florent Castelli72424402022-04-06 03:45:10 +0200172 PeerConnectionDependencies pc_dependencies(observer.get());
173 pc_dependencies.allocator = std::move(port_allocator);
174 auto result = pc_factory_->CreatePeerConnectionOrError(
175 modified_config, std::move(pc_dependencies));
176 if (!result.ok()) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700177 return nullptr;
178 }
179
Niels Möllerafb246b2022-04-20 14:26:50 +0200180 observer->SetPeerConnectionInterface(result.value().get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200181 auto wrapper = std::make_unique<PeerConnectionWrapperForIceTest>(
Florent Castelli72424402022-04-06 03:45:10 +0200182 pc_factory_, result.MoveValue(), std::move(observer));
Steve Antonf1c6db12017-10-13 11:13:35 -0700183 wrapper->set_network(fake_network);
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200184 wrapper->port_allocator_ = port_allocator_copy;
Steve Antonf1c6db12017-10-13 11:13:35 -0700185 return wrapper;
186 }
187
188 // Accepts the same arguments as CreatePeerConnection and adds default audio
189 // and video tracks.
190 template <typename... Args>
191 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
192 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
193 if (!wrapper) {
194 return nullptr;
195 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700196 wrapper->AddAudioTrack("a");
197 wrapper->AddVideoTrack("v");
Steve Antonf1c6db12017-10-13 11:13:35 -0700198 return wrapper;
199 }
200
201 cricket::Candidate CreateLocalUdpCandidate(
202 const rtc::SocketAddress& address) {
203 cricket::Candidate candidate;
204 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
205 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
206 candidate.set_address(address);
207 candidate.set_type(cricket::LOCAL_PORT_TYPE);
208 return candidate;
209 }
210
211 // Remove all ICE ufrag/pwd lines from the given session description.
212 void RemoveIceUfragPwd(SessionDescriptionInterface* sdesc) {
213 SetIceUfragPwd(sdesc, "", "");
214 }
215
216 // Sets all ICE ufrag/pwds on the given session description.
217 void SetIceUfragPwd(SessionDescriptionInterface* sdesc,
218 const std::string& ufrag,
219 const std::string& pwd) {
220 auto* desc = sdesc->description();
221 for (const auto& content : desc->contents()) {
222 auto* transport_info = desc->GetTransportInfoByName(content.name);
223 transport_info->description.ice_ufrag = ufrag;
224 transport_info->description.ice_pwd = pwd;
225 }
226 }
227
Qingsi Wange1692722017-11-29 13:27:20 -0800228 // Set ICE mode on the given session description.
229 void SetIceMode(SessionDescriptionInterface* sdesc,
230 const cricket::IceMode ice_mode) {
231 auto* desc = sdesc->description();
232 for (const auto& content : desc->contents()) {
233 auto* transport_info = desc->GetTransportInfoByName(content.name);
234 transport_info->description.ice_mode = ice_mode;
235 }
236 }
237
Steve Antonf1c6db12017-10-13 11:13:35 -0700238 cricket::TransportDescription* GetFirstTransportDescription(
239 SessionDescriptionInterface* sdesc) {
240 auto* desc = sdesc->description();
241 RTC_DCHECK(desc->contents().size() > 0);
242 auto* transport_info =
243 desc->GetTransportInfoByName(desc->contents()[0].name);
244 RTC_DCHECK(transport_info);
245 return &transport_info->description;
246 }
247
248 const cricket::TransportDescription* GetFirstTransportDescription(
249 const SessionDescriptionInterface* sdesc) {
250 auto* desc = sdesc->description();
251 RTC_DCHECK(desc->contents().size() > 0);
252 auto* transport_info =
253 desc->GetTransportInfoByName(desc->contents()[0].name);
254 RTC_DCHECK(transport_info);
255 return &transport_info->description;
256 }
257
Qingsi Wange1692722017-11-29 13:27:20 -0800258 // TODO(qingsi): Rewrite this method in terms of the standard IceTransport
259 // after it is implemented.
260 cricket::IceRole GetIceRole(const WrapperPtr& pc_wrapper_ptr) {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100261 auto* pc_proxy =
262 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
263 pc_wrapper_ptr->pc());
264 PeerConnection* pc = static_cast<PeerConnection*>(pc_proxy->internal());
Mirko Bonadei739baf02019-01-27 17:29:42 +0100265 for (const auto& transceiver : pc->GetTransceiversInternal()) {
Steve Anton69470252018-02-09 11:43:08 -0800266 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700267 auto dtls_transport = pc->LookupDtlsTransportByMidInternal(
Tomas Gunnarsson5411b172022-01-24 08:45:26 +0100268 transceiver->internal()->channel()->mid());
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700269 return dtls_transport->ice_transport()->internal()->GetIceRole();
Steve Anton46d926a2018-01-23 10:23:06 -0800270 }
271 }
Artem Titovd3251962021-11-15 16:57:07 +0100272 RTC_DCHECK_NOTREACHED();
Steve Anton46d926a2018-01-23 10:23:06 -0800273 return cricket::ICEROLE_UNKNOWN;
Qingsi Wange1692722017-11-29 13:27:20 -0800274 }
275
Henrik Boström79b69802019-07-18 11:16:56 +0200276 // Returns a list of (ufrag, pwd) pairs in the order that they appear in
Artem Titov880fa812021-07-30 22:30:23 +0200277 // `description`, or the empty list if `description` is null.
Henrik Boström79b69802019-07-18 11:16:56 +0200278 std::vector<std::pair<std::string, std::string>> GetIceCredentials(
279 const SessionDescriptionInterface* description) {
280 std::vector<std::pair<std::string, std::string>> ice_credentials;
281 if (!description)
282 return ice_credentials;
283 const auto* desc = description->description();
284 for (const auto& content_info : desc->contents()) {
285 const auto* transport_info =
286 desc->GetTransportInfoByName(content_info.name);
287 if (transport_info) {
288 ice_credentials.push_back(
289 std::make_pair(transport_info->description.ice_ufrag,
290 transport_info->description.ice_pwd));
291 }
292 }
293 return ice_credentials;
294 }
295
Steve Antonf1c6db12017-10-13 11:13:35 -0700296 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
297 SessionDescriptionInterface* sdesc) {
298 auto* desc = sdesc->description();
299 RTC_DCHECK(desc->contents().size() > 0);
300 const auto& first_content = desc->contents()[0];
301 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -0700302 std::unique_ptr<IceCandidateInterface> jsep_candidate =
303 CreateIceCandidate(first_content.name, 0, *candidate);
304 return sdesc->AddCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700305 }
306
307 rtc::FakeNetworkManager* NewFakeNetwork() {
308 // The PeerConnection's port allocator is tied to the PeerConnection's
309 // lifetime and expects the underlying NetworkManager to outlive it. That
310 // prevents us from having the PeerConnectionWrapper own the fake network.
311 // Therefore, the test fixture will own all the fake networks even though
312 // tests should access the fake network through the PeerConnectionWrapper.
313 auto* fake_network = new rtc::FakeNetworkManager();
314 fake_networks_.emplace_back(fake_network);
315 return fake_network;
316 }
317
318 std::unique_ptr<rtc::VirtualSocketServer> vss_;
319 rtc::AutoSocketServerThread main_;
320 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
321 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton46d926a2018-01-23 10:23:06 -0800322 const SdpSemantics sdp_semantics_;
323};
324
325class PeerConnectionIceTest
326 : public PeerConnectionIceBaseTest,
327 public ::testing::WithParamInterface<SdpSemantics> {
328 protected:
Harald Alvestrand76829d72018-07-18 23:24:36 +0200329 PeerConnectionIceTest() : PeerConnectionIceBaseTest(GetParam()) {
330 webrtc::metrics::Reset();
331 }
Steve Antonf1c6db12017-10-13 11:13:35 -0700332};
333
334::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
335 const char* b_expr,
336 const cricket::Candidate& a,
337 const cricket::Candidate& b) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200338 rtc::StringBuilder failure_info;
Steve Antonf1c6db12017-10-13 11:13:35 -0700339 if (a.component() != b.component()) {
340 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
341 }
342 if (a.protocol() != b.protocol()) {
343 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
344 }
345 if (a.address() != b.address()) {
346 failure_info << "\naddress: " << a.address().ToString()
347 << " != " << b.address().ToString();
348 }
349 if (a.type() != b.type()) {
350 failure_info << "\ntype: " << a.type() << " != " << b.type();
351 }
352 std::string failure_info_str = failure_info.str();
353 if (failure_info_str.empty()) {
354 return ::testing::AssertionSuccess();
355 } else {
356 return ::testing::AssertionFailure()
357 << a_expr << " and " << b_expr << " are not equal"
358 << failure_info_str;
359 }
360}
361
Steve Anton46d926a2018-01-23 10:23:06 -0800362TEST_P(PeerConnectionIceTest, OfferContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700363 const SocketAddress kLocalAddress("1.1.1.1", 0);
364
365 auto caller = CreatePeerConnectionWithAudioVideo();
366 caller->network()->AddInterface(kLocalAddress);
367
368 // Start ICE candidate gathering by setting the local offer.
369 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
370
371 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
372
373 auto offer = caller->CreateOffer();
374 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
375 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
376 offer->candidates(0)->count());
377 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
378 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
379 offer->candidates(1)->count());
380}
381
Steve Anton46d926a2018-01-23 10:23:06 -0800382TEST_P(PeerConnectionIceTest, AnswerContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700383 const SocketAddress kCallerAddress("1.1.1.1", 0);
384
385 auto caller = CreatePeerConnectionWithAudioVideo();
386 auto callee = CreatePeerConnectionWithAudioVideo();
387 caller->network()->AddInterface(kCallerAddress);
388
389 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
390 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
391
392 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
393
Steve Antondffead82018-02-06 10:31:29 -0800394 auto* answer = callee->pc()->local_description();
Steve Antonf1c6db12017-10-13 11:13:35 -0700395 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
396 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
397 answer->candidates(0)->count());
398 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
399 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
400 answer->candidates(1)->count());
401}
402
Steve Anton46d926a2018-01-23 10:23:06 -0800403TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700404 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
405 const SocketAddress kCallerAddress("1.1.1.1", 1111);
406
407 auto caller = CreatePeerConnectionWithAudioVideo();
408 auto callee = CreatePeerConnectionWithAudioVideo();
409
410 auto offer = caller->CreateOfferAndSetAsLocal();
411 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
412 AddCandidateToFirstTransport(&candidate, offer.get());
413
414 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
415 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
416 ASSERT_EQ(1u, remote_candidates.size());
417 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
418 remote_candidates[0]->candidate());
419}
420
Steve Anton46d926a2018-01-23 10:23:06 -0800421TEST_P(PeerConnectionIceTest, SetLocalDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700422 auto caller = CreatePeerConnectionWithAudioVideo();
423
424 auto offer = caller->CreateOffer();
425 RemoveIceUfragPwd(offer.get());
426
427 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
428}
429
Steve Anton46d926a2018-01-23 10:23:06 -0800430TEST_P(PeerConnectionIceTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700431 auto caller = CreatePeerConnectionWithAudioVideo();
432 auto callee = CreatePeerConnectionWithAudioVideo();
433
434 auto offer = caller->CreateOfferAndSetAsLocal();
435 RemoveIceUfragPwd(offer.get());
436
437 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
438}
439
Steve Antonf764cf42018-05-01 14:32:17 -0700440// Test that doing an offer/answer exchange with no transport (i.e., no data
441// channel or media) results in the ICE connection state staying at New.
442TEST_P(PeerConnectionIceTest,
443 OfferAnswerWithNoTransportsDoesNotChangeIceConnectionState) {
444 auto caller = CreatePeerConnection();
445 auto callee = CreatePeerConnection();
446
447 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
448
449 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
450 caller->pc()->ice_connection_state());
451 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
452 callee->pc()->ice_connection_state());
453}
454
Steve Antonf1c6db12017-10-13 11:13:35 -0700455// The following group tests that ICE candidates are not generated before
456// SetLocalDescription is called on a PeerConnection.
457
Steve Anton46d926a2018-01-23 10:23:06 -0800458TEST_P(PeerConnectionIceTest, NoIceCandidatesBeforeSetLocalDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700459 const SocketAddress kLocalAddress("1.1.1.1", 0);
460
461 auto caller = CreatePeerConnectionWithAudioVideo();
462 caller->network()->AddInterface(kLocalAddress);
463
464 // Pump for 1 second and verify that no candidates are generated.
465 rtc::Thread::Current()->ProcessMessages(1000);
466
467 EXPECT_EQ(0u, caller->observer()->candidates_.size());
468}
Steve Anton46d926a2018-01-23 10:23:06 -0800469TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700470 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
471 const SocketAddress kCallerAddress("1.1.1.1", 1111);
472
473 auto caller = CreatePeerConnectionWithAudioVideo();
474 auto callee = CreatePeerConnectionWithAudioVideo();
475 caller->network()->AddInterface(kCallerAddress);
476
477 auto offer = caller->CreateOfferAndSetAsLocal();
478 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
479 AddCandidateToFirstTransport(&candidate, offer.get());
480 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
481
482 // Pump for 1 second and verify that no candidates are generated.
483 rtc::Thread::Current()->ProcessMessages(1000);
484
485 EXPECT_EQ(0u, callee->observer()->candidates_.size());
486}
487
Steve Anton46d926a2018-01-23 10:23:06 -0800488TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenRemoteDescriptionNotSet) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700489 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
490
491 auto caller = CreatePeerConnectionWithAudioVideo();
492 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton27ab0e52018-07-23 15:11:53 -0700493 std::unique_ptr<IceCandidateInterface> jsep_candidate =
494 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
Steve Antonf1c6db12017-10-13 11:13:35 -0700495
Steve Anton27ab0e52018-07-23 15:11:53 -0700496 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700497
498 caller->CreateOfferAndSetAsLocal();
499
Steve Anton27ab0e52018-07-23 15:11:53 -0700500 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Ying Wangef3998f2019-12-09 13:06:53 +0100501 EXPECT_METRIC_THAT(
502 webrtc::metrics::Samples("WebRTC.PeerConnection.AddIceCandidate"),
503 ElementsAre(Pair(kAddIceCandidateFailNoRemoteDescription, 2)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700504}
505
Steve Antonc79268f2018-04-24 09:54:10 -0700506TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenPeerConnectionClosed) {
507 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
508
509 auto caller = CreatePeerConnectionWithAudioVideo();
510 auto callee = CreatePeerConnectionWithAudioVideo();
511
512 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
513
514 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
515 auto* audio_content = cricket::GetFirstAudioContent(
516 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700517 std::unique_ptr<IceCandidateInterface> jsep_candidate =
518 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700519
520 caller->pc()->Close();
521
Steve Anton27ab0e52018-07-23 15:11:53 -0700522 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700523}
524
Steve Anton46d926a2018-01-23 10:23:06 -0800525TEST_P(PeerConnectionIceTest, DuplicateIceCandidateIgnoredWhenAdded) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700526 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
527
528 auto caller = CreatePeerConnectionWithAudioVideo();
529 auto callee = CreatePeerConnectionWithAudioVideo();
530
531 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
532 ASSERT_TRUE(
533 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
534
535 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
536 caller->AddIceCandidate(&candidate);
537 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
538 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
539}
540
Tomas Gunnarsson27bc6e22021-02-12 13:16:26 +0100541// TODO(tommi): Re-enable after updating RTCPeerConnection-blockedPorts.html in
542// Chromium (the test needs setRemoteDescription to succeed for an invalid
543// candidate).
544TEST_P(PeerConnectionIceTest, DISABLED_ErrorOnInvalidRemoteIceCandidateAdded) {
Tomas Gunnarsson8cb97062021-02-08 18:57:04 +0100545 auto caller = CreatePeerConnectionWithAudioVideo();
546 auto callee = CreatePeerConnectionWithAudioVideo();
547 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
548 // Add a candidate to the remote description with a candidate that has an
549 // invalid address (port number == 2).
550 auto answer = callee->CreateAnswerAndSetAsLocal();
551 cricket::Candidate bad_candidate =
552 CreateLocalUdpCandidate(SocketAddress("2.2.2.2", 2));
553 RTC_LOG(LS_INFO) << "Bad candidate: " << bad_candidate.ToString();
554 AddCandidateToFirstTransport(&bad_candidate, answer.get());
555 // Now the call to SetRemoteDescription should fail.
556 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
557}
558
Steve Anton46d926a2018-01-23 10:23:06 -0800559TEST_P(PeerConnectionIceTest,
Steve Antonc79268f2018-04-24 09:54:10 -0700560 CannotRemoveIceCandidatesWhenPeerConnectionClosed) {
561 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
562
563 auto caller = CreatePeerConnectionWithAudioVideo();
564 auto callee = CreatePeerConnectionWithAudioVideo();
565
566 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
567
568 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
569 auto* audio_content = cricket::GetFirstAudioContent(
570 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700571 std::unique_ptr<IceCandidateInterface> ice_candidate =
572 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700573
Steve Anton27ab0e52018-07-23 15:11:53 -0700574 ASSERT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700575
576 caller->pc()->Close();
577
578 EXPECT_FALSE(caller->pc()->RemoveIceCandidates({candidate}));
579}
580
581TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700582 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
583 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
584
585 auto caller = CreatePeerConnectionWithAudioVideo();
586 auto callee = CreatePeerConnectionWithAudioVideo();
587
588 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
589 ASSERT_TRUE(
590 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
591
Artem Titovcfea2182021-08-10 01:22:31 +0200592 // `candidate.transport_name()` is empty.
Steve Antonf1c6db12017-10-13 11:13:35 -0700593 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton46d926a2018-01-23 10:23:06 -0800594 auto* audio_content = cricket::GetFirstAudioContent(
595 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700596 std::unique_ptr<IceCandidateInterface> ice_candidate =
597 CreateIceCandidate(audio_content->name, 0, candidate);
598 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700599 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
600}
601
Steve Anton46d926a2018-01-23 10:23:06 -0800602TEST_P(PeerConnectionIceTest, RemoveCandidateRemovesFromRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700603 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
604
605 auto caller = CreatePeerConnectionWithAudioVideo();
606 auto callee = CreatePeerConnectionWithAudioVideo();
607
608 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
609 ASSERT_TRUE(
610 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
611
612 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
613 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
614 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
615 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
616}
617
618// Test that if a candidate is added via AddIceCandidate and via an updated
619// remote description, then both candidates appear in the stored remote
620// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800621TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700622 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
623 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
624 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
625
626 auto caller = CreatePeerConnectionWithAudioVideo();
627 auto callee = CreatePeerConnectionWithAudioVideo();
628
629 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
630 ASSERT_TRUE(
631 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
632
Artem Titov880fa812021-07-30 22:30:23 +0200633 // Add one candidate via `AddIceCandidate`.
Steve Antonf1c6db12017-10-13 11:13:35 -0700634 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
635 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
636
637 // Add the second candidate via a reoffer.
638 auto offer = caller->CreateOffer();
639 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
640 AddCandidateToFirstTransport(&candidate2, offer.get());
641
642 // Expect both candidates to appear in the callee's remote description.
643 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
644 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
645}
646
647// The follow test verifies that SetLocal/RemoteDescription fails when an offer
648// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
649// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
650// pwd must be 22-256 characters and ufrag must be 4-256 characters.
Steve Anton46d926a2018-01-23 10:23:06 -0800651TEST_P(PeerConnectionIceTest, VerifyUfragPwdLength) {
Yves Gerey665174f2018-06-19 15:03:05 +0200652 auto set_local_description_with_ufrag_pwd_length = [this](int ufrag_len,
653 int pwd_len) {
654 auto pc = CreatePeerConnectionWithAudioVideo();
655 auto offer = pc->CreateOffer();
656 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
657 std::string(pwd_len, 'x'));
658 return pc->SetLocalDescription(std::move(offer));
659 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700660
Yves Gerey665174f2018-06-19 15:03:05 +0200661 auto set_remote_description_with_ufrag_pwd_length = [this](int ufrag_len,
662 int pwd_len) {
663 auto pc = CreatePeerConnectionWithAudioVideo();
664 auto offer = pc->CreateOffer();
665 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
666 std::string(pwd_len, 'x'));
667 return pc->SetRemoteDescription(std::move(offer));
668 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700669
670 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
671 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
672 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
673 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
674 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
675 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
676 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
677 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
678 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
679 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
680 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
681 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
682}
683
684::testing::AssertionResult AssertIpInCandidates(
685 const char* address_expr,
686 const char* candidates_expr,
687 const SocketAddress& address,
688 const std::vector<IceCandidateInterface*> candidates) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200689 rtc::StringBuilder candidate_hosts;
Steve Antonf1c6db12017-10-13 11:13:35 -0700690 for (const auto* candidate : candidates) {
691 const auto& candidate_ip = candidate->candidate().address().ipaddr();
692 if (candidate_ip == address.ipaddr()) {
693 return ::testing::AssertionSuccess();
694 }
Jonas Olssonabbe8412018-04-03 13:40:05 +0200695 candidate_hosts << "\n" << candidate_ip.ToString();
Steve Antonf1c6db12017-10-13 11:13:35 -0700696 }
697 return ::testing::AssertionFailure()
698 << address_expr << " (host " << address.HostAsURIString()
699 << ") not in " << candidates_expr
700 << " which have the following address hosts:" << candidate_hosts.str();
701}
702
Steve Anton46d926a2018-01-23 10:23:06 -0800703TEST_P(PeerConnectionIceTest, CandidatesGeneratedForEachLocalInterface) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700704 const SocketAddress kLocalAddress1("1.1.1.1", 0);
705 const SocketAddress kLocalAddress2("2.2.2.2", 0);
706
707 auto caller = CreatePeerConnectionWithAudioVideo();
708 caller->network()->AddInterface(kLocalAddress1);
709 caller->network()->AddInterface(kLocalAddress2);
710
711 caller->CreateOfferAndSetAsLocal();
712 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
713
714 auto candidates = caller->observer()->GetCandidatesByMline(0);
715 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
716 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
717}
718
Steve Anton46d926a2018-01-23 10:23:06 -0800719TEST_P(PeerConnectionIceTest, TrickledSingleCandidateAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700720 const SocketAddress kCallerAddress("1.1.1.1", 1111);
721
722 auto caller = CreatePeerConnectionWithAudioVideo();
723 auto callee = CreatePeerConnectionWithAudioVideo();
724
725 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
726
727 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
728 callee->AddIceCandidate(&candidate);
729 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
730 ASSERT_EQ(1u, candidates.size());
731 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
732 candidates[0]->candidate());
733}
734
Steve Anton46d926a2018-01-23 10:23:06 -0800735TEST_P(PeerConnectionIceTest, TwoTrickledCandidatesAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700736 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
737 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
738
739 auto caller = CreatePeerConnectionWithAudioVideo();
740 auto callee = CreatePeerConnectionWithAudioVideo();
741
742 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
743 ASSERT_TRUE(
744 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
745
746 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
747 caller->AddIceCandidate(&candidate1);
748
749 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
750 caller->AddIceCandidate(&candidate2);
751
752 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
753 ASSERT_EQ(2u, candidates.size());
754 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
755 candidates[0]->candidate());
756 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
757 candidates[1]->candidate());
758}
759
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100760TEST_P(PeerConnectionIceTest, AsyncAddIceCandidateIsAddedToRemoteDescription) {
761 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
762
763 auto caller = CreatePeerConnectionWithAudioVideo();
764 auto callee = CreatePeerConnectionWithAudioVideo();
765
766 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
767
768 auto jsep_candidate =
769 callee->CreateJsepCandidateForFirstTransport(&candidate);
770 bool operation_completed = false;
771 callee->pc()->AddIceCandidate(std::move(jsep_candidate),
772 [&operation_completed](RTCError result) {
773 EXPECT_TRUE(result.ok());
774 operation_completed = true;
775 });
776 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
777
778 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
779 ASSERT_EQ(1u, candidates.size());
780 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
781 candidates[0]->candidate());
782}
783
784TEST_P(PeerConnectionIceTest,
785 AsyncAddIceCandidateCompletesImmediatelyIfNoPendingOperation) {
786 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
787
788 auto caller = CreatePeerConnectionWithAudioVideo();
789 auto callee = CreatePeerConnectionWithAudioVideo();
790
791 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
792
793 auto jsep_candidate =
794 callee->CreateJsepCandidateForFirstTransport(&candidate);
795 bool operation_completed = false;
796 callee->pc()->AddIceCandidate(
797 std::move(jsep_candidate),
798 [&operation_completed](RTCError result) { operation_completed = true; });
799 EXPECT_TRUE(operation_completed);
800}
801
802TEST_P(PeerConnectionIceTest,
803 AsyncAddIceCandidateCompletesWhenPendingOperationCompletes) {
804 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
805
806 auto caller = CreatePeerConnectionWithAudioVideo();
807 auto callee = CreatePeerConnectionWithAudioVideo();
808
809 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
810
811 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200812 auto answer_observer =
813 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Niels Möllerafb246b2022-04-20 14:26:50 +0200814 callee->pc()->CreateAnswer(answer_observer.get(), RTCOfferAnswerOptions());
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100815
816 auto jsep_candidate =
817 callee->CreateJsepCandidateForFirstTransport(&candidate);
818 bool operation_completed = false;
819 callee->pc()->AddIceCandidate(
820 std::move(jsep_candidate),
821 [&operation_completed](RTCError result) { operation_completed = true; });
822 // The operation will not be able to complete until we EXPECT_TRUE_WAIT()
823 // allowing CreateAnswer() to complete.
824 EXPECT_FALSE(operation_completed);
825 EXPECT_TRUE_WAIT(answer_observer->called(), kWaitTimeout);
826 // As soon as it does, AddIceCandidate() will execute without delay, so it
827 // must also have completed.
828 EXPECT_TRUE(operation_completed);
829}
830
831TEST_P(PeerConnectionIceTest,
832 AsyncAddIceCandidateFailsBeforeSetRemoteDescription) {
833 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
834
835 auto caller = CreatePeerConnectionWithAudioVideo();
836 std::unique_ptr<IceCandidateInterface> jsep_candidate =
837 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
838
839 bool operation_completed = false;
840 caller->pc()->AddIceCandidate(
841 std::move(jsep_candidate), [&operation_completed](RTCError result) {
842 EXPECT_FALSE(result.ok());
843 EXPECT_EQ(result.message(),
Henrik Boström347488e2022-01-21 15:18:08 +0100844 std::string("The remote description was null"));
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100845 operation_completed = true;
846 });
847 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
848}
849
850TEST_P(PeerConnectionIceTest,
851 AsyncAddIceCandidateFailsIfPeerConnectionDestroyed) {
852 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
853
854 auto caller = CreatePeerConnectionWithAudioVideo();
855 auto callee = CreatePeerConnectionWithAudioVideo();
856
857 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
858
859 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200860 auto answer_observer =
861 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Niels Möllerafb246b2022-04-20 14:26:50 +0200862 callee->pc()->CreateAnswer(answer_observer.get(), RTCOfferAnswerOptions());
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100863
864 auto jsep_candidate =
865 callee->CreateJsepCandidateForFirstTransport(&candidate);
866 bool operation_completed = false;
867 callee->pc()->AddIceCandidate(
868 std::move(jsep_candidate), [&operation_completed](RTCError result) {
869 EXPECT_FALSE(result.ok());
870 EXPECT_EQ(
871 result.message(),
872 std::string(
873 "AddIceCandidate failed because the session was shut down"));
874 operation_completed = true;
875 });
876 // The operation will not be able to run until EXPECT_TRUE_WAIT(), giving us
877 // time to remove all references to the PeerConnection.
878 EXPECT_FALSE(operation_completed);
879 // This should delete the callee PC.
880 callee = nullptr;
881 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
882}
883
Steve Anton46d926a2018-01-23 10:23:06 -0800884TEST_P(PeerConnectionIceTest, LocalDescriptionUpdatedWhenContinualGathering) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700885 const SocketAddress kLocalAddress("1.1.1.1", 0);
886
887 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100888 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700889 config.continual_gathering_policy =
890 PeerConnectionInterface::GATHER_CONTINUALLY;
891 auto caller = CreatePeerConnectionWithAudioVideo(config);
892 caller->network()->AddInterface(kLocalAddress);
893
894 // Start ICE candidate gathering by setting the local offer.
895 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
896
897 // Since we're using continual gathering, we won't get "gathering done".
898 EXPECT_TRUE_WAIT(
899 caller->pc()->local_description()->candidates(0)->count() > 0,
900 kIceCandidatesTimeout);
901}
902
903// Test that when continual gathering is enabled, and a network interface goes
904// down, the candidate is signaled as removed and removed from the local
905// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800906TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700907 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
908 const SocketAddress kLocalAddress("1.1.1.1", 0);
909
910 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100911 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700912 config.continual_gathering_policy =
913 PeerConnectionInterface::GATHER_CONTINUALLY;
914 auto caller = CreatePeerConnectionWithAudioVideo(config);
915 caller->network()->AddInterface(kLocalAddress);
916
917 // Start ICE candidate gathering by setting the local offer.
918 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
919
920 EXPECT_TRUE_WAIT(
921 caller->pc()->local_description()->candidates(0)->count() > 0,
922 kIceCandidatesTimeout);
923
924 // Remove the only network interface, causing the PeerConnection to signal
925 // the removal of all candidates derived from this interface.
926 caller->network()->RemoveInterface(kLocalAddress);
927
928 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
929 kIceCandidatesTimeout);
930 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
931}
932
Steve Anton46d926a2018-01-23 10:23:06 -0800933TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700934 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
935 const SocketAddress kLocalAddress("1.1.1.1", 0);
936
937 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100938 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700939 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
940 auto caller = CreatePeerConnectionWithAudioVideo(config);
941 caller->network()->AddInterface(kLocalAddress);
942
943 // Start ICE candidate gathering by setting the local offer.
944 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
945
946 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
947
948 caller->network()->RemoveInterface(kLocalAddress);
949
950 // Verify that the local candidates are not removed;
951 rtc::Thread::Current()->ProcessMessages(1000);
952 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
953}
954
955// The following group tests that when an offer includes a new ufrag or pwd
956// (indicating an ICE restart) the old candidates are removed and new candidates
957// added to the remote description.
958
Steve Anton46d926a2018-01-23 10:23:06 -0800959TEST_P(PeerConnectionIceTest, IceRestartOfferClearsExistingCandidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700960 const SocketAddress kCallerAddress("1.1.1.1", 1111);
961
962 auto caller = CreatePeerConnectionWithAudioVideo();
963 auto callee = CreatePeerConnectionWithAudioVideo();
964
Amit Hilbuchae3df542019-01-07 12:13:08 -0800965 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700966 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
967 AddCandidateToFirstTransport(&candidate, offer.get());
968
969 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
970
971 RTCOfferAnswerOptions options;
972 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800973 ASSERT_TRUE(
974 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700975
976 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
977}
Steve Anton46d926a2018-01-23 10:23:06 -0800978TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700979 IceRestartOfferCandidateReplacesExistingCandidate) {
980 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
981 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
982
983 auto caller = CreatePeerConnectionWithAudioVideo();
984 auto callee = CreatePeerConnectionWithAudioVideo();
985
Amit Hilbuchae3df542019-01-07 12:13:08 -0800986 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700987 cricket::Candidate old_candidate =
988 CreateLocalUdpCandidate(kFirstCallerAddress);
989 AddCandidateToFirstTransport(&old_candidate, offer.get());
990
991 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
992
993 RTCOfferAnswerOptions options;
994 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800995 auto restart_offer = caller->CreateOfferAndSetAsLocal(options);
Steve Antonf1c6db12017-10-13 11:13:35 -0700996 cricket::Candidate new_candidate =
997 CreateLocalUdpCandidate(kRestartedCallerAddress);
998 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
999
1000 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
1001
1002 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
1003 ASSERT_EQ(1u, remote_candidates.size());
1004 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
1005 remote_candidates[0]->candidate());
1006}
1007
1008// Test that if there is not an ICE restart (i.e., nothing changes), then the
1009// answer to a later offer should have the same ufrag/pwd as the first answer.
Steve Anton46d926a2018-01-23 10:23:06 -08001010TEST_P(PeerConnectionIceTest, LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
Steve Antonf1c6db12017-10-13 11:13:35 -07001011 auto caller = CreatePeerConnectionWithAudioVideo();
1012 auto callee = CreatePeerConnectionWithAudioVideo();
1013
1014 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1015 ASSERT_TRUE(
1016 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1017
1018 // Re-offer.
1019 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1020
1021 auto answer = callee->CreateAnswer();
1022 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
1023 auto* local_transport_desc =
1024 GetFirstTransportDescription(callee->pc()->local_description());
1025
1026 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
1027 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
1028}
1029
Henrik Boström79b69802019-07-18 11:16:56 +02001030TEST_P(PeerConnectionIceTest, RestartIceGeneratesNewCredentials) {
1031 auto caller = CreatePeerConnectionWithAudioVideo();
1032 auto callee = CreatePeerConnectionWithAudioVideo();
1033
1034 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1035 auto initial_ice_credentials =
1036 GetIceCredentials(caller->pc()->local_description());
1037 caller->pc()->RestartIce();
1038 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1039 auto restarted_ice_credentials =
1040 GetIceCredentials(caller->pc()->local_description());
1041 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1042}
1043
1044TEST_P(PeerConnectionIceTest,
1045 RestartIceWhileLocalOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1046 auto caller = CreatePeerConnectionWithAudioVideo();
1047 auto callee = CreatePeerConnectionWithAudioVideo();
1048
1049 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1050 auto initial_ice_credentials =
1051 GetIceCredentials(caller->pc()->local_description());
Artem Titov880fa812021-07-30 22:30:23 +02001052 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001053 // offerer.
1054 caller->pc()->RestartIce();
1055 ASSERT_TRUE(
1056 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1057 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1058 auto restarted_ice_credentials =
1059 GetIceCredentials(caller->pc()->local_description());
1060 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1061}
1062
1063TEST_P(PeerConnectionIceTest,
1064 RestartIceWhileRemoteOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1065 auto caller = CreatePeerConnectionWithAudioVideo();
1066 auto callee = CreatePeerConnectionWithAudioVideo();
1067
1068 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1069 auto initial_ice_credentials =
1070 GetIceCredentials(caller->pc()->local_description());
1071 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001072 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001073 // answerer.
1074 caller->pc()->RestartIce();
1075 ASSERT_TRUE(
1076 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
1077 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1078 auto restarted_ice_credentials =
1079 GetIceCredentials(caller->pc()->local_description());
1080 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1081}
1082
1083TEST_P(PeerConnectionIceTest, RestartIceTriggeredByRemoteSide) {
1084 auto caller = CreatePeerConnectionWithAudioVideo();
1085 auto callee = CreatePeerConnectionWithAudioVideo();
1086
1087 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1088 auto initial_ice_credentials =
1089 GetIceCredentials(caller->pc()->local_description());
1090
Artem Titov880fa812021-07-30 22:30:23 +02001091 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001092 // restart ICE locally as well.
1093 callee->pc()->RestartIce();
1094 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1095
1096 auto restarted_ice_credentials =
1097 GetIceCredentials(caller->pc()->local_description());
1098 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1099}
1100
1101TEST_P(PeerConnectionIceTest, RestartIceCausesNegotiationNeeded) {
1102 auto caller = CreatePeerConnectionWithAudioVideo();
1103 auto callee = CreatePeerConnectionWithAudioVideo();
1104
1105 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001106 caller->observer()->clear_legacy_renegotiation_needed();
1107 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001108 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001109 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1110 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001111}
1112
1113// In Unified Plan, "onnegotiationneeded" is spec-compliant, including not
1114// firing multipe times in a row, or firing when returning to the stable
1115// signaling state if negotiation is still needed. In Plan B it fires any time
1116// something changes. As such, some tests are SdpSemantics-specific.
1117class PeerConnectionIceTestUnifiedPlan : public PeerConnectionIceBaseTest {
1118 protected:
1119 PeerConnectionIceTestUnifiedPlan()
1120 : PeerConnectionIceBaseTest(SdpSemantics::kUnifiedPlan) {}
1121};
1122
1123TEST_F(PeerConnectionIceTestUnifiedPlan,
1124 RestartIceWhileLocalOfferIsPendingCausesNegotiationNeededWhenStable) {
1125 auto caller = CreatePeerConnectionWithAudioVideo();
1126 auto callee = CreatePeerConnectionWithAudioVideo();
1127
1128 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001129 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001130 // offerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001131 caller->observer()->clear_legacy_renegotiation_needed();
1132 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001133 caller->pc()->RestartIce();
1134 // In Unified Plan, the event should not fire until we are back in the stable
1135 // signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001136 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1137 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001138 ASSERT_TRUE(
1139 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001140 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1141 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001142}
1143
1144TEST_F(PeerConnectionIceTestUnifiedPlan,
1145 RestartIceWhileRemoteOfferIsPendingCausesNegotiationNeededWhenStable) {
1146 auto caller = CreatePeerConnectionWithAudioVideo();
1147 auto callee = CreatePeerConnectionWithAudioVideo();
1148
1149 // Establish initial credentials as the caller.
1150 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1151 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001152 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001153 // answerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001154 caller->observer()->clear_legacy_renegotiation_needed();
1155 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001156 caller->pc()->RestartIce();
1157 // In Unified Plan, the event should not fire until we are back in the stable
1158 // signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001159 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1160 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001161 ASSERT_TRUE(
1162 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001163 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1164 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001165}
1166
1167TEST_F(PeerConnectionIceTestUnifiedPlan,
1168 RestartIceTriggeredByRemoteSideCauseNegotiationNotNeeded) {
1169 auto caller = CreatePeerConnectionWithAudioVideo();
1170 auto callee = CreatePeerConnectionWithAudioVideo();
1171
1172 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1173 // Local restart.
1174 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001175 caller->observer()->clear_legacy_renegotiation_needed();
1176 caller->observer()->clear_latest_negotiation_needed_event();
Artem Titov880fa812021-07-30 22:30:23 +02001177 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001178 // restart ICE locally as well.
1179 callee->pc()->RestartIce();
1180 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1181 // Having restarted ICE by the remote offer, we do not need to renegotiate ICE
1182 // credentials when back in the stable signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001183 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1184 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001185}
1186
1187TEST_F(PeerConnectionIceTestUnifiedPlan,
1188 RestartIceTwiceDoesNotFireNegotiationNeededTwice) {
1189 auto caller = CreatePeerConnectionWithAudioVideo();
1190 auto callee = CreatePeerConnectionWithAudioVideo();
1191
1192 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1193 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001194 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1195 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1196 caller->observer()->clear_legacy_renegotiation_needed();
1197 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001198 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001199 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1200 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001201}
1202
1203// In Plan B, "onnegotiationneeded" is not spec-compliant, firing based on if
1204// something changed rather than if negotiation is needed. In Unified Plan it
1205// fires according to spec. As such, some tests are SdpSemantics-specific.
1206class PeerConnectionIceTestPlanB : public PeerConnectionIceBaseTest {
1207 protected:
1208 PeerConnectionIceTestPlanB()
Florent Castelli15a38de2022-04-06 00:38:21 +02001209 : PeerConnectionIceBaseTest(SdpSemantics::kPlanB_DEPRECATED) {}
Henrik Boström79b69802019-07-18 11:16:56 +02001210};
1211
1212TEST_F(PeerConnectionIceTestPlanB,
1213 RestartIceWhileOfferIsPendingCausesNegotiationNeededImmediately) {
1214 auto caller = CreatePeerConnectionWithAudioVideo();
1215 auto callee = CreatePeerConnectionWithAudioVideo();
1216
1217 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001218 caller->observer()->clear_legacy_renegotiation_needed();
1219 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001220 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001221 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1222 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1223 caller->observer()->clear_legacy_renegotiation_needed();
1224 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001225 ASSERT_TRUE(
1226 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1227 // In Plan B, the event fired early so we don't expect it to fire now. This is
1228 // not spec-compliant but follows the pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001229 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1230 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001231}
1232
1233TEST_F(PeerConnectionIceTestPlanB,
1234 RestartIceTwiceDoesFireNegotiationNeededTwice) {
1235 auto caller = CreatePeerConnectionWithAudioVideo();
1236 auto callee = CreatePeerConnectionWithAudioVideo();
1237
1238 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001239 caller->observer()->clear_legacy_renegotiation_needed();
1240 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001241 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001242 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1243 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1244 caller->observer()->clear_legacy_renegotiation_needed();
1245 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001246 caller->pc()->RestartIce();
1247 // In Plan B, the event fires every time something changed, even if we have
1248 // already fired the event. This is not spec-compliant but follows the same
1249 // pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001250 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1251 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001252}
1253
Steve Antonf1c6db12017-10-13 11:13:35 -07001254// The following parameterized test verifies that if an offer is sent with a
1255// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
1256// other side has initiated an ICE restart and generate a new ufrag and pwd.
1257// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
1258// a=ice-pwd attributes compared to the previous SDP from the peer, it
1259// indicates that ICE is restarting for this media stream."
1260
Steve Anton46d926a2018-01-23 10:23:06 -08001261class PeerConnectionIceUfragPwdAnswerTest
1262 : public PeerConnectionIceBaseTest,
1263 public ::testing::WithParamInterface<
1264 std::tuple<SdpSemantics, std::tuple<bool, bool>>> {
Steve Antonf1c6db12017-10-13 11:13:35 -07001265 protected:
Steve Anton46d926a2018-01-23 10:23:06 -08001266 PeerConnectionIceUfragPwdAnswerTest()
1267 : PeerConnectionIceBaseTest(std::get<0>(GetParam())) {
1268 auto param = std::get<1>(GetParam());
1269 offer_new_ufrag_ = std::get<0>(param);
1270 offer_new_pwd_ = std::get<1>(param);
Steve Antonf1c6db12017-10-13 11:13:35 -07001271 }
1272
1273 bool offer_new_ufrag_;
1274 bool offer_new_pwd_;
1275};
1276
Steve Anton46d926a2018-01-23 10:23:06 -08001277TEST_P(PeerConnectionIceUfragPwdAnswerTest, TestIncludedInAnswer) {
Steve Antonf1c6db12017-10-13 11:13:35 -07001278 auto caller = CreatePeerConnectionWithAudioVideo();
1279 auto callee = CreatePeerConnectionWithAudioVideo();
1280
1281 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1282 ASSERT_TRUE(
1283 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1284
1285 auto offer = caller->CreateOffer();
1286 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
1287 if (offer_new_ufrag_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001288 offer_transport_desc->ice_ufrag += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001289 }
1290 if (offer_new_pwd_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001291 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001292 }
1293
1294 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1295
1296 auto answer = callee->CreateAnswer();
1297 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
1298 auto* local_transport_desc =
1299 GetFirstTransportDescription(callee->pc()->local_description());
1300
1301 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
1302 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
1303}
1304
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001305INSTANTIATE_TEST_SUITE_P(
Steve Anton46d926a2018-01-23 10:23:06 -08001306 PeerConnectionIceTest,
1307 PeerConnectionIceUfragPwdAnswerTest,
Florent Castelli15a38de2022-04-06 00:38:21 +02001308 Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Anton46d926a2018-01-23 10:23:06 -08001309 Values(std::make_pair(true, true), // Both changed.
1310 std::make_pair(true, false), // Only ufrag changed.
1311 std::make_pair(false, true)))); // Only pwd changed.
Steve Antonf1c6db12017-10-13 11:13:35 -07001312
1313// Test that if an ICE restart is offered on one media section, then the answer
1314// will only change ICE ufrag/pwd for that section and keep the other sections
1315// the same.
1316// Note that this only works if we have disabled BUNDLE, otherwise all media
1317// sections will share the same transport.
Steve Anton46d926a2018-01-23 10:23:06 -08001318TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -07001319 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
1320 auto caller = CreatePeerConnectionWithAudioVideo();
1321 auto callee = CreatePeerConnectionWithAudioVideo();
1322
1323 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1324 ASSERT_TRUE(
1325 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1326
1327 RTCOfferAnswerOptions disable_bundle_options;
1328 disable_bundle_options.use_rtp_mux = false;
1329
1330 auto offer = caller->CreateOffer(disable_bundle_options);
1331
1332 // Signal ICE restart on the first media section.
1333 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
Steve Anton71ff0732020-01-24 16:28:15 -08001334 offer_transport_desc->ice_ufrag += "+new";
1335 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001336
1337 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1338
1339 auto answer = callee->CreateAnswer(disable_bundle_options);
1340 const auto& answer_transports = answer->description()->transport_infos();
1341 const auto& local_transports =
1342 callee->pc()->local_description()->description()->transport_infos();
1343
1344 EXPECT_NE(answer_transports[0].description.ice_ufrag,
1345 local_transports[0].description.ice_ufrag);
1346 EXPECT_NE(answer_transports[0].description.ice_pwd,
1347 local_transports[0].description.ice_pwd);
1348 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
1349 local_transports[1].description.ice_ufrag);
1350 EXPECT_EQ(answer_transports[1].description.ice_pwd,
1351 local_transports[1].description.ice_pwd);
1352}
1353
Qingsi Wange1692722017-11-29 13:27:20 -08001354// Test that when the initial offerer (caller) uses the lite implementation of
1355// ICE and the callee uses the full implementation, the caller takes the
1356// CONTROLLED role and the callee takes the CONTROLLING role. This is specified
1357// in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001358TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001359 OfferFromLiteIceControlledAndAnswerFromFullIceControlling) {
1360 auto caller = CreatePeerConnectionWithAudioVideo();
1361 auto callee = CreatePeerConnectionWithAudioVideo();
1362
1363 auto offer = caller->CreateOffer();
1364 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1365 ASSERT_TRUE(
1366 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1367 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1368
1369 auto answer = callee->CreateAnswer();
1370 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_FULL);
1371 ASSERT_TRUE(
1372 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1373 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1374
1375 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(caller));
1376 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(callee));
1377}
1378
1379// Test that when the caller and the callee both use the lite implementation of
1380// ICE, the initial offerer (caller) takes the CONTROLLING role and the callee
1381// takes the CONTROLLED role. This is specified in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001382TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001383 OfferFromLiteIceControllingAndAnswerFromLiteIceControlled) {
1384 auto caller = CreatePeerConnectionWithAudioVideo();
1385 auto callee = CreatePeerConnectionWithAudioVideo();
1386
1387 auto offer = caller->CreateOffer();
1388 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1389 ASSERT_TRUE(
1390 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1391 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1392
1393 auto answer = callee->CreateAnswer();
1394 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_LITE);
1395 ASSERT_TRUE(
1396 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1397 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1398
1399 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(caller));
1400 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(callee));
1401}
1402
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001403INSTANTIATE_TEST_SUITE_P(PeerConnectionIceTest,
1404 PeerConnectionIceTest,
Florent Castelli15a38de2022-04-06 00:38:21 +02001405 Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001406 SdpSemantics::kUnifiedPlan));
Steve Anton46d926a2018-01-23 10:23:06 -08001407
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001408class PeerConnectionIceConfigTest : public ::testing::Test {
Byoungchan Leed58f5262022-06-27 18:05:22 +09001409 public:
1410 PeerConnectionIceConfigTest()
1411 : socket_server_(rtc::CreateDefaultSocketServer()),
1412 main_thread_(socket_server_.get()) {}
1413
Qingsi Wang4ff54432018-03-01 18:25:20 -08001414 protected:
1415 void SetUp() override {
1416 pc_factory_ = CreatePeerConnectionFactory(
1417 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
1418 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
Anders Carlsson67537952018-05-03 11:28:29 +02001419 CreateBuiltinAudioDecoderFactory(), CreateBuiltinVideoEncoderFactory(),
1420 CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
1421 nullptr /* audio_processing */);
Qingsi Wang4ff54432018-03-01 18:25:20 -08001422 }
1423 void CreatePeerConnection(const RTCConfiguration& config) {
Byoungchan Leed58f5262022-06-27 18:05:22 +09001424 packet_socket_factory_.reset(
1425 new rtc::BasicPacketSocketFactory(socket_server_.get()));
Qingsi Wang4ff54432018-03-01 18:25:20 -08001426 std::unique_ptr<cricket::FakePortAllocator> port_allocator(
Byoungchan Leed58f5262022-06-27 18:05:22 +09001427 new cricket::FakePortAllocator(rtc::Thread::Current(),
1428 packet_socket_factory_.get()));
Qingsi Wang4ff54432018-03-01 18:25:20 -08001429 port_allocator_ = port_allocator.get();
Philipp Hanckefd91d022022-10-27 20:08:23 +02001430 port_allocator_->SetIceTiebreaker(kTiebreakerDefault);
Florent Castelli72424402022-04-06 03:45:10 +02001431 PeerConnectionDependencies pc_dependencies(&observer_);
1432 pc_dependencies.allocator = std::move(port_allocator);
1433 auto result = pc_factory_->CreatePeerConnectionOrError(
1434 config, std::move(pc_dependencies));
1435 EXPECT_TRUE(result.ok());
1436 pc_ = result.MoveValue();
Qingsi Wang4ff54432018-03-01 18:25:20 -08001437 }
1438
Byoungchan Leed58f5262022-06-27 18:05:22 +09001439 std::unique_ptr<rtc::SocketServer> socket_server_;
1440 rtc::AutoSocketServerThread main_thread_;
Qingsi Wang4ff54432018-03-01 18:25:20 -08001441 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_ = nullptr;
1442 rtc::scoped_refptr<PeerConnectionInterface> pc_ = nullptr;
Byoungchan Leed58f5262022-06-27 18:05:22 +09001443 std::unique_ptr<rtc::PacketSocketFactory> packet_socket_factory_;
Qingsi Wang4ff54432018-03-01 18:25:20 -08001444 cricket::FakePortAllocator* port_allocator_ = nullptr;
1445
1446 MockPeerConnectionObserver observer_;
1447};
1448
1449TEST_F(PeerConnectionIceConfigTest, SetStunCandidateKeepaliveInterval) {
1450 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001451 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Qingsi Wang4ff54432018-03-01 18:25:20 -08001452 config.stun_candidate_keepalive_interval = 123;
1453 config.ice_candidate_pool_size = 1;
1454 CreatePeerConnection(config);
1455 ASSERT_NE(port_allocator_, nullptr);
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001456 absl::optional<int> actual_stun_keepalive_interval =
Qingsi Wang4ff54432018-03-01 18:25:20 -08001457 port_allocator_->stun_candidate_keepalive_interval();
1458 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 123);
1459 config.stun_candidate_keepalive_interval = 321;
Niels Möller2579f0c2019-08-19 09:58:17 +02001460 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
Qingsi Wang4ff54432018-03-01 18:25:20 -08001461 actual_stun_keepalive_interval =
1462 port_allocator_->stun_candidate_keepalive_interval();
1463 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 321);
1464}
1465
Derek Bailey6c127a12021-04-15 12:42:41 -07001466TEST_F(PeerConnectionIceConfigTest, SetStableWritableConnectionInterval) {
1467 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001468 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001469 config.stable_writable_connection_ping_interval_ms = 3500;
1470 CreatePeerConnection(config);
1471 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1472 EXPECT_EQ(pc_->GetConfiguration().stable_writable_connection_ping_interval_ms,
1473 config.stable_writable_connection_ping_interval_ms);
1474}
1475
1476TEST_F(PeerConnectionIceConfigTest,
1477 SetStableWritableConnectionInterval_FailsValidation) {
1478 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001479 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001480 CreatePeerConnection(config);
1481 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1482 config.stable_writable_connection_ping_interval_ms = 5000;
1483 config.ice_check_interval_strong_connectivity = 7500;
1484 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1485}
1486
1487TEST_F(PeerConnectionIceConfigTest,
1488 SetStableWritableConnectionInterval_DefaultValue_FailsValidation) {
1489 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001490 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001491 CreatePeerConnection(config);
1492 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1493 config.ice_check_interval_strong_connectivity = 2500;
1494 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1495 config.ice_check_interval_strong_connectivity = 2501;
1496 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1497}
1498
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001499TEST_P(PeerConnectionIceTest, IceCredentialsCreateOffer) {
1500 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001501 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001502 config.ice_candidate_pool_size = 1;
1503 auto pc = CreatePeerConnectionWithAudioVideo(config);
1504 ASSERT_NE(pc->port_allocator_, nullptr);
1505 auto offer = pc->CreateOffer();
1506 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1507 ASSERT_EQ(1u, credentials.size());
1508
1509 auto* desc = offer->description();
1510 for (const auto& content : desc->contents()) {
1511 auto* transport_info = desc->GetTransportInfoByName(content.name);
1512 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1513 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1514 }
1515}
1516
1517TEST_P(PeerConnectionIceTest, IceCredentialsCreateAnswer) {
1518 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001519 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001520 config.ice_candidate_pool_size = 1;
1521 auto pc = CreatePeerConnectionWithAudioVideo(config);
1522 ASSERT_NE(pc->port_allocator_, nullptr);
1523 auto offer = pc->CreateOffer();
1524 ASSERT_TRUE(pc->SetRemoteDescription(std::move(offer)));
1525 auto answer = pc->CreateAnswer();
1526
1527 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1528 ASSERT_EQ(1u, credentials.size());
1529
1530 auto* desc = answer->description();
1531 for (const auto& content : desc->contents()) {
1532 auto* transport_info = desc->GetTransportInfoByName(content.name);
1533 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1534 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1535 }
1536}
1537
Steve Antonec47b572020-01-24 14:53:37 -08001538// Regression test for https://bugs.chromium.org/p/webrtc/issues/detail?id=4728
1539TEST_P(PeerConnectionIceTest, CloseDoesNotTransitionGatheringStateToComplete) {
1540 auto pc = CreatePeerConnectionWithAudioVideo();
1541 pc->pc()->Close();
1542 EXPECT_FALSE(pc->IsIceGatheringDone());
1543 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
1544 pc->pc()->ice_gathering_state());
1545}
1546
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001547TEST_P(PeerConnectionIceTest, PrefersMidOverMLineIndex) {
1548 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
1549
1550 auto caller = CreatePeerConnectionWithAudioVideo();
1551 auto callee = CreatePeerConnectionWithAudioVideo();
1552
1553 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1554 ASSERT_TRUE(
1555 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1556
Artem Titovcfea2182021-08-10 01:22:31 +02001557 // `candidate.transport_name()` is empty.
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001558 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
1559 auto* audio_content = cricket::GetFirstAudioContent(
1560 caller->pc()->local_description()->description());
1561 std::unique_ptr<IceCandidateInterface> ice_candidate =
1562 CreateIceCandidate(audio_content->name, 65535, candidate);
1563 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
1564 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
1565}
1566
Steve Antonf1c6db12017-10-13 11:13:35 -07001567} // namespace webrtc