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