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 70namespace WebCore { 71 72namespace { 73 74static 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 86PassRefPtr<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 160PassRefPtrWillBeRawPtr<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 178RTCPeerConnection::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 217RTCPeerConnection::~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 228void 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 243void 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 258void 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 273PassRefPtrWillBeRawPtr<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 282void 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 297PassRefPtrWillBeRawPtr<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 306void 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 324void 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 339void 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 359String 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 380String 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 395String 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 418void 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 443void 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 464MediaStreamVector RTCPeerConnection::getLocalStreams() const 465{ 466 return m_localStreams; 467} 468 469MediaStreamVector RTCPeerConnection::getRemoteStreams() const 470{ 471 return m_remoteStreams; 472} 473 474MediaStream* 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 489void 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 496PassRefPtrWillBeRawPtr<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 524bool 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 533PassRefPtrWillBeRawPtr<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 556void 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 569void RTCPeerConnection::negotiationNeeded() 570{ 571 ASSERT(!m_closed); 572 scheduleDispatchEvent(Event::create(EventTypeNames::negotiationneeded)); 573} 574 575void 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 587void RTCPeerConnection::didChangeSignalingState(SignalingState newState) 588{ 589 ASSERT(!m_closed); 590 ASSERT(executionContext()->isContextThread()); 591 changeSignalingState(newState); 592} 593 594void RTCPeerConnection::didChangeICEGatheringState(ICEGatheringState newState) 595{ 596 ASSERT(!m_closed); 597 ASSERT(executionContext()->isContextThread()); 598 changeIceGatheringState(newState); 599} 600 601void RTCPeerConnection::didChangeICEConnectionState(ICEConnectionState newState) 602{ 603 ASSERT(!m_closed); 604 ASSERT(executionContext()->isContextThread()); 605 changeIceConnectionState(newState); 606} 607 608void 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 622void 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 643void 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 657void RTCPeerConnection::releasePeerConnectionHandler() 658{ 659 stop(); 660} 661 662const AtomicString& RTCPeerConnection::interfaceName() const 663{ 664 return EventTargetNames::RTCPeerConnection; 665} 666 667ExecutionContext* RTCPeerConnection::executionContext() const 668{ 669 return ActiveDOMObject::executionContext(); 670} 671 672void RTCPeerConnection::suspend() 673{ 674 m_dispatchScheduledEventRunner.suspend(); 675} 676 677void RTCPeerConnection::resume() 678{ 679 m_dispatchScheduledEventRunner.resume(); 680} 681 682void 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 701void 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 709void RTCPeerConnection::changeIceGatheringState(ICEGatheringState iceGatheringState) 710{ 711 m_iceGatheringState = iceGatheringState; 712} 713 714void 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 722void RTCPeerConnection::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event) 723{ 724 m_scheduledEvents.append(event); 725 726 m_dispatchScheduledEventRunner.runAsync(); 727} 728 729void 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 744void 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