1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h"
6
7 #include "third_party/blink/public/platform/platform.h"
8 #include "third_party/blink/public/web/web_local_frame.h"
9 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_gather_options.h"
10 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_parameters.h"
11 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_server.h"
12 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_peer_connection_ice_event_init.h"
13 #include "third_party/blink/renderer/core/dom/events/event.h"
14 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
15 #include "third_party/blink/renderer/core/frame/local_frame.h"
16 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
17 #include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_cross_thread_factory.h"
18 #include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h"
19 #include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h"
20 #include "third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h"
21 #include "third_party/blink/renderer/modules/peerconnection/rtc_error_util.h"
22 #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h"
23 #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h"
24 #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h"
25 #include "third_party/blink/renderer/platform/heap/heap.h"
26 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
27 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
28 #include "third_party/webrtc/api/ice_transport_factory.h"
29 #include "third_party/webrtc/api/ice_transport_interface.h"
30 #include "third_party/webrtc/api/jsep_ice_candidate.h"
31 #include "third_party/webrtc/api/peer_connection_interface.h"
32 #include "third_party/webrtc/p2p/base/port_allocator.h"
33 #include "third_party/webrtc/p2p/base/transport_description.h"
34 #include "third_party/webrtc/pc/ice_server_parsing.h"
35 #include "third_party/webrtc/pc/webrtc_sdp.h"
36
37 namespace blink {
38 namespace {
39
40 const char* kIceRoleControllingStr = "controlling";
41 const char* kIceRoleControlledStr = "controlled";
42
ConvertToCricketIceCandidate(const RTCIceCandidate & candidate)43 base::Optional<cricket::Candidate> ConvertToCricketIceCandidate(
44 const RTCIceCandidate& candidate) {
45 webrtc::JsepIceCandidate jsep_candidate("", 0);
46 webrtc::SdpParseError error;
47 if (!webrtc::SdpDeserializeCandidate(candidate.candidate().Utf8(),
48 &jsep_candidate, &error)) {
49 LOG(WARNING) << "Failed to deserialize candidate: " << error.description;
50 return base::nullopt;
51 }
52 return jsep_candidate.candidate();
53 }
54
ConvertToRtcIceCandidate(const cricket::Candidate & candidate)55 RTCIceCandidate* ConvertToRtcIceCandidate(const cricket::Candidate& candidate) {
56 return RTCIceCandidate::Create(MakeGarbageCollected<RTCIceCandidatePlatform>(
57 String::FromUTF8(webrtc::SdpSerializeCandidate(candidate)), "", 0));
58 }
59
60 class DtlsIceTransportAdapterCrossThreadFactory
61 : public IceTransportAdapterCrossThreadFactory {
62 public:
DtlsIceTransportAdapterCrossThreadFactory(rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport)63 explicit DtlsIceTransportAdapterCrossThreadFactory(
64 rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport)
65 : ice_transport_(ice_transport) {}
InitializeOnMainThread(LocalFrame & frame)66 void InitializeOnMainThread(LocalFrame& frame) override {
67 }
68
ConstructOnWorkerThread(IceTransportAdapter::Delegate * delegate)69 std::unique_ptr<IceTransportAdapter> ConstructOnWorkerThread(
70 IceTransportAdapter::Delegate* delegate) override {
71 DCHECK(ice_transport_);
72 return std::make_unique<IceTransportAdapterImpl>(delegate,
73 std::move(ice_transport_));
74 }
75
76 private:
77 rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport_;
78 };
79
80 class DefaultIceTransportAdapterCrossThreadFactory
81 : public IceTransportAdapterCrossThreadFactory {
82 public:
InitializeOnMainThread(LocalFrame & frame)83 void InitializeOnMainThread(LocalFrame& frame) override {
84 DCHECK(!port_allocator_);
85 DCHECK(!async_resolver_factory_);
86
87 auto* rtc_dependency_factory =
88 blink::PeerConnectionDependencyFactory::GetInstance();
89 port_allocator_ = rtc_dependency_factory->CreatePortAllocator(
90 frame.Client()->GetWebFrame());
91 async_resolver_factory_ =
92 rtc_dependency_factory->CreateAsyncResolverFactory();
93 }
94
ConstructOnWorkerThread(IceTransportAdapter::Delegate * delegate)95 std::unique_ptr<IceTransportAdapter> ConstructOnWorkerThread(
96 IceTransportAdapter::Delegate* delegate) override {
97 DCHECK(port_allocator_);
98 DCHECK(async_resolver_factory_);
99 return std::make_unique<IceTransportAdapterImpl>(
100 delegate, std::move(port_allocator_),
101 std::move(async_resolver_factory_));
102 }
103
104 private:
105 std::unique_ptr<cricket::PortAllocator> port_allocator_;
106 std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory_;
107 };
108
109 } // namespace
110
Create(ExecutionContext * context)111 RTCIceTransport* RTCIceTransport::Create(ExecutionContext* context) {
112 scoped_refptr<base::SingleThreadTaskRunner> proxy_thread =
113 context->GetTaskRunner(TaskType::kNetworking);
114
115 PeerConnectionDependencyFactory::GetInstance()->EnsureInitialized();
116 scoped_refptr<base::SingleThreadTaskRunner> host_thread =
117 PeerConnectionDependencyFactory::GetInstance()
118 ->GetWebRtcNetworkTaskRunner();
119 return MakeGarbageCollected<RTCIceTransport>(
120 context, std::move(proxy_thread), std::move(host_thread),
121 std::make_unique<DefaultIceTransportAdapterCrossThreadFactory>());
122 }
123
Create(ExecutionContext * context,rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport,RTCPeerConnection * peer_connection)124 RTCIceTransport* RTCIceTransport::Create(
125 ExecutionContext* context,
126 rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport,
127 RTCPeerConnection* peer_connection) {
128 scoped_refptr<base::SingleThreadTaskRunner> proxy_thread =
129 context->GetTaskRunner(TaskType::kNetworking);
130
131 PeerConnectionDependencyFactory::GetInstance()->EnsureInitialized();
132 scoped_refptr<base::SingleThreadTaskRunner> host_thread =
133 PeerConnectionDependencyFactory::GetInstance()
134 ->GetWebRtcNetworkTaskRunner();
135 return MakeGarbageCollected<RTCIceTransport>(
136 context, std::move(proxy_thread), std::move(host_thread),
137 std::make_unique<DtlsIceTransportAdapterCrossThreadFactory>(
138 std::move(ice_transport)),
139 peer_connection);
140 }
141
Create(ExecutionContext * context,scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,scoped_refptr<base::SingleThreadTaskRunner> host_thread,std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory)142 RTCIceTransport* RTCIceTransport::Create(
143 ExecutionContext* context,
144 scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
145 scoped_refptr<base::SingleThreadTaskRunner> host_thread,
146 std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory) {
147 return MakeGarbageCollected<RTCIceTransport>(context, std::move(proxy_thread),
148 std::move(host_thread),
149 std::move(adapter_factory));
150 }
151
RTCIceTransport(ExecutionContext * context,scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,scoped_refptr<base::SingleThreadTaskRunner> host_thread,std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory,RTCPeerConnection * peer_connection)152 RTCIceTransport::RTCIceTransport(
153 ExecutionContext* context,
154 scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
155 scoped_refptr<base::SingleThreadTaskRunner> host_thread,
156 std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory,
157 RTCPeerConnection* peer_connection)
158 : ExecutionContextLifecycleObserver(context),
159 peer_connection_(peer_connection) {
160 DCHECK(context);
161 DCHECK(proxy_thread);
162 DCHECK(host_thread);
163 DCHECK(adapter_factory);
164 DCHECK(proxy_thread->BelongsToCurrentThread());
165
166 LocalFrame* frame = To<LocalDOMWindow>(context)->GetFrame();
167 DCHECK(frame);
168 proxy_ = std::make_unique<IceTransportProxy>(*frame, std::move(proxy_thread),
169 std::move(host_thread), this,
170 std::move(adapter_factory));
171
172 GenerateLocalParameters();
173 }
174
RTCIceTransport(ExecutionContext * context,scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,scoped_refptr<base::SingleThreadTaskRunner> host_thread,std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory)175 RTCIceTransport::RTCIceTransport(
176 ExecutionContext* context,
177 scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
178 scoped_refptr<base::SingleThreadTaskRunner> host_thread,
179 std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory)
180 : RTCIceTransport(context,
181 std::move(proxy_thread),
182 std::move(host_thread),
183 std::move(adapter_factory),
184 nullptr) {}
185
~RTCIceTransport()186 RTCIceTransport::~RTCIceTransport() {
187 DCHECK(!proxy_);
188 }
189
IsFromPeerConnection() const190 bool RTCIceTransport::IsFromPeerConnection() const {
191 return peer_connection_;
192 }
193
role() const194 String RTCIceTransport::role() const {
195 switch (role_) {
196 case cricket::ICEROLE_CONTROLLING:
197 return kIceRoleControllingStr;
198 case cricket::ICEROLE_CONTROLLED:
199 return kIceRoleControlledStr;
200 case cricket::ICEROLE_UNKNOWN:
201 return String();
202 }
203 NOTREACHED();
204 return String();
205 }
206
state() const207 String RTCIceTransport::state() const {
208 switch (state_) {
209 case webrtc::IceTransportState::kNew:
210 return "new";
211 case webrtc::IceTransportState::kChecking:
212 return "checking";
213 case webrtc::IceTransportState::kConnected:
214 return "connected";
215 case webrtc::IceTransportState::kCompleted:
216 return "completed";
217 case webrtc::IceTransportState::kDisconnected:
218 return "disconnected";
219 case webrtc::IceTransportState::kFailed:
220 return "failed";
221 case webrtc::IceTransportState::kClosed:
222 return "closed";
223 }
224 NOTREACHED();
225 return g_empty_string;
226 }
227
gatheringState() const228 String RTCIceTransport::gatheringState() const {
229 switch (gathering_state_) {
230 case cricket::kIceGatheringNew:
231 return "new";
232 case cricket::kIceGatheringGathering:
233 return "gathering";
234 case cricket::kIceGatheringComplete:
235 return "complete";
236 default:
237 NOTREACHED();
238 return g_empty_string;
239 }
240 }
241
getLocalCandidates() const242 const HeapVector<Member<RTCIceCandidate>>& RTCIceTransport::getLocalCandidates()
243 const {
244 return local_candidates_;
245 }
246
247 const HeapVector<Member<RTCIceCandidate>>&
getRemoteCandidates() const248 RTCIceTransport::getRemoteCandidates() const {
249 return remote_candidates_;
250 }
251
getSelectedCandidatePair() const252 RTCIceCandidatePair* RTCIceTransport::getSelectedCandidatePair() const {
253 return selected_candidate_pair_;
254 }
255
getLocalParameters() const256 RTCIceParameters* RTCIceTransport::getLocalParameters() const {
257 return local_parameters_;
258 }
259
getRemoteParameters() const260 RTCIceParameters* RTCIceTransport::getRemoteParameters() const {
261 return remote_parameters_;
262 }
263
ConvertIceServer(const RTCIceServer * ice_server)264 static webrtc::PeerConnectionInterface::IceServer ConvertIceServer(
265 const RTCIceServer* ice_server) {
266 webrtc::PeerConnectionInterface::IceServer converted_ice_server;
267 // Prefer standardized 'urls' field over deprecated 'url' field.
268 Vector<String> url_strings;
269 if (ice_server->hasUrls()) {
270 if (ice_server->urls().IsString()) {
271 url_strings.push_back(ice_server->urls().GetAsString());
272 } else if (ice_server->urls().IsStringSequence()) {
273 url_strings = ice_server->urls().GetAsStringSequence();
274 }
275 } else if (ice_server->hasUrl()) {
276 url_strings.push_back(ice_server->url());
277 }
278 for (const String& url_string : url_strings) {
279 converted_ice_server.urls.push_back(url_string.Utf8());
280 }
281 if (ice_server->hasUsername()) {
282 converted_ice_server.username = ice_server->username().Utf8();
283 }
284 if (ice_server->hasCredential()) {
285 converted_ice_server.password = ice_server->credential().Utf8();
286 }
287 return converted_ice_server;
288 }
289
ConvertIceParameters(const RTCIceParameters * raw_ice_parameters)290 static webrtc::RTCErrorOr<cricket::IceParameters> ConvertIceParameters(
291 const RTCIceParameters* raw_ice_parameters) {
292 std::string raw_ufrag = raw_ice_parameters->usernameFragment().Utf8();
293 std::string raw_pwd = raw_ice_parameters->password().Utf8();
294 return cricket::IceParameters::Parse(raw_ufrag, raw_pwd);
295 }
296
ConvertIceServers(const HeapVector<Member<RTCIceServer>> & ice_servers)297 static WebVector<webrtc::PeerConnectionInterface::IceServer> ConvertIceServers(
298 const HeapVector<Member<RTCIceServer>>& ice_servers) {
299 WebVector<webrtc::PeerConnectionInterface::IceServer> converted_ice_servers;
300 for (const RTCIceServer* ice_server : ice_servers) {
301 converted_ice_servers.emplace_back(ConvertIceServer(ice_server));
302 }
303 return converted_ice_servers;
304 }
305
IceTransportPolicyFromString(const String & str)306 static IceTransportPolicy IceTransportPolicyFromString(const String& str) {
307 if (str == "relay") {
308 return IceTransportPolicy::kRelay;
309 }
310 if (str == "all") {
311 return IceTransportPolicy::kAll;
312 }
313 NOTREACHED();
314 return IceTransportPolicy::kAll;
315 }
316
gather(RTCIceGatherOptions * options,ExceptionState & exception_state)317 void RTCIceTransport::gather(RTCIceGatherOptions* options,
318 ExceptionState& exception_state) {
319 if (RaiseExceptionIfClosed(exception_state)) {
320 return;
321 }
322 // TODO(github.com/w3c/webrtc-ice/issues/7): Possibly support calling gather()
323 // more than once.
324 if (gathering_state_ != cricket::kIceGatheringNew) {
325 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
326 "Can only call gather() once.");
327 return;
328 }
329 WebVector<webrtc::PeerConnectionInterface::IceServer> ice_servers;
330 if (options->hasIceServers()) {
331 ice_servers = ConvertIceServers(options->iceServers());
332 }
333 cricket::ServerAddresses stun_servers;
334 std::vector<cricket::RelayServerConfig> turn_servers;
335 webrtc::RTCErrorType error_type = webrtc::ParseIceServers(
336 ice_servers.ReleaseVector(), &stun_servers, &turn_servers);
337 if (error_type != webrtc::RTCErrorType::NONE) {
338 ThrowExceptionFromRTCError(
339 webrtc::RTCError(error_type, "Invalid ICE server URL(s)."),
340 exception_state);
341 return;
342 }
343 gathering_state_ = cricket::kIceGatheringGathering;
344 proxy_->StartGathering(ConvertIceParameters(local_parameters_).value(),
345 stun_servers, turn_servers,
346 IceTransportPolicyFromString(options->gatherPolicy()));
347 }
348
IceRoleFromString(const String & role_string)349 static cricket::IceRole IceRoleFromString(const String& role_string) {
350 if (role_string == kIceRoleControllingStr) {
351 return cricket::ICEROLE_CONTROLLING;
352 }
353 if (role_string == kIceRoleControlledStr) {
354 return cricket::ICEROLE_CONTROLLED;
355 }
356 NOTREACHED();
357 return cricket::ICEROLE_UNKNOWN;
358 }
359
RTCIceParametersAreEqual(const RTCIceParameters * a,const RTCIceParameters * b)360 static bool RTCIceParametersAreEqual(const RTCIceParameters* a,
361 const RTCIceParameters* b) {
362 return a->usernameFragment() == b->usernameFragment() &&
363 a->password() == b->password();
364 }
365
start(RTCIceParameters * raw_remote_parameters,const String & role_string,ExceptionState & exception_state)366 void RTCIceTransport::start(RTCIceParameters* raw_remote_parameters,
367 const String& role_string,
368 ExceptionState& exception_state) {
369 if (RaiseExceptionIfClosed(exception_state)) {
370 return;
371 }
372 if (!raw_remote_parameters->hasUsernameFragment() ||
373 !raw_remote_parameters->hasPassword()) {
374 exception_state.ThrowTypeError(
375 "remoteParameters must have usernameFragment and password fields set.");
376 return;
377 }
378 webrtc::RTCErrorOr<cricket::IceParameters> maybe_remote_parameters =
379 ConvertIceParameters(raw_remote_parameters);
380 if (!maybe_remote_parameters.ok()) {
381 ThrowExceptionFromRTCError(maybe_remote_parameters.error(),
382 exception_state);
383 return;
384 }
385 cricket::IceParameters remote_parameters =
386 maybe_remote_parameters.MoveValue();
387 cricket::IceRole role = IceRoleFromString(role_string);
388 if (role_ != cricket::ICEROLE_UNKNOWN && role != role_) {
389 exception_state.ThrowDOMException(
390 DOMExceptionCode::kInvalidStateError,
391 "Cannot change role once start() has been called.");
392 return;
393 }
394 if (remote_parameters_ &&
395 RTCIceParametersAreEqual(remote_parameters_, raw_remote_parameters)) {
396 // No change to remote parameters: do nothing.
397 return;
398 }
399 if (!remote_parameters_) {
400 // Calling start() for the first time.
401 role_ = role;
402 if (remote_candidates_.size() > 0) {
403 state_ = webrtc::IceTransportState::kChecking;
404 }
405 Vector<cricket::Candidate> initial_remote_candidates;
406 for (RTCIceCandidate* remote_candidate : remote_candidates_) {
407 // This conversion is safe since we throw an exception in
408 // addRemoteCandidate on malformed ICE candidates.
409 initial_remote_candidates.push_back(
410 *ConvertToCricketIceCandidate(*remote_candidate));
411 }
412 proxy_->Start(remote_parameters, role, initial_remote_candidates);
413 } else {
414 remote_candidates_.clear();
415 state_ = webrtc::IceTransportState::kNew;
416 proxy_->HandleRemoteRestart(remote_parameters);
417 }
418
419 remote_parameters_ = raw_remote_parameters;
420 }
421
stop()422 void RTCIceTransport::stop() {
423 Close(CloseReason::kStopped);
424 }
425
addRemoteCandidate(RTCIceCandidate * remote_candidate,ExceptionState & exception_state)426 void RTCIceTransport::addRemoteCandidate(RTCIceCandidate* remote_candidate,
427 ExceptionState& exception_state) {
428 if (RaiseExceptionIfClosed(exception_state)) {
429 return;
430 }
431 base::Optional<cricket::Candidate> converted_remote_candidate =
432 ConvertToCricketIceCandidate(*remote_candidate);
433 if (!converted_remote_candidate) {
434 exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
435 "Invalid ICE candidate.");
436 return;
437 }
438 remote_candidates_.push_back(remote_candidate);
439 if (remote_parameters_) {
440 proxy_->AddRemoteCandidate(*converted_remote_candidate);
441 state_ = webrtc::IceTransportState::kChecking;
442 }
443 }
444
GenerateLocalParameters()445 void RTCIceTransport::GenerateLocalParameters() {
446 local_parameters_ = RTCIceParameters::Create();
447 local_parameters_->setUsernameFragment(
448 String::FromUTF8(rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH)));
449 local_parameters_->setPassword(
450 String::FromUTF8(rtc::CreateRandomString(cricket::ICE_PWD_LENGTH)));
451 }
452
OnGatheringStateChanged(cricket::IceGatheringState new_state)453 void RTCIceTransport::OnGatheringStateChanged(
454 cricket::IceGatheringState new_state) {
455 if (new_state == gathering_state_) {
456 return;
457 }
458 if (new_state == cricket::kIceGatheringComplete) {
459 // Generate a null ICE candidate to signal the end of candidates.
460 DispatchEvent(*RTCPeerConnectionIceEvent::Create(nullptr));
461 }
462 gathering_state_ = new_state;
463 DispatchEvent(*Event::Create(event_type_names::kGatheringstatechange));
464 }
465
OnCandidateGathered(const cricket::Candidate & parsed_candidate)466 void RTCIceTransport::OnCandidateGathered(
467 const cricket::Candidate& parsed_candidate) {
468 RTCIceCandidate* candidate = ConvertToRtcIceCandidate(parsed_candidate);
469 local_candidates_.push_back(candidate);
470 RTCPeerConnectionIceEventInit* event_init =
471 RTCPeerConnectionIceEventInit::Create();
472 event_init->setCandidate(candidate);
473 DispatchEvent(*RTCPeerConnectionIceEvent::Create(
474 event_type_names::kIcecandidate, event_init));
475 }
476
OnStateChanged(webrtc::IceTransportState new_state)477 void RTCIceTransport::OnStateChanged(webrtc::IceTransportState new_state) {
478 // MONKEY PATCH:
479 // Due to crbug.com/957487, the lower layers signal kFailed when they
480 // should have been sending kDisconnected. Remap the state.
481 if (new_state == webrtc::IceTransportState::kFailed) {
482 LOG(INFO) << "crbug/957487: Remapping ICE state failed to disconnected";
483 new_state = webrtc::IceTransportState::kDisconnected;
484 }
485 if (new_state == state_) {
486 return;
487 }
488 state_ = new_state;
489 if (state_ == webrtc::IceTransportState::kFailed) {
490 selected_candidate_pair_ = nullptr;
491 }
492 // Make sure the peerconnection's state is updated before the event fires.
493 if (peer_connection_) {
494 peer_connection_->UpdateIceConnectionState();
495 }
496 DispatchEvent(*Event::Create(event_type_names::kStatechange));
497 if (state_ == webrtc::IceTransportState::kClosed ||
498 state_ == webrtc::IceTransportState::kFailed) {
499 stop();
500 }
501 }
502
OnSelectedCandidatePairChanged(const std::pair<cricket::Candidate,cricket::Candidate> & selected_candidate_pair)503 void RTCIceTransport::OnSelectedCandidatePairChanged(
504 const std::pair<cricket::Candidate, cricket::Candidate>&
505 selected_candidate_pair) {
506 RTCIceCandidate* local =
507 ConvertToRtcIceCandidate(selected_candidate_pair.first);
508 RTCIceCandidate* remote =
509 ConvertToRtcIceCandidate(selected_candidate_pair.second);
510 selected_candidate_pair_ = RTCIceCandidatePair::Create();
511 selected_candidate_pair_->setLocal(local);
512 selected_candidate_pair_->setRemote(remote);
513 DispatchEvent(*Event::Create(event_type_names::kSelectedcandidatepairchange));
514 }
515
Close(CloseReason reason)516 void RTCIceTransport::Close(CloseReason reason) {
517 if (IsClosed()) {
518 return;
519 }
520 state_ = webrtc::IceTransportState::kClosed;
521 selected_candidate_pair_ = nullptr;
522 proxy_.reset();
523 }
524
RaiseExceptionIfClosed(ExceptionState & exception_state) const525 bool RTCIceTransport::RaiseExceptionIfClosed(
526 ExceptionState& exception_state) const {
527 if (IsClosed()) {
528 exception_state.ThrowDOMException(
529 DOMExceptionCode::kInvalidStateError,
530 "The RTCIceTransport's state is 'closed'.");
531 return true;
532 }
533 return false;
534 }
535
InterfaceName() const536 const AtomicString& RTCIceTransport::InterfaceName() const {
537 return event_target_names::kRTCIceTransport;
538 }
539
GetExecutionContext() const540 ExecutionContext* RTCIceTransport::GetExecutionContext() const {
541 return ExecutionContextLifecycleObserver::GetExecutionContext();
542 }
543
ContextDestroyed()544 void RTCIceTransport::ContextDestroyed() {
545 Close(CloseReason::kContextDestroyed);
546 }
547
HasPendingActivity() const548 bool RTCIceTransport::HasPendingActivity() const {
549 // Only allow the RTCIceTransport to be garbage collected if the ICE
550 // implementation is not active.
551 return !!proxy_;
552 }
553
Trace(Visitor * visitor) const554 void RTCIceTransport::Trace(Visitor* visitor) const {
555 visitor->Trace(local_candidates_);
556 visitor->Trace(remote_candidates_);
557 visitor->Trace(local_parameters_);
558 visitor->Trace(remote_parameters_);
559 visitor->Trace(selected_candidate_pair_);
560 visitor->Trace(peer_connection_);
561 EventTargetWithInlineData::Trace(visitor);
562 ExecutionContextLifecycleObserver::Trace(visitor);
563 }
564
Dispose()565 void RTCIceTransport::Dispose() {
566 Close(CloseReason::kDisposed);
567 }
568
569 } // namespace blink
570