Commit dbadef0a authored by mcasas@chromium.org's avatar mcasas@chromium.org

MediaRecorder Blink part

This CL adds the Blink classes needed for implementing
MediaRecorder API and two tests.This API allows for
recording a MediaStream, i.e. a local or remote feed of 
live media(s). This CL does not include a BlobEvent to
communicate recorded data to JS.

See DD @ https://goo.gl/vSjzC5 (*) for the plan and
https://codereview.chromium.org/1211973012/ for a
hack of all Chrome parts.

(*) Used to be https://goo.gl/kreaQj

BUG=262211

Review URL: https://codereview.chromium.org/1255873002

git-svn-id: svn://svn.chromium.org/blink/trunk@201727 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 0dfba69f
This is a testharness.js-based test.
FAIL checks the video-only MediaRecorder API. assert_unreached: Exception while creating MediaRecorder: NotSupportedError: Failed to construct 'MediaRecorder': No MediaRecorder handler can be created. Reached unreachable code
Harness: the test ran to completion.
<!DOCTYPE html>
<script src=../../resources/testharness.js></script>
<script src=../../resources/testharnessreport.js></script>
<script>
var test = async_test('checks the video-only MediaRecorder API.');
recorderOnDataAvailable = test.step_func(function(event) {
assert_greater_than(event.data.size, 0, 'Recorded data size should be > 0');
assert_eq(recorder.state, "recording");
// TODO(mcasas): Let the test record for a while.
// TODO(mcasas): Consider storing the recorded data and playing it back.
test.done();
});
recorderOnStop = test.step_func(function() {
assert_unreached('Recording stopped.');
});
gotStream = test.step_func(function(s) {
stream = s;
assert_equals(stream.getAudioTracks().length, 0);
assert_equals(stream.getVideoTracks().length, 1);
try {
recorder = new MediaRecorder(stream);
} catch (e) {
assert_unreached('Exception while creating MediaRecorder: ' + e);
}
assert_eq(recorder.state, "inactive");
recorder.ondataavailable = recorderOnDataAvailable;
recorder.onstop = recorderOnStop;
recorder.start();
});
onError = test.step_func(function() {
assert_unreached('Error creating MediaRecorder.');
});
try {
navigator.webkitGetUserMedia({video:true}, gotStream, onError);
} catch(e) {
assert_unreached('Exception launching getUserMedia(): ' + e);
}
</script>
This is a testharness.js-based test.
PASS check MediaRecorder.canRecordMimeType() with video/invalid
FAIL check MediaRecorder.canRecordMimeType() with video/webm and vp8 assert_equals: expected "maybe" but got ""
PASS check MediaRecorder.canRecordMimeType() with audio/invalid
FAIL check MediaRecorder.canRecordMimeType() with audio/webm and opus assert_equals: expected "maybe" but got ""
Harness: the test ran to completion.
<!DOCTYPE html>
<script src=../../resources/testharness.js></script>
<script src=../../resources/testharnessreport.js></script>
<script>
// Check one Video format that should be recordable and another that should be.
// Supported formats return "maybe". Same for Audio.
// https://w3c.github.io/mediacapture-record/MediaRecorder.html#methods
test(function() {
assert_equals(MediaRecorder.canRecordMimeType("video/invalid"), "");
}, 'check MediaRecorder.canRecordMimeType() with video/invalid');
test(function() {
assert_equals(MediaRecorder.canRecordMimeType('video/webm, codecs="vp8"'), "maybe");
}, 'check MediaRecorder.canRecordMimeType() with video/webm and vp8');
test(function() {
assert_equals(MediaRecorder.canRecordMimeType("audio/invalid"), "");
}, 'check MediaRecorder.canRecordMimeType() with audio/invalid');
test(function() {
assert_equals(MediaRecorder.canRecordMimeType("audio/webm;codecs=opus"), "maybe");
}, 'check MediaRecorder.canRecordMimeType() with audio/webm and opus');
</script>
......@@ -3236,6 +3236,30 @@ interface MediaQueryListEvent
getter matches
getter media
method constructor
interface MediaRecorder
getter ignoreMutedMedia
getter mimeType
getter ondataavailable
getter onerror
getter onpause
getter onresume
getter onstart
getter onstop
getter state
getter stream
method constructor
method pause
method requestData
method resume
method start
method stop
setter ignoreMutedMedia
setter ondataavailable
setter onerror
setter onpause
setter onresume
setter onstart
setter onstop
interface MediaSource
getter activeSourceBuffers
getter duration
......
......@@ -70,6 +70,7 @@ dischargingtimechange
disconnect
display
downloading
dataavailable
drag
dragend
dragenter
......@@ -203,6 +204,7 @@ speechend
speechstart
stalled
start
stop
statechange
storage
submit
......
......@@ -12,6 +12,7 @@
namespace blink {
class IDBRequest;
class MediaRecorder;
class MediaStream;
} // namespace blink
......
......@@ -10,6 +10,7 @@ modules/indexeddb/IDBDatabase
modules/indexeddb/IDBOpenDBRequest
modules/indexeddb/IDBRequest
modules/indexeddb/IDBTransaction
modules/mediarecorder/MediaRecorder
modules/mediasource/MediaSource
modules/mediasource/SourceBuffer
modules/mediasource/SourceBufferList
......
include_rules = [
"+core",
"-modules",
"+modules/EventModules.h",
"+modules/EventTargetModules.h",
"+modules/ModulesExport.h",
"+modules/mediarecorder",
"+modules/mediastream",
"+platform",
"+public/platform",
"-web",
]
// 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/MediaRecorder.h"
#include "core/dom/DOMError.h"
#include "core/fileapi/Blob.h"
#include "modules/EventModules.h"
#include "modules/EventTargetModules.h"
#include "modules/mediarecorder/MediaRecorderErrorEvent.h"
#include "platform/blob/BlobData.h"
#include "public/platform/Platform.h"
#include "public/platform/WebMediaStream.h"
namespace blink {
namespace {
String stateToString(MediaRecorder::State state)
{
switch (state) {
case MediaRecorder::State::Inactive:
return "inactive";
case MediaRecorder::State::Recording:
return "recording";
case MediaRecorder::State::Paused:
return "paused";
}
ASSERT_NOT_REACHED();
return String();
}
} // namespace
MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* stream, ExceptionState& exceptionState)
{
MediaRecorder* recorder = new MediaRecorder(context, stream, String(), exceptionState);
recorder->suspendIfNeeded();
return recorder;
}
MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* stream, const String& mimeType, ExceptionState& exceptionState)
{
MediaRecorder* recorder = new MediaRecorder(context, stream, mimeType, exceptionState);
recorder->suspendIfNeeded();
return recorder;
}
MediaRecorder::MediaRecorder(ExecutionContext* context, MediaStream* stream, const String& mimeType, ExceptionState& exceptionState)
: ActiveDOMObject(context)
, m_stream(stream)
, m_mimeType(mimeType)
, m_stopped(true)
, m_ignoreMutedMedia(true)
, m_state(State::Inactive)
, m_dispatchScheduledEventRunner(this, &MediaRecorder::dispatchScheduledEvent)
{
m_recorderHandler = adoptPtr(Platform::current()->createMediaRecorderHandler());
// TODO(mcasas): Once http://crbug.com/262211 has landed the Chromium parts,
// and more concretetely the createMediaRecorderHandler() implementation,
// ASSERT() here for |m_recorderHandler|.
// We deviate from the spec by not returning |UnsupportedOption|, see https://github.com/w3c/mediacapture-record/issues/18
if (!m_recorderHandler) {
exceptionState.throwDOMException(NotSupportedError, "No MediaRecorder handler can be created.");
return;
}
if (!m_recorderHandler->initialize(this, stream->descriptor(), m_mimeType)) {
exceptionState.throwDOMException(NotSupportedError, "Failed to initialize native MediaRecorder, the type provided " + m_mimeType + "is unsupported." );
return;
}
m_stopped = false;
}
String MediaRecorder::state() const
{
return stateToString(m_state);
}
void MediaRecorder::start(ExceptionState& exceptionState)
{
if (m_state != State::Inactive) {
exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + stateToString(m_state) + "'.");
return;
}
m_state = State::Recording;
m_recorderHandler->start();
}
void MediaRecorder::start(int timeSlice, ExceptionState& exceptionState)
{
if (m_state != State::Inactive) {
exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + stateToString(m_state) + "'.");
return;
}
m_state = State::Recording;
m_recorderHandler->start(timeSlice);
}
void MediaRecorder::stop(ExceptionState& exceptionState)
{
if (m_state == State::Inactive) {
exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + stateToString(m_state) + "'.");
return;
}
stopRecording();
}
void MediaRecorder::pause(ExceptionState& exceptionState)
{
if (m_state == State::Inactive) {
exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + stateToString(m_state) + "'.");
return;
}
if (m_state == State::Paused)
return;
m_state = State::Paused;
m_recorderHandler->pause();
scheduleDispatchEvent(Event::create(EventTypeNames::pause));
}
void MediaRecorder::resume(ExceptionState& exceptionState)
{
if (m_state == State::Inactive) {
exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + stateToString(m_state) + "'.");
return;
}
if (m_state == State::Recording)
return;
m_state = State::Recording;
m_recorderHandler->resume();
}
void MediaRecorder::requestData(ExceptionState& exceptionState)
{
if (m_state != State::Recording) {
exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + stateToString(m_state) + "'.");
return;
}
createBlobEvent(BlobData::create());
}
String MediaRecorder::canRecordMimeType(const String& mimeType)
{
RawPtr<WebMediaRecorderHandler> handler = Platform::current()->createMediaRecorderHandler();
if (!handler)
return emptyString();
// MediaRecorder canRecordMimeType() MUST return 'probably' "if the UA is
// confident that mimeType represents a type that it can record" [1], but a
// number of reasons could prevent the recording from happening as expected,
// so 'maybe' is a better option: "Implementors are encouraged to return
// "maybe" unless the type can be confidently established as being supported
// or not.". Hence this method returns '' or 'maybe', never 'probably'.
// [1] http://w3c.github.io/mediacapture-record/MediaRecorder.html#methods
return handler->canSupportMimeType(mimeType) ? "maybe" : emptyString();
}
const AtomicString& MediaRecorder::interfaceName() const
{
return EventTargetNames::MediaRecorder;
}
ExecutionContext* MediaRecorder::executionContext() const
{
return ActiveDOMObject::executionContext();
}
void MediaRecorder::suspend()
{
m_dispatchScheduledEventRunner.suspend();
}
void MediaRecorder::resume()
{
m_dispatchScheduledEventRunner.resume();
}
void MediaRecorder::stop()
{
if (m_stopped)
return;
m_stopped = true;
m_stream.clear();
m_recorderHandler.clear();
scheduleDispatchEvent(Event::create(EventTypeNames::stop));
}
void MediaRecorder::writeData(const char* data, size_t length, bool lastInSlice)
{
ASSERT(m_state == State::Recording);
if (m_stopped) {
m_stopped = false;
scheduleDispatchEvent(Event::create(EventTypeNames::start));
}
// 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());
}
void MediaRecorder::failOutOfMemory(const WebString& message)
{
scheduleDispatchEvent(MediaRecorderErrorEvent::create(
EventTypeNames::error, false, false, "OutOfMemory", message));
if (m_state == State::Recording)
stopRecording();
}
void MediaRecorder::failIllegalStreamModification(const WebString& message)
{
scheduleDispatchEvent(MediaRecorderErrorEvent::create(
EventTypeNames::error, false, false, "IllegalStreamModification", message));
if (m_state == State::Recording)
stopRecording();
}
void MediaRecorder::failOtherRecordingError(const WebString& message)
{
scheduleDispatchEvent(MediaRecorderErrorEvent::create(
EventTypeNames::error, false, false, "OtherRecordingError", message));
if (m_state == State::Recording)
stopRecording();
}
void MediaRecorder::createBlobEvent(PassOwnPtr<BlobData> blobData)
{
// TODO(mcasas): Launch a BlobEvent when that class is landed, but also see https://github.com/w3c/mediacapture-record/issues/17.
ASSERT_NOT_REACHED();
}
void MediaRecorder::stopRecording()
{
ASSERT(m_state != State::Inactive);
m_state = State::Inactive;
m_recorderHandler->stop();
createBlobEvent(BlobData::create());
scheduleDispatchEvent(Event::create(EventTypeNames::stop));
}
void MediaRecorder::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
{
m_scheduledEvents.append(event);
m_dispatchScheduledEventRunner.runAsync();
}
void MediaRecorder::dispatchScheduledEvent()
{
WillBeHeapVector<RefPtrWillBeMember<Event>> events;
events.swap(m_scheduledEvents);
for (const auto& event : events)
dispatchEvent(event);
}
DEFINE_TRACE(MediaRecorder)
{
visitor->trace(m_stream);
RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>::trace(visitor);
ActiveDOMObject::trace(visitor);
}
} // namespace blink
// 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 MediaRecorder_h
#define MediaRecorder_h
#include "core/dom/ActiveDOMObject.h"
#include "core/events/EventTarget.h"
#include "modules/EventTargetModules.h"
#include "modules/ModulesExport.h"
#include "modules/mediastream/MediaStream.h"
#include "platform/AsyncMethodRunner.h"
#include "public/platform/WebMediaRecorderHandler.h"
#include "public/platform/WebMediaRecorderHandlerClient.h"
namespace blink {
class BlobData;
class ExceptionState;
class MODULES_EXPORT MediaRecorder final
: public RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>
, public WebMediaRecorderHandlerClient
, public ActiveDOMObject {
REFCOUNTED_GARBAGE_COLLECTED_EVENT_TARGET(MediaRecorder);
WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(MediaRecorder);
DEFINE_WRAPPERTYPEINFO();
public:
enum class State {
Inactive = 0,
Recording,
Paused
};
static MediaRecorder* create(ExecutionContext*, MediaStream*, ExceptionState&);
static MediaRecorder* create(ExecutionContext*, MediaStream*, const String& mimeType, ExceptionState&);
virtual ~MediaRecorder() {}
MediaStream* stream() const { return m_stream.get(); }
const String& mimeType() const { return m_mimeType; }
String state() const;
bool ignoreMutedMedia() const { return m_ignoreMutedMedia; }
void setIgnoreMutedMedia(bool ignoreMutedMedia) { m_ignoreMutedMedia = ignoreMutedMedia; }
DEFINE_ATTRIBUTE_EVENT_LISTENER(start);
DEFINE_ATTRIBUTE_EVENT_LISTENER(stop);
DEFINE_ATTRIBUTE_EVENT_LISTENER(dataavailable);
DEFINE_ATTRIBUTE_EVENT_LISTENER(pause);
DEFINE_ATTRIBUTE_EVENT_LISTENER(resume);
DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
void start(ExceptionState&);
void start(int timeSlice, ExceptionState&);
void stop(ExceptionState&);
void pause(ExceptionState&);
void resume(ExceptionState&);
void requestData(ExceptionState&);
static String canRecordMimeType(const String& mimeType);
// EventTarget
virtual const AtomicString& interfaceName() const override;
virtual ExecutionContext* executionContext() const override;
// ActiveDOMObject
virtual void suspend() override;
virtual void resume() override;
virtual void stop() override;
virtual bool hasPendingActivity() const override { return !m_stopped; }
// WebMediaRecorderHandlerClient
virtual void writeData(const char* data, size_t length, bool lastInSlice) override;
virtual void failOutOfMemory(const WebString& message) override;
virtual void failIllegalStreamModification(const WebString& message) override;
virtual void failOtherRecordingError(const WebString& message) override;
DECLARE_VIRTUAL_TRACE();
private:
MediaRecorder(ExecutionContext*, MediaStream*, const String& mimeType, ExceptionState&);
void createBlobEvent(PassOwnPtr<BlobData> blobData);
void stopRecording();
void scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event>);
void dispatchScheduledEvent();
Member<MediaStream> m_stream;
String m_mimeType;
bool m_stopped;
bool m_ignoreMutedMedia;
State m_state;
OwnPtr<WebMediaRecorderHandler> m_recorderHandler;
AsyncMethodRunner<MediaRecorder> m_dispatchScheduledEventRunner;
WillBeHeapVector<RefPtrWillBeMember<Event>> m_scheduledEvents;
};
} // namespace blink
#endif // MediaRecorder_h
// 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#MediaRecorderAPI
enum RecordingStateEnum { "inactive", "recording", "paused" };
[
GarbageCollected,
ActiveDOMObject,
// TODO(mcasas): consider changing |mimeType| to a dictionary with said key, see https://github.com/w3c/mediacapture-record/issues/19
Constructor(MediaStream stream, [TreatUndefinedAs=Missing] optional DOMString mimeType),
ConstructorCallWith=ExecutionContext,
RaisesException=Constructor,
RuntimeEnabled=MediaRecorder
] interface MediaRecorder : EventTarget {
readonly attribute MediaStream stream;
readonly attribute DOMString mimeType;
readonly attribute RecordingStateEnum state;
attribute boolean ignoreMutedMedia;
attribute EventHandler onstart;
attribute EventHandler onstop;
attribute EventHandler ondataavailable;
attribute EventHandler onpause;
attribute EventHandler onresume;
attribute EventHandler onerror;
[RaisesException] void start(optional long timeslice);
[RaisesException] void stop();
[RaisesException] void pause();
[RaisesException] void resume();
[RaisesException] void requestData();
static DOMString canRecordMimeType(DOMString mimeType);
};
// 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/MediaRecorderErrorEvent.h"
namespace blink {
// static
PassRefPtrWillBeRawPtr<MediaRecorderErrorEvent> MediaRecorderErrorEvent::create()
{
return adoptRefWillBeNoop(new MediaRecorderErrorEvent);
}
// static
PassRefPtrWillBeRawPtr<MediaRecorderErrorEvent> MediaRecorderErrorEvent::create(const AtomicString& type, bool canBubble, bool cancelable, const String& name, const String& message)
{
return adoptRefWillBeNoop(new MediaRecorderErrorEvent(type, canBubble, cancelable, name, message));
}
const AtomicString& MediaRecorderErrorEvent::interfaceName() const
{
return EventNames::MediaRecorderErrorEvent;
}
MediaRecorderErrorEvent::MediaRecorderErrorEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& name, const String& message)
: Event(type, canBubble, cancelable)
, m_name(name)
, m_message(message)
{
}
} // namespace blink
// 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 MediaRecorderErrorEvent_h
#define MediaRecorderErrorEvent_h
#include "modules/EventModules.h"
#include "modules/ModulesExport.h"
#include "wtf/text/AtomicString.h"
#include "wtf/text/WTFString.h"
namespace blink {
// TODO(mcasas): Remove completely MediaRecorderErrorEvent, see https://github.com/w3c/mediacapture-record/issues/14.
class MODULES_EXPORT MediaRecorderErrorEvent final : public Event {
DEFINE_WRAPPERTYPEINFO();
public:
virtual ~MediaRecorderErrorEvent() {}
static PassRefPtrWillBeRawPtr<MediaRecorderErrorEvent> create();
static PassRefPtrWillBeRawPtr<MediaRecorderErrorEvent> create(const AtomicString& type, bool canBubble, bool cancelable, const String& name, const String& message);
const String& name() const { return m_name; }
const String& message() const { return m_message; }
// Event
virtual const AtomicString& interfaceName() const override;
DEFINE_INLINE_VIRTUAL_TRACE() { Event::trace(visitor); }
private:
MediaRecorderErrorEvent() {}
MediaRecorderErrorEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& name, const String& message);
String m_name;
String m_message;
};
} // namespace blink
#endif // MediaRecorderErrorEvent_h
// 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#MediaRecorderErrorEvent
// https://w3c.github.io/mediacapture-record/MediaRecorder.html#idl-def-RecordingErrorNameEnum
// TODO(mcasas): Remove completely MediaRecorderErrorEvent.* and use generic DOMException instead, see https://github.com/w3c/mediacapture-record/issues/14.
enum RecordingErrorNameEnum {
"InvalidState",
"OutOfMemory",
"IllegalStreamModification",
"SecurityError",
"OtherRecordingError"
};
// TODO(mcasas): This object should not be a NoInterfaceObject, https://github.com/w3c/mediacapture-record/issues/15.
[
NoInterfaceObject
] interface MediaRecorderErrorEvent : Event {
readonly attribute RecordingErrorNameEnum name;
readonly attribute DOMString? message;
};
mcasas@chromium.org
peter@chromium.org
......@@ -105,13 +105,15 @@
'indexeddb/IDBRequest.idl',
'indexeddb/IDBTransaction.idl',
'indexeddb/IDBVersionChangeEvent.idl',
'mediarecorder/MediaRecorder.idl',
'mediarecorder/MediaRecorderErrorEvent.idl',
'mediasession/MediaSession.idl',
'mediasource/MediaSource.idl',
'mediasource/SourceBuffer.idl',
'mediasource/SourceBufferList.idl',
'mediasource/TrackDefault.idl',
'mediasource/TrackDefaultList.idl',
'mediasource/VideoPlaybackQuality.idl',
'mediasession/MediaSession.idl',
'mediastream/MediaDeviceInfo.idl',
'mediastream/MediaDevices.idl',
'mediastream/MediaStream.idl',
......@@ -391,6 +393,7 @@
'gamepad/GamepadEvent.idl',
'geofencing/GeofencingEvent.idl',
'indexeddb/IDBVersionChangeEvent.idl',
'mediarecorder/MediaRecorderErrorEvent.idl',
'mediastream/MediaStreamEvent.idl',
'mediastream/MediaStreamTrackEvent.idl',
'mediastream/RTCDTMFToneChangeEvent.idl',
......@@ -1081,6 +1084,10 @@
'indexeddb/WebIDBDatabaseCallbacksImpl.h',
'indexeddb/WorkerGlobalScopeIndexedDatabase.cpp',
'indexeddb/WorkerGlobalScopeIndexedDatabase.h',
'mediarecorder/MediaRecorder.cpp',
'mediarecorder/MediaRecorder.h',
'mediarecorder/MediaRecorderErrorEvent.cpp',
'mediarecorder/MediaRecorderErrorEvent.h',
'mediasession/HTMLMediaElementMediaSession.cpp',
'mediasession/HTMLMediaElementMediaSession.h',
'mediasession/MediaSession.cpp',
......
......@@ -94,6 +94,7 @@ Media status=stable
MediaCapture
MediaController depends_on=Media, status=experimental
MediaDevices status=stable
MediaRecorder status=test
MediaSession
MediaSource status=stable
MediaSourceExperimental depends_on=MediaSource, status=experimental
......
......@@ -159,6 +159,11 @@ void WebRuntimeFeatures::enableMediaCapture(bool enable)
RuntimeEnabledFeatures::setMediaCaptureEnabled(enable);
}
void WebRuntimeFeatures::enableMediaRecorder(bool enable)
{
RuntimeEnabledFeatures::setMediaRecorderEnabled(enable);
}
void WebRuntimeFeatures::enableMediaSource(bool enable)
{
RuntimeEnabledFeatures::setMediaSourceEnabled(enable);
......
......@@ -82,6 +82,7 @@ class WebGraphicsContext3DProvider;
class WebIDBFactory;
class WebMIDIAccessor;
class WebMIDIAccessorClient;
class WebMediaRecorderHandler;
class WebMediaStreamCenter;
class WebMediaStreamCenterClient;
class WebMemoryDumpProvider;
......@@ -627,10 +628,13 @@ public:
// May return null if WebRTC functionality is not avaliable or out of resources.
virtual WebRTCPeerConnectionHandler* createRTCPeerConnectionHandler(WebRTCPeerConnectionHandlerClient*) { return nullptr; }
// Creates an WebMediaRecorderHandler to record MediaStreams.
// May return null if the functionality is not available or out of resources.
virtual WebMediaRecorderHandler* createMediaRecorderHandler() { return nullptr; }
// May return null if WebRTC functionality is not avaliable or out of resources.
virtual WebMediaStreamCenter* createMediaStreamCenter(WebMediaStreamCenterClient*) { return nullptr; }
// WebWorker ----------------------------------------------------------
virtual void didStartWorkerRunLoop() { }
......
// 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 WebMediaRecorderHandler_h
#define WebMediaRecorderHandler_h
#include "WebCommon.h"
namespace blink {
class WebMediaRecorderHandlerClient;
class WebMediaStream;
class WebString;
// Platform interface of a MediaRecorder.
class BLINK_PLATFORM_EXPORT WebMediaRecorderHandler {
public:
virtual ~WebMediaRecorderHandler() = default;
virtual bool initialize(WebMediaRecorderHandlerClient* client, const WebMediaStream& stream, const WebString& mimeType) { return false; }
virtual bool start() { return false; }
virtual bool start(int timeslice) { return false; }
virtual void stop() {}
virtual void pause() {}
virtual void resume() {}
// MediaRecorder API canRecordMimeType() is a tristate in which the returned
// value 'probably' means that "the user agent is confident that mimeType
// represents a type that it can record" [1], but a number of reasons might
// prevent a firm answer at this stage, so a boolean is a better option,
// because "Implementors are encouraged to return "maybe" unless the type
// can be confidently established as being supported or not." [1].
// [1] https://w3c.github.io/mediacapture-record/MediaRecorder.html#methods
virtual bool canSupportMimeType(const WebString& mimeType) { return false; }
};
} // namespace blink
#endif // WebMediaRecorderHandler_h
// 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 WebMediaRecorderHandlerClient_h
#define WebMediaRecorderHandlerClient_h
#include "WebCommon.h"
namespace blink {
class WebString;
// Interface used by a MediaRecorder to get errors and recorded data delivered.
class WebMediaRecorderHandlerClient {
public:
virtual void writeData(const char* data, size_t length, bool lastInslice) = 0;
virtual void failOutOfMemory(const WebString& message) = 0;
virtual void failIllegalStreamModification(const WebString& message) = 0;
virtual void failOtherRecordingError(const WebString& message) = 0;
};
} // namespace blink
#endif // WebMediaRecorderHandlerClient_h
......@@ -93,6 +93,8 @@ public:
BLINK_EXPORT static void enableMediaCapture(bool);
BLINK_EXPORT static void enableMediaRecorder(bool);
BLINK_EXPORT static void enableMediaSource(bool);
BLINK_EXPORT static void enableNotificationConstructor(bool);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment