Chromium Code Reviews| 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 |