| OLD | NEW |
| (Empty) |
| 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 AN
Y | |
| 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 AN
Y | |
| 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 O
N | |
| 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 "modules/mediastream/RTCDataChannel.h" | |
| 26 | |
| 27 #include "bindings/core/v8/ExceptionState.h" | |
| 28 #include "core/dom/DOMArrayBuffer.h" | |
| 29 #include "core/dom/DOMArrayBufferView.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 "modules/mediastream/RTCPeerConnection.h" | |
| 35 #include "public/platform/WebRTCPeerConnectionHandler.h" | |
| 36 #include "wtf/PtrUtil.h" | |
| 37 #include <memory> | |
| 38 | |
| 39 namespace blink { | |
| 40 | |
| 41 static void throwNotOpenException(ExceptionState& exceptionState) | |
| 42 { | |
| 43 exceptionState.throwDOMException(InvalidStateError, "RTCDataChannel.readySta
te 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 implem
ented yet"); | |
| 54 } | |
| 55 | |
| 56 RTCDataChannel* RTCDataChannel::create(ExecutionContext* context, std::unique_pt
r<WebRTCDataChannelHandler> handler) | |
| 57 { | |
| 58 DCHECK(handler); | |
| 59 RTCDataChannel* channel = new RTCDataChannel(context, std::move(handler)); | |
| 60 channel->suspendIfNeeded(); | |
| 61 | |
| 62 return channel; | |
| 63 } | |
| 64 | |
| 65 RTCDataChannel* RTCDataChannel::create(ExecutionContext* context, WebRTCPeerConn
ectionHandler* peerConnectionHandler, const String& label, const WebRTCDataChann
elInit& init, ExceptionState& exceptionState) | |
| 66 { | |
| 67 std::unique_ptr<WebRTCDataChannelHandler> handler = wrapUnique(peerConnectio
nHandler->createDataChannel(label, init)); | |
| 68 if (!handler) { | |
| 69 exceptionState.throwDOMException(NotSupportedError, "RTCDataChannel is n
ot supported"); | |
| 70 return nullptr; | |
| 71 } | |
| 72 RTCDataChannel* channel = new RTCDataChannel(context, std::move(handler)); | |
| 73 channel->suspendIfNeeded(); | |
| 74 | |
| 75 return channel; | |
| 76 } | |
| 77 | |
| 78 RTCDataChannel::RTCDataChannel(ExecutionContext* context, std::unique_ptr<WebRTC
DataChannelHandler> handler) | |
| 79 : ActiveScriptWrappable(this) | |
| 80 , ActiveDOMObject(context) | |
| 81 , m_handler(std::move(handler)) | |
| 82 , m_readyState(ReadyStateConnecting) | |
| 83 , m_binaryType(BinaryTypeArrayBuffer) | |
| 84 , m_scheduledEventTimer(this, &RTCDataChannel::scheduledEventTimerFired) | |
| 85 , m_bufferedAmountLowThreshold(0U) | |
| 86 , m_stopped(false) | |
| 87 { | |
| 88 ThreadState::current()->registerPreFinalizer(this); | |
| 89 m_handler->setClient(this); | |
| 90 } | |
| 91 | |
| 92 RTCDataChannel::~RTCDataChannel() | |
| 93 { | |
| 94 } | |
| 95 | |
| 96 void RTCDataChannel::dispose() | |
| 97 { | |
| 98 if (m_stopped) | |
| 99 return; | |
| 100 | |
| 101 // Promptly clears a raw reference from content/ to an on-heap object | |
| 102 // so that content/ doesn't access it in a lazy sweeping phase. | |
| 103 m_handler->setClient(nullptr); | |
| 104 m_handler.reset(); | |
| 105 } | |
| 106 | |
| 107 RTCDataChannel::ReadyState RTCDataChannel::getHandlerState() const | |
| 108 { | |
| 109 return m_handler->state(); | |
| 110 } | |
| 111 | |
| 112 String RTCDataChannel::label() const | |
| 113 { | |
| 114 return m_handler->label(); | |
| 115 } | |
| 116 | |
| 117 bool RTCDataChannel::reliable() const | |
| 118 { | |
| 119 return m_handler->isReliable(); | |
| 120 } | |
| 121 | |
| 122 bool RTCDataChannel::ordered() const | |
| 123 { | |
| 124 return m_handler->ordered(); | |
| 125 } | |
| 126 | |
| 127 unsigned short RTCDataChannel::maxRetransmitTime() const | |
| 128 { | |
| 129 return m_handler->maxRetransmitTime(); | |
| 130 } | |
| 131 | |
| 132 unsigned short RTCDataChannel::maxRetransmits() const | |
| 133 { | |
| 134 return m_handler->maxRetransmits(); | |
| 135 } | |
| 136 | |
| 137 String RTCDataChannel::protocol() const | |
| 138 { | |
| 139 return m_handler->protocol(); | |
| 140 } | |
| 141 | |
| 142 bool RTCDataChannel::negotiated() const | |
| 143 { | |
| 144 return m_handler->negotiated(); | |
| 145 } | |
| 146 | |
| 147 unsigned short RTCDataChannel::id() const | |
| 148 { | |
| 149 return m_handler->id(); | |
| 150 } | |
| 151 | |
| 152 String RTCDataChannel::readyState() const | |
| 153 { | |
| 154 switch (m_readyState) { | |
| 155 case ReadyStateConnecting: | |
| 156 return "connecting"; | |
| 157 case ReadyStateOpen: | |
| 158 return "open"; | |
| 159 case ReadyStateClosing: | |
| 160 return "closing"; | |
| 161 case ReadyStateClosed: | |
| 162 return "closed"; | |
| 163 } | |
| 164 | |
| 165 NOTREACHED(); | |
| 166 return String(); | |
| 167 } | |
| 168 | |
| 169 unsigned RTCDataChannel::bufferedAmount() const | |
| 170 { | |
| 171 return m_handler->bufferedAmount(); | |
| 172 } | |
| 173 | |
| 174 unsigned RTCDataChannel::bufferedAmountLowThreshold() const | |
| 175 { | |
| 176 return m_bufferedAmountLowThreshold; | |
| 177 } | |
| 178 | |
| 179 void RTCDataChannel::setBufferedAmountLowThreshold(unsigned threshold) | |
| 180 { | |
| 181 m_bufferedAmountLowThreshold = threshold; | |
| 182 } | |
| 183 | |
| 184 String RTCDataChannel::binaryType() const | |
| 185 { | |
| 186 switch (m_binaryType) { | |
| 187 case BinaryTypeBlob: | |
| 188 return "blob"; | |
| 189 case BinaryTypeArrayBuffer: | |
| 190 return "arraybuffer"; | |
| 191 } | |
| 192 NOTREACHED(); | |
| 193 return String(); | |
| 194 } | |
| 195 | |
| 196 void RTCDataChannel::setBinaryType(const String& binaryType, ExceptionState& exc
eptionState) | |
| 197 { | |
| 198 if (binaryType == "blob") | |
| 199 throwNoBlobSupportException(exceptionState); | |
| 200 else if (binaryType == "arraybuffer") | |
| 201 m_binaryType = BinaryTypeArrayBuffer; | |
| 202 else | |
| 203 exceptionState.throwDOMException(TypeMismatchError, "Unknown binary type
: " + binaryType); | |
| 204 } | |
| 205 | |
| 206 void RTCDataChannel::send(const String& data, ExceptionState& exceptionState) | |
| 207 { | |
| 208 if (m_readyState != ReadyStateOpen) { | |
| 209 throwNotOpenException(exceptionState); | |
| 210 return; | |
| 211 } | |
| 212 if (!m_handler->sendStringData(data)) { | |
| 213 // FIXME: This should not throw an exception but instead forcefully clos
e the data channel. | |
| 214 throwCouldNotSendDataException(exceptionState); | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 void RTCDataChannel::send(DOMArrayBuffer* data, ExceptionState& exceptionState) | |
| 219 { | |
| 220 if (m_readyState != ReadyStateOpen) { | |
| 221 throwNotOpenException(exceptionState); | |
| 222 return; | |
| 223 } | |
| 224 | |
| 225 size_t dataLength = data->byteLength(); | |
| 226 if (!dataLength) | |
| 227 return; | |
| 228 | |
| 229 if (!m_handler->sendRawData(static_cast<const char*>((data->data())), dataLe
ngth)) { | |
| 230 // FIXME: This should not throw an exception but instead forcefully clos
e the data channel. | |
| 231 throwCouldNotSendDataException(exceptionState); | |
| 232 } | |
| 233 } | |
| 234 | |
| 235 void RTCDataChannel::send(DOMArrayBufferView* data, ExceptionState& exceptionSta
te) | |
| 236 { | |
| 237 if (!m_handler->sendRawData(static_cast<const char*>(data->baseAddress()), d
ata->byteLength())) { | |
| 238 // FIXME: This should not throw an exception but instead forcefully clos
e the data channel. | |
| 239 throwCouldNotSendDataException(exceptionState); | |
| 240 } | |
| 241 } | |
| 242 | |
| 243 void RTCDataChannel::send(Blob* data, ExceptionState& exceptionState) | |
| 244 { | |
| 245 // FIXME: implement | |
| 246 throwNoBlobSupportException(exceptionState); | |
| 247 } | |
| 248 | |
| 249 void RTCDataChannel::close() | |
| 250 { | |
| 251 m_handler->close(); | |
| 252 } | |
| 253 | |
| 254 void RTCDataChannel::didChangeReadyState(WebRTCDataChannelHandlerClient::ReadySt
ate newState) | |
| 255 { | |
| 256 if (m_readyState == ReadyStateClosed) | |
| 257 return; | |
| 258 | |
| 259 m_readyState = newState; | |
| 260 | |
| 261 switch (m_readyState) { | |
| 262 case ReadyStateOpen: | |
| 263 scheduleDispatchEvent(Event::create(EventTypeNames::open)); | |
| 264 break; | |
| 265 case ReadyStateClosed: | |
| 266 scheduleDispatchEvent(Event::create(EventTypeNames::close)); | |
| 267 break; | |
| 268 default: | |
| 269 break; | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 void RTCDataChannel::didDecreaseBufferedAmount(unsigned previousAmount) | |
| 274 { | |
| 275 if (previousAmount > m_bufferedAmountLowThreshold | |
| 276 && bufferedAmount() <= m_bufferedAmountLowThreshold) { | |
| 277 scheduleDispatchEvent(Event::create(EventTypeNames::bufferedamountlow)); | |
| 278 } | |
| 279 } | |
| 280 | |
| 281 void RTCDataChannel::didReceiveStringData(const WebString& text) | |
| 282 { | |
| 283 scheduleDispatchEvent(MessageEvent::create(text)); | |
| 284 } | |
| 285 | |
| 286 void RTCDataChannel::didReceiveRawData(const char* data, size_t dataLength) | |
| 287 { | |
| 288 if (m_binaryType == BinaryTypeBlob) { | |
| 289 // FIXME: Implement. | |
| 290 return; | |
| 291 } | |
| 292 if (m_binaryType == BinaryTypeArrayBuffer) { | |
| 293 DOMArrayBuffer* buffer = DOMArrayBuffer::create(data, dataLength); | |
| 294 scheduleDispatchEvent(MessageEvent::create(buffer)); | |
| 295 return; | |
| 296 } | |
| 297 NOTREACHED(); | |
| 298 } | |
| 299 | |
| 300 void RTCDataChannel::didDetectError() | |
| 301 { | |
| 302 scheduleDispatchEvent(Event::create(EventTypeNames::error)); | |
| 303 } | |
| 304 | |
| 305 const AtomicString& RTCDataChannel::interfaceName() const | |
| 306 { | |
| 307 return EventTargetNames::RTCDataChannel; | |
| 308 } | |
| 309 | |
| 310 ExecutionContext* RTCDataChannel::getExecutionContext() const | |
| 311 { | |
| 312 return ActiveDOMObject::getExecutionContext(); | |
| 313 } | |
| 314 | |
| 315 // ActiveDOMObject | |
| 316 void RTCDataChannel::suspend() | |
| 317 { | |
| 318 m_scheduledEventTimer.stop(); | |
| 319 } | |
| 320 | |
| 321 void RTCDataChannel::resume() | |
| 322 { | |
| 323 if (!m_scheduledEvents.isEmpty() && !m_scheduledEventTimer.isActive()) | |
| 324 m_scheduledEventTimer.startOneShot(0, BLINK_FROM_HERE); | |
| 325 } | |
| 326 | |
| 327 void RTCDataChannel::stop() | |
| 328 { | |
| 329 if (m_stopped) | |
| 330 return; | |
| 331 | |
| 332 m_stopped = true; | |
| 333 m_handler->setClient(nullptr); | |
| 334 m_handler.reset(); | |
| 335 } | |
| 336 | |
| 337 // ActiveScriptWrappable | |
| 338 bool RTCDataChannel::hasPendingActivity() const | |
| 339 { | |
| 340 if (m_stopped) | |
| 341 return false; | |
| 342 | |
| 343 // A RTCDataChannel object must not be garbage collected if its | |
| 344 // * readyState is connecting and at least one event listener is registered | |
| 345 // for open events, message events, error events, or close events. | |
| 346 // * readyState is open and at least one event listener is registered for | |
| 347 // message events, error events, or close events. | |
| 348 // * readyState is closing and at least one event listener is registered for | |
| 349 // error events, or close events. | |
| 350 // * underlying data transport is established and data is queued to be | |
| 351 // transmitted. | |
| 352 bool hasValidListeners = false; | |
| 353 switch (m_readyState) { | |
| 354 case ReadyStateConnecting: | |
| 355 hasValidListeners |= hasEventListeners(EventTypeNames::open); | |
| 356 // fallthrough intended | |
| 357 case ReadyStateOpen: | |
| 358 hasValidListeners |= hasEventListeners(EventTypeNames::message); | |
| 359 // fallthrough intended | |
| 360 case ReadyStateClosing: | |
| 361 hasValidListeners |= hasEventListeners(EventTypeNames::error) || hasEven
tListeners(EventTypeNames::close); | |
| 362 break; | |
| 363 default: | |
| 364 break; | |
| 365 } | |
| 366 | |
| 367 if (hasValidListeners) | |
| 368 return true; | |
| 369 | |
| 370 return m_readyState != ReadyStateClosed && bufferedAmount() > 0; | |
| 371 } | |
| 372 | |
| 373 void RTCDataChannel::scheduleDispatchEvent(Event* event) | |
| 374 { | |
| 375 m_scheduledEvents.append(event); | |
| 376 | |
| 377 if (!m_scheduledEventTimer.isActive()) | |
| 378 m_scheduledEventTimer.startOneShot(0, BLINK_FROM_HERE); | |
| 379 } | |
| 380 | |
| 381 void RTCDataChannel::scheduledEventTimerFired(Timer<RTCDataChannel>*) | |
| 382 { | |
| 383 HeapVector<Member<Event>> events; | |
| 384 events.swap(m_scheduledEvents); | |
| 385 | |
| 386 HeapVector<Member<Event>>::iterator it = events.begin(); | |
| 387 for (; it != events.end(); ++it) | |
| 388 dispatchEvent((*it).release()); | |
| 389 | |
| 390 events.clear(); | |
| 391 } | |
| 392 | |
| 393 DEFINE_TRACE(RTCDataChannel) | |
| 394 { | |
| 395 visitor->trace(m_scheduledEvents); | |
| 396 EventTargetWithInlineData::trace(visitor); | |
| 397 ActiveDOMObject::trace(visitor); | |
| 398 } | |
| 399 | |
| 400 } // namespace blink | |
| OLD | NEW |