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/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