MediaRecorder: Adding BlobEvent and connecting it in MediaRecorderHandler
Note: MediaRecorder-basic-video.html is not reconnected yet
due to missing infra (See http://crbug.com/532509 and
this is ref'd in TestExpectations [1])
BUG=262211
TEST= https://rawgit.com/Miguelao/demos/master/mediarecorder.html
(video of it at [2] -- sorry, just for @google accounts).
[1] https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/LayoutTests/TestExpectations&sq=package:chromium&type=cs&q=TestExpectations%20MEdiaRecorder&l=409
[2] https://drive.google.com/open?id=0BwgFm5xOT0yCU3hScVh4WjIzZzQ
Review URL: https://codereview.chromium.org/1354863002
git-svn-id: svn://svn.chromium.org/blink/trunk@202646 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/LayoutTests/fast/mediarecorder/BlobEvent-basic.html b/LayoutTests/fast/mediarecorder/BlobEvent-basic.html
new file mode 100644
index 0000000..64e9f80
--- /dev/null
+++ b/LayoutTests/fast/mediarecorder/BlobEvent-basic.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script>
+
+test(function() {
+ var array = new Uint8Array([0x70, 0x71, 0x72, 0x73]);
+ var blob = new Blob([array]);
+ var blobEvent = new BlobEvent('BlobEvent', {data : blob});
+
+ var reader = new FileReader();
+ reader.addEventListener("loadend", function() {
+ // |reader.result| contains the contents of blob as an ArrayBuffer.
+ var outputArray = new Uint8Array(reader.result);
+ assert_equals(array.length, outputArray.length);
+ for (var index in outputArray) {
+ assert_equals(array[index], outputArray[index]);
+ }
+ });
+ reader.readAsArrayBuffer(blob);
+
+}, 'check BlobEvent creation and content management');
+
+
+</script>
diff --git a/LayoutTests/fast/mediarecorder/MediaRecorder-basic-video.html b/LayoutTests/fast/mediarecorder/MediaRecorder-basic-video.html
index fff0eea..7021d36 100644
--- a/LayoutTests/fast/mediarecorder/MediaRecorder-basic-video.html
+++ b/LayoutTests/fast/mediarecorder/MediaRecorder-basic-video.html
@@ -4,21 +4,35 @@
<script>
var test = async_test('checks the video-only MediaRecorder API.');
+var recorder;
recorderOnDataAvailable = test.step_func(function(event) {
- assert_greater_than(event.data.size, 0, 'Recorded data size should be > 0');
- assert_equals(recorder.state, "recording");
+ if (event) {
+ assert_greater_than(event.data.size, 0, 'Recorded data size should be > 0');
+ assert_equals(recorder.state, "recording");
+ } else {
+ assert_equals(recorder.state, "inactive");
+ }
// TODO(mcasas): Let the test record for a while.
// TODO(mcasas): Consider storing the recorded data and playing it back.
+ recorder.onstop = recorderOnStopExpected;
+ recorder.stop();
+});
+
+recorderOnStopExpected = test.step_func(function() {
test.done();
});
-recorderOnStop = test.step_func(function() {
+recorderOnStopUnexpected = test.step_func(function() {
assert_unreached('Recording stopped.');
});
+recorderOnError = test.step_func(function() {
+ assert_unreached('Recording error.');
+});
+
gotStream = test.step_func(function(stream) {
assert_equals(stream.getAudioTracks().length, 0);
assert_equals(stream.getVideoTracks().length, 1);
@@ -32,7 +46,8 @@
assert_equals(recorder.state, "inactive");
recorder.ondataavailable = recorderOnDataAvailable;
- recorder.onstop = recorderOnStop;
+ recorder.onstop = recorderOnStopUnexpected;
+ recorder.onerror = recorderOnError;
recorder.start();
assert_equals(recorder.state, "recording");
diff --git a/LayoutTests/webexposed/global-interface-listing-expected.txt b/LayoutTests/webexposed/global-interface-listing-expected.txt
index 7c427ca..34490e4 100644
--- a/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -286,6 +286,9 @@
method close
method constructor
method slice
+interface BlobEvent
+ getter data
+ method constructor
interface BluetoothDevice
getter deviceClass
getter instanceID
diff --git a/Source/modules/mediarecorder/BlobEvent.cpp b/Source/modules/mediarecorder/BlobEvent.cpp
new file mode 100644
index 0000000..f94509c
--- /dev/null
+++ b/Source/modules/mediarecorder/BlobEvent.cpp
@@ -0,0 +1,55 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+
+#include "modules/mediarecorder/BlobEvent.h"
+
+#include "modules/mediarecorder/BlobEventInit.h"
+
+namespace blink {
+
+// static
+PassRefPtrWillBeRawPtr<BlobEvent> BlobEvent::create()
+{
+ return adoptRefWillBeNoop(new BlobEvent);
+}
+
+// static
+PassRefPtrWillBeRawPtr<BlobEvent> BlobEvent::create(const AtomicString& type, const BlobEventInit& initializer)
+{
+ return adoptRefWillBeNoop(new BlobEvent(type, initializer));
+}
+
+// static
+PassRefPtrWillBeRawPtr<BlobEvent> BlobEvent::create(const AtomicString& type, Blob* blob)
+{
+ return adoptRefWillBeNoop(new BlobEvent(type, blob));
+}
+
+const AtomicString& BlobEvent::interfaceName() const
+{
+ return EventNames::BlobEvent;
+}
+
+DEFINE_TRACE(BlobEvent)
+{
+ visitor->trace(m_blob);
+ Event::trace(visitor);
+}
+
+BlobEvent::BlobEvent(const AtomicString& type, const BlobEventInit& initializer)
+ : Event(type, initializer)
+{
+ if (initializer.hasBlob())
+ m_blob = initializer.blob();
+}
+
+BlobEvent::BlobEvent(const AtomicString& type, Blob* blob)
+ : Event(type, false /* canBubble */, false /* cancelable */)
+ , m_blob(blob)
+{
+}
+
+} // namespace blink
diff --git a/Source/modules/mediarecorder/BlobEvent.h b/Source/modules/mediarecorder/BlobEvent.h
new file mode 100644
index 0000000..a28fec4
--- /dev/null
+++ b/Source/modules/mediarecorder/BlobEvent.h
@@ -0,0 +1,44 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BlobEvent_h
+#define BlobEvent_h
+
+#include "core/fileapi/Blob.h"
+#include "modules/EventModules.h"
+#include "modules/ModulesExport.h"
+#include "wtf/text/AtomicString.h"
+
+namespace blink {
+
+class Blob;
+class BlobEventInit;
+
+class MODULES_EXPORT BlobEvent final : public Event {
+ DEFINE_WRAPPERTYPEINFO();
+public:
+ ~BlobEvent() override {}
+
+ static PassRefPtrWillBeRawPtr<BlobEvent> create();
+ static PassRefPtrWillBeRawPtr<BlobEvent> create(const AtomicString& type, const BlobEventInit& initializer);
+ static PassRefPtrWillBeRawPtr<BlobEvent> create(const AtomicString& type, Blob*);
+
+ Blob* data() const { return m_blob.get(); }
+
+ // Event
+ const AtomicString& interfaceName() const final;
+
+ DECLARE_VIRTUAL_TRACE();
+
+private:
+ BlobEvent() {}
+ BlobEvent(const AtomicString& type, const BlobEventInit& initializer);
+ BlobEvent(const AtomicString& type, Blob*);
+
+ PersistentWillBeMember<Blob> m_blob;
+};
+
+} // namespace blink
+
+#endif // BlobEvent_h
diff --git a/Source/modules/mediarecorder/BlobEvent.idl b/Source/modules/mediarecorder/BlobEvent.idl
new file mode 100644
index 0000000..08edd28
--- /dev/null
+++ b/Source/modules/mediarecorder/BlobEvent.idl
@@ -0,0 +1,15 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/mediacapture-record/MediaRecorder.html#blob-event
+
+[
+ // This constructor is yet to be added to the specification, see:
+ // https://github.com/w3c/mediacapture-record/issues/11
+ Constructor(DOMString type, optional BlobEventInit eventInit),
+ RuntimeEnabled=MediaRecorder
+]
+interface BlobEvent : Event {
+ readonly attribute Blob data;
+};
diff --git a/Source/modules/mediarecorder/BlobEventInit.idl b/Source/modules/mediarecorder/BlobEventInit.idl
new file mode 100644
index 0000000..5ffbe06
--- /dev/null
+++ b/Source/modules/mediarecorder/BlobEventInit.idl
@@ -0,0 +1,7 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+dictionary BlobEventInit : EventInit {
+ Blob? blob = null;
+};
diff --git a/Source/modules/mediarecorder/MediaRecorder.cpp b/Source/modules/mediarecorder/MediaRecorder.cpp
index 3183ca6..bd0f537 100644
--- a/Source/modules/mediarecorder/MediaRecorder.cpp
+++ b/Source/modules/mediarecorder/MediaRecorder.cpp
@@ -9,6 +9,7 @@
#include "core/fileapi/Blob.h"
#include "modules/EventModules.h"
#include "modules/EventTargetModules.h"
+#include "modules/mediarecorder/BlobEvent.h"
#include "modules/mediarecorder/MediaRecorderErrorEvent.h"
#include "platform/NotImplemented.h"
#include "platform/blob/BlobData.h"
@@ -152,7 +153,7 @@
return;
}
- createBlobEvent(BlobData::create());
+ createBlobEvent(nullptr);
}
String MediaRecorder::canRecordMimeType(const String& mimeType)
@@ -212,10 +213,9 @@
// TODO(mcasas): Act as |m_ignoredMutedMedia| instructs if |m_stream| track(s) is in muted() state.
// TODO(mcasas): Use |lastInSlice| to indicate to JS that recording is done.
-
OwnPtr<BlobData> blobData = BlobData::create();
blobData->appendBytes(data, length);
- createBlobEvent(blobData.release());
+ createBlobEvent(Blob::create(BlobDataHandle::create(blobData.release(), length)));
}
void MediaRecorder::failOutOfMemory(const WebString& message)
@@ -245,10 +245,10 @@
stopRecording();
}
-void MediaRecorder::createBlobEvent(PassOwnPtr<BlobData> blobData)
+void MediaRecorder::createBlobEvent(Blob* blob)
{
- // TODO(mcasas): Launch a BlobEvent when that class is landed, but also see https://github.com/w3c/mediacapture-record/issues/17.
- notImplemented();
+ // TODO(mcasas): Consider launching an Event with a TypedArray inside, see https://github.com/w3c/mediacapture-record/issues/17.
+ scheduleDispatchEvent(BlobEvent::create(EventTypeNames::dataavailable, blob));
}
void MediaRecorder::stopRecording()
@@ -258,7 +258,7 @@
m_recorderHandler->stop();
- createBlobEvent(BlobData::create());
+ createBlobEvent(nullptr);
scheduleDispatchEvent(Event::create(EventTypeNames::stop));
}
diff --git a/Source/modules/mediarecorder/MediaRecorder.h b/Source/modules/mediarecorder/MediaRecorder.h
index 028515b..80ae6db 100644
--- a/Source/modules/mediarecorder/MediaRecorder.h
+++ b/Source/modules/mediarecorder/MediaRecorder.h
@@ -16,7 +16,7 @@
namespace blink {
-class BlobData;
+class Blob;
class ExceptionState;
class MODULES_EXPORT MediaRecorder final
@@ -81,7 +81,7 @@
private:
MediaRecorder(ExecutionContext*, MediaStream*, const String& mimeType, ExceptionState&);
- void createBlobEvent(PassOwnPtr<BlobData> blobData);
+ void createBlobEvent(Blob*);
void stopRecording();
void scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event>);
diff --git a/Source/modules/mediarecorder/MediaRecorder.idl b/Source/modules/mediarecorder/MediaRecorder.idl
index 3b360ee..92004b4 100644
--- a/Source/modules/mediarecorder/MediaRecorder.idl
+++ b/Source/modules/mediarecorder/MediaRecorder.idl
@@ -10,6 +10,7 @@
GarbageCollected,
ActiveDOMObject,
// TODO(mcasas): consider changing |mimeType| to a dictionary with said key, see https://github.com/w3c/mediacapture-record/issues/19
+ // TODO(mcasas): Remove [TreatUndefinedAs], see https://github.com/w3c/mediacapture-record/issues/7
Constructor(MediaStream stream, [TreatUndefinedAs=Missing] optional DOMString mimeType),
ConstructorCallWith=ExecutionContext,
RaisesException=Constructor,
diff --git a/Source/modules/modules.gypi b/Source/modules/modules.gypi
index 855af39..bf24044 100644
--- a/Source/modules/modules.gypi
+++ b/Source/modules/modules.gypi
@@ -105,6 +105,7 @@
'indexeddb/IDBRequest.idl',
'indexeddb/IDBTransaction.idl',
'indexeddb/IDBVersionChangeEvent.idl',
+ 'mediarecorder/BlobEvent.idl',
'mediarecorder/MediaRecorder.idl',
'mediarecorder/MediaRecorderErrorEvent.idl',
'mediasession/MediaSession.idl',
@@ -395,6 +396,7 @@
'gamepad/GamepadEvent.idl',
'geofencing/GeofencingEvent.idl',
'indexeddb/IDBVersionChangeEvent.idl',
+ 'mediarecorder/BlobEvent.idl',
'mediarecorder/MediaRecorderErrorEvent.idl',
'mediastream/MediaStreamEvent.idl',
'mediastream/MediaStreamTrackEvent.idl',
@@ -451,6 +453,7 @@
'indexeddb/IDBIndexParameters.idl',
'indexeddb/IDBObjectStoreParameters.idl',
'indexeddb/IDBVersionChangeEventInit.idl',
+ 'mediarecorder/BlobEventInit.idl',
'mediastream/MediaStreamConstraints.idl',
'mediastream/MediaStreamEventInit.idl',
'mediastream/RTCDTMFToneChangeEventInit.idl',
@@ -562,6 +565,8 @@
'<(blink_modules_output_dir)/indexeddb/IDBObjectStoreParameters.h',
'<(blink_modules_output_dir)/indexeddb/IDBVersionChangeEventInit.cpp',
'<(blink_modules_output_dir)/indexeddb/IDBVersionChangeEventInit.h',
+ '<(blink_modules_output_dir)/mediarecorder/BlobEventInit.cpp',
+ '<(blink_modules_output_dir)/mediarecorder/BlobEventInit.h',
'<(blink_modules_output_dir)/mediastream/MediaStreamConstraints.cpp',
'<(blink_modules_output_dir)/mediastream/MediaStreamConstraints.h',
'<(blink_modules_output_dir)/mediastream/MediaStreamEventInit.cpp',
@@ -1086,6 +1091,8 @@
'indexeddb/WebIDBDatabaseCallbacksImpl.h',
'indexeddb/WorkerGlobalScopeIndexedDatabase.cpp',
'indexeddb/WorkerGlobalScopeIndexedDatabase.h',
+ 'mediarecorder/BlobEvent.cpp',
+ 'mediarecorder/BlobEvent.h',
'mediarecorder/MediaRecorder.cpp',
'mediarecorder/MediaRecorder.h',
'mediarecorder/MediaRecorderErrorEvent.cpp',