1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * 3. Neither the name of Google Inc. nor the names of its contributors
15 * may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32
33 #include "modules/mediastream/RTCPeerConnection.h"
34
35 #include "bindings/v8/ArrayValue.h"
36 #include "bindings/v8/ExceptionState.h"
37 #include "core/dom/Document.h"
38 #include "core/events/Event.h"
39 #include "core/dom/ExceptionCode.h"
40 #include "core/dom/ExecutionContext.h"
41 #include "core/html/VoidCallback.h"
42 #include "core/loader/FrameLoader.h"
43 #include "core/loader/FrameLoaderClient.h"
44 #include "core/frame/Frame.h"
45 #include "core/platform/mediastream/RTCDataChannelHandler.h"
46 #include "modules/mediastream/MediaConstraintsImpl.h"
47 #include "modules/mediastream/MediaStreamEvent.h"
48 #include "modules/mediastream/RTCDTMFSender.h"
49 #include "modules/mediastream/RTCDataChannel.h"
50 #include "modules/mediastream/RTCDataChannelEvent.h"
51 #include "modules/mediastream/RTCErrorCallback.h"
52 #include "modules/mediastream/RTCIceCandidateEvent.h"
53 #include "modules/mediastream/RTCSessionDescription.h"
54 #include "modules/mediastream/RTCSessionDescriptionCallback.h"
55 #include "modules/mediastream/RTCSessionDescriptionRequestImpl.h"
56 #include "modules/mediastream/RTCStatsCallback.h"
57 #include "modules/mediastream/RTCStatsRequestImpl.h"
58 #include "modules/mediastream/RTCVoidRequestImpl.h"
59 #include "platform/mediastream/RTCConfiguration.h"
60 #include "public/platform/WebRTCDataChannelInit.h"
61 #include "public/platform/WebRTCICECandidate.h"
62 #include "public/platform/WebRTCSessionDescription.h"
63
64 namespace WebCore {
65
parseConfiguration(const Dictionary & configuration,ExceptionState & exceptionState)66 PassRefPtr<RTCConfiguration> RTCPeerConnection::parseConfiguration(const Dictionary& configuration, ExceptionState& exceptionState)
67 {
68 if (configuration.isUndefinedOrNull())
69 return 0;
70
71 ArrayValue iceServers;
72 bool ok = configuration.get("iceServers", iceServers);
73 if (!ok || iceServers.isUndefinedOrNull()) {
74 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
75 return 0;
76 }
77
78 size_t numberOfServers;
79 ok = iceServers.length(numberOfServers);
80 if (!ok) {
81 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
82 return 0;
83 }
84
85 RefPtr<RTCConfiguration> rtcConfiguration = RTCConfiguration::create();
86
87 for (size_t i = 0; i < numberOfServers; ++i) {
88 Dictionary iceServer;
89 ok = iceServers.get(i, iceServer);
90 if (!ok) {
91 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
92 return 0;
93 }
94
95 String urlString, username, credential;
96 ok = iceServer.get("url", urlString);
97 if (!ok) {
98 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
99 return 0;
100 }
101 KURL url(KURL(), urlString);
102 if (!url.isValid() || !(url.protocolIs("turn") || url.protocolIs("turns") || url.protocolIs("stun"))) {
103 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
104 return 0;
105 }
106
107 iceServer.get("username", username);
108 iceServer.get("credential", credential);
109
110 rtcConfiguration->appendServer(RTCIceServer::create(url, username, credential));
111 }
112
113 return rtcConfiguration.release();
114 }
115
create(ExecutionContext * context,const Dictionary & rtcConfiguration,const Dictionary & mediaConstraints,ExceptionState & exceptionState)116 PassRefPtr<RTCPeerConnection> RTCPeerConnection::create(ExecutionContext* context, const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
117 {
118 RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, exceptionState);
119 if (exceptionState.hadException())
120 return 0;
121
122 RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
123 if (exceptionState.hadException())
124 return 0;
125
126 RefPtr<RTCPeerConnection> peerConnection = adoptRef(new RTCPeerConnection(context, configuration.release(), constraints.release(), exceptionState));
127 peerConnection->suspendIfNeeded();
128 if (exceptionState.hadException())
129 return 0;
130
131 return peerConnection.release();
132 }
133
RTCPeerConnection(ExecutionContext * context,PassRefPtr<RTCConfiguration> configuration,PassRefPtr<MediaConstraints> constraints,ExceptionState & exceptionState)134 RTCPeerConnection::RTCPeerConnection(ExecutionContext* context, PassRefPtr<RTCConfiguration> configuration, PassRefPtr<MediaConstraints> constraints, ExceptionState& exceptionState)
135 : ActiveDOMObject(context)
136 , m_signalingState(SignalingStateStable)
137 , m_iceGatheringState(IceGatheringStateNew)
138 , m_iceConnectionState(IceConnectionStateNew)
139 , m_dispatchScheduledEventRunner(this, &RTCPeerConnection::dispatchScheduledEvent)
140 , m_stopped(false)
141 {
142 ScriptWrappable::init(this);
143 Document* document = toDocument(executionContext());
144
145 if (!document->frame()) {
146 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
147 return;
148 }
149
150 m_peerHandler = RTCPeerConnectionHandler::create(this);
151 if (!m_peerHandler) {
152 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
153 return;
154 }
155
156 document->frame()->loader().client()->dispatchWillStartUsingPeerConnectionHandler(m_peerHandler.get());
157
158 if (!m_peerHandler->initialize(configuration, constraints)) {
159 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
160 return;
161 }
162 }
163
~RTCPeerConnection()164 RTCPeerConnection::~RTCPeerConnection()
165 {
166 stop();
167 }
168
createOffer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,const Dictionary & mediaConstraints,ExceptionState & exceptionState)169 void RTCPeerConnection::createOffer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
170 {
171 if (m_signalingState == SignalingStateClosed) {
172 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
173 return;
174 }
175
176 if (!successCallback) {
177 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
178 return;
179 }
180
181 RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
182 if (exceptionState.hadException())
183 return;
184
185 RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(executionContext(), successCallback, errorCallback);
186 m_peerHandler->createOffer(request.release(), constraints);
187 }
188
createAnswer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,const Dictionary & mediaConstraints,ExceptionState & exceptionState)189 void RTCPeerConnection::createAnswer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
190 {
191 if (m_signalingState == SignalingStateClosed) {
192 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
193 return;
194 }
195
196 if (!successCallback) {
197 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
198 return;
199 }
200
201 RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
202 if (exceptionState.hadException())
203 return;
204
205 RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(executionContext(), successCallback, errorCallback);
206 m_peerHandler->createAnswer(request.release(), constraints.release());
207 }
208
setLocalDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)209 void RTCPeerConnection::setLocalDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
210 {
211 if (m_signalingState == SignalingStateClosed) {
212 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
213 return;
214 }
215
216 RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
217 if (!sessionDescription) {
218 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
219 return;
220 }
221
222 RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(executionContext(), successCallback, errorCallback);
223 m_peerHandler->setLocalDescription(request.release(), sessionDescription->webSessionDescription());
224 }
225
localDescription(ExceptionState & exceptionState)226 PassRefPtr<RTCSessionDescription> RTCPeerConnection::localDescription(ExceptionState& exceptionState)
227 {
228 blink::WebRTCSessionDescription webSessionDescription = m_peerHandler->localDescription();
229 if (webSessionDescription.isNull())
230 return 0;
231
232 RefPtr<RTCSessionDescription> sessionDescription = RTCSessionDescription::create(webSessionDescription);
233 return sessionDescription.release();
234 }
235
setRemoteDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)236 void RTCPeerConnection::setRemoteDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
237 {
238 if (m_signalingState == SignalingStateClosed) {
239 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
240 return;
241 }
242
243 RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
244 if (!sessionDescription) {
245 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
246 return;
247 }
248
249 RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(executionContext(), successCallback, errorCallback);
250 m_peerHandler->setRemoteDescription(request.release(), sessionDescription->webSessionDescription());
251 }
252
remoteDescription(ExceptionState & exceptionState)253 PassRefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription(ExceptionState& exceptionState)
254 {
255 blink::WebRTCSessionDescription webSessionDescription = m_peerHandler->remoteDescription();
256 if (webSessionDescription.isNull())
257 return 0;
258
259 RefPtr<RTCSessionDescription> desc = RTCSessionDescription::create(webSessionDescription);
260 return desc.release();
261 }
262
updateIce(const Dictionary & rtcConfiguration,const Dictionary & mediaConstraints,ExceptionState & exceptionState)263 void RTCPeerConnection::updateIce(const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
264 {
265 if (m_signalingState == SignalingStateClosed) {
266 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
267 return;
268 }
269
270 RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, exceptionState);
271 if (exceptionState.hadException())
272 return;
273
274 RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
275 if (exceptionState.hadException())
276 return;
277
278 bool valid = m_peerHandler->updateIce(configuration, constraints);
279 if (!valid)
280 exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
281 }
282
addIceCandidate(RTCIceCandidate * iceCandidate,ExceptionState & exceptionState)283 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, ExceptionState& exceptionState)
284 {
285 if (m_signalingState == SignalingStateClosed) {
286 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
287 return;
288 }
289
290 if (!iceCandidate) {
291 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
292 return;
293 }
294
295 bool valid = m_peerHandler->addIceCandidate(iceCandidate->webCandidate());
296 if (!valid)
297 exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
298 }
299
addIceCandidate(RTCIceCandidate * iceCandidate,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)300 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
301 {
302 if (m_signalingState == SignalingStateClosed) {
303 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
304 return;
305 }
306
307 if (!iceCandidate || !successCallback || !errorCallback) {
308 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
309 return;
310 }
311
312 RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(executionContext(), successCallback, errorCallback);
313
314 bool implemented = m_peerHandler->addIceCandidate(request.release(), iceCandidate->webCandidate());
315 if (!implemented)
316 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
317 }
318
signalingState() const319 String RTCPeerConnection::signalingState() const
320 {
321 switch (m_signalingState) {
322 case SignalingStateStable:
323 return "stable";
324 case SignalingStateHaveLocalOffer:
325 return "have-local-offer";
326 case SignalingStateHaveRemoteOffer:
327 return "have-remote-offer";
328 case SignalingStateHaveLocalPrAnswer:
329 return "have-local-pranswer";
330 case SignalingStateHaveRemotePrAnswer:
331 return "have-remote-pranswer";
332 case SignalingStateClosed:
333 return "closed";
334 }
335
336 ASSERT_NOT_REACHED();
337 return String();
338 }
339
iceGatheringState() const340 String RTCPeerConnection::iceGatheringState() const
341 {
342 switch (m_iceGatheringState) {
343 case IceGatheringStateNew:
344 return "new";
345 case IceGatheringStateGathering:
346 return "gathering";
347 case IceGatheringStateComplete:
348 return "complete";
349 }
350
351 ASSERT_NOT_REACHED();
352 return String();
353 }
354
iceConnectionState() const355 String RTCPeerConnection::iceConnectionState() const
356 {
357 switch (m_iceConnectionState) {
358 case IceConnectionStateNew:
359 return "new";
360 case IceConnectionStateChecking:
361 return "checking";
362 case IceConnectionStateConnected:
363 return "connected";
364 case IceConnectionStateCompleted:
365 return "completed";
366 case IceConnectionStateFailed:
367 return "failed";
368 case IceConnectionStateDisconnected:
369 return "disconnected";
370 case IceConnectionStateClosed:
371 return "closed";
372 }
373
374 ASSERT_NOT_REACHED();
375 return String();
376 }
377
addStream(PassRefPtr<MediaStream> prpStream,const Dictionary & mediaConstraints,ExceptionState & exceptionState)378 void RTCPeerConnection::addStream(PassRefPtr<MediaStream> prpStream, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
379 {
380 if (m_signalingState == SignalingStateClosed) {
381 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
382 return;
383 }
384
385 RefPtr<MediaStream> stream = prpStream;
386 if (!stream) {
387 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
388 return;
389 }
390
391 if (m_localStreams.contains(stream))
392 return;
393
394 RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
395 if (exceptionState.hadException())
396 return;
397
398 m_localStreams.append(stream);
399
400 bool valid = m_peerHandler->addStream(stream->descriptor(), constraints);
401 if (!valid)
402 exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
403 }
404
removeStream(PassRefPtr<MediaStream> prpStream,ExceptionState & exceptionState)405 void RTCPeerConnection::removeStream(PassRefPtr<MediaStream> prpStream, ExceptionState& exceptionState)
406 {
407 if (m_signalingState == SignalingStateClosed) {
408 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
409 return;
410 }
411
412 if (!prpStream) {
413 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
414 return;
415 }
416
417 RefPtr<MediaStream> stream = prpStream;
418
419 size_t pos = m_localStreams.find(stream);
420 if (pos == kNotFound)
421 return;
422
423 m_localStreams.remove(pos);
424
425 m_peerHandler->removeStream(stream->descriptor());
426 }
427
getLocalStreams() const428 MediaStreamVector RTCPeerConnection::getLocalStreams() const
429 {
430 return m_localStreams;
431 }
432
getRemoteStreams() const433 MediaStreamVector RTCPeerConnection::getRemoteStreams() const
434 {
435 return m_remoteStreams;
436 }
437
getStreamById(const String & streamId)438 MediaStream* RTCPeerConnection::getStreamById(const String& streamId)
439 {
440 for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
441 if ((*iter)->id() == streamId)
442 return iter->get();
443 }
444
445 for (MediaStreamVector::iterator iter = m_remoteStreams.begin(); iter != m_remoteStreams.end(); ++iter) {
446 if ((*iter)->id() == streamId)
447 return iter->get();
448 }
449
450 return 0;
451 }
452
getStats(PassOwnPtr<RTCStatsCallback> successCallback,PassRefPtr<MediaStreamTrack> selector)453 void RTCPeerConnection::getStats(PassOwnPtr<RTCStatsCallback> successCallback, PassRefPtr<MediaStreamTrack> selector)
454 {
455 RefPtr<RTCStatsRequestImpl> statsRequest = RTCStatsRequestImpl::create(executionContext(), successCallback, selector);
456 // FIXME: Add passing selector as part of the statsRequest.
457 m_peerHandler->getStats(statsRequest.release());
458 }
459
createDataChannel(String label,const Dictionary & options,ExceptionState & exceptionState)460 PassRefPtr<RTCDataChannel> RTCPeerConnection::createDataChannel(String label, const Dictionary& options, ExceptionState& exceptionState)
461 {
462 if (m_signalingState == SignalingStateClosed) {
463 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
464 return 0;
465 }
466
467 blink::WebRTCDataChannelInit init;
468 options.get("ordered", init.ordered);
469 options.get("negotiated", init.negotiated);
470
471 unsigned short value = 0;
472 if (options.get("id", value))
473 init.id = value;
474 if (options.get("maxRetransmits", value))
475 init.maxRetransmits = value;
476 if (options.get("maxRetransmitTime", value))
477 init.maxRetransmitTime = value;
478
479 String protocolString;
480 options.get("protocol", protocolString);
481 init.protocol = protocolString;
482
483 RefPtr<RTCDataChannel> channel = RTCDataChannel::create(executionContext(), m_peerHandler.get(), label, init, exceptionState);
484 if (exceptionState.hadException())
485 return 0;
486 m_dataChannels.append(channel);
487 return channel.release();
488 }
489
hasLocalStreamWithTrackId(const String & trackId)490 bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId)
491 {
492 for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
493 if ((*iter)->getTrackById(trackId))
494 return true;
495 }
496 return false;
497 }
498
createDTMFSender(PassRefPtr<MediaStreamTrack> prpTrack,ExceptionState & exceptionState)499 PassRefPtr<RTCDTMFSender> RTCPeerConnection::createDTMFSender(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionState& exceptionState)
500 {
501 if (m_signalingState == SignalingStateClosed) {
502 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
503 return 0;
504 }
505
506 if (!prpTrack) {
507 exceptionState.throwUninformativeAndGenericTypeError();
508 return 0;
509 }
510
511 RefPtr<MediaStreamTrack> track = prpTrack;
512
513 if (!hasLocalStreamWithTrackId(track->id())) {
514 exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
515 return 0;
516 }
517
518 RefPtr<RTCDTMFSender> dtmfSender = RTCDTMFSender::create(executionContext(), m_peerHandler.get(), track.release(), exceptionState);
519 if (exceptionState.hadException())
520 return 0;
521 return dtmfSender.release();
522 }
523
close(ExceptionState & exceptionState)524 void RTCPeerConnection::close(ExceptionState& exceptionState)
525 {
526 if (m_signalingState == SignalingStateClosed) {
527 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
528 return;
529 }
530
531 m_peerHandler->stop();
532
533 changeIceConnectionState(IceConnectionStateClosed);
534 changeIceGatheringState(IceGatheringStateComplete);
535 changeSignalingState(SignalingStateClosed);
536 }
537
negotiationNeeded()538 void RTCPeerConnection::negotiationNeeded()
539 {
540 scheduleDispatchEvent(Event::create(EventTypeNames::negotiationneeded));
541 }
542
didGenerateIceCandidate(blink::WebRTCICECandidate webCandidate)543 void RTCPeerConnection::didGenerateIceCandidate(blink::WebRTCICECandidate webCandidate)
544 {
545 ASSERT(executionContext()->isContextThread());
546 if (webCandidate.isNull())
547 scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, 0));
548 else {
549 RefPtr<RTCIceCandidate> iceCandidate = RTCIceCandidate::create(webCandidate);
550 scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCandidate.release()));
551 }
552 }
553
didChangeSignalingState(SignalingState newState)554 void RTCPeerConnection::didChangeSignalingState(SignalingState newState)
555 {
556 ASSERT(executionContext()->isContextThread());
557 changeSignalingState(newState);
558 }
559
didChangeIceGatheringState(IceGatheringState newState)560 void RTCPeerConnection::didChangeIceGatheringState(IceGatheringState newState)
561 {
562 ASSERT(executionContext()->isContextThread());
563 changeIceGatheringState(newState);
564 }
565
didChangeIceConnectionState(IceConnectionState newState)566 void RTCPeerConnection::didChangeIceConnectionState(IceConnectionState newState)
567 {
568 ASSERT(executionContext()->isContextThread());
569 changeIceConnectionState(newState);
570 }
571
didAddRemoteStream(PassRefPtr<MediaStreamDescriptor> streamDescriptor)572 void RTCPeerConnection::didAddRemoteStream(PassRefPtr<MediaStreamDescriptor> streamDescriptor)
573 {
574 ASSERT(executionContext()->isContextThread());
575
576 if (m_signalingState == SignalingStateClosed)
577 return;
578
579 RefPtr<MediaStream> stream = MediaStream::create(executionContext(), streamDescriptor);
580 m_remoteStreams.append(stream);
581
582 scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::addstream, false, false, stream.release()));
583 }
584
didRemoveRemoteStream(MediaStreamDescriptor * streamDescriptor)585 void RTCPeerConnection::didRemoveRemoteStream(MediaStreamDescriptor* streamDescriptor)
586 {
587 ASSERT(executionContext()->isContextThread());
588 ASSERT(streamDescriptor->client());
589
590 RefPtr<MediaStream> stream = static_cast<MediaStream*>(streamDescriptor->client());
591 stream->streamEnded();
592
593 if (m_signalingState == SignalingStateClosed)
594 return;
595
596 size_t pos = m_remoteStreams.find(stream);
597 ASSERT(pos != kNotFound);
598 m_remoteStreams.remove(pos);
599
600 scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::removestream, false, false, stream.release()));
601 }
602
didAddRemoteDataChannel(PassOwnPtr<RTCDataChannelHandler> handler)603 void RTCPeerConnection::didAddRemoteDataChannel(PassOwnPtr<RTCDataChannelHandler> handler)
604 {
605 ASSERT(executionContext()->isContextThread());
606
607 if (m_signalingState == SignalingStateClosed)
608 return;
609
610 RefPtr<RTCDataChannel> channel = RTCDataChannel::create(executionContext(), handler);
611 m_dataChannels.append(channel);
612
613 scheduleDispatchEvent(RTCDataChannelEvent::create(EventTypeNames::datachannel, false, false, channel.release()));
614 }
615
interfaceName() const616 const AtomicString& RTCPeerConnection::interfaceName() const
617 {
618 return EventTargetNames::RTCPeerConnection;
619 }
620
executionContext() const621 ExecutionContext* RTCPeerConnection::executionContext() const
622 {
623 return ActiveDOMObject::executionContext();
624 }
625
suspend()626 void RTCPeerConnection::suspend()
627 {
628 m_dispatchScheduledEventRunner.suspend();
629 }
630
resume()631 void RTCPeerConnection::resume()
632 {
633 m_dispatchScheduledEventRunner.resume();
634 }
635
stop()636 void RTCPeerConnection::stop()
637 {
638 if (m_stopped)
639 return;
640
641 m_stopped = true;
642 m_iceConnectionState = IceConnectionStateClosed;
643 m_signalingState = SignalingStateClosed;
644
645 Vector<RefPtr<RTCDataChannel> >::iterator i = m_dataChannels.begin();
646 for (; i != m_dataChannels.end(); ++i)
647 (*i)->stop();
648
649 m_dispatchScheduledEventRunner.stop();
650 }
651
changeSignalingState(SignalingState signalingState)652 void RTCPeerConnection::changeSignalingState(SignalingState signalingState)
653 {
654 if (m_signalingState != SignalingStateClosed && m_signalingState != signalingState) {
655 m_signalingState = signalingState;
656 scheduleDispatchEvent(Event::create(EventTypeNames::signalingstatechange));
657 }
658 }
659
changeIceGatheringState(IceGatheringState iceGatheringState)660 void RTCPeerConnection::changeIceGatheringState(IceGatheringState iceGatheringState)
661 {
662 m_iceGatheringState = iceGatheringState;
663 }
664
changeIceConnectionState(IceConnectionState iceConnectionState)665 void RTCPeerConnection::changeIceConnectionState(IceConnectionState iceConnectionState)
666 {
667 if (m_iceConnectionState != IceConnectionStateClosed && m_iceConnectionState != iceConnectionState) {
668 m_iceConnectionState = iceConnectionState;
669 scheduleDispatchEvent(Event::create(EventTypeNames::iceconnectionstatechange));
670 }
671 }
672
scheduleDispatchEvent(PassRefPtr<Event> event)673 void RTCPeerConnection::scheduleDispatchEvent(PassRefPtr<Event> event)
674 {
675 m_scheduledEvents.append(event);
676
677 m_dispatchScheduledEventRunner.runAsync();
678 }
679
dispatchScheduledEvent()680 void RTCPeerConnection::dispatchScheduledEvent()
681 {
682 if (m_stopped)
683 return;
684
685 Vector<RefPtr<Event> > events;
686 events.swap(m_scheduledEvents);
687
688 Vector<RefPtr<Event> >::iterator it = events.begin();
689 for (; it != events.end(); ++it)
690 dispatchEvent((*it).release());
691
692 events.clear();
693 }
694
695 } // namespace WebCore
696