mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
Bug 803414 - Part 4: Audio Recording - Web API & Implementation. r=roc
This commit is contained in:
parent
e875f86d18
commit
9175f35127
@ -1906,6 +1906,9 @@ GK_ATOM(canplaythrough, "canplaythrough")
|
||||
GK_ATOM(ratechange, "ratechange")
|
||||
GK_ATOM(durationchange, "durationchange")
|
||||
GK_ATOM(volumechange, "volumechange")
|
||||
GK_ATOM(ondataavailable, "ondataavailable")
|
||||
GK_ATOM(onwarning, "onwarning")
|
||||
GK_ATOM(onstop, "onstop")
|
||||
#ifdef MOZ_GAMEPAD
|
||||
GK_ATOM(ongamepadbuttondown, "ongamepadbuttondown")
|
||||
GK_ATOM(ongamepadbuttonup, "ongamepadbuttonup")
|
||||
|
@ -597,6 +597,21 @@ NON_IDL_EVENT(open,
|
||||
EventNameType_None,
|
||||
NS_EVENT)
|
||||
|
||||
NON_IDL_EVENT(dataavailable,
|
||||
NS_MEDIARECORDER_DATAAVAILABLE,
|
||||
EventNameType_None,
|
||||
NS_EVENT)
|
||||
|
||||
NON_IDL_EVENT(stop,
|
||||
NS_MEDIARECORDER_STOP,
|
||||
EventNameType_None,
|
||||
NS_EVENT)
|
||||
|
||||
NON_IDL_EVENT(warning,
|
||||
NS_MEDIARECORDER_WARNING,
|
||||
EventNameType_None,
|
||||
NS_EVENT)
|
||||
|
||||
// Events that only have on* attributes on XUL elements
|
||||
NON_IDL_EVENT(text,
|
||||
NS_TEXT_TEXT,
|
||||
|
370
content/media/MediaRecorder.cpp
Normal file
370
content/media/MediaRecorder.cpp
Normal file
@ -0,0 +1,370 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaRecorder.h"
|
||||
#include "GeneratedEvents.h"
|
||||
#include "MediaEncoder.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMBlobEvent.h"
|
||||
#include "nsIDOMRecordErrorEvent.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_2(MediaRecorder, nsDOMEventTargetHelper,
|
||||
mStream,
|
||||
mReadThread)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaRecorder)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(MediaRecorder, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(MediaRecorder, nsDOMEventTargetHelper)
|
||||
|
||||
// This task is used for triggering the creating blob object and it runs at main thread.
|
||||
class MediaRecorder::PushBlobTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
PushBlobTask(MediaRecorder* recorder)
|
||||
: mRecorder(recorder) {}
|
||||
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsresult rv = mRecorder->CreateAndDispatchBlobEvent();
|
||||
if (NS_FAILED(rv)) {
|
||||
mRecorder->NotifyError(rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
MediaRecorder* mRecorder;
|
||||
};
|
||||
|
||||
// This task is for firing the error message from encoder and it runs in main thread
|
||||
class MediaRecorder::PushErrorMessageTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
PushErrorMessageTask(MediaRecorder* recorder, nsresult aError)
|
||||
: mRecorder(recorder),
|
||||
mError(aError) { }
|
||||
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mRecorder->NotifyError(mError);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
MediaRecorder* mRecorder;
|
||||
nsresult mError;
|
||||
};
|
||||
|
||||
// This class is used for avoiding abort by directly use the NS_NewRunnableMethod and invoke ExtractEncodedData function
|
||||
// The abort is checking if the destructor runs at main thread during the cycle-collect step in nsDOMEventTargetHelper
|
||||
class MediaRecorder::ExtractEncodedDataTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ExtractEncodedDataTask(MediaRecorder* aRecorder, MediaEncoder* aEncoder)
|
||||
: mRecorder(aRecorder),
|
||||
mEncoder(aEncoder) {}
|
||||
|
||||
class ReleaseEncoderThreadTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ReleaseEncoderThreadTask(already_AddRefed<MediaRecorder> recorder)
|
||||
: mRecorder(recorder) {}
|
||||
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mRecorder->DispatchSimpleEvent(NS_LITERAL_STRING("stop"));
|
||||
mRecorder->mReadThread->Shutdown();
|
||||
mRecorder->mReadThread = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<MediaRecorder> mRecorder;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
mRecorder->ExtractEncodedData();
|
||||
NS_DispatchToMainThread(new ReleaseEncoderThreadTask(mRecorder.forget()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<MediaRecorder> mRecorder;
|
||||
nsRefPtr<MediaEncoder> mEncoder;
|
||||
};
|
||||
|
||||
MediaRecorder::~MediaRecorder()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MediaRecorder::Init(JSContext* aCx, nsPIDOMWindow* aOwnerWindow)
|
||||
{
|
||||
MOZ_ASSERT(aOwnerWindow);
|
||||
MOZ_ASSERT(aOwnerWindow->IsInnerWindow());
|
||||
BindToOwner(aOwnerWindow);
|
||||
}
|
||||
|
||||
MediaRecorder::MediaRecorder(DOMMediaStream& aStream)
|
||||
: mTimeSlice(0),
|
||||
mState(RecordingState::Inactive)
|
||||
{
|
||||
mStream = &aStream;
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
void
|
||||
MediaRecorder::ExtractEncodedData()
|
||||
{
|
||||
TimeStamp lastBlobTimeStamp = TimeStamp::Now();
|
||||
do {
|
||||
nsTArray<nsTArray<uint8_t> > outputBufs;
|
||||
mEncoder->GetEncodedData(&outputBufs, mMimeType);
|
||||
for (uint i = 0; i < outputBufs.Length(); i++) {
|
||||
mEncodedBufferCache->AppendBuffer(outputBufs[i]);
|
||||
}
|
||||
|
||||
if ((TimeStamp::Now() - lastBlobTimeStamp).ToMilliseconds() > mTimeSlice) {
|
||||
NS_DispatchToMainThread(new PushBlobTask(this));
|
||||
lastBlobTimeStamp = TimeStamp::Now();
|
||||
}
|
||||
} while (mState == RecordingState::Recording && !mEncoder->IsShutdown());
|
||||
|
||||
NS_DispatchToMainThread(new PushBlobTask(this));
|
||||
}
|
||||
|
||||
void
|
||||
MediaRecorder::Start(const Optional<int32_t>& aTimeSlice, ErrorResult& aResult)
|
||||
{
|
||||
if (mState != RecordingState::Inactive) {
|
||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckPrincipal()) {
|
||||
aResult.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aTimeSlice.WasPassed()) {
|
||||
if (aTimeSlice.Value() < 0) {
|
||||
aResult.Throw(NS_ERROR_INVALID_ARG);
|
||||
return;
|
||||
}
|
||||
mTimeSlice = aTimeSlice.Value();
|
||||
} else {
|
||||
mTimeSlice = 0;
|
||||
}
|
||||
if (mEncodedBufferCache == nullptr) {
|
||||
mEncodedBufferCache = new EncodedBufferCache(MAX_ALLOW_MEMORY_BUFFER);
|
||||
}
|
||||
|
||||
if (mEncoder == nullptr) {
|
||||
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""));
|
||||
}
|
||||
MOZ_ASSERT(mEncoder, "CreateEncoder failed");
|
||||
|
||||
if (mEncoder) {
|
||||
mStream.get()->GetStream()->AddListener(mEncoder);
|
||||
} else {
|
||||
aResult.Throw(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
|
||||
if (!mReadThread) {
|
||||
nsresult rv = NS_NewNamedThread("Media Encoder",
|
||||
getter_AddRefs(mReadThread));
|
||||
if (NS_FAILED(rv)) {
|
||||
aResult.Throw(rv);
|
||||
return;
|
||||
}
|
||||
nsRefPtr<ExtractEncodedDataTask> event = new ExtractEncodedDataTask(this, mEncoder);
|
||||
mReadThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
mState = RecordingState::Recording;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaRecorder::Stop(ErrorResult& aResult)
|
||||
{
|
||||
if (mState == RecordingState::Inactive) {
|
||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
mStream.get()->GetStream()->RemoveListener(mEncoder);
|
||||
mState = RecordingState::Inactive;
|
||||
}
|
||||
|
||||
void
|
||||
MediaRecorder::RequestData(ErrorResult& aResult)
|
||||
{
|
||||
if (mState != RecordingState::Recording) {
|
||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = CreateAndDispatchBlobEvent();
|
||||
if (NS_FAILED(rv)) {
|
||||
aResult.Throw(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
MediaRecorder::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
return MediaRecorderBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<MediaRecorder>
|
||||
MediaRecorder::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
DOMMediaStream& aStream, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobal.Get());
|
||||
if (!sgo) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.Get());
|
||||
if (!ownerWindow) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<MediaRecorder> object = new MediaRecorder(aStream);
|
||||
object->Init(aCx, ownerWindow);
|
||||
return object.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaRecorder::CreateAndDispatchBlobEvent()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
|
||||
if (!CheckPrincipal()) {
|
||||
// Media is not same-origin, don't allow the data out.
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob;
|
||||
blob = mEncodedBufferCache->ExtractBlob(mMimeType);
|
||||
|
||||
// create an event that uses the MessageEvent interface,
|
||||
// which does not bubble, is not cancelable, and has no default action
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
nsresult rv = NS_NewDOMBlobEvent(getter_AddRefs(event), this, nullptr, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMBlobEvent> blobEvent = do_QueryInterface(event);
|
||||
rv = blobEvent->InitBlobEvent(NS_LITERAL_STRING("dataavailable"),
|
||||
false, false, blob);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
event->SetTrusted(true);
|
||||
return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
MediaRecorder::DispatchSimpleEvent(const nsAString & aStr)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
nsresult rv = CheckInnerWindowCorrectness();
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to create the error event!!!");
|
||||
return;
|
||||
}
|
||||
rv = event->InitEvent(aStr, false, false);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to init the error event!!!");
|
||||
return;
|
||||
}
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Failed to dispatch the event!!!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaRecorder::NotifyError(nsresult aRv)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
nsresult rv = CheckInnerWindowCorrectness();
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
nsString errorMsg;
|
||||
switch (aRv) {
|
||||
case NS_ERROR_DOM_SECURITY_ERR:
|
||||
errorMsg = NS_LITERAL_STRING("SecurityError");
|
||||
break;
|
||||
case NS_ERROR_OUT_OF_MEMORY:
|
||||
errorMsg = NS_LITERAL_STRING("OutOfMemoryError");
|
||||
break;
|
||||
default:
|
||||
errorMsg = NS_LITERAL_STRING("GenericError");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
rv = NS_NewDOMRecordErrorEvent(getter_AddRefs(event), this, nullptr, nullptr);
|
||||
|
||||
nsCOMPtr<nsIDOMRecordErrorEvent> errorEvent = do_QueryInterface(event);
|
||||
rv = errorEvent->InitRecordErrorEvent(NS_LITERAL_STRING("error"),
|
||||
false, false, errorMsg);
|
||||
|
||||
event->SetTrusted(true);
|
||||
rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Failed to dispatch the error event!!!");
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool MediaRecorder::CheckPrincipal()
|
||||
{
|
||||
nsCOMPtr<nsIPrincipal> principal = mStream->GetPrincipal();
|
||||
nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
|
||||
if (!doc || !principal)
|
||||
return false;
|
||||
|
||||
bool subsumes;
|
||||
if (NS_FAILED(doc->NodePrincipal()->Subsumes(principal, &subsumes)))
|
||||
return false;
|
||||
|
||||
return subsumes;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
120
content/media/MediaRecorder.h
Normal file
120
content/media/MediaRecorder.h
Normal file
@ -0,0 +1,120 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MediaRecorder_h
|
||||
#define MediaRecorder_h
|
||||
|
||||
#include "DOMMediaStream.h"
|
||||
#include "MediaEncoder.h"
|
||||
#include "mozilla/dom/MediaRecorderBinding.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "EncodedBufferCache.h"
|
||||
|
||||
// Max size for allowing queue encoded data in memory
|
||||
#define MAX_ALLOW_MEMORY_BUFFER 1024000
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* Implementation of https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-capture/MediaRecorder.html
|
||||
* The MediaRecorder accepts a mediaStream as input source passed from UA. When recorder starts,
|
||||
* a MediaEncoder will be created and accept the mediaStream as input source.
|
||||
* Encoder will get the raw data by track data changes, encode it by selected MIME Type, then store the encoded in EncodedBufferCache object.
|
||||
* The encoded data will be extracted on every timeslice passed from Start function call or by RequestData function.
|
||||
* Thread model:
|
||||
* When the recorder starts, it creates a "Media Encoder" thread to read data from MediaEncoder object and store buffer in EncodedBufferCache object.
|
||||
* Also extract the encoded data and create blobs on every timeslice passed from start function or RequestData function called by UA.
|
||||
*/
|
||||
|
||||
class MediaRecorder : public nsDOMEventTargetHelper
|
||||
{
|
||||
class ExtractEncodedDataTask;
|
||||
class PushBlobTask;
|
||||
class PushErrorMessageTask;
|
||||
public:
|
||||
MediaRecorder(DOMMediaStream&);
|
||||
virtual ~MediaRecorder();
|
||||
|
||||
// nsWrapperCache
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
nsPIDOMWindow* GetParentObject() { return GetOwner(); }
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaRecorder,
|
||||
nsDOMEventTargetHelper)
|
||||
|
||||
// WebIDL
|
||||
// Start recording. If timeSlice has been provided, mediaRecorder will
|
||||
// raise a dataavailable event containing the Blob of collected data on every timeSlice milliseconds.
|
||||
// If timeSlice isn't provided, UA should call the RequestData to obtain the Blob data, also set the mTimeSlice to zero.
|
||||
void Start(const Optional<int32_t>& timeSlice, ErrorResult & aResult);
|
||||
// Stop the recording activiy. Including stop the Media Encoder thread, un-hook the mediaStreamListener to encoder.
|
||||
void Stop(ErrorResult& aResult);
|
||||
// Extract encoded data Blob from EncodedBufferCache.
|
||||
void RequestData(ErrorResult& aResult);
|
||||
// Return the The DOMMediaStream passed from UA.
|
||||
DOMMediaStream* Stream() const { return mStream; }
|
||||
// The current state of the MediaRecorder object.
|
||||
RecordingState State() const { return mState; }
|
||||
// Return the current encoding MIME type selected by the MediaEncoder.
|
||||
void GetMimeType(nsString &aMimeType) { aMimeType = mMimeType; }
|
||||
|
||||
static already_AddRefed<MediaRecorder>
|
||||
Constructor(const GlobalObject& aGlobal, JSContext* aCx, DOMMediaStream& aStream,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// EventHandler
|
||||
IMPL_EVENT_HANDLER(dataavailable)
|
||||
IMPL_EVENT_HANDLER(error)
|
||||
IMPL_EVENT_HANDLER(stop)
|
||||
IMPL_EVENT_HANDLER(warning)
|
||||
|
||||
friend class ExtractEncodedData;
|
||||
|
||||
protected:
|
||||
void Init(JSContext* aCx, nsPIDOMWindow* aOwnerWindow);
|
||||
// Copy encoded data from encoder to EncodedBufferCache. This function runs in the Media Encoder Thread.
|
||||
void ExtractEncodedData();
|
||||
|
||||
MediaRecorder& operator = (const MediaRecorder& x) MOZ_DELETE;
|
||||
// Create dataavailable event with Blob data and it runs in main thread
|
||||
nsresult CreateAndDispatchBlobEvent();
|
||||
// Creating a simple event to notify UA simple event.
|
||||
void DispatchSimpleEvent(const nsAString & aStr);
|
||||
// Creating a error event with message.
|
||||
void NotifyError(nsresult aRv);
|
||||
// Check if the recorder's principal is the subsume of mediaStream
|
||||
bool CheckPrincipal();
|
||||
|
||||
MediaRecorder(const MediaRecorder& x) MOZ_DELETE; // prevent bad usage
|
||||
|
||||
|
||||
// Runnable thread for read data from mediaEncoder. It starts at MediaRecorder::Start() and stops at MediaRecorder::Stop().
|
||||
nsCOMPtr<nsIThread> mReadThread;
|
||||
// The MediaEncoder object initializes on start() and destroys in ~MediaRecorder.
|
||||
nsRefPtr<MediaEncoder> mEncoder;
|
||||
// MediaStream passed from js context
|
||||
nsRefPtr<DOMMediaStream> mStream;
|
||||
// This object creates on start() and destroys in ~MediaRecorder.
|
||||
nsAutoPtr<EncodedBufferCache> mEncodedBufferCache;
|
||||
// It specifies the container format as well as the audio and video capture formats.
|
||||
nsString mMimeType;
|
||||
// The interval of timer passed from Start(). On every mTimeSlice milliseconds, if there are buffers store in the EncodedBufferCache,
|
||||
// a dataavailable event will be fired.
|
||||
int32_t mTimeSlice;
|
||||
// The current state of the MediaRecorder object.
|
||||
RecordingState mState;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -60,6 +60,7 @@ EXPORTS += [
|
||||
'BufferMediaResource.h',
|
||||
'DOMMediaStream.h',
|
||||
'DecoderTraits.h',
|
||||
'EncodedBufferCache.h',
|
||||
'FileBlockCache.h',
|
||||
'MediaCache.h',
|
||||
'MediaDecoder.h',
|
||||
@ -67,6 +68,7 @@ EXPORTS += [
|
||||
'MediaDecoderReader.h',
|
||||
'MediaDecoderStateMachine.h',
|
||||
'MediaMetadataManager.h',
|
||||
'MediaRecorder.h',
|
||||
'MediaResource.h',
|
||||
'MediaSegment.h',
|
||||
'MediaStreamGraph.h',
|
||||
@ -101,11 +103,13 @@ CPP_SOURCES += [
|
||||
'AudioStreamTrack.cpp',
|
||||
'DOMMediaStream.cpp',
|
||||
'DecoderTraits.cpp',
|
||||
'EncodedBufferCache.cpp',
|
||||
'FileBlockCache.cpp',
|
||||
'MediaCache.cpp',
|
||||
'MediaDecoder.cpp',
|
||||
'MediaDecoderReader.cpp',
|
||||
'MediaDecoderStateMachine.cpp',
|
||||
'MediaRecorder.cpp',
|
||||
'MediaResource.cpp',
|
||||
'MediaStreamGraph.cpp',
|
||||
'MediaStreamTrack.cpp',
|
||||
|
@ -647,6 +647,12 @@ DOMInterfaces = {
|
||||
'concrete': False
|
||||
},
|
||||
|
||||
'MediaRecorder': {
|
||||
'headerFile': 'MediaRecorder.h',
|
||||
'implicitJSContext': [ 'constructor' ],
|
||||
'resultNotAddRefed': [ 'stream' ]
|
||||
},
|
||||
|
||||
'MessageEvent': {
|
||||
'nativeType': 'nsDOMMessageEvent',
|
||||
},
|
||||
|
45
dom/webidl/MediaRecorder.webidl
Normal file
45
dom/webidl/MediaRecorder.webidl
Normal file
@ -0,0 +1,45 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-capture/MediaRecorder.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
enum RecordingState { "inactive", "recording", "paused" };
|
||||
|
||||
[Constructor(MediaStream stream)]
|
||||
interface MediaRecorder : EventTarget {
|
||||
|
||||
readonly attribute MediaStream stream;
|
||||
|
||||
readonly attribute RecordingState state;
|
||||
|
||||
readonly attribute DOMString mimeType;
|
||||
|
||||
[SetterThrows]
|
||||
attribute EventHandler ondataavailable;
|
||||
|
||||
[SetterThrows]
|
||||
attribute EventHandler onerror;
|
||||
|
||||
[SetterThrows]
|
||||
attribute EventHandler onstop;
|
||||
|
||||
[SetterThrows]
|
||||
attribute EventHandler onwarning;
|
||||
|
||||
[Throws]
|
||||
void start(optional long timeSlice);
|
||||
|
||||
[Throws]
|
||||
void stop();
|
||||
|
||||
[Throws]
|
||||
void requestData();
|
||||
};
|
||||
|
@ -174,6 +174,7 @@ webidl_files = \
|
||||
LocalMediaStream.webidl \
|
||||
Location.webidl \
|
||||
MediaError.webidl \
|
||||
MediaRecorder.webidl \
|
||||
MediaSource.webidl \
|
||||
MediaStream.webidl \
|
||||
MediaStreamAudioDestinationNode.webidl \
|
||||
|
@ -461,6 +461,12 @@ enum nsEventStructType {
|
||||
#define NS_NETWORK_UPLOAD_EVENT (NS_NETWORK_EVENT_START + 1)
|
||||
#define NS_NETWORK_DOWNLOAD_EVENT (NS_NETWORK_EVENT_START + 2)
|
||||
|
||||
// MediaRecorder events.
|
||||
#define NS_MEDIARECORDER_EVENT_START 5700
|
||||
#define NS_MEDIARECORDER_DATAAVAILABLE (NS_MEDIARECORDER_EVENT_START + 1)
|
||||
#define NS_MEDIARECORDER_WARNING (NS_MEDIARECORDER_EVENT_START + 2)
|
||||
#define NS_MEDIARECORDER_STOP (NS_MEDIARECORDER_EVENT_START + 3)
|
||||
|
||||
#ifdef MOZ_GAMEPAD
|
||||
// Gamepad input events
|
||||
#define NS_GAMEPAD_START 6000
|
||||
|
Loading…
Reference in New Issue
Block a user