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/ExceptionMessages.h"
37 #include "bindings/v8/ExceptionState.h"
38 #include "core/dom/Document.h"
39 #include "core/dom/ExceptionCode.h"
40 #include "core/dom/ExecutionContext.h"
41 #include "core/frame/LocalFrame.h"
42 #include "core/html/VoidCallback.h"
43 #include "core/loader/FrameLoader.h"
44 #include "core/loader/FrameLoaderClient.h"
45 #include "modules/mediastream/MediaConstraintsImpl.h"
46 #include "modules/mediastream/MediaStreamEvent.h"
47 #include "modules/mediastream/RTCDTMFSender.h"
48 #include "modules/mediastream/RTCDataChannel.h"
49 #include "modules/mediastream/RTCDataChannelEvent.h"
50 #include "modules/mediastream/RTCErrorCallback.h"
51 #include "modules/mediastream/RTCIceCandidateEvent.h"
52 #include "modules/mediastream/RTCSessionDescription.h"
53 #include "modules/mediastream/RTCSessionDescriptionCallback.h"
54 #include "modules/mediastream/RTCSessionDescriptionRequestImpl.h"
55 #include "modules/mediastream/RTCStatsCallback.h"
56 #include "modules/mediastream/RTCStatsRequestImpl.h"
57 #include "modules/mediastream/RTCVoidRequestImpl.h"
58 #include "platform/mediastream/RTCConfiguration.h"
59 #include "public/platform/Platform.h"
60 #include "public/platform/WebMediaStream.h"
61 #include "public/platform/WebRTCConfiguration.h"
62 #include "public/platform/WebRTCDataChannelHandler.h"
63 #include "public/platform/WebRTCDataChannelInit.h"
64 #include "public/platform/WebRTCICECandidate.h"
65 #include "public/platform/WebRTCSessionDescription.h"
66 #include "public/platform/WebRTCSessionDescriptionRequest.h"
67 #include "public/platform/WebRTCStatsRequest.h"
68 #include "public/platform/WebRTCVoidRequest.h"
69
70 namespace WebCore {
71
72 namespace {
73
throwExceptionIfSignalingStateClosed(RTCPeerConnection::SignalingState state,ExceptionState & exceptionState)74 static bool throwExceptionIfSignalingStateClosed(RTCPeerConnection::SignalingState state, ExceptionState& exceptionState)
75 {
76 if (state == RTCPeerConnection::SignalingStateClosed) {
77 exceptionState.throwDOMException(InvalidStateError, "The RTCPeerConnection's signalingState is 'closed'.");
78 return true;
79 }
80
81 return false;
82 }
83
84 } // namespace
85
parseConfiguration(const Dictionary & configuration,ExceptionState & exceptionState)86 PassRefPtr<RTCConfiguration> RTCPeerConnection::parseConfiguration(const Dictionary& configuration, ExceptionState& exceptionState)
87 {
88 if (configuration.isUndefinedOrNull())
89 return nullptr;
90
91 ArrayValue iceServers;
92 bool ok = configuration.get("iceServers", iceServers);
93 if (!ok || iceServers.isUndefinedOrNull()) {
94 exceptionState.throwTypeError("Malformed RTCConfiguration");
95 return nullptr;
96 }
97
98 size_t numberOfServers;
99 ok = iceServers.length(numberOfServers);
100 if (!ok) {
101 exceptionState.throwTypeError("Malformed RTCConfiguration");
102 return nullptr;
103 }
104
105 RefPtr<RTCConfiguration> rtcConfiguration = RTCConfiguration::create();
106
107 for (size_t i = 0; i < numberOfServers; ++i) {
108 Dictionary iceServer;
109 ok = iceServers.get(i, iceServer);
110 if (!ok) {
111 exceptionState.throwTypeError("Malformed RTCIceServer");
112 return nullptr;
113 }
114
115 Vector<String> names;
116 iceServer.getOwnPropertyNames(names);
117
118 Vector<String> urlStrings;
119 if (names.contains("urls")) {
120 if (!iceServer.get("urls", urlStrings) || !urlStrings.size()) {
121 String urlString;
122 if (iceServer.get("urls", urlString)) {
123 urlStrings.append(urlString);
124 } else {
125 exceptionState.throwTypeError("Malformed RTCIceServer");
126 return nullptr;
127 }
128 }
129 } else if (names.contains("url")) {
130 String urlString;
131 if (iceServer.get("url", urlString)) {
132 urlStrings.append(urlString);
133 } else {
134 exceptionState.throwTypeError("Malformed RTCIceServer");
135 return nullptr;
136 }
137 } else {
138 exceptionState.throwTypeError("Malformed RTCIceServer");
139 return nullptr;
140 }
141
142 String username, credential;
143 iceServer.get("username", username);
144 iceServer.get("credential", credential);
145
146 for (Vector<String>::iterator iter = urlStrings.begin(); iter != urlStrings.end(); ++iter) {
147 KURL url(KURL(), *iter);
148 if (!url.isValid() || !(url.protocolIs("turn") || url.protocolIs("turns") || url.protocolIs("stun"))) {
149 exceptionState.throwTypeError("Malformed URL");
150 return nullptr;
151 }
152
153 rtcConfiguration->appendServer(RTCIceServer::create(url, username, credential));
154 }
155 }
156
157 return rtcConfiguration.release();
158 }
159
create(ExecutionContext * context,const Dictionary & rtcConfiguration,const Dictionary & mediaConstraints,ExceptionState & exceptionState)160 PassRefPtrWillBeRawPtr<RTCPeerConnection> RTCPeerConnection::create(ExecutionContext* context, const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
161 {
162 RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, exceptionState);
163 if (exceptionState.hadException())
164 return nullptr;
165
166 blink::WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
167 if (exceptionState.hadException())
168 return nullptr;
169
170 RefPtrWillBeRawPtr<RTCPeerConnection> peerConnection = adoptRefWillBeRefCountedGarbageCollected(new RTCPeerConnection(context, configuration.release(), constraints, exceptionState));
171 peerConnection->suspendIfNeeded();
172 if (exceptionState.hadException())
173 return nullptr;
174
175 return peerConnection.release();
176 }
177
RTCPeerConnection(ExecutionContext * context,PassRefPtr<RTCConfiguration> configuration,blink::WebMediaConstraints constraints,ExceptionState & exceptionState)178 RTCPeerConnection::RTCPeerConnection(ExecutionContext* context, PassRefPtr<RTCConfiguration> configuration, blink::WebMediaConstraints constraints, ExceptionState& exceptionState)
179 : ActiveDOMObject(context)
180 , m_signalingState(SignalingStateStable)
181 , m_iceGatheringState(ICEGatheringStateNew)
182 , m_iceConnectionState(ICEConnectionStateNew)
183 , m_dispatchScheduledEventRunner(this, &RTCPeerConnection::dispatchScheduledEvent)
184 , m_stopped(false)
185 , m_closed(false)
186 {
187 ScriptWrappable::init(this);
188 Document* document = toDocument(executionContext());
189
190 // If we fail, set |m_closed| and |m_stopped| to true, to avoid hitting the assert in the destructor.
191
192 if (!document->frame()) {
193 m_closed = true;
194 m_stopped = true;
195 exceptionState.throwDOMException(NotSupportedError, "PeerConnections may not be created in detached documents.");
196 return;
197 }
198
199 m_peerHandler = adoptPtr(blink::Platform::current()->createRTCPeerConnectionHandler(this));
200 if (!m_peerHandler) {
201 m_closed = true;
202 m_stopped = true;
203 exceptionState.throwDOMException(NotSupportedError, "No PeerConnection handler can be created, perhaps WebRTC is disabled?");
204 return;
205 }
206
207 document->frame()->loader().client()->dispatchWillStartUsingPeerConnectionHandler(m_peerHandler.get());
208
209 if (!m_peerHandler->initialize(configuration, constraints)) {
210 m_closed = true;
211 m_stopped = true;
212 exceptionState.throwDOMException(NotSupportedError, "Failed to initialize native PeerConnection.");
213 return;
214 }
215 }
216
~RTCPeerConnection()217 RTCPeerConnection::~RTCPeerConnection()
218 {
219 // This checks that close() or stop() is called before the destructor.
220 // We are assuming that a wrapper is always created when RTCPeerConnection is created.
221 ASSERT(m_closed || m_stopped);
222
223 #if !ENABLE(OILPAN)
224 stop();
225 #endif
226 }
227
createOffer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,const Dictionary & mediaConstraints,ExceptionState & exceptionState)228 void RTCPeerConnection::createOffer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
229 {
230 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
231 return;
232
233 ASSERT(successCallback);
234
235 blink::WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
236 if (exceptionState.hadException())
237 return;
238
239 RefPtr<RTCSessionDescriptionRequest> request = RTCSessionDescriptionRequestImpl::create(executionContext(), this, successCallback, errorCallback);
240 m_peerHandler->createOffer(request.release(), constraints);
241 }
242
createAnswer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,const Dictionary & mediaConstraints,ExceptionState & exceptionState)243 void RTCPeerConnection::createAnswer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
244 {
245 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
246 return;
247
248 ASSERT(successCallback);
249
250 blink::WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
251 if (exceptionState.hadException())
252 return;
253
254 RefPtr<RTCSessionDescriptionRequest> request = RTCSessionDescriptionRequestImpl::create(executionContext(), this, successCallback, errorCallback);
255 m_peerHandler->createAnswer(request.release(), constraints);
256 }
257
setLocalDescription(PassRefPtrWillBeRawPtr<RTCSessionDescription> prpSessionDescription,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)258 void RTCPeerConnection::setLocalDescription(PassRefPtrWillBeRawPtr<RTCSessionDescription> prpSessionDescription, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
259 {
260 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
261 return;
262
263 RefPtrWillBeRawPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
264 if (!sessionDescription) {
265 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCSessionDescription"));
266 return;
267 }
268
269 RefPtr<RTCVoidRequest> request = RTCVoidRequestImpl::create(executionContext(), this, successCallback, errorCallback);
270 m_peerHandler->setLocalDescription(request.release(), sessionDescription->webSessionDescription());
271 }
272
localDescription(ExceptionState & exceptionState)273 PassRefPtrWillBeRawPtr<RTCSessionDescription> RTCPeerConnection::localDescription(ExceptionState& exceptionState)
274 {
275 blink::WebRTCSessionDescription webSessionDescription = m_peerHandler->localDescription();
276 if (webSessionDescription.isNull())
277 return nullptr;
278
279 return RTCSessionDescription::create(webSessionDescription);
280 }
281
setRemoteDescription(PassRefPtrWillBeRawPtr<RTCSessionDescription> prpSessionDescription,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)282 void RTCPeerConnection::setRemoteDescription(PassRefPtrWillBeRawPtr<RTCSessionDescription> prpSessionDescription, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
283 {
284 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
285 return;
286
287 RefPtrWillBeRawPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
288 if (!sessionDescription) {
289 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCSessionDescription"));
290 return;
291 }
292
293 RefPtr<RTCVoidRequest> request = RTCVoidRequestImpl::create(executionContext(), this, successCallback, errorCallback);
294 m_peerHandler->setRemoteDescription(request.release(), sessionDescription->webSessionDescription());
295 }
296
remoteDescription(ExceptionState & exceptionState)297 PassRefPtrWillBeRawPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription(ExceptionState& exceptionState)
298 {
299 blink::WebRTCSessionDescription webSessionDescription = m_peerHandler->remoteDescription();
300 if (webSessionDescription.isNull())
301 return nullptr;
302
303 return RTCSessionDescription::create(webSessionDescription);
304 }
305
updateIce(const Dictionary & rtcConfiguration,const Dictionary & mediaConstraints,ExceptionState & exceptionState)306 void RTCPeerConnection::updateIce(const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
307 {
308 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
309 return;
310
311 RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, exceptionState);
312 if (exceptionState.hadException())
313 return;
314
315 blink::WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
316 if (exceptionState.hadException())
317 return;
318
319 bool valid = m_peerHandler->updateICE(configuration.release(), constraints);
320 if (!valid)
321 exceptionState.throwDOMException(SyntaxError, "Could not update the ICE Agent with the given configuration.");
322 }
323
addIceCandidate(RTCIceCandidate * iceCandidate,ExceptionState & exceptionState)324 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, ExceptionState& exceptionState)
325 {
326 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
327 return;
328
329 if (!iceCandidate) {
330 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCIceCandidate"));
331 return;
332 }
333
334 bool valid = m_peerHandler->addICECandidate(iceCandidate->webCandidate());
335 if (!valid)
336 exceptionState.throwDOMException(SyntaxError, "The ICE candidate could not be added.");
337 }
338
addIceCandidate(RTCIceCandidate * iceCandidate,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)339 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
340 {
341 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
342 return;
343
344 if (!iceCandidate) {
345 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCIceCandidate"));
346 return;
347 }
348 ASSERT(successCallback);
349 ASSERT(errorCallback);
350
351 RefPtr<RTCVoidRequest> request = RTCVoidRequestImpl::create(executionContext(), this, successCallback, errorCallback);
352
353 bool implemented = m_peerHandler->addICECandidate(request.release(), iceCandidate->webCandidate());
354 if (!implemented) {
355 exceptionState.throwDOMException(NotSupportedError, "This method is not yet implemented.");
356 }
357 }
358
signalingState() const359 String RTCPeerConnection::signalingState() const
360 {
361 switch (m_signalingState) {
362 case SignalingStateStable:
363 return "stable";
364 case SignalingStateHaveLocalOffer:
365 return "have-local-offer";
366 case SignalingStateHaveRemoteOffer:
367 return "have-remote-offer";
368 case SignalingStateHaveLocalPrAnswer:
369 return "have-local-pranswer";
370 case SignalingStateHaveRemotePrAnswer:
371 return "have-remote-pranswer";
372 case SignalingStateClosed:
373 return "closed";
374 }
375
376 ASSERT_NOT_REACHED();
377 return String();
378 }
379
iceGatheringState() const380 String RTCPeerConnection::iceGatheringState() const
381 {
382 switch (m_iceGatheringState) {
383 case ICEGatheringStateNew:
384 return "new";
385 case ICEGatheringStateGathering:
386 return "gathering";
387 case ICEGatheringStateComplete:
388 return "complete";
389 }
390
391 ASSERT_NOT_REACHED();
392 return String();
393 }
394
iceConnectionState() const395 String RTCPeerConnection::iceConnectionState() const
396 {
397 switch (m_iceConnectionState) {
398 case ICEConnectionStateNew:
399 return "new";
400 case ICEConnectionStateChecking:
401 return "checking";
402 case ICEConnectionStateConnected:
403 return "connected";
404 case ICEConnectionStateCompleted:
405 return "completed";
406 case ICEConnectionStateFailed:
407 return "failed";
408 case ICEConnectionStateDisconnected:
409 return "disconnected";
410 case ICEConnectionStateClosed:
411 return "closed";
412 }
413
414 ASSERT_NOT_REACHED();
415 return String();
416 }
417
addStream(PassRefPtrWillBeRawPtr<MediaStream> prpStream,const Dictionary & mediaConstraints,ExceptionState & exceptionState)418 void RTCPeerConnection::addStream(PassRefPtrWillBeRawPtr<MediaStream> prpStream, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
419 {
420 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
421 return;
422
423 RefPtrWillBeRawPtr<MediaStream> stream = prpStream;
424 if (!stream) {
425 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "MediaStream"));
426 return;
427 }
428
429 if (m_localStreams.contains(stream))
430 return;
431
432 blink::WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
433 if (exceptionState.hadException())
434 return;
435
436 m_localStreams.append(stream);
437
438 bool valid = m_peerHandler->addStream(stream->descriptor(), constraints);
439 if (!valid)
440 exceptionState.throwDOMException(SyntaxError, "Unable to add the provided stream.");
441 }
442
removeStream(PassRefPtrWillBeRawPtr<MediaStream> prpStream,ExceptionState & exceptionState)443 void RTCPeerConnection::removeStream(PassRefPtrWillBeRawPtr<MediaStream> prpStream, ExceptionState& exceptionState)
444 {
445 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
446 return;
447
448 if (!prpStream) {
449 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "MediaStream"));
450 return;
451 }
452
453 RefPtrWillBeRawPtr<MediaStream> stream = prpStream;
454
455 size_t pos = m_localStreams.find(stream);
456 if (pos == kNotFound)
457 return;
458
459 m_localStreams.remove(pos);
460
461 m_peerHandler->removeStream(stream->descriptor());
462 }
463
getLocalStreams() const464 MediaStreamVector RTCPeerConnection::getLocalStreams() const
465 {
466 return m_localStreams;
467 }
468
getRemoteStreams() const469 MediaStreamVector RTCPeerConnection::getRemoteStreams() const
470 {
471 return m_remoteStreams;
472 }
473
getStreamById(const String & streamId)474 MediaStream* RTCPeerConnection::getStreamById(const String& streamId)
475 {
476 for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
477 if ((*iter)->id() == streamId)
478 return iter->get();
479 }
480
481 for (MediaStreamVector::iterator iter = m_remoteStreams.begin(); iter != m_remoteStreams.end(); ++iter) {
482 if ((*iter)->id() == streamId)
483 return iter->get();
484 }
485
486 return 0;
487 }
488
getStats(PassOwnPtr<RTCStatsCallback> successCallback,PassRefPtr<MediaStreamTrack> selector)489 void RTCPeerConnection::getStats(PassOwnPtr<RTCStatsCallback> successCallback, PassRefPtr<MediaStreamTrack> selector)
490 {
491 RefPtr<RTCStatsRequest> statsRequest = RTCStatsRequestImpl::create(executionContext(), this, successCallback, selector);
492 // FIXME: Add passing selector as part of the statsRequest.
493 m_peerHandler->getStats(statsRequest.release());
494 }
495
createDataChannel(String label,const Dictionary & options,ExceptionState & exceptionState)496 PassRefPtrWillBeRawPtr<RTCDataChannel> RTCPeerConnection::createDataChannel(String label, const Dictionary& options, ExceptionState& exceptionState)
497 {
498 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
499 return nullptr;
500
501 blink::WebRTCDataChannelInit init;
502 options.get("ordered", init.ordered);
503 options.get("negotiated", init.negotiated);
504
505 unsigned short value = 0;
506 if (options.get("id", value))
507 init.id = value;
508 if (options.get("maxRetransmits", value))
509 init.maxRetransmits = value;
510 if (options.get("maxRetransmitTime", value))
511 init.maxRetransmitTime = value;
512
513 String protocolString;
514 options.get("protocol", protocolString);
515 init.protocol = protocolString;
516
517 RefPtrWillBeRawPtr<RTCDataChannel> channel = RTCDataChannel::create(executionContext(), this, m_peerHandler.get(), label, init, exceptionState);
518 if (exceptionState.hadException())
519 return nullptr;
520 m_dataChannels.append(channel);
521 return channel.release();
522 }
523
hasLocalStreamWithTrackId(const String & trackId)524 bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId)
525 {
526 for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
527 if ((*iter)->getTrackById(trackId))
528 return true;
529 }
530 return false;
531 }
532
createDTMFSender(PassRefPtrWillBeRawPtr<MediaStreamTrack> prpTrack,ExceptionState & exceptionState)533 PassRefPtrWillBeRawPtr<RTCDTMFSender> RTCPeerConnection::createDTMFSender(PassRefPtrWillBeRawPtr<MediaStreamTrack> prpTrack, ExceptionState& exceptionState)
534 {
535 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
536 return nullptr;
537
538 if (!prpTrack) {
539 exceptionState.throwTypeError(ExceptionMessages::argumentNullOrIncorrectType(1, "MediaStreamTrack"));
540 return nullptr;
541 }
542
543 RefPtrWillBeRawPtr<MediaStreamTrack> track = prpTrack;
544
545 if (!hasLocalStreamWithTrackId(track->id())) {
546 exceptionState.throwDOMException(SyntaxError, "No local stream is available for the track provided.");
547 return nullptr;
548 }
549
550 RefPtrWillBeRawPtr<RTCDTMFSender> dtmfSender = RTCDTMFSender::create(executionContext(), m_peerHandler.get(), track.release(), exceptionState);
551 if (exceptionState.hadException())
552 return nullptr;
553 return dtmfSender.release();
554 }
555
close(ExceptionState & exceptionState)556 void RTCPeerConnection::close(ExceptionState& exceptionState)
557 {
558 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
559 return;
560
561 m_peerHandler->stop();
562 m_closed = true;
563
564 changeIceConnectionState(ICEConnectionStateClosed);
565 changeIceGatheringState(ICEGatheringStateComplete);
566 changeSignalingState(SignalingStateClosed);
567 }
568
negotiationNeeded()569 void RTCPeerConnection::negotiationNeeded()
570 {
571 ASSERT(!m_closed);
572 scheduleDispatchEvent(Event::create(EventTypeNames::negotiationneeded));
573 }
574
didGenerateICECandidate(const blink::WebRTCICECandidate & webCandidate)575 void RTCPeerConnection::didGenerateICECandidate(const blink::WebRTCICECandidate& webCandidate)
576 {
577 ASSERT(!m_closed);
578 ASSERT(executionContext()->isContextThread());
579 if (webCandidate.isNull())
580 scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, nullptr));
581 else {
582 RefPtrWillBeRawPtr<RTCIceCandidate> iceCandidate = RTCIceCandidate::create(webCandidate);
583 scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCandidate.release()));
584 }
585 }
586
didChangeSignalingState(SignalingState newState)587 void RTCPeerConnection::didChangeSignalingState(SignalingState newState)
588 {
589 ASSERT(!m_closed);
590 ASSERT(executionContext()->isContextThread());
591 changeSignalingState(newState);
592 }
593
didChangeICEGatheringState(ICEGatheringState newState)594 void RTCPeerConnection::didChangeICEGatheringState(ICEGatheringState newState)
595 {
596 ASSERT(!m_closed);
597 ASSERT(executionContext()->isContextThread());
598 changeIceGatheringState(newState);
599 }
600
didChangeICEConnectionState(ICEConnectionState newState)601 void RTCPeerConnection::didChangeICEConnectionState(ICEConnectionState newState)
602 {
603 ASSERT(!m_closed);
604 ASSERT(executionContext()->isContextThread());
605 changeIceConnectionState(newState);
606 }
607
didAddRemoteStream(const blink::WebMediaStream & remoteStream)608 void RTCPeerConnection::didAddRemoteStream(const blink::WebMediaStream& remoteStream)
609 {
610 ASSERT(!m_closed);
611 ASSERT(executionContext()->isContextThread());
612
613 if (m_signalingState == SignalingStateClosed)
614 return;
615
616 RefPtrWillBeRawPtr<MediaStream> stream = MediaStream::create(executionContext(), remoteStream);
617 m_remoteStreams.append(stream);
618
619 scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::addstream, false, false, stream.release()));
620 }
621
didRemoveRemoteStream(const blink::WebMediaStream & remoteStream)622 void RTCPeerConnection::didRemoveRemoteStream(const blink::WebMediaStream& remoteStream)
623 {
624 ASSERT(!m_closed);
625 ASSERT(executionContext()->isContextThread());
626
627 MediaStreamDescriptor* streamDescriptor = remoteStream;
628 ASSERT(streamDescriptor->client());
629
630 RefPtrWillBeRawPtr<MediaStream> stream = static_cast<MediaStream*>(streamDescriptor->client());
631 stream->streamEnded();
632
633 if (m_signalingState == SignalingStateClosed)
634 return;
635
636 size_t pos = m_remoteStreams.find(stream);
637 ASSERT(pos != kNotFound);
638 m_remoteStreams.remove(pos);
639
640 scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::removestream, false, false, stream.release()));
641 }
642
didAddRemoteDataChannel(blink::WebRTCDataChannelHandler * handler)643 void RTCPeerConnection::didAddRemoteDataChannel(blink::WebRTCDataChannelHandler* handler)
644 {
645 ASSERT(!m_closed);
646 ASSERT(executionContext()->isContextThread());
647
648 if (m_signalingState == SignalingStateClosed)
649 return;
650
651 RefPtrWillBeRawPtr<RTCDataChannel> channel = RTCDataChannel::create(executionContext(), this, adoptPtr(handler));
652 m_dataChannels.append(channel);
653
654 scheduleDispatchEvent(RTCDataChannelEvent::create(EventTypeNames::datachannel, false, false, channel.release()));
655 }
656
releasePeerConnectionHandler()657 void RTCPeerConnection::releasePeerConnectionHandler()
658 {
659 stop();
660 }
661
interfaceName() const662 const AtomicString& RTCPeerConnection::interfaceName() const
663 {
664 return EventTargetNames::RTCPeerConnection;
665 }
666
executionContext() const667 ExecutionContext* RTCPeerConnection::executionContext() const
668 {
669 return ActiveDOMObject::executionContext();
670 }
671
suspend()672 void RTCPeerConnection::suspend()
673 {
674 m_dispatchScheduledEventRunner.suspend();
675 }
676
resume()677 void RTCPeerConnection::resume()
678 {
679 m_dispatchScheduledEventRunner.resume();
680 }
681
stop()682 void RTCPeerConnection::stop()
683 {
684 if (m_stopped)
685 return;
686
687 m_stopped = true;
688 m_iceConnectionState = ICEConnectionStateClosed;
689 m_signalingState = SignalingStateClosed;
690
691 WillBeHeapVector<RefPtrWillBeMember<RTCDataChannel> >::iterator i = m_dataChannels.begin();
692 for (; i != m_dataChannels.end(); ++i)
693 (*i)->stop();
694 m_dataChannels.clear();
695
696 m_dispatchScheduledEventRunner.stop();
697
698 m_peerHandler.clear();
699 }
700
changeSignalingState(SignalingState signalingState)701 void RTCPeerConnection::changeSignalingState(SignalingState signalingState)
702 {
703 if (m_signalingState != SignalingStateClosed && m_signalingState != signalingState) {
704 m_signalingState = signalingState;
705 scheduleDispatchEvent(Event::create(EventTypeNames::signalingstatechange));
706 }
707 }
708
changeIceGatheringState(ICEGatheringState iceGatheringState)709 void RTCPeerConnection::changeIceGatheringState(ICEGatheringState iceGatheringState)
710 {
711 m_iceGatheringState = iceGatheringState;
712 }
713
changeIceConnectionState(ICEConnectionState iceConnectionState)714 void RTCPeerConnection::changeIceConnectionState(ICEConnectionState iceConnectionState)
715 {
716 if (m_iceConnectionState != ICEConnectionStateClosed && m_iceConnectionState != iceConnectionState) {
717 m_iceConnectionState = iceConnectionState;
718 scheduleDispatchEvent(Event::create(EventTypeNames::iceconnectionstatechange));
719 }
720 }
721
scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)722 void RTCPeerConnection::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
723 {
724 m_scheduledEvents.append(event);
725
726 m_dispatchScheduledEventRunner.runAsync();
727 }
728
dispatchScheduledEvent()729 void RTCPeerConnection::dispatchScheduledEvent()
730 {
731 if (m_stopped)
732 return;
733
734 WillBeHeapVector<RefPtrWillBeMember<Event> > events;
735 events.swap(m_scheduledEvents);
736
737 WillBeHeapVector<RefPtrWillBeMember<Event> >::iterator it = events.begin();
738 for (; it != events.end(); ++it)
739 dispatchEvent((*it).release());
740
741 events.clear();
742 }
743
trace(Visitor * visitor)744 void RTCPeerConnection::trace(Visitor* visitor)
745 {
746 visitor->trace(m_localStreams);
747 visitor->trace(m_remoteStreams);
748 visitor->trace(m_dataChannels);
749 visitor->trace(m_scheduledEvents);
750 EventTargetWithInlineData::trace(visitor);
751 }
752
753 } // namespace WebCore
754