Home | History | Annotate | Download | only in mediastream
      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