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 |