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