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/events/Event.h"
     30 #include "core/dom/ExceptionCode.h"
     31 #include "core/dom/ExecutionContext.h"
     32 #include "core/events/MessageEvent.h"
     33 #include "core/fileapi/Blob.h"
     34 #include "core/platform/mediastream/RTCDataChannelHandler.h"
     35 #include "core/platform/mediastream/RTCPeerConnectionHandler.h"
     36 #include "wtf/ArrayBuffer.h"
     37 #include "wtf/ArrayBufferView.h"
     38 
     39 namespace WebCore {
     40 
     41 static void throwNotOpenException(ExceptionState& exceptionState)
     42 {
     43     exceptionState.throwDOMException(InvalidStateError, "RTCDataChannel.readyState is not 'open'");
     44 }
     45 
     46 static void throwCouldNotSendDataException(ExceptionState& exceptionState)
     47 {
     48     exceptionState.throwDOMException(NetworkError, "Could not send data");
     49 }
     50 
     51 static void throwNoBlobSupportException(ExceptionState& exceptionState)
     52 {
     53     exceptionState.throwDOMException(NotSupportedError, "Blob support not implemented yet");
     54 }
     55 
     56 PassRefPtr<RTCDataChannel> RTCDataChannel::create(ExecutionContext* context, PassOwnPtr<RTCDataChannelHandler> handler)
     57 {
     58     ASSERT(handler);
     59     return adoptRef(new RTCDataChannel(context, handler));
     60 }
     61 
     62 PassRefPtr<RTCDataChannel> RTCDataChannel::create(ExecutionContext* context, RTCPeerConnectionHandler* peerConnectionHandler, const String& label, const blink::WebRTCDataChannelInit& init, ExceptionState& exceptionState)
     63 {
     64     OwnPtr<RTCDataChannelHandler> handler = peerConnectionHandler->createDataChannel(label, init);
     65     if (!handler) {
     66         exceptionState.throwDOMException(NotSupportedError, "RTCDataChannel is not supported");
     67         return 0;
     68     }
     69     return adoptRef(new RTCDataChannel(context, handler.release()));
     70 }
     71 
     72 RTCDataChannel::RTCDataChannel(ExecutionContext* context, PassOwnPtr<RTCDataChannelHandler> handler)
     73     : m_executionContext(context)
     74     , m_handler(handler)
     75     , m_stopped(false)
     76     , m_readyState(ReadyStateConnecting)
     77     , m_binaryType(BinaryTypeArrayBuffer)
     78     , m_scheduledEventTimer(this, &RTCDataChannel::scheduledEventTimerFired)
     79 {
     80     ScriptWrappable::init(this);
     81     m_handler->setClient(this);
     82 }
     83 
     84 RTCDataChannel::~RTCDataChannel()
     85 {
     86 }
     87 
     88 String RTCDataChannel::label() const
     89 {
     90     return m_handler->label();
     91 }
     92 
     93 bool RTCDataChannel::reliable() const
     94 {
     95     return m_handler->isReliable();
     96 }
     97 
     98 bool RTCDataChannel::ordered() const
     99 {
    100     return m_handler->ordered();
    101 }
    102 
    103 unsigned short RTCDataChannel::maxRetransmitTime() const
    104 {
    105     return m_handler->maxRetransmitTime();
    106 }
    107 
    108 unsigned short RTCDataChannel::maxRetransmits() const
    109 {
    110     return m_handler->maxRetransmits();
    111 }
    112 
    113 String RTCDataChannel::protocol() const
    114 {
    115     return m_handler->protocol();
    116 }
    117 
    118 bool RTCDataChannel::negotiated() const
    119 {
    120     return m_handler->negotiated();
    121 }
    122 
    123 unsigned short RTCDataChannel::id() const
    124 {
    125     return m_handler->id();
    126 }
    127 
    128 String RTCDataChannel::readyState() const
    129 {
    130     switch (m_readyState) {
    131     case ReadyStateConnecting:
    132         return "connecting";
    133     case ReadyStateOpen:
    134         return "open";
    135     case ReadyStateClosing:
    136         return "closing";
    137     case ReadyStateClosed:
    138         return "closed";
    139     }
    140 
    141     ASSERT_NOT_REACHED();
    142     return String();
    143 }
    144 
    145 unsigned long RTCDataChannel::bufferedAmount() const
    146 {
    147     return m_handler->bufferedAmount();
    148 }
    149 
    150 String RTCDataChannel::binaryType() const
    151 {
    152     switch (m_binaryType) {
    153     case BinaryTypeBlob:
    154         return "blob";
    155     case BinaryTypeArrayBuffer:
    156         return "arraybuffer";
    157     }
    158     ASSERT_NOT_REACHED();
    159     return String();
    160 }
    161 
    162 void RTCDataChannel::setBinaryType(const String& binaryType, ExceptionState& exceptionState)
    163 {
    164     if (binaryType == "blob")
    165         throwNoBlobSupportException(exceptionState);
    166     else if (binaryType == "arraybuffer")
    167         m_binaryType = BinaryTypeArrayBuffer;
    168     else
    169         exceptionState.throwDOMException(TypeMismatchError, "Unknown binary type : " + binaryType);
    170 }
    171 
    172 void RTCDataChannel::send(const String& data, ExceptionState& exceptionState)
    173 {
    174     if (m_readyState != ReadyStateOpen) {
    175         throwNotOpenException(exceptionState);
    176         return;
    177     }
    178     if (!m_handler->sendStringData(data)) {
    179         // FIXME: This should not throw an exception but instead forcefully close the data channel.
    180         throwCouldNotSendDataException(exceptionState);
    181     }
    182 }
    183 
    184 void RTCDataChannel::send(PassRefPtr<ArrayBuffer> prpData, ExceptionState& exceptionState)
    185 {
    186     if (m_readyState != ReadyStateOpen) {
    187         throwNotOpenException(exceptionState);
    188         return;
    189     }
    190 
    191     RefPtr<ArrayBuffer> data = prpData;
    192 
    193     size_t dataLength = data->byteLength();
    194     if (!dataLength)
    195         return;
    196 
    197     const char* dataPointer = static_cast<const char*>(data->data());
    198 
    199     if (!m_handler->sendRawData(dataPointer, dataLength)) {
    200         // FIXME: This should not throw an exception but instead forcefully close the data channel.
    201         throwCouldNotSendDataException(exceptionState);
    202     }
    203 }
    204 
    205 void RTCDataChannel::send(PassRefPtr<ArrayBufferView> data, ExceptionState& exceptionState)
    206 {
    207     RefPtr<ArrayBuffer> arrayBuffer(data->buffer());
    208     send(arrayBuffer.release(), exceptionState);
    209 }
    210 
    211 void RTCDataChannel::send(PassRefPtr<Blob> data, ExceptionState& exceptionState)
    212 {
    213     // FIXME: implement
    214     throwNoBlobSupportException(exceptionState);
    215 }
    216 
    217 void RTCDataChannel::close()
    218 {
    219     if (m_stopped)
    220         return;
    221 
    222     m_handler->close();
    223 }
    224 
    225 void RTCDataChannel::didChangeReadyState(ReadyState newState)
    226 {
    227     if (m_stopped || m_readyState == ReadyStateClosed)
    228         return;
    229 
    230     m_readyState = newState;
    231 
    232     switch (m_readyState) {
    233     case ReadyStateOpen:
    234         scheduleDispatchEvent(Event::create(EventTypeNames::open));
    235         break;
    236     case ReadyStateClosed:
    237         scheduleDispatchEvent(Event::create(EventTypeNames::close));
    238         break;
    239     default:
    240         break;
    241     }
    242 }
    243 
    244 void RTCDataChannel::didReceiveStringData(const String& text)
    245 {
    246     if (m_stopped)
    247         return;
    248 
    249     scheduleDispatchEvent(MessageEvent::create(text));
    250 }
    251 
    252 void RTCDataChannel::didReceiveRawData(const char* data, size_t dataLength)
    253 {
    254     if (m_stopped)
    255         return;
    256 
    257     if (m_binaryType == BinaryTypeBlob) {
    258         // FIXME: Implement.
    259         return;
    260     }
    261     if (m_binaryType == BinaryTypeArrayBuffer) {
    262         RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(data, dataLength);
    263         scheduleDispatchEvent(MessageEvent::create(buffer.release()));
    264         return;
    265     }
    266     ASSERT_NOT_REACHED();
    267 }
    268 
    269 void RTCDataChannel::didDetectError()
    270 {
    271     if (m_stopped)
    272         return;
    273 
    274     scheduleDispatchEvent(Event::create(EventTypeNames::error));
    275 }
    276 
    277 const AtomicString& RTCDataChannel::interfaceName() const
    278 {
    279     return EventTargetNames::RTCDataChannel;
    280 }
    281 
    282 ExecutionContext* RTCDataChannel::executionContext() const
    283 {
    284     return m_executionContext;
    285 }
    286 
    287 void RTCDataChannel::stop()
    288 {
    289     m_stopped = true;
    290     m_readyState = ReadyStateClosed;
    291     m_handler->setClient(0);
    292     m_executionContext = 0;
    293 }
    294 
    295 void RTCDataChannel::scheduleDispatchEvent(PassRefPtr<Event> event)
    296 {
    297     m_scheduledEvents.append(event);
    298 
    299     if (!m_scheduledEventTimer.isActive())
    300         m_scheduledEventTimer.startOneShot(0);
    301 }
    302 
    303 void RTCDataChannel::scheduledEventTimerFired(Timer<RTCDataChannel>*)
    304 {
    305     if (m_stopped)
    306         return;
    307 
    308     Vector<RefPtr<Event> > events;
    309     events.swap(m_scheduledEvents);
    310 
    311     Vector<RefPtr<Event> >::iterator it = events.begin();
    312     for (; it != events.end(); ++it)
    313         dispatchEvent((*it).release());
    314 
    315     events.clear();
    316 }
    317 
    318 } // namespace WebCore
    319