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/ExceptionState.h"
     37 #include "core/dom/Document.h"
     38 #include "core/dom/Event.h"
     39 #include "core/dom/ExceptionCode.h"
     40 #include "core/dom/ScriptExecutionContext.h"
     41 #include "core/html/VoidCallback.h"
     42 #include "core/loader/FrameLoader.h"
     43 #include "core/loader/FrameLoaderClient.h"
     44 #include "core/page/Frame.h"
     45 #include "core/platform/mediastream/RTCConfiguration.h"
     46 #include "core/platform/mediastream/RTCDataChannelHandler.h"
     47 #include "modules/mediastream/MediaConstraintsImpl.h"
     48 #include "modules/mediastream/MediaStreamEvent.h"
     49 #include "modules/mediastream/RTCDTMFSender.h"
     50 #include "modules/mediastream/RTCDataChannel.h"
     51 #include "modules/mediastream/RTCDataChannelEvent.h"
     52 #include "modules/mediastream/RTCErrorCallback.h"
     53 #include "modules/mediastream/RTCIceCandidate.h"
     54 #include "modules/mediastream/RTCIceCandidateEvent.h"
     55 #include "modules/mediastream/RTCSessionDescription.h"
     56 #include "modules/mediastream/RTCSessionDescriptionCallback.h"
     57 #include "modules/mediastream/RTCSessionDescriptionRequestImpl.h"
     58 #include "modules/mediastream/RTCStatsCallback.h"
     59 #include "modules/mediastream/RTCStatsRequestImpl.h"
     60 #include "modules/mediastream/RTCVoidRequestImpl.h"
     61 #include "public/platform/WebRTCDataChannelInit.h"
     62 #include "public/platform/WebRTCICECandidate.h"
     63 #include "public/platform/WebRTCSessionDescription.h"
     64 
     65 namespace WebCore {
     66 
     67 PassRefPtr<RTCConfiguration> RTCPeerConnection::parseConfiguration(const Dictionary& configuration, ExceptionState& es)
     68 {
     69     if (configuration.isUndefinedOrNull())
     70         return 0;
     71 
     72     ArrayValue iceServers;
     73     bool ok = configuration.get("iceServers", iceServers);
     74     if (!ok || iceServers.isUndefinedOrNull()) {
     75         es.throwDOMException(TypeMismatchError);
     76         return 0;
     77     }
     78 
     79     size_t numberOfServers;
     80     ok = iceServers.length(numberOfServers);
     81     if (!ok) {
     82         es.throwDOMException(TypeMismatchError);
     83         return 0;
     84     }
     85 
     86     RefPtr<RTCConfiguration> rtcConfiguration = RTCConfiguration::create();
     87 
     88     for (size_t i = 0; i < numberOfServers; ++i) {
     89         Dictionary iceServer;
     90         ok = iceServers.get(i, iceServer);
     91         if (!ok) {
     92             es.throwDOMException(TypeMismatchError);
     93             return 0;
     94         }
     95 
     96         String urlString, username, credential;
     97         ok = iceServer.get("url", urlString);
     98         if (!ok) {
     99             es.throwDOMException(TypeMismatchError);
    100             return 0;
    101         }
    102         KURL url(KURL(), urlString);
    103         if (!url.isValid() || !(url.protocolIs("turn") || url.protocolIs("turns") || url.protocolIs("stun"))) {
    104             es.throwDOMException(TypeMismatchError);
    105             return 0;
    106         }
    107 
    108         iceServer.get("username", username);
    109         iceServer.get("credential", credential);
    110 
    111         rtcConfiguration->appendServer(RTCIceServer::create(url, username, credential));
    112     }
    113 
    114     return rtcConfiguration.release();
    115 }
    116 
    117 PassRefPtr<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext* context, const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& es)
    118 {
    119     RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, es);
    120     if (es.hadException())
    121         return 0;
    122 
    123     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, es);
    124     if (es.hadException())
    125         return 0;
    126 
    127     RefPtr<RTCPeerConnection> peerConnection = adoptRef(new RTCPeerConnection(context, configuration.release(), constraints.release(), es));
    128     peerConnection->suspendIfNeeded();
    129     if (es.hadException())
    130         return 0;
    131 
    132     return peerConnection.release();
    133 }
    134 
    135 RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext* context, PassRefPtr<RTCConfiguration> configuration, PassRefPtr<MediaConstraints> constraints, ExceptionState& es)
    136     : ActiveDOMObject(context)
    137     , m_signalingState(SignalingStateStable)
    138     , m_iceGatheringState(IceGatheringStateNew)
    139     , m_iceConnectionState(IceConnectionStateNew)
    140     , m_scheduledEventTimer(this, &RTCPeerConnection::scheduledEventTimerFired)
    141     , m_stopped(false)
    142 {
    143     ScriptWrappable::init(this);
    144     Document* document = toDocument(scriptExecutionContext());
    145 
    146     if (!document->frame()) {
    147         es.throwDOMException(NotSupportedError);
    148         return;
    149     }
    150 
    151     m_peerHandler = RTCPeerConnectionHandler::create(this);
    152     if (!m_peerHandler) {
    153         es.throwDOMException(NotSupportedError);
    154         return;
    155     }
    156 
    157     document->frame()->loader()->client()->dispatchWillStartUsingPeerConnectionHandler(m_peerHandler.get());
    158 
    159     if (!m_peerHandler->initialize(configuration, constraints)) {
    160         es.throwDOMException(NotSupportedError);
    161         return;
    162     }
    163 }
    164 
    165 RTCPeerConnection::~RTCPeerConnection()
    166 {
    167     stop();
    168 }
    169 
    170 void RTCPeerConnection::createOffer(PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionState& es)
    171 {
    172     if (m_signalingState == SignalingStateClosed) {
    173         es.throwDOMException(InvalidStateError);
    174         return;
    175     }
    176 
    177     if (!successCallback) {
    178         es.throwDOMException(TypeMismatchError);
    179         return;
    180     }
    181 
    182     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, es);
    183     if (es.hadException())
    184         return;
    185 
    186     RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
    187     m_peerHandler->createOffer(request.release(), constraints);
    188 }
    189 
    190 void RTCPeerConnection::createAnswer(PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionState& es)
    191 {
    192     if (m_signalingState == SignalingStateClosed) {
    193         es.throwDOMException(InvalidStateError);
    194         return;
    195     }
    196 
    197     if (!successCallback) {
    198         es.throwDOMException(TypeMismatchError);
    199         return;
    200     }
    201 
    202     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, es);
    203     if (es.hadException())
    204         return;
    205 
    206     RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
    207     m_peerHandler->createAnswer(request.release(), constraints.release());
    208 }
    209 
    210 void RTCPeerConnection::setLocalDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCErrorCallback> errorCallback, ExceptionState& es)
    211 {
    212     if (m_signalingState == SignalingStateClosed) {
    213         es.throwDOMException(InvalidStateError);
    214         return;
    215     }
    216 
    217     RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
    218     if (!sessionDescription) {
    219         es.throwDOMException(TypeMismatchError);
    220         return;
    221     }
    222 
    223     RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
    224     m_peerHandler->setLocalDescription(request.release(), sessionDescription->webSessionDescription());
    225 }
    226 
    227 PassRefPtr<RTCSessionDescription> RTCPeerConnection::localDescription(ExceptionState& es)
    228 {
    229     WebKit::WebRTCSessionDescription webSessionDescription = m_peerHandler->localDescription();
    230     if (webSessionDescription.isNull())
    231         return 0;
    232 
    233     RefPtr<RTCSessionDescription> sessionDescription = RTCSessionDescription::create(webSessionDescription);
    234     return sessionDescription.release();
    235 }
    236 
    237 void RTCPeerConnection::setRemoteDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCErrorCallback> errorCallback, ExceptionState& es)
    238 {
    239     if (m_signalingState == SignalingStateClosed) {
    240         es.throwDOMException(InvalidStateError);
    241         return;
    242     }
    243 
    244     RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
    245     if (!sessionDescription) {
    246         es.throwDOMException(TypeMismatchError);
    247         return;
    248     }
    249 
    250     RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
    251     m_peerHandler->setRemoteDescription(request.release(), sessionDescription->webSessionDescription());
    252 }
    253 
    254 PassRefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription(ExceptionState& es)
    255 {
    256     WebKit::WebRTCSessionDescription webSessionDescription = m_peerHandler->remoteDescription();
    257     if (webSessionDescription.isNull())
    258         return 0;
    259 
    260     RefPtr<RTCSessionDescription> desc = RTCSessionDescription::create(webSessionDescription);
    261     return desc.release();
    262 }
    263 
    264 void RTCPeerConnection::updateIce(const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& es)
    265 {
    266     if (m_signalingState == SignalingStateClosed) {
    267         es.throwDOMException(InvalidStateError);
    268         return;
    269     }
    270 
    271     RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, es);
    272     if (es.hadException())
    273         return;
    274 
    275     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, es);
    276     if (es.hadException())
    277         return;
    278 
    279     bool valid = m_peerHandler->updateIce(configuration, constraints);
    280     if (!valid)
    281         es.throwDOMException(SyntaxError);
    282 }
    283 
    284 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, ExceptionState& es)
    285 {
    286     if (m_signalingState == SignalingStateClosed) {
    287         es.throwDOMException(InvalidStateError);
    288         return;
    289     }
    290 
    291     if (!iceCandidate) {
    292         es.throwDOMException(TypeMismatchError);
    293         return;
    294     }
    295 
    296     bool valid = m_peerHandler->addIceCandidate(iceCandidate->webCandidate());
    297     if (!valid)
    298         es.throwDOMException(SyntaxError);
    299 }
    300 
    301 String RTCPeerConnection::signalingState() const
    302 {
    303     switch (m_signalingState) {
    304     case SignalingStateStable:
    305         return "stable";
    306     case SignalingStateHaveLocalOffer:
    307         return "have-local-offer";
    308     case SignalingStateHaveRemoteOffer:
    309         return "have-remote-offer";
    310     case SignalingStateHaveLocalPrAnswer:
    311         return "have-local-pranswer";
    312     case SignalingStateHaveRemotePrAnswer:
    313         return "have-remote-pranswer";
    314     case SignalingStateClosed:
    315         return "closed";
    316     }
    317 
    318     ASSERT_NOT_REACHED();
    319     return String();
    320 }
    321 
    322 String RTCPeerConnection::iceGatheringState() const
    323 {
    324     switch (m_iceGatheringState) {
    325     case IceGatheringStateNew:
    326         return "new";
    327     case IceGatheringStateGathering:
    328         return "gathering";
    329     case IceGatheringStateComplete:
    330         return "complete";
    331     }
    332 
    333     ASSERT_NOT_REACHED();
    334     return String();
    335 }
    336 
    337 String RTCPeerConnection::iceConnectionState() const
    338 {
    339     switch (m_iceConnectionState) {
    340     case IceConnectionStateNew:
    341         return "new";
    342     case IceConnectionStateChecking:
    343         return "checking";
    344     case IceConnectionStateConnected:
    345         return "connected";
    346     case IceConnectionStateCompleted:
    347         return "completed";
    348     case IceConnectionStateFailed:
    349         return "failed";
    350     case IceConnectionStateDisconnected:
    351         return "disconnected";
    352     case IceConnectionStateClosed:
    353         return "closed";
    354     }
    355 
    356     ASSERT_NOT_REACHED();
    357     return String();
    358 }
    359 
    360 void RTCPeerConnection::addStream(PassRefPtr<MediaStream> prpStream, const Dictionary& mediaConstraints, ExceptionState& es)
    361 {
    362     if (m_signalingState == SignalingStateClosed) {
    363         es.throwDOMException(InvalidStateError);
    364         return;
    365     }
    366 
    367     RefPtr<MediaStream> stream = prpStream;
    368     if (!stream) {
    369         es.throwDOMException(TypeMismatchError);
    370         return;
    371     }
    372 
    373     if (m_localStreams.contains(stream))
    374         return;
    375 
    376     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, es);
    377     if (es.hadException())
    378         return;
    379 
    380     m_localStreams.append(stream);
    381 
    382     bool valid = m_peerHandler->addStream(stream->descriptor(), constraints);
    383     if (!valid)
    384         es.throwDOMException(SyntaxError);
    385 }
    386 
    387 void RTCPeerConnection::removeStream(PassRefPtr<MediaStream> prpStream, ExceptionState& es)
    388 {
    389     if (m_signalingState == SignalingStateClosed) {
    390         es.throwDOMException(InvalidStateError);
    391         return;
    392     }
    393 
    394     if (!prpStream) {
    395         es.throwDOMException(TypeMismatchError);
    396         return;
    397     }
    398 
    399     RefPtr<MediaStream> stream = prpStream;
    400 
    401     size_t pos = m_localStreams.find(stream);
    402     if (pos == notFound)
    403         return;
    404 
    405     m_localStreams.remove(pos);
    406 
    407     m_peerHandler->removeStream(stream->descriptor());
    408 }
    409 
    410 MediaStreamVector RTCPeerConnection::getLocalStreams() const
    411 {
    412     return m_localStreams;
    413 }
    414 
    415 MediaStreamVector RTCPeerConnection::getRemoteStreams() const
    416 {
    417     return m_remoteStreams;
    418 }
    419 
    420 MediaStream* RTCPeerConnection::getStreamById(const String& streamId)
    421 {
    422     for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
    423         if ((*iter)->id() == streamId)
    424             return iter->get();
    425     }
    426 
    427     for (MediaStreamVector::iterator iter = m_remoteStreams.begin(); iter != m_remoteStreams.end(); ++iter) {
    428         if ((*iter)->id() == streamId)
    429             return iter->get();
    430     }
    431 
    432     return 0;
    433 }
    434 
    435 void RTCPeerConnection::getStats(PassRefPtr<RTCStatsCallback> successCallback, PassRefPtr<MediaStreamTrack> selector)
    436 {
    437     RefPtr<RTCStatsRequestImpl> statsRequest = RTCStatsRequestImpl::create(scriptExecutionContext(), successCallback, selector);
    438     // FIXME: Add passing selector as part of the statsRequest.
    439     m_peerHandler->getStats(statsRequest.release());
    440 }
    441 
    442 PassRefPtr<RTCDataChannel> RTCPeerConnection::createDataChannel(String label, const Dictionary& options, ExceptionState& es)
    443 {
    444     if (m_signalingState == SignalingStateClosed) {
    445         es.throwDOMException(InvalidStateError);
    446         return 0;
    447     }
    448 
    449     WebKit::WebRTCDataChannelInit init;
    450     options.get("ordered", init.ordered);
    451     options.get("negotiated", init.negotiated);
    452 
    453     unsigned short value = 0;
    454     if (options.get("id", value))
    455         init.id = value;
    456     if (options.get("maxRetransmits", value))
    457         init.maxRetransmits = value;
    458     if (options.get("maxRetransmitTime", value))
    459         init.maxRetransmitTime = value;
    460 
    461     String protocolString;
    462     options.get("protocol", protocolString);
    463     init.protocol = protocolString;
    464 
    465     RefPtr<RTCDataChannel> channel = RTCDataChannel::create(scriptExecutionContext(), m_peerHandler.get(), label, init, es);
    466     if (es.hadException())
    467         return 0;
    468     m_dataChannels.append(channel);
    469     return channel.release();
    470 }
    471 
    472 bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId)
    473 {
    474     for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
    475         if ((*iter)->getTrackById(trackId))
    476             return true;
    477     }
    478     return false;
    479 }
    480 
    481 PassRefPtr<RTCDTMFSender> RTCPeerConnection::createDTMFSender(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionState& es)
    482 {
    483     if (m_signalingState == SignalingStateClosed) {
    484         es.throwDOMException(InvalidStateError);
    485         return 0;
    486     }
    487 
    488     if (!prpTrack) {
    489         es.throwTypeError();
    490         return 0;
    491     }
    492 
    493     RefPtr<MediaStreamTrack> track = prpTrack;
    494 
    495     if (!hasLocalStreamWithTrackId(track->id())) {
    496         es.throwDOMException(SyntaxError);
    497         return 0;
    498     }
    499 
    500     RefPtr<RTCDTMFSender> dtmfSender = RTCDTMFSender::create(scriptExecutionContext(), m_peerHandler.get(), track.release(), es);
    501     if (es.hadException())
    502         return 0;
    503     return dtmfSender.release();
    504 }
    505 
    506 void RTCPeerConnection::close(ExceptionState& es)
    507 {
    508     if (m_signalingState == SignalingStateClosed) {
    509         es.throwDOMException(InvalidStateError);
    510         return;
    511     }
    512 
    513     m_peerHandler->stop();
    514 
    515     changeIceConnectionState(IceConnectionStateClosed);
    516     changeIceGatheringState(IceGatheringStateComplete);
    517     changeSignalingState(SignalingStateClosed);
    518 }
    519 
    520 void RTCPeerConnection::negotiationNeeded()
    521 {
    522     scheduleDispatchEvent(Event::create(eventNames().negotiationneededEvent, false, false));
    523 }
    524 
    525 void RTCPeerConnection::didGenerateIceCandidate(WebKit::WebRTCICECandidate webCandidate)
    526 {
    527     ASSERT(scriptExecutionContext()->isContextThread());
    528     if (webCandidate.isNull())
    529         scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, 0));
    530     else {
    531         RefPtr<RTCIceCandidate> iceCandidate = RTCIceCandidate::create(webCandidate);
    532         scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCandidate.release()));
    533     }
    534 }
    535 
    536 void RTCPeerConnection::didChangeSignalingState(SignalingState newState)
    537 {
    538     ASSERT(scriptExecutionContext()->isContextThread());
    539     changeSignalingState(newState);
    540 }
    541 
    542 void RTCPeerConnection::didChangeIceGatheringState(IceGatheringState newState)
    543 {
    544     ASSERT(scriptExecutionContext()->isContextThread());
    545     changeIceGatheringState(newState);
    546 }
    547 
    548 void RTCPeerConnection::didChangeIceConnectionState(IceConnectionState newState)
    549 {
    550     ASSERT(scriptExecutionContext()->isContextThread());
    551     changeIceConnectionState(newState);
    552 }
    553 
    554 void RTCPeerConnection::didAddRemoteStream(PassRefPtr<MediaStreamDescriptor> streamDescriptor)
    555 {
    556     ASSERT(scriptExecutionContext()->isContextThread());
    557 
    558     if (m_signalingState == SignalingStateClosed)
    559         return;
    560 
    561     RefPtr<MediaStream> stream = MediaStream::create(scriptExecutionContext(), streamDescriptor);
    562     m_remoteStreams.append(stream);
    563 
    564     scheduleDispatchEvent(MediaStreamEvent::create(eventNames().addstreamEvent, false, false, stream.release()));
    565 }
    566 
    567 void RTCPeerConnection::didRemoveRemoteStream(MediaStreamDescriptor* streamDescriptor)
    568 {
    569     ASSERT(scriptExecutionContext()->isContextThread());
    570     ASSERT(streamDescriptor->client());
    571 
    572     RefPtr<MediaStream> stream = static_cast<MediaStream*>(streamDescriptor->client());
    573     stream->streamEnded();
    574 
    575     if (m_signalingState == SignalingStateClosed)
    576         return;
    577 
    578     size_t pos = m_remoteStreams.find(stream);
    579     ASSERT(pos != notFound);
    580     m_remoteStreams.remove(pos);
    581 
    582     scheduleDispatchEvent(MediaStreamEvent::create(eventNames().removestreamEvent, false, false, stream.release()));
    583 }
    584 
    585 void RTCPeerConnection::didAddRemoteDataChannel(PassOwnPtr<RTCDataChannelHandler> handler)
    586 {
    587     ASSERT(scriptExecutionContext()->isContextThread());
    588 
    589     if (m_signalingState == SignalingStateClosed)
    590         return;
    591 
    592     RefPtr<RTCDataChannel> channel = RTCDataChannel::create(scriptExecutionContext(), handler);
    593     m_dataChannels.append(channel);
    594 
    595     scheduleDispatchEvent(RTCDataChannelEvent::create(eventNames().datachannelEvent, false, false, channel.release()));
    596 }
    597 
    598 const AtomicString& RTCPeerConnection::interfaceName() const
    599 {
    600     return eventNames().interfaceForRTCPeerConnection;
    601 }
    602 
    603 ScriptExecutionContext* RTCPeerConnection::scriptExecutionContext() const
    604 {
    605     return ActiveDOMObject::scriptExecutionContext();
    606 }
    607 
    608 void RTCPeerConnection::stop()
    609 {
    610     if (m_stopped)
    611         return;
    612 
    613     m_stopped = true;
    614     m_iceConnectionState = IceConnectionStateClosed;
    615     m_signalingState = SignalingStateClosed;
    616 
    617     Vector<RefPtr<RTCDataChannel> >::iterator i = m_dataChannels.begin();
    618     for (; i != m_dataChannels.end(); ++i)
    619         (*i)->stop();
    620 }
    621 
    622 EventTargetData* RTCPeerConnection::eventTargetData()
    623 {
    624     return &m_eventTargetData;
    625 }
    626 
    627 EventTargetData* RTCPeerConnection::ensureEventTargetData()
    628 {
    629     return &m_eventTargetData;
    630 }
    631 
    632 void RTCPeerConnection::changeSignalingState(SignalingState signalingState)
    633 {
    634     if (m_signalingState != SignalingStateClosed && m_signalingState != signalingState) {
    635         m_signalingState = signalingState;
    636         scheduleDispatchEvent(Event::create(eventNames().signalingstatechangeEvent, false, false));
    637     }
    638 }
    639 
    640 void RTCPeerConnection::changeIceGatheringState(IceGatheringState iceGatheringState)
    641 {
    642     m_iceGatheringState = iceGatheringState;
    643 }
    644 
    645 void RTCPeerConnection::changeIceConnectionState(IceConnectionState iceConnectionState)
    646 {
    647     if (m_iceConnectionState != IceConnectionStateClosed && m_iceConnectionState != iceConnectionState) {
    648         m_iceConnectionState = iceConnectionState;
    649         scheduleDispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, false, false));
    650     }
    651 }
    652 
    653 void RTCPeerConnection::scheduleDispatchEvent(PassRefPtr<Event> event)
    654 {
    655     m_scheduledEvents.append(event);
    656 
    657     if (!m_scheduledEventTimer.isActive())
    658         m_scheduledEventTimer.startOneShot(0);
    659 }
    660 
    661 void RTCPeerConnection::scheduledEventTimerFired(Timer<RTCPeerConnection>*)
    662 {
    663     if (m_stopped)
    664         return;
    665 
    666     Vector<RefPtr<Event> > events;
    667     events.swap(m_scheduledEvents);
    668 
    669     Vector<RefPtr<Event> >::iterator it = events.begin();
    670     for (; it != events.end(); ++it)
    671         dispatchEvent((*it).release());
    672 
    673     events.clear();
    674 }
    675 
    676 } // namespace WebCore
    677