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