Index: Source/modules/mediastream/RTCDataChannel.cpp |
diff --git a/Source/modules/mediastream/RTCDataChannel.cpp b/Source/modules/mediastream/RTCDataChannel.cpp |
index 43e24e8ff655fb5f953b15db69d7cea026a0f45d..69ae692b043ac185e869831b0696919ed837481c 100644 |
--- a/Source/modules/mediastream/RTCDataChannel.cpp |
+++ b/Source/modules/mediastream/RTCDataChannel.cpp |
@@ -31,9 +31,11 @@ |
#include "core/events/Event.h" |
#include "core/events/MessageEvent.h" |
#include "core/fileapi/Blob.h" |
+#include "core/fileapi/FileReaderLoader.h" |
#include "public/platform/WebRTCPeerConnectionHandler.h" |
#include "wtf/ArrayBuffer.h" |
#include "wtf/ArrayBufferView.h" |
+#include "wtf/OwnPtr.h" |
namespace WebCore { |
@@ -47,11 +49,6 @@ static void throwCouldNotSendDataException(ExceptionState& exceptionState) |
exceptionState.throwDOMException(NetworkError, "Could not send data"); |
} |
-static void throwNoBlobSupportException(ExceptionState& exceptionState) |
-{ |
- exceptionState.throwDOMException(NotSupportedError, "Blob support not implemented yet"); |
-} |
- |
PassRefPtr<RTCDataChannel> RTCDataChannel::create(ExecutionContext* context, PassOwnPtr<blink::WebRTCDataChannelHandler> handler) |
{ |
ASSERT(handler); |
@@ -73,7 +70,8 @@ RTCDataChannel::RTCDataChannel(ExecutionContext* context, PassOwnPtr<blink::WebR |
, m_handler(handler) |
, m_stopped(false) |
, m_readyState(ReadyStateConnecting) |
- , m_binaryType(BinaryTypeArrayBuffer) |
+ , m_binaryType(BinaryTypeBlob) |
+ , m_blobLoaderStatus(BlobLoaderNotStarted) |
, m_scheduledEventTimer(this, &RTCDataChannel::scheduledEventTimerFired) |
{ |
ScriptWrappable::init(this); |
@@ -161,7 +159,7 @@ String RTCDataChannel::binaryType() const |
void RTCDataChannel::setBinaryType(const String& binaryType, ExceptionState& exceptionState) |
{ |
if (binaryType == "blob") |
- throwNoBlobSupportException(exceptionState); |
+ m_binaryType = BinaryTypeBlob; |
else if (binaryType == "arraybuffer") |
m_binaryType = BinaryTypeArrayBuffer; |
else |
@@ -209,8 +207,12 @@ void RTCDataChannel::send(PassRefPtr<ArrayBufferView> data, ExceptionState& exce |
void RTCDataChannel::send(PassRefPtrWillBeRawPtr<Blob> data, ExceptionState& exceptionState) |
{ |
- // FIXME: implement |
- throwNoBlobSupportException(exceptionState); |
+ if (m_readyState != ReadyStateOpen) { |
+ throwNotOpenException(exceptionState); |
+ return; |
+ } |
+ m_outgoingBlobQueue.append(data->blobDataHandle()); |
+ processOutgoingBlobQueue(); |
} |
void RTCDataChannel::close() |
@@ -254,7 +256,14 @@ void RTCDataChannel::didReceiveRawData(const char* data, size_t dataLength) |
return; |
if (m_binaryType == BinaryTypeBlob) { |
- // FIXME: Implement. |
+ OwnPtr<BlobData> blobData = BlobData::create(); |
+ RefPtr<RawData> rawData = RawData::create(); |
+ OwnPtr<Vector<char> > binaryData = adoptPtr(new Vector<char>(dataLength)); |
michaeln
2014/05/06 02:36:49
this also probably won't work well with large blob
Li Yin
2014/05/06 07:09:37
When blob is large, it needs much memory, do you m
|
+ memcpy(binaryData->data(), data, dataLength); |
+ binaryData->swap(*rawData->mutableData()); |
+ blobData->appendData(rawData, 0, BlobDataItem::toEndOfFile); |
+ RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), dataLength)); |
+ scheduleDispatchEvent(MessageEvent::create(blob.release())); |
return; |
} |
if (m_binaryType == BinaryTypeArrayBuffer) { |
@@ -314,4 +323,68 @@ void RTCDataChannel::scheduledEventTimerFired(Timer<RTCDataChannel>*) |
events.clear(); |
} |
+void RTCDataChannel::didStartLoading() |
+{ |
+ ASSERT(m_blobLoader); |
+ ASSERT(m_blobLoaderStatus == BlobLoaderStarted); |
+} |
+ |
+void RTCDataChannel::didReceiveData() |
+{ |
+ ASSERT(m_blobLoader); |
+ ASSERT(m_blobLoaderStatus == BlobLoaderStarted); |
+} |
+ |
+void RTCDataChannel::didFinishLoading() |
+{ |
+ ASSERT(m_blobLoader); |
+ ASSERT(m_blobLoaderStatus == BlobLoaderStarted); |
+ m_blobLoaderStatus = BlobLoaderFinished; |
+ processOutgoingBlobQueue(); |
+ deref(); |
+} |
+ |
+void RTCDataChannel::didFail(FileError::ErrorCode errorCode) |
+{ |
+ ASSERT(m_blobLoader); |
+ ASSERT(m_blobLoaderStatus == BlobLoaderStarted); |
+ m_blobLoader.clear(); |
+ m_blobLoaderStatus = BlobLoaderFailed; |
+ close(); |
+ deref(); |
+} |
+ |
+void RTCDataChannel::processOutgoingBlobQueue() |
+{ |
+ while (!m_outgoingBlobQueue.isEmpty()) { |
+ RefPtr<BlobDataHandle> blobDataHandle = m_outgoingBlobQueue.takeFirst(); |
+ switch (m_blobLoaderStatus) { |
+ case BlobLoaderNotStarted: |
+ ref(); // Will be derefed after didFinishLoading() or didFail(). |
+ ASSERT(!m_blobLoader); |
+ m_blobLoader = adoptPtr(new FileReaderLoader(FileReaderLoader::ReadAsArrayBuffer, this)); |
+ m_blobLoaderStatus = BlobLoaderStarted; |
+ m_blobLoader->start(m_executionContext, blobDataHandle.get()); |
+ m_outgoingBlobQueue.prepend(blobDataHandle.release()); |
+ return; |
+ |
+ case BlobLoaderStarted: |
+ case BlobLoaderFailed: |
+ m_outgoingBlobQueue.prepend(blobDataHandle.release()); |
+ return; |
+ |
+ case BlobLoaderFinished: { |
+ RefPtr<ArrayBuffer> result = m_blobLoader->arrayBufferResult(); |
michaeln
2014/05/06 02:36:49
this probably won't work well with large blobs, ha
Li Yin
2014/05/06 07:09:37
Yeah, your concern looks reasonable, but unfortuna
|
+ m_blobLoader.clear(); |
+ m_blobLoaderStatus = BlobLoaderNotStarted; |
+ if (!m_handler->sendRawData(static_cast<const char*>(result->data()), result->byteLength())) { |
+ // FIXME: This should forcefully close the data channel. |
+ return; |
+ } |
+ break; |
+ } |
+ } |
+ } |
+} |
+ |
} // namespace WebCore |