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