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