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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 359 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 380 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 395 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 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 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 464 MediaStreamVector RTCPeerConnection::getLocalStreams() const 465 { 466 return m_localStreams; 467 } 468 469 MediaStreamVector RTCPeerConnection::getRemoteStreams() const 470 { 471 return m_remoteStreams; 472 } 473 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 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 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 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 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 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 569 void RTCPeerConnection::negotiationNeeded() 570 { 571 ASSERT(!m_closed); 572 scheduleDispatchEvent(Event::create(EventTypeNames::negotiationneeded)); 573 } 574 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 587 void RTCPeerConnection::didChangeSignalingState(SignalingState newState) 588 { 589 ASSERT(!m_closed); 590 ASSERT(executionContext()->isContextThread()); 591 changeSignalingState(newState); 592 } 593 594 void RTCPeerConnection::didChangeICEGatheringState(ICEGatheringState newState) 595 { 596 ASSERT(!m_closed); 597 ASSERT(executionContext()->isContextThread()); 598 changeIceGatheringState(newState); 599 } 600 601 void RTCPeerConnection::didChangeICEConnectionState(ICEConnectionState newState) 602 { 603 ASSERT(!m_closed); 604 ASSERT(executionContext()->isContextThread()); 605 changeIceConnectionState(newState); 606 } 607 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 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 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 657 void RTCPeerConnection::releasePeerConnectionHandler() 658 { 659 stop(); 660 } 661 662 const AtomicString& RTCPeerConnection::interfaceName() const 663 { 664 return EventTargetNames::RTCPeerConnection; 665 } 666 667 ExecutionContext* RTCPeerConnection::executionContext() const 668 { 669 return ActiveDOMObject::executionContext(); 670 } 671 672 void RTCPeerConnection::suspend() 673 { 674 m_dispatchScheduledEventRunner.suspend(); 675 } 676 677 void RTCPeerConnection::resume() 678 { 679 m_dispatchScheduledEventRunner.resume(); 680 } 681 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 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 709 void RTCPeerConnection::changeIceGatheringState(ICEGatheringState iceGatheringState) 710 { 711 m_iceGatheringState = iceGatheringState; 712 } 713 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 722 void RTCPeerConnection::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event) 723 { 724 m_scheduledEvents.append(event); 725 726 m_dispatchScheduledEventRunner.runAsync(); 727 } 728 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 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