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  * 1.  Redistributions of source code must retain the above copyright
      8  *     notice, this list of conditions and the following disclaimer.
      9  * 2.  Redistributions in binary form must reproduce the above copyright
     10  *     notice, this list of conditions and the following disclaimer in the
     11  *     documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 #include "modules/mediastream/RTCDataChannel.h"
     27 
     28 #include "bindings/v8/ExceptionState.h"
     29 #include "core/dom/ExceptionCode.h"
     30 #include "core/dom/ExecutionContext.h"
     31 #include "core/events/MessageEvent.h"
     32 #include "core/fileapi/Blob.h"
     33 #include "public/platform/WebRTCPeerConnectionHandler.h"
     34 #include "wtf/ArrayBuffer.h"
     35 #include "wtf/ArrayBufferView.h"
     36 
     37 namespace WebCore {
     38 
     39 static void throwNotOpenException(ExceptionState& exceptionState)
     40 {
     41     exceptionState.throwDOMException(InvalidStateError, "RTCDataChannel.readyState is not 'open'");
     42 }
     43 
     44 static void throwCouldNotSendDataException(ExceptionState& exceptionState)
     45 {
     46     exceptionState.throwDOMException(NetworkError, "Could not send data");
     47 }
     48 
     49 static void throwNoBlobSupportException(ExceptionState& exceptionState)
     50 {
     51     exceptionState.throwDOMException(NotSupportedError, "Blob support not implemented yet");
     52 }
     53 
     54 PassRefPtrWillBeRawPtr<RTCDataChannel> RTCDataChannel::create(ExecutionContext* context, RTCPeerConnection* connection, PassOwnPtr<blink::WebRTCDataChannelHandler> handler)
     55 {
     56     ASSERT(handler);
     57     return adoptRefWillBeRefCountedGarbageCollected(new RTCDataChannel(context, connection, handler));
     58 }
     59 
     60 PassRefPtrWillBeRawPtr<RTCDataChannel> RTCDataChannel::create(ExecutionContext* context, RTCPeerConnection* connection, blink::WebRTCPeerConnectionHandler* peerConnectionHandler, const String& label, const blink::WebRTCDataChannelInit& init, ExceptionState& exceptionState)
     61 {
     62     OwnPtr<blink::WebRTCDataChannelHandler> handler = adoptPtr(peerConnectionHandler->createDataChannel(label, init));
     63     if (!handler) {
     64         exceptionState.throwDOMException(NotSupportedError, "RTCDataChannel is not supported");
     65         return nullptr;
     66     }
     67     return adoptRefWillBeRefCountedGarbageCollected(new RTCDataChannel(context, connection, handler.release()));
     68 }
     69 
     70 RTCDataChannel::RTCDataChannel(ExecutionContext* context, RTCPeerConnection* connection, PassOwnPtr<blink::WebRTCDataChannelHandler> handler)
     71     : m_executionContext(context)
     72     , m_handler(handler)
     73     , m_stopped(false)
     74     , m_readyState(ReadyStateConnecting)
     75     , m_binaryType(BinaryTypeArrayBuffer)
     76     , m_scheduledEventTimer(this, &RTCDataChannel::scheduledEventTimerFired)
     77 #if ENABLE(OILPAN)
     78     , m_connection(connection)
     79 #endif
     80 {
     81     ScriptWrappable::init(this);
     82     m_handler->setClient(this);
     83 }
     84 
     85 RTCDataChannel::~RTCDataChannel()
     86 {
     87 #if ENABLE(OILPAN)
     88     // If the peer connection and the data channel die in the same
     89     // GC cycle stop has not been called and we need to notify the
     90     // client that the channel is gone.
     91     if (!m_stopped)
     92         m_handler->setClient(0);
     93 #else
     94     ASSERT(m_stopped);
     95 #endif
     96 }
     97 
     98 String RTCDataChannel::label() const
     99 {
    100     return m_handler->label();
    101 }
    102 
    103 bool RTCDataChannel::reliable() const
    104 {
    105     return m_handler->isReliable();
    106 }
    107 
    108 bool RTCDataChannel::ordered() const
    109 {
    110     return m_handler->ordered();
    111 }
    112 
    113 unsigned short RTCDataChannel::maxRetransmitTime() const
    114 {
    115     return m_handler->maxRetransmitTime();
    116 }
    117 
    118 unsigned short RTCDataChannel::maxRetransmits() const
    119 {
    120     return m_handler->maxRetransmits();
    121 }
    122 
    123 String RTCDataChannel::protocol() const
    124 {
    125     return m_handler->protocol();
    126 }
    127 
    128 bool RTCDataChannel::negotiated() const
    129 {
    130     return m_handler->negotiated();
    131 }
    132 
    133 unsigned short RTCDataChannel::id() const
    134 {
    135     return m_handler->id();
    136 }
    137 
    138 String RTCDataChannel::readyState() const
    139 {
    140     switch (m_readyState) {
    141     case ReadyStateConnecting:
    142         return "connecting";
    143     case ReadyStateOpen:
    144         return "open";
    145     case ReadyStateClosing:
    146         return "closing";
    147     case ReadyStateClosed:
    148         return "closed";
    149     }
    150 
    151     ASSERT_NOT_REACHED();
    152     return String();
    153 }
    154 
    155 unsigned long RTCDataChannel::bufferedAmount() const
    156 {
    157     return m_handler->bufferedAmount();
    158 }
    159 
    160 String RTCDataChannel::binaryType() const
    161 {
    162     switch (m_binaryType) {
    163     case BinaryTypeBlob:
    164         return "blob";
    165     case BinaryTypeArrayBuffer:
    166         return "arraybuffer";
    167     }
    168     ASSERT_NOT_REACHED();
    169     return String();
    170 }
    171 
    172 void RTCDataChannel::setBinaryType(const String& binaryType, ExceptionState& exceptionState)
    173 {
    174     if (binaryType == "blob")
    175         throwNoBlobSupportException(exceptionState);
    176     else if (binaryType == "arraybuffer")
    177         m_binaryType = BinaryTypeArrayBuffer;
    178     else
    179         exceptionState.throwDOMException(TypeMismatchError, "Unknown binary type : " + binaryType);
    180 }
    181 
    182 void RTCDataChannel::send(const String& data, ExceptionState& exceptionState)
    183 {
    184     if (m_readyState != ReadyStateOpen) {
    185         throwNotOpenException(exceptionState);
    186         return;
    187     }
    188     if (!m_handler->sendStringData(data)) {
    189         // FIXME: This should not throw an exception but instead forcefully close the data channel.
    190         throwCouldNotSendDataException(exceptionState);
    191     }
    192 }
    193 
    194 void RTCDataChannel::send(PassRefPtr<ArrayBuffer> prpData, ExceptionState& exceptionState)
    195 {
    196     if (m_readyState != ReadyStateOpen) {
    197         throwNotOpenException(exceptionState);
    198         return;
    199     }
    200 
    201     RefPtr<ArrayBuffer> data = prpData;
    202 
    203     size_t dataLength = data->byteLength();
    204     if (!dataLength)
    205         return;
    206 
    207     if (!m_handler->sendRawData(static_cast<const char*>((data->data())), dataLength)) {
    208         // FIXME: This should not throw an exception but instead forcefully close the data channel.
    209         throwCouldNotSendDataException(exceptionState);
    210     }
    211 }
    212 
    213 void RTCDataChannel::send(PassRefPtr<ArrayBufferView> data, ExceptionState& exceptionState)
    214 {
    215     if (!m_handler->sendRawData(static_cast<const char*>(data->baseAddress()), data->byteLength())) {
    216         // FIXME: This should not throw an exception but instead forcefully close the data channel.
    217         throwCouldNotSendDataException(exceptionState);
    218     }
    219 }
    220 
    221 void RTCDataChannel::send(PassRefPtrWillBeRawPtr<Blob> data, ExceptionState& exceptionState)
    222 {
    223     // FIXME: implement
    224     throwNoBlobSupportException(exceptionState);
    225 }
    226 
    227 void RTCDataChannel::close()
    228 {
    229     if (m_stopped)
    230         return;
    231 
    232     m_handler->close();
    233 }
    234 
    235 void RTCDataChannel::didChangeReadyState(blink::WebRTCDataChannelHandlerClient::ReadyState newState)
    236 {
    237     if (m_stopped || m_readyState == ReadyStateClosed)
    238         return;
    239 
    240     m_readyState = newState;
    241 
    242     switch (m_readyState) {
    243     case ReadyStateOpen:
    244         scheduleDispatchEvent(Event::create(EventTypeNames::open));
    245         break;
    246     case ReadyStateClosed:
    247         scheduleDispatchEvent(Event::create(EventTypeNames::close));
    248         break;
    249     default:
    250         break;
    251     }
    252 }
    253 
    254 void RTCDataChannel::didReceiveStringData(const blink::WebString& text)
    255 {
    256     if (m_stopped)
    257         return;
    258 
    259     scheduleDispatchEvent(MessageEvent::create(text));
    260 }
    261 
    262 void RTCDataChannel::didReceiveRawData(const char* data, size_t dataLength)
    263 {
    264     if (m_stopped)
    265         return;
    266 
    267     if (m_binaryType == BinaryTypeBlob) {
    268         // FIXME: Implement.
    269         return;
    270     }
    271     if (m_binaryType == BinaryTypeArrayBuffer) {
    272         RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(data, dataLength);
    273         scheduleDispatchEvent(MessageEvent::create(buffer.release()));
    274         return;
    275     }
    276     ASSERT_NOT_REACHED();
    277 }
    278 
    279 void RTCDataChannel::didDetectError()
    280 {
    281     if (m_stopped)
    282         return;
    283 
    284     scheduleDispatchEvent(Event::create(EventTypeNames::error));
    285 }
    286 
    287 const AtomicString& RTCDataChannel::interfaceName() const
    288 {
    289     return EventTargetNames::RTCDataChannel;
    290 }
    291 
    292 ExecutionContext* RTCDataChannel::executionContext() const
    293 {
    294     return m_executionContext;
    295 }
    296 
    297 void RTCDataChannel::stop()
    298 {
    299     m_stopped = true;
    300     m_readyState = ReadyStateClosed;
    301     m_handler->setClient(0);
    302     m_executionContext = 0;
    303 }
    304 
    305 void RTCDataChannel::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
    306 {
    307     m_scheduledEvents.append(event);
    308 
    309     if (!m_scheduledEventTimer.isActive())
    310         m_scheduledEventTimer.startOneShot(0, FROM_HERE);
    311 }
    312 
    313 void RTCDataChannel::scheduledEventTimerFired(Timer<RTCDataChannel>*)
    314 {
    315     if (m_stopped)
    316         return;
    317 
    318     WillBeHeapVector<RefPtrWillBeMember<Event> > events;
    319     events.swap(m_scheduledEvents);
    320 
    321     WillBeHeapVector<RefPtrWillBeMember<Event> >::iterator it = events.begin();
    322     for (; it != events.end(); ++it)
    323         dispatchEvent((*it).release());
    324 
    325     events.clear();
    326 }
    327 
    328 #if ENABLE(OILPAN)
    329 void RTCDataChannel::clearWeakMembers(Visitor* visitor)
    330 {
    331     if (visitor->isAlive(m_connection))
    332         return;
    333     stop();
    334     m_connection = nullptr;
    335 }
    336 #endif
    337 
    338 void RTCDataChannel::trace(Visitor* visitor)
    339 {
    340 #if ENABLE(OILPAN)
    341     visitor->trace(m_scheduledEvents);
    342     visitor->registerWeakMembers<RTCDataChannel, &RTCDataChannel::clearWeakMembers>(this);
    343 #endif
    344     EventTargetWithInlineData::trace(visitor);
    345 }
    346 
    347 } // namespace WebCore
    348