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 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 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 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 164 RTCPeerConnection::~RTCPeerConnection() 165 { 166 stop(); 167 } 168 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 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 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 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 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 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 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 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 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 319 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 340 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 355 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 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 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 428 MediaStreamVector RTCPeerConnection::getLocalStreams() const 429 { 430 return m_localStreams; 431 } 432 433 MediaStreamVector RTCPeerConnection::getRemoteStreams() const 434 { 435 return m_remoteStreams; 436 } 437 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 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 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 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 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 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 538 void RTCPeerConnection::negotiationNeeded() 539 { 540 scheduleDispatchEvent(Event::create(EventTypeNames::negotiationneeded)); 541 } 542 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 554 void RTCPeerConnection::didChangeSignalingState(SignalingState newState) 555 { 556 ASSERT(executionContext()->isContextThread()); 557 changeSignalingState(newState); 558 } 559 560 void RTCPeerConnection::didChangeIceGatheringState(IceGatheringState newState) 561 { 562 ASSERT(executionContext()->isContextThread()); 563 changeIceGatheringState(newState); 564 } 565 566 void RTCPeerConnection::didChangeIceConnectionState(IceConnectionState newState) 567 { 568 ASSERT(executionContext()->isContextThread()); 569 changeIceConnectionState(newState); 570 } 571 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 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 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 616 const AtomicString& RTCPeerConnection::interfaceName() const 617 { 618 return EventTargetNames::RTCPeerConnection; 619 } 620 621 ExecutionContext* RTCPeerConnection::executionContext() const 622 { 623 return ActiveDOMObject::executionContext(); 624 } 625 626 void RTCPeerConnection::suspend() 627 { 628 m_dispatchScheduledEventRunner.suspend(); 629 } 630 631 void RTCPeerConnection::resume() 632 { 633 m_dispatchScheduledEventRunner.resume(); 634 } 635 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 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 660 void RTCPeerConnection::changeIceGatheringState(IceGatheringState iceGatheringState) 661 { 662 m_iceGatheringState = iceGatheringState; 663 } 664 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 673 void RTCPeerConnection::scheduleDispatchEvent(PassRefPtr<Event> event) 674 { 675 m_scheduledEvents.append(event); 676 677 m_dispatchScheduledEventRunner.runAsync(); 678 } 679 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