Bug 1858958 - WebIDL file and skeleton code for AudioData. r=chunmin,webidl,saschanaz

Differential Revision: https://phabricator.services.mozilla.com/D190943
This commit is contained in:
Paul Adenot 2024-03-06 14:00:12 +00:00
Родитель 84afc3d817
Коммит 7ffa65915d
5 изменённых файлов: 542 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,301 @@
/* -*- 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/Assertions.h"
#include "mozilla/Logging.h"
#include "mozilla/dom/AudioData.h"
#include "mozilla/dom/AudioDataBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "nsStringFwd.h"
#include <utility>
#include "AudioSampleFormat.h"
#include "WebCodecsUtils.h"
#include "js/StructuredClone.h"
#include "mozilla/Maybe.h"
#include "mozilla/Result.h"
extern mozilla::LazyLogModule gWebCodecsLog;
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 LOGD
# undef LOGD
#endif // LOGD
#define LOGD(msg, ...) LOG_INTERNAL(Debug, 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_CLASS(AudioData)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioData)
tmp->CloseIfNeeded();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioData)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioData)
// AudioData should be released as soon as its refcount drops to zero,
// without waiting for async deletion by the cycle collector, since it may hold
// a large-size PCM buffer.
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(AudioData, CloseIfNeeded())
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioData)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
/*
* W3C Webcodecs AudioData implementation
*/
AudioData::AudioData(nsIGlobalObject* aParent,
const AudioDataSerializedData& aData)
: mParent(aParent),
mTimestamp(aData.mTimestamp),
mNumberOfChannels(aData.mNumberOfChannels),
mNumberOfFrames(aData.mNumberOfFrames),
mSampleRate(aData.mSampleRate),
mAudioSampleFormat(aData.mAudioSampleFormat),
// The resource is not copied, but referenced
mResource(aData.mResource) {
MOZ_ASSERT(mParent);
MOZ_ASSERT(mResource,
"Resource should always be present then receiving a transfer.");
}
AudioData::AudioData(const AudioData& aOther)
: mParent(aOther.mParent),
mTimestamp(aOther.mTimestamp),
mNumberOfChannels(aOther.mNumberOfChannels),
mNumberOfFrames(aOther.mNumberOfFrames),
mSampleRate(aOther.mSampleRate),
mAudioSampleFormat(aOther.mAudioSampleFormat),
// The resource is not copied, but referenced
mResource(aOther.mResource) {
MOZ_ASSERT(mParent);
}
Result<already_AddRefed<AudioDataResource>, nsresult>
AudioDataResource::Construct(
const OwningMaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer& aInit) {
FallibleTArray<uint8_t> copied;
uint8_t* rv = ProcessTypedArraysFixed(
aInit, [&](const Span<uint8_t>& aData) -> uint8_t* {
return copied.AppendElements(aData.Elements(), aData.Length(),
fallible);
});
if (!rv) {
LOGE("AudioDataResource::Ctor: OOM");
return Err(NS_ERROR_OUT_OF_MEMORY);
}
return MakeAndAddRef<AudioDataResource>(std::move(copied));
}
AudioData::AudioData(
nsIGlobalObject* aParent,
already_AddRefed<mozilla::dom::AudioDataResource> aResource,
const AudioDataInit& aInit)
: mParent(aParent),
mTimestamp(aInit.mTimestamp),
mNumberOfChannels(aInit.mNumberOfChannels),
mNumberOfFrames(aInit.mNumberOfFrames),
mSampleRate(aInit.mSampleRate),
mAudioSampleFormat(Some(aInit.mFormat)),
mResource(std::move(aResource)) {
MOZ_ASSERT(mParent);
}
nsIGlobalObject* AudioData::GetParentObject() const {
AssertIsOnOwningThread();
return mParent.get();
}
JSObject* AudioData::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
AssertIsOnOwningThread();
return AudioData_Binding::Wrap(aCx, this, aGivenProto);
}
uint32_t BytesPerSamples(const mozilla::dom::AudioSampleFormat& aFormat) {
switch (aFormat) {
case AudioSampleFormat::U8:
case AudioSampleFormat::U8_planar:
return sizeof(uint8_t);
case AudioSampleFormat::S16:
case AudioSampleFormat::S16_planar:
return sizeof(int16_t);
case AudioSampleFormat::S32:
case AudioSampleFormat::F32:
case AudioSampleFormat::S32_planar:
case AudioSampleFormat::F32_planar:
return sizeof(float);
}
}
Result<Ok, nsCString> IsValidAudioDataInit(const AudioDataInit& aInit) {
return Ok();
}
const char* FormatToString(AudioSampleFormat aFormat) {
switch (aFormat) {
case AudioSampleFormat::U8:
return "u8";
case AudioSampleFormat::S16:
return "s16";
case AudioSampleFormat::S32:
return "s32";
case AudioSampleFormat::F32:
return "f32";
case AudioSampleFormat::U8_planar:
return "u8-planar";
case AudioSampleFormat::S16_planar:
return "s16-planar";
case AudioSampleFormat::S32_planar:
return "s32-planar";
case AudioSampleFormat::F32_planar:
return "f32-planar";
}
}
/* static */
already_AddRefed<AudioData> AudioData::Constructor(const GlobalObject& aGlobal,
const AudioDataInit& aInit,
ErrorResult& aRv) {
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
LOGD("[%p] AudioData(fmt: %s, rate: %f, ch: %" PRIu32 ", ts: %" PRId64 ")",
global.get(), FormatToString(aInit.mFormat), aInit.mSampleRate,
aInit.mNumberOfChannels, aInit.mTimestamp);
if (!global) {
LOGE("Global unavailable");
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
return MakeAndAddRef<mozilla::dom::AudioData>(global, resource.unwrap(),
aInit);
}
// https://w3c.github.io/webcodecs/#dom-audiodata-format
Nullable<mozilla::dom::AudioSampleFormat> AudioData::GetFormat() const {
AssertIsOnOwningThread();
return MaybeToNullable(mAudioSampleFormat);
}
// https://w3c.github.io/webcodecs/#dom-audiodata-samplerate
float AudioData::SampleRate() const {
AssertIsOnOwningThread();
return mSampleRate;
}
// https://w3c.github.io/webcodecs/#dom-audiodata-numberofframes
uint32_t AudioData::NumberOfFrames() const {
AssertIsOnOwningThread();
return mNumberOfFrames;
}
// https://w3c.github.io/webcodecs/#dom-audiodata-numberofchannels
uint32_t AudioData::NumberOfChannels() const {
AssertIsOnOwningThread();
return mNumberOfChannels;
}
// https://w3c.github.io/webcodecs/#dom-audiodata-duration
uint64_t AudioData::Duration() const {
AssertIsOnOwningThread();
// The spec isn't clear in which direction to convert to integer.
// https://github.com/w3c/webcodecs/issues/726
return static_cast<uint64_t>(
static_cast<float>(USECS_PER_S * mNumberOfFrames) / mSampleRate);
}
// https://w3c.github.io/webcodecs/#dom-audiodata-timestamp
int64_t AudioData::Timestamp() const {
AssertIsOnOwningThread();
return mTimestamp;
}
nsCString AudioData::ToString() const {
if (!mResource) {
return nsCString("AudioData[detached]");
}
return nsPrintfCString("AudioData[%zu bytes %s %fHz %" PRIu32 "x%" PRIu32
"ch]",
mResource->Data().LengthBytes(),
FormatToString(mAudioSampleFormat.value()),
mSampleRate, mNumberOfFrames, mNumberOfChannels);
}
// https://w3c.github.io/webcodecs/#dom-audiodata-copyto
void AudioData::CopyTo(
const MaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer& aDestination,
const AudioDataCopyToOptions& aOptions, ErrorResult& aRv) {
AssertIsOnOwningThread();
}
// https://w3c.github.io/webcodecs/#dom-audiodata-clone
already_AddRefed<AudioData> AudioData::Clone(ErrorResult& aRv) {
AssertIsOnOwningThread();
}
// https://w3c.github.io/webcodecs/#close-audiodata
void AudioData::Close() {
AssertIsOnOwningThread();
}
// https://w3c.github.io/webcodecs/#ref-for-deserialization-steps%E2%91%A1
/* static */
JSObject* AudioData::ReadStructuredClone(JSContext* aCx,
nsIGlobalObject* aGlobal,
JSStructuredCloneReader* aReader,
const AudioDataSerializedData& aData) {
}
// https://w3c.github.io/webcodecs/#ref-for-audiodata%E2%91%A2%E2%91%A2
bool AudioData::WriteStructuredClone(JSStructuredCloneWriter* aWriter,
StructuredCloneHolder* aHolder) const {
AssertIsOnOwningThread();
}
// https://w3c.github.io/webcodecs/#ref-for-transfer-steps
UniquePtr<AudioData::TransferredData> AudioData::Transfer() {
AssertIsOnOwningThread();
}
// https://w3c.github.io/webcodecs/#ref-for-transfer-receiving-steps
/* static */
already_AddRefed<AudioData> AudioData::FromTransferred(nsIGlobalObject* aGlobal,
TransferredData* aData) {
}
void AudioData::CloseIfNeeded() {
if (mResource) {
mResource = nullptr;
}
}
#undef LOGD
#undef LOGE
#undef LOG_INTERNAL
} // namespace mozilla::dom

Просмотреть файл

@ -0,0 +1,175 @@
/* -*- 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_AudioData_h
#define mozilla_dom_AudioData_h
#include "AudioSampleFormat.h"
#include "WebCodecsUtils.h"
#include "js/TypeDecls.h"
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/NotNull.h"
#include "mozilla/Span.h"
#include "mozilla/dom/AudioDataBinding.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/TypedArray.h"
#include "mozilla/dom/StructuredCloneHolder.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
class nsIGlobalObject;
class nsIURI;
namespace mozilla::dom {
class MaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer;
class OwningMaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer;
class Promise;
struct AudioDataBufferInit;
struct AudioDataCopyToOptions;
struct AudioDataInit;
} // namespace mozilla::dom
namespace mozilla::dom {
class AudioData;
class AudioDataResource;
struct AudioDataSerializedData;
class AudioData final : public nsISupports, public nsWrapperCache {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(AudioData)
public:
AudioData(nsIGlobalObject* aParent, const AudioDataSerializedData& aData);
AudioData(nsIGlobalObject* aParent,
already_AddRefed<AudioDataResource> aResource,
const AudioDataInit& aInit);
AudioData(const AudioData& aOther);
protected:
~AudioData() = default;
public:
nsIGlobalObject* GetParentObject() const;
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<AudioData> Constructor(const GlobalObject& aGlobal,
const AudioDataInit& aInit,
ErrorResult& aRv);
Nullable<mozilla::dom::AudioSampleFormat> GetFormat() const;
float SampleRate() const;
uint32_t NumberOfFrames() const;
uint32_t NumberOfChannels() const;
uint64_t Duration() const; // microseconds
int64_t Timestamp() const; // microseconds
uint32_t AllocationSize(const AudioDataCopyToOptions& aOptions,
ErrorResult& aRv);
void CopyTo(
const MaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer& aDestination,
const AudioDataCopyToOptions& aOptions, ErrorResult& aRv);
already_AddRefed<AudioData> Clone(ErrorResult& aRv);
void Close();
// [Serializable] implementations: {Read, Write}StructuredClone
static JSObject* ReadStructuredClone(JSContext* aCx, nsIGlobalObject* aGlobal,
JSStructuredCloneReader* aReader,
const AudioDataSerializedData& aData);
bool WriteStructuredClone(JSStructuredCloneWriter* aWriter,
StructuredCloneHolder* aHolder) const;
// [Transferable] implementations: Transfer, FromTransferred
using TransferredData = AudioDataSerializedData;
UniquePtr<TransferredData> Transfer();
static already_AddRefed<AudioData> FromTransferred(nsIGlobalObject* aGlobal,
TransferredData* aData);
private:
size_t ComputeCopyElementCount(const AudioDataCopyToOptions& aOptions,
ErrorResult& aRv);
nsCString ToString() const;
// AudioData can run on either main thread or worker thread.
void AssertIsOnOwningThread() const { NS_ASSERT_OWNINGTHREAD(AudioData); }
void CloseIfNeeded();
nsCOMPtr<nsIGlobalObject> mParent;
friend struct AudioDataSerializedData;
int64_t mTimestamp;
uint32_t mNumberOfChannels;
uint32_t mNumberOfFrames;
float mSampleRate;
Maybe<AudioSampleFormat> mAudioSampleFormat;
RefPtr<mozilla::dom::AudioDataResource> mResource;
};
class AudioDataResource final {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioDataResource);
AudioDataResource(FallibleTArray<uint8_t>&& aData)
: mData(std::move(aData)) {}
explicit AudioDataResource()
: mData() {}
static AudioDataResource* Create(const Span<uint8_t>& aData) {
AudioDataResource* resource = new AudioDataResource();
if (!resource->mData.AppendElements(aData, mozilla::fallible_t())) {
return nullptr;
}
return resource;
}
static Result<already_AddRefed<AudioDataResource>, nsresult> Construct(
const OwningMaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer& aInit);
Span<uint8_t> Data() { return Span(mData.Elements(), mData.Length()); };
private:
~AudioDataResource() = default;
// It's always possible for the allocation to fail -- the size is
// controled by script.
FallibleTArray<uint8_t> mData;
};
struct AudioDataSerializedData {
AudioDataSerializedData(const AudioData& aFrom)
: mTimestamp(aFrom.Timestamp()),
mNumberOfChannels(aFrom.NumberOfChannels()),
mNumberOfFrames(aFrom.NumberOfFrames()),
mSampleRate(aFrom.SampleRate()),
mAudioSampleFormat(NullableToMaybe(aFrom.GetFormat())),
mResource(aFrom.mResource) {}
int64_t mTimestamp{};
uint32_t mNumberOfChannels{};
uint32_t mNumberOfFrames{};
float mSampleRate{};
Maybe<AudioSampleFormat> mAudioSampleFormat;
RefPtr<AudioDataResource> mResource;
};
} // namespace mozilla::dom
#endif // mozilla_dom_AudioData_h

Просмотреть файл

@ -21,6 +21,7 @@ EXPORTS.mozilla += [
]
EXPORTS.mozilla.dom += [
"AudioData.h",
"DecoderTemplate.h",
"DecoderTypes.h",
"EncodedVideoChunk.h",
@ -35,6 +36,7 @@ EXPORTS.mozilla.dom += [
]
UNIFIED_SOURCES += [
"AudioData.cpp",
"DecoderAgent.cpp",
"DecoderTemplate.cpp",
"EncodedVideoChunk.cpp",

Просмотреть файл

@ -0,0 +1,63 @@
/* -*- 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/#audiodata
*/
// [Serializable, Transferable] are implemented without adding attributes here,
// but directly with {Read,Write}StructuredClone and Transfer/FromTransfered.
[Exposed=(Window,DedicatedWorker)]
interface AudioData {
[Throws]
constructor(AudioDataInit init);
readonly attribute AudioSampleFormat? format;
readonly attribute float sampleRate;
readonly attribute unsigned long numberOfFrames;
readonly attribute unsigned long numberOfChannels;
readonly attribute unsigned long long duration; // microseconds
readonly attribute long long timestamp; // microseconds
[Throws]
unsigned long allocationSize(AudioDataCopyToOptions options);
[Throws]
undefined copyTo(
// bug 1696216: Should be `copyTo(AllowSharedBufferSource destination, ...)`
([AllowShared] ArrayBufferView or [AllowShared] ArrayBuffer) destination,
AudioDataCopyToOptions options);
[Throws]
AudioData clone();
undefined close();
};
dictionary AudioDataInit {
required AudioSampleFormat format;
required float sampleRate;
required [EnforceRange] unsigned long numberOfFrames;
required [EnforceRange] unsigned long numberOfChannels;
required [EnforceRange] long long timestamp; // microseconds
// bug 1696216: Should be AllowSharedBufferSource
required ([AllowShared] ArrayBufferView or [AllowShared] ArrayBuffer) data;
sequence<ArrayBuffer> transfer = [];
};
enum AudioSampleFormat {
"u8",
"s16",
"s32",
"f32",
"u8-planar",
"s16-planar",
"s32-planar",
"f32-planar",
};
dictionary AudioDataCopyToOptions {
required [EnforceRange] unsigned long planeIndex;
[EnforceRange] unsigned long frameOffset = 0;
[EnforceRange] unsigned long frameCount;
AudioSampleFormat format;
};

Просмотреть файл

@ -416,6 +416,7 @@ WEBIDL_FILES = [
"AudioBuffer.webidl",
"AudioBufferSourceNode.webidl",
"AudioContext.webidl",
"AudioData.webidl",
"AudioDestinationNode.webidl",
"AudioListener.webidl",
"AudioNode.webidl",