mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1859536 - Implement EncodedAudioChunk. r=chunmin,webidl,saschanaz
I thought about not copy-pasting, but it didn't result in something that was clearer, it was in fact more complex. Differential Revision: https://phabricator.services.mozilla.com/D192337
This commit is contained in:
parent
384df9f700
commit
28499f8b24
@ -34,6 +34,8 @@
|
|||||||
#include "mozilla/dom/DOMTypes.h"
|
#include "mozilla/dom/DOMTypes.h"
|
||||||
#include "mozilla/dom/Directory.h"
|
#include "mozilla/dom/Directory.h"
|
||||||
#include "mozilla/dom/DocGroup.h"
|
#include "mozilla/dom/DocGroup.h"
|
||||||
|
#include "mozilla/dom/EncodedAudioChunk.h"
|
||||||
|
#include "mozilla/dom/EncodedAudioChunkBinding.h"
|
||||||
#include "mozilla/dom/EncodedVideoChunk.h"
|
#include "mozilla/dom/EncodedVideoChunk.h"
|
||||||
#include "mozilla/dom/EncodedVideoChunkBinding.h"
|
#include "mozilla/dom/EncodedVideoChunkBinding.h"
|
||||||
#include "mozilla/dom/File.h"
|
#include "mozilla/dom/File.h"
|
||||||
@ -400,6 +402,7 @@ void StructuredCloneHolder::Read(nsIGlobalObject* aGlobal, JSContext* aCx,
|
|||||||
mClonedSurfaces.Clear();
|
mClonedSurfaces.Clear();
|
||||||
mInputStreamArray.Clear();
|
mInputStreamArray.Clear();
|
||||||
mVideoFrames.Clear();
|
mVideoFrames.Clear();
|
||||||
|
mEncodedAudioChunks.Clear();
|
||||||
mEncodedVideoChunks.Clear();
|
mEncodedVideoChunks.Clear();
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
@ -1139,6 +1142,18 @@ JSObject* StructuredCloneHolder::CustomReadHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (StaticPrefs::dom_media_webcodecs_enabled() &&
|
||||||
|
aTag == SCTAG_DOM_ENCODEDAUDIOCHUNK &&
|
||||||
|
CloneScope() == StructuredCloneScope::SameProcess &&
|
||||||
|
aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
|
||||||
|
JS::Rooted<JSObject*> global(aCx, mGlobal->GetGlobalJSObject());
|
||||||
|
if (EncodedAudioChunk_Binding::ConstructorEnabled(aCx, global)) {
|
||||||
|
return EncodedAudioChunk::ReadStructuredClone(
|
||||||
|
aCx, mGlobal, aReader, EncodedAudioChunks()[aIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return ReadFullySerializableObjects(aCx, aReader, aTag, false);
|
return ReadFullySerializableObjects(aCx, aReader, aTag, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1269,6 +1284,18 @@ bool StructuredCloneHolder::CustomWriteHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See if this is a EncodedAudioChunk object.
|
||||||
|
if (StaticPrefs::dom_media_webcodecs_enabled()) {
|
||||||
|
EncodedAudioChunk* encodedAudioChunk = nullptr;
|
||||||
|
if (NS_SUCCEEDED(
|
||||||
|
UNWRAP_OBJECT(EncodedAudioChunk, &obj, encodedAudioChunk))) {
|
||||||
|
SameProcessScopeRequired(aSameProcessScopeRequired);
|
||||||
|
return CloneScope() == StructuredCloneScope::SameProcess
|
||||||
|
? encodedAudioChunk->WriteStructuredClone(aWriter, this)
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// We only care about streams, so ReflectorToISupportsStatic is fine.
|
// We only care about streams, so ReflectorToISupportsStatic is fine.
|
||||||
nsCOMPtr<nsISupports> base = xpc::ReflectorToISupportsStatic(aObj);
|
nsCOMPtr<nsISupports> base = xpc::ReflectorToISupportsStatic(aObj);
|
||||||
|
@ -165,6 +165,7 @@ class StructuredCloneHolderBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class BlobImpl;
|
class BlobImpl;
|
||||||
|
class EncodedAudioChunkData;
|
||||||
class EncodedVideoChunkData;
|
class EncodedVideoChunkData;
|
||||||
class MessagePort;
|
class MessagePort;
|
||||||
class MessagePortIdentifier;
|
class MessagePortIdentifier;
|
||||||
@ -277,6 +278,10 @@ class StructuredCloneHolder : public StructuredCloneHolderBase {
|
|||||||
return mEncodedVideoChunks;
|
return mEncodedVideoChunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsTArray<EncodedAudioChunkData>& EncodedAudioChunks() {
|
||||||
|
return mEncodedAudioChunks;
|
||||||
|
}
|
||||||
|
|
||||||
// Implementations of the virtual methods to allow cloning of objects which
|
// Implementations of the virtual methods to allow cloning of objects which
|
||||||
// JS engine itself doesn't clone.
|
// JS engine itself doesn't clone.
|
||||||
|
|
||||||
@ -388,6 +393,9 @@ class StructuredCloneHolder : public StructuredCloneHolderBase {
|
|||||||
// Used for cloning EncodedVideoChunk in the structured cloning algorithm.
|
// Used for cloning EncodedVideoChunk in the structured cloning algorithm.
|
||||||
nsTArray<EncodedVideoChunkData> mEncodedVideoChunks;
|
nsTArray<EncodedVideoChunkData> mEncodedVideoChunks;
|
||||||
|
|
||||||
|
// Used for cloning EncodedAudioChunk in the structured cloning algorithm.
|
||||||
|
nsTArray<EncodedAudioChunkData> mEncodedAudioChunks;
|
||||||
|
|
||||||
// This raw pointer is only set within ::Read() and is unset by the end.
|
// This raw pointer is only set within ::Read() and is unset by the end.
|
||||||
nsIGlobalObject* MOZ_NON_OWNING_REF mGlobal;
|
nsIGlobalObject* MOZ_NON_OWNING_REF mGlobal;
|
||||||
|
|
||||||
|
@ -159,6 +159,8 @@ enum StructuredCloneTags : uint32_t {
|
|||||||
|
|
||||||
SCTAG_DOM_AUDIODATA,
|
SCTAG_DOM_AUDIODATA,
|
||||||
|
|
||||||
|
SCTAG_DOM_ENCODEDAUDIOCHUNK,
|
||||||
|
|
||||||
// IMPORTANT: If you plan to add an new IDB tag, it _must_ be add before the
|
// IMPORTANT: If you plan to add an new IDB tag, it _must_ be add before the
|
||||||
// "less stable" tags!
|
// "less stable" tags!
|
||||||
};
|
};
|
||||||
|
260
dom/media/webcodecs/EncodedAudioChunk.cpp
Normal file
260
dom/media/webcodecs/EncodedAudioChunk.cpp
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
/* -*- 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 "mozilla/dom/EncodedAudioChunk.h"
|
||||||
|
#include "mozilla/dom/EncodedAudioChunkBinding.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "MediaData.h"
|
||||||
|
#include "TimeUnits.h"
|
||||||
|
#include "mozilla/CheckedInt.h"
|
||||||
|
#include "mozilla/Logging.h"
|
||||||
|
#include "mozilla/PodOperations.h"
|
||||||
|
#include "mozilla/dom/StructuredCloneHolder.h"
|
||||||
|
#include "mozilla/dom/StructuredCloneTags.h"
|
||||||
|
#include "mozilla/dom/WebCodecsUtils.h"
|
||||||
|
|
||||||
|
extern mozilla::LazyLogModule gWebCodecsLog;
|
||||||
|
using mozilla::media::TimeUnit;
|
||||||
|
|
||||||
|
namespace mozilla::dom {
|
||||||
|
|
||||||
|
#ifdef LOG_INTERNAL
|
||||||
|
# undef LOG_INTERNAL
|
||||||
|
#endif // LOG_INTERNAL
|
||||||
|
#define LOG_INTERNAL(level, msg, ...) \
|
||||||
|
MOZ_LOG(gWebCodecsLog, LogLevel::level, (msg, ##__VA_ARGS__))
|
||||||
|
|
||||||
|
#ifdef LOGW
|
||||||
|
# undef LOGW
|
||||||
|
#endif // LOGW
|
||||||
|
#define LOGW(msg, ...) LOG_INTERNAL(Warning, msg, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#ifdef LOGE
|
||||||
|
# undef LOGE
|
||||||
|
#endif // LOGE
|
||||||
|
#define LOGE(msg, ...) LOG_INTERNAL(Error, msg, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
// Only needed for refcounted objects.
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(EncodedAudioChunk, mParent)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(EncodedAudioChunk)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(EncodedAudioChunk)
|
||||||
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EncodedAudioChunk)
|
||||||
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
EncodedAudioChunkData::EncodedAudioChunkData(
|
||||||
|
already_AddRefed<MediaAlignedByteBuffer> aBuffer,
|
||||||
|
const EncodedAudioChunkType& aType, int64_t aTimestamp,
|
||||||
|
Maybe<uint64_t>&& aDuration)
|
||||||
|
: mBuffer(aBuffer),
|
||||||
|
mType(aType),
|
||||||
|
mTimestamp(aTimestamp),
|
||||||
|
mDuration(aDuration) {
|
||||||
|
MOZ_ASSERT(mBuffer);
|
||||||
|
MOZ_ASSERT(mBuffer->Length() == mBuffer->Size());
|
||||||
|
MOZ_ASSERT(mBuffer->Length() <=
|
||||||
|
static_cast<size_t>(std::numeric_limits<uint32_t>::max()));
|
||||||
|
}
|
||||||
|
|
||||||
|
UniquePtr<EncodedAudioChunkData> EncodedAudioChunkData::Clone() const {
|
||||||
|
if (!mBuffer) {
|
||||||
|
LOGE("No buffer in EncodedAudioChunkData %p to clone!", this);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since EncodedAudioChunkData can be zero-sized, cloning a zero-sized chunk
|
||||||
|
// is allowed.
|
||||||
|
if (mBuffer->Size() == 0) {
|
||||||
|
LOGW("Cloning an empty EncodedAudioChunkData %p", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buffer =
|
||||||
|
MakeRefPtr<MediaAlignedByteBuffer>(mBuffer->Data(), mBuffer->Length());
|
||||||
|
if (!buffer || buffer->Size() != mBuffer->Size()) {
|
||||||
|
LOGE("OOM to copy EncodedAudioChunkData %p", this);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MakeUnique<EncodedAudioChunkData>(buffer.forget(), mType, mTimestamp,
|
||||||
|
Maybe<uint64_t>(mDuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<MediaRawData> EncodedAudioChunkData::TakeData() {
|
||||||
|
if (!mBuffer || !(*mBuffer)) {
|
||||||
|
LOGE("EncodedAudioChunkData %p has no data!", this);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<MediaRawData> sample(new MediaRawData(std::move(*mBuffer)));
|
||||||
|
sample->mKeyframe = mType == EncodedAudioChunkType::Key;
|
||||||
|
sample->mTime = TimeUnit::FromMicroseconds(mTimestamp);
|
||||||
|
sample->mTimecode = TimeUnit::FromMicroseconds(mTimestamp);
|
||||||
|
|
||||||
|
if (mDuration) {
|
||||||
|
CheckedInt64 duration(*mDuration);
|
||||||
|
if (!duration.isValid()) {
|
||||||
|
LOGE("EncodedAudioChunkData %p 's duration exceeds TimeUnit's limit",
|
||||||
|
this);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
sample->mDuration = TimeUnit::FromMicroseconds(duration.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
return sample.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodedAudioChunk::EncodedAudioChunk(
|
||||||
|
nsIGlobalObject* aParent, already_AddRefed<MediaAlignedByteBuffer> aBuffer,
|
||||||
|
const EncodedAudioChunkType& aType, int64_t aTimestamp,
|
||||||
|
Maybe<uint64_t>&& aDuration)
|
||||||
|
: EncodedAudioChunkData(std::move(aBuffer), aType, aTimestamp,
|
||||||
|
std::move(aDuration)),
|
||||||
|
mParent(aParent) {}
|
||||||
|
|
||||||
|
EncodedAudioChunk::EncodedAudioChunk(nsIGlobalObject* aParent,
|
||||||
|
const EncodedAudioChunkData& aData)
|
||||||
|
: EncodedAudioChunkData(aData), mParent(aParent) {}
|
||||||
|
|
||||||
|
nsIGlobalObject* EncodedAudioChunk::GetParentObject() const {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
return mParent.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject* EncodedAudioChunk::WrapObject(JSContext* aCx,
|
||||||
|
JS::Handle<JSObject*> aGivenProto) {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
return EncodedAudioChunk_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/webcodecs/#encodedaudiochunk-constructors
|
||||||
|
/* static */
|
||||||
|
already_AddRefed<EncodedAudioChunk> EncodedAudioChunk::Constructor(
|
||||||
|
const GlobalObject& aGlobal, const EncodedAudioChunkInit& aInit,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||||
|
if (!global) {
|
||||||
|
aRv.Throw(NS_ERROR_FAILURE);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buffer = ProcessTypedArrays(
|
||||||
|
aInit.mData,
|
||||||
|
[&](const Span<uint8_t>& aData,
|
||||||
|
JS::AutoCheckCannotGC&&) -> RefPtr<MediaAlignedByteBuffer> {
|
||||||
|
// Make sure it's in uint32_t's range.
|
||||||
|
CheckedUint32 byteLength(aData.Length());
|
||||||
|
if (!byteLength.isValid()) {
|
||||||
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (aData.Length() == 0) {
|
||||||
|
LOGW("Buffer for constructing EncodedAudioChunk is empty!");
|
||||||
|
}
|
||||||
|
RefPtr<MediaAlignedByteBuffer> buf = MakeRefPtr<MediaAlignedByteBuffer>(
|
||||||
|
aData.Elements(), aData.Length());
|
||||||
|
|
||||||
|
// Instead of checking *buf, size comparision is used to allow
|
||||||
|
// constructing a zero-sized EncodedAudioChunk.
|
||||||
|
if (!buf || buf->Size() != aData.Length()) {
|
||||||
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
});
|
||||||
|
|
||||||
|
RefPtr<EncodedAudioChunk> chunk(new EncodedAudioChunk(
|
||||||
|
global, buffer.forget(), aInit.mType, aInit.mTimestamp,
|
||||||
|
OptionalToMaybe(aInit.mDuration)));
|
||||||
|
return aRv.Failed() ? nullptr : chunk.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodedAudioChunkType EncodedAudioChunk::Type() const {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
return mType;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t EncodedAudioChunk::Timestamp() const {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
return mTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Nullable<uint64_t> EncodedAudioChunk::GetDuration() const {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
return MaybeToNullable(mDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t EncodedAudioChunk::ByteLength() const {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
MOZ_ASSERT(mBuffer);
|
||||||
|
|
||||||
|
return static_cast<uint32_t>(mBuffer->Length());
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/webcodecs/#dom-encodedaudiochunk-copyto
|
||||||
|
void EncodedAudioChunk::CopyTo(
|
||||||
|
const MaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer& aDestination,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
ProcessTypedArraysFixed(aDestination, [&](const Span<uint8_t>& aData) {
|
||||||
|
if (mBuffer->Size() > aData.size_bytes()) {
|
||||||
|
aRv.ThrowTypeError(
|
||||||
|
"Destination ArrayBuffer smaller than source EncodedAudioChunk");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PodCopy(aData.data(), mBuffer->Data(), mBuffer->Size());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/webcodecs/#ref-for-deserialization-steps
|
||||||
|
/* static */
|
||||||
|
JSObject* EncodedAudioChunk::ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal, JSStructuredCloneReader* aReader,
|
||||||
|
const EncodedAudioChunkData& aData) {
|
||||||
|
JS::Rooted<JS::Value> value(aCx, JS::NullValue());
|
||||||
|
// To avoid a rooting hazard error from returning a raw JSObject* before
|
||||||
|
// running the RefPtr destructor, RefPtr needs to be destructed before
|
||||||
|
// returning the raw JSObject*, which is why the RefPtr<EncodedAudioChunk> is
|
||||||
|
// created in the scope below. Otherwise, the static analysis infers the
|
||||||
|
// RefPtr cannot be safely destructed while the unrooted return JSObject* is
|
||||||
|
// on the stack.
|
||||||
|
{
|
||||||
|
auto frame = MakeRefPtr<EncodedAudioChunk>(aGlobal, aData);
|
||||||
|
if (!GetOrCreateDOMReflector(aCx, frame, &value) || !value.isObject()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value.toObjectOrNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/webcodecs/#ref-for-serialization-steps
|
||||||
|
bool EncodedAudioChunk::WriteStructuredClone(
|
||||||
|
JSStructuredCloneWriter* aWriter, StructuredCloneHolder* aHolder) const {
|
||||||
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
// Indexing the chunk and send the index to the receiver.
|
||||||
|
const uint32_t index =
|
||||||
|
static_cast<uint32_t>(aHolder->EncodedAudioChunks().Length());
|
||||||
|
// The serialization is limited to the same process scope so it's ok to
|
||||||
|
// serialize a reference instead of a copy.
|
||||||
|
aHolder->EncodedAudioChunks().AppendElement(EncodedAudioChunkData(*this));
|
||||||
|
return !NS_WARN_IF(
|
||||||
|
!JS_WriteUint32Pair(aWriter, SCTAG_DOM_ENCODEDAUDIOCHUNK, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef LOGW
|
||||||
|
#undef LOGE
|
||||||
|
#undef LOG_INTERNAL
|
||||||
|
|
||||||
|
} // namespace mozilla::dom
|
117
dom/media/webcodecs/EncodedAudioChunk.h
Normal file
117
dom/media/webcodecs/EncodedAudioChunk.h
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/* -*- 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 mozilla_dom_EncodedAudioChunk_h
|
||||||
|
#define mozilla_dom_EncodedAudioChunk_h
|
||||||
|
|
||||||
|
#include "js/TypeDecls.h"
|
||||||
|
#include "mozilla/ErrorResult.h"
|
||||||
|
#include "mozilla/Maybe.h"
|
||||||
|
#include "mozilla/dom/BindingDeclarations.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
#include "nsWrapperCache.h"
|
||||||
|
|
||||||
|
class nsIGlobalObject;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
class MediaAlignedByteBuffer;
|
||||||
|
class MediaRawData;
|
||||||
|
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class MaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer;
|
||||||
|
class OwningMaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer;
|
||||||
|
class StructuredCloneHolder;
|
||||||
|
|
||||||
|
enum class EncodedAudioChunkType : uint8_t;
|
||||||
|
struct EncodedAudioChunkInit;
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
namespace mozilla::dom {
|
||||||
|
|
||||||
|
class EncodedAudioChunkData {
|
||||||
|
public:
|
||||||
|
EncodedAudioChunkData(already_AddRefed<MediaAlignedByteBuffer> aBuffer,
|
||||||
|
const EncodedAudioChunkType& aType, int64_t aTimestamp,
|
||||||
|
Maybe<uint64_t>&& aDuration);
|
||||||
|
EncodedAudioChunkData(const EncodedAudioChunkData& aData) = default;
|
||||||
|
~EncodedAudioChunkData() = default;
|
||||||
|
|
||||||
|
UniquePtr<EncodedAudioChunkData> Clone() const;
|
||||||
|
already_AddRefed<MediaRawData> TakeData();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// mBuffer's byte length is guaranteed to be smaller than UINT32_MAX.
|
||||||
|
RefPtr<MediaAlignedByteBuffer> mBuffer;
|
||||||
|
EncodedAudioChunkType mType;
|
||||||
|
int64_t mTimestamp;
|
||||||
|
Maybe<uint64_t> mDuration;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EncodedAudioChunk final : public EncodedAudioChunkData,
|
||||||
|
public nsISupports,
|
||||||
|
public nsWrapperCache {
|
||||||
|
public:
|
||||||
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(EncodedAudioChunk)
|
||||||
|
|
||||||
|
public:
|
||||||
|
EncodedAudioChunk(nsIGlobalObject* aParent,
|
||||||
|
already_AddRefed<MediaAlignedByteBuffer> aBuffer,
|
||||||
|
const EncodedAudioChunkType& aType, int64_t aTimestamp,
|
||||||
|
Maybe<uint64_t>&& aDuration);
|
||||||
|
|
||||||
|
EncodedAudioChunk(nsIGlobalObject* aParent,
|
||||||
|
const EncodedAudioChunkData& aData);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~EncodedAudioChunk() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
nsIGlobalObject* GetParentObject() const;
|
||||||
|
|
||||||
|
JSObject* WrapObject(JSContext* aCx,
|
||||||
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
static already_AddRefed<EncodedAudioChunk> Constructor(
|
||||||
|
const GlobalObject& aGlobal, const EncodedAudioChunkInit& aInit,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
EncodedAudioChunkType Type() const;
|
||||||
|
|
||||||
|
int64_t Timestamp() const;
|
||||||
|
|
||||||
|
Nullable<uint64_t> GetDuration() const;
|
||||||
|
|
||||||
|
uint32_t ByteLength() const;
|
||||||
|
|
||||||
|
void CopyTo(
|
||||||
|
const MaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer& aDestination,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
// [Serializable] implementations: {Read, Write}StructuredClone
|
||||||
|
static JSObject* ReadStructuredClone(JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader,
|
||||||
|
const EncodedAudioChunkData& aData);
|
||||||
|
|
||||||
|
bool WriteStructuredClone(JSStructuredCloneWriter* aWriter,
|
||||||
|
StructuredCloneHolder* aHolder) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// EncodedAudioChunk can run on either main thread or worker thread.
|
||||||
|
void AssertIsOnOwningThread() const {
|
||||||
|
NS_ASSERT_OWNINGTHREAD(EncodedAudioChunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIGlobalObject> mParent;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla::dom
|
||||||
|
|
||||||
|
#endif // mozilla_dom_EncodedAudioChunk_h
|
@ -24,6 +24,7 @@ EXPORTS.mozilla.dom += [
|
|||||||
"AudioData.h",
|
"AudioData.h",
|
||||||
"DecoderTemplate.h",
|
"DecoderTemplate.h",
|
||||||
"DecoderTypes.h",
|
"DecoderTypes.h",
|
||||||
|
"EncodedAudioChunk.h",
|
||||||
"EncodedVideoChunk.h",
|
"EncodedVideoChunk.h",
|
||||||
"EncoderAgent.h",
|
"EncoderAgent.h",
|
||||||
"EncoderTemplate.h",
|
"EncoderTemplate.h",
|
||||||
@ -39,6 +40,7 @@ UNIFIED_SOURCES += [
|
|||||||
"AudioData.cpp",
|
"AudioData.cpp",
|
||||||
"DecoderAgent.cpp",
|
"DecoderAgent.cpp",
|
||||||
"DecoderTemplate.cpp",
|
"DecoderTemplate.cpp",
|
||||||
|
"EncodedAudioChunk.cpp",
|
||||||
"EncodedVideoChunk.cpp",
|
"EncodedVideoChunk.cpp",
|
||||||
"EncoderAgent.cpp",
|
"EncoderAgent.cpp",
|
||||||
"EncoderTemplate.cpp",
|
"EncoderTemplate.cpp",
|
||||||
|
38
dom/webidl/EncodedAudioChunk.webidl
Normal file
38
dom/webidl/EncodedAudioChunk.webidl
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/* -*- 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://w3c.github.io/webcodecs/#encodedaudiochunk
|
||||||
|
*/
|
||||||
|
|
||||||
|
// [Serializable] is implemented without adding attribute here.
|
||||||
|
[Exposed=(Window,DedicatedWorker), Pref="dom.media.webcodecs.enabled"]
|
||||||
|
interface EncodedAudioChunk {
|
||||||
|
[Throws]
|
||||||
|
constructor(EncodedAudioChunkInit init);
|
||||||
|
readonly attribute EncodedAudioChunkType type;
|
||||||
|
readonly attribute long long timestamp; // microseconds
|
||||||
|
readonly attribute unsigned long long? duration; // microseconds
|
||||||
|
readonly attribute unsigned long byteLength;
|
||||||
|
|
||||||
|
[Throws]
|
||||||
|
undefined copyTo(
|
||||||
|
// bug 1696216: Should be `copyTo(AllowSharedBufferSource destination, ...)`
|
||||||
|
([AllowShared] ArrayBufferView or [AllowShared] ArrayBuffer) destination);
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary EncodedAudioChunkInit {
|
||||||
|
required EncodedAudioChunkType type;
|
||||||
|
required [EnforceRange] long long timestamp; // microseconds
|
||||||
|
[EnforceRange] unsigned long long duration; // microseconds
|
||||||
|
// bug 1696216: Should be AllowSharedBufferSource
|
||||||
|
required ([AllowShared] ArrayBufferView or [AllowShared] ArrayBuffer) data;
|
||||||
|
sequence<ArrayBuffer> transfer = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EncodedAudioChunkType {
|
||||||
|
"key",
|
||||||
|
"delta"
|
||||||
|
};
|
@ -527,6 +527,7 @@ WEBIDL_FILES = [
|
|||||||
"DynamicsCompressorNode.webidl",
|
"DynamicsCompressorNode.webidl",
|
||||||
"Element.webidl",
|
"Element.webidl",
|
||||||
"ElementInternals.webidl",
|
"ElementInternals.webidl",
|
||||||
|
"EncodedAudioChunk.webidl",
|
||||||
"EncodedVideoChunk.webidl",
|
"EncodedVideoChunk.webidl",
|
||||||
"Event.webidl",
|
"Event.webidl",
|
||||||
"EventHandler.webidl",
|
"EventHandler.webidl",
|
||||||
|
Loading…
Reference in New Issue
Block a user