Bug 1839170 - Refactor Snap pulling, Add Firefox Snap Core22 and GNOME 42 SDK symbols...
[gecko.git] / dom / media / webaudio / AudioNodeEngine.h
blob64dd3c642a17a3c0f4094c3c77c74f6fac4bb1a3
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef MOZILLA_AUDIONODEENGINE_H_
7 #define MOZILLA_AUDIONODEENGINE_H_
9 #include "AudioSegment.h"
10 #include "mozilla/dom/AudioNode.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "mozilla/Mutex.h"
14 namespace WebCore {
15 class Reverb;
16 } // namespace WebCore
18 namespace mozilla {
20 namespace dom {
21 struct ThreeDPoint;
22 class AudioParamTimeline;
23 class DelayNodeEngine;
24 struct AudioTimelineEvent;
25 } // namespace dom
27 class AbstractThread;
28 class AudioBlock;
29 class AudioNodeTrack;
31 /**
32 * This class holds onto a set of immutable channel buffers. The storage
33 * for the buffers must be malloced, but the buffer pointers and the malloc
34 * pointers can be different (e.g. if the buffers are contained inside
35 * some malloced object).
37 class ThreadSharedFloatArrayBufferList final : public ThreadSharedObject {
38 public:
39 /**
40 * Construct with null channel data pointers.
42 explicit ThreadSharedFloatArrayBufferList(uint32_t aCount) {
43 mContents.SetLength(aCount);
45 /**
46 * Create with buffers suitable for transfer to
47 * JS::NewArrayBufferWithContents(). The buffer contents are uninitialized
48 * and so should be set using GetDataForWrite().
50 static already_AddRefed<ThreadSharedFloatArrayBufferList> Create(
51 uint32_t aChannelCount, size_t aLength, const mozilla::fallible_t&);
53 ThreadSharedFloatArrayBufferList* AsThreadSharedFloatArrayBufferList()
54 override {
55 return this;
58 struct Storage final {
59 Storage() : mDataToFree(nullptr), mFree(nullptr), mSampleData(nullptr) {}
60 ~Storage() {
61 if (mFree) {
62 mFree(mDataToFree);
63 } else {
64 MOZ_ASSERT(!mDataToFree);
67 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
68 // NB: mSampleData might not be owned, if it is it just points to
69 // mDataToFree.
70 return aMallocSizeOf(mDataToFree);
72 void* mDataToFree;
73 void (*mFree)(void*);
74 float* mSampleData;
77 /**
78 * This can be called on any thread.
80 uint32_t GetChannels() const { return mContents.Length(); }
81 /**
82 * This can be called on any thread.
84 const float* GetData(uint32_t aIndex) const {
85 return mContents[aIndex].mSampleData;
87 /**
88 * This can be called on any thread, but only when the calling thread is the
89 * only owner.
91 float* GetDataForWrite(uint32_t aIndex) {
92 MOZ_ASSERT(!IsShared());
93 return mContents[aIndex].mSampleData;
96 /**
97 * Call this only during initialization, before the object is handed to
98 * any other thread.
100 void SetData(uint32_t aIndex, void* aDataToFree, void (*aFreeFunc)(void*),
101 float* aData) {
102 Storage* s = &mContents[aIndex];
103 if (s->mFree) {
104 s->mFree(s->mDataToFree);
105 } else {
106 MOZ_ASSERT(!s->mDataToFree);
109 s->mDataToFree = aDataToFree;
110 s->mFree = aFreeFunc;
111 s->mSampleData = aData;
115 * Put this object into an error state where there are no channels.
117 void Clear() { mContents.Clear(); }
119 size_t SizeOfExcludingThis(
120 mozilla::MallocSizeOf aMallocSizeOf) const override {
121 size_t amount = ThreadSharedObject::SizeOfExcludingThis(aMallocSizeOf);
122 amount += mContents.ShallowSizeOfExcludingThis(aMallocSizeOf);
123 for (size_t i = 0; i < mContents.Length(); i++) {
124 amount += mContents[i].SizeOfExcludingThis(aMallocSizeOf);
127 return amount;
130 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
131 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
134 private:
135 AutoTArray<Storage, 2> mContents;
139 * aChunk must have been allocated by AllocateAudioBlock.
141 void WriteZeroesToAudioBlock(AudioBlock* aChunk, uint32_t aStart,
142 uint32_t aLength);
145 * Copy with scale. aScale == 1.0f should be optimized.
147 void AudioBufferCopyWithScale(const float* aInput, float aScale, float* aOutput,
148 uint32_t aSize);
151 * Pointwise multiply-add operation. aScale == 1.0f should be optimized.
153 void AudioBufferAddWithScale(const float* aInput, float aScale, float* aOutput,
154 uint32_t aSize);
157 * Pointwise multiply-add operation. aScale == 1.0f should be optimized.
159 void AudioBlockAddChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
160 float aScale,
161 float aOutput[WEBAUDIO_BLOCK_SIZE]);
164 * Pointwise copy-scaled operation. aScale == 1.0f should be optimized.
166 * Buffer size is implicitly assumed to be WEBAUDIO_BLOCK_SIZE.
168 void AudioBlockCopyChannelWithScale(const float* aInput, float aScale,
169 float* aOutput);
172 * Vector copy-scaled operation.
174 void AudioBlockCopyChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
175 const float aScale[WEBAUDIO_BLOCK_SIZE],
176 float aOutput[WEBAUDIO_BLOCK_SIZE]);
179 * Vector complex multiplication on arbitrary sized buffers.
181 void BufferComplexMultiply(const float* aInput, const float* aScale,
182 float* aOutput, uint32_t aSize);
185 * Vector maximum element magnitude ( max(abs(aInput)) ).
187 float AudioBufferPeakValue(const float* aInput, uint32_t aSize);
190 * In place gain. aScale == 1.0f should be optimized.
192 void AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE], float aScale);
195 * In place gain. aScale == 1.0f should be optimized.
197 void AudioBufferInPlaceScale(float* aBlock, float aScale, uint32_t aSize);
200 * a-rate in place gain.
202 void AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE],
203 float aScale[WEBAUDIO_BLOCK_SIZE]);
205 * a-rate in place gain.
207 void AudioBufferInPlaceScale(float* aBlock, float* aScale, uint32_t aSize);
210 * Upmix a mono input to a stereo output, scaling the two output channels by two
211 * different gain value.
212 * This algorithm is specified in the WebAudio spec.
214 void AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
215 float aGainL, float aGainR,
216 float aOutputL[WEBAUDIO_BLOCK_SIZE],
217 float aOutputR[WEBAUDIO_BLOCK_SIZE]);
219 void AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
220 float aGainL[WEBAUDIO_BLOCK_SIZE],
221 float aGainR[WEBAUDIO_BLOCK_SIZE],
222 float aOutputL[WEBAUDIO_BLOCK_SIZE],
223 float aOutputR[WEBAUDIO_BLOCK_SIZE]);
225 * Pan a stereo source according to right and left gain, and the position
226 * (whether the listener is on the left of the source or not).
227 * This algorithm is specified in the WebAudio spec.
229 void AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE],
230 const float aInputR[WEBAUDIO_BLOCK_SIZE],
231 float aGainL, float aGainR, bool aIsOnTheLeft,
232 float aOutputL[WEBAUDIO_BLOCK_SIZE],
233 float aOutputR[WEBAUDIO_BLOCK_SIZE]);
234 void AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE],
235 const float aInputR[WEBAUDIO_BLOCK_SIZE],
236 const float aGainL[WEBAUDIO_BLOCK_SIZE],
237 const float aGainR[WEBAUDIO_BLOCK_SIZE],
238 const bool aIsOnTheLeft[WEBAUDIO_BLOCK_SIZE],
239 float aOutputL[WEBAUDIO_BLOCK_SIZE],
240 float aOutputR[WEBAUDIO_BLOCK_SIZE]);
243 * Replace NaN by zeros in aSamples.
245 void NaNToZeroInPlace(float* aSamples, size_t aCount);
248 * Return the sum of squares of all of the samples in the input.
250 float AudioBufferSumOfSquares(const float* aInput, uint32_t aLength);
253 * All methods of this class and its subclasses are called on the
254 * MediaTrackGraph thread.
256 class AudioNodeEngine {
257 public:
258 // This should be compatible with AudioNodeTrack::OutputChunks.
259 typedef AutoTArray<AudioBlock, 1> OutputChunks;
261 explicit AudioNodeEngine(dom::AudioNode* aNode);
263 virtual ~AudioNodeEngine() {
264 MOZ_ASSERT(!mNode, "The node reference must be already cleared");
265 MOZ_COUNT_DTOR(AudioNodeEngine);
268 virtual dom::DelayNodeEngine* AsDelayNodeEngine() { return nullptr; }
270 virtual void SetTrackTimeParameter(uint32_t aIndex, TrackTime aParam) {
271 NS_ERROR("Invalid SetTrackTimeParameter index");
273 virtual void SetDoubleParameter(uint32_t aIndex, double aParam) {
274 NS_ERROR("Invalid SetDoubleParameter index");
276 virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam) {
277 NS_ERROR("Invalid SetInt32Parameter index");
279 virtual void RecvTimelineEvent(uint32_t aIndex,
280 dom::AudioTimelineEvent& aValue) {
281 NS_ERROR("Invalid RecvTimelineEvent index");
283 virtual void SetBuffer(AudioChunk&& aBuffer) {
284 NS_ERROR("SetBuffer called on engine that doesn't support it");
286 // This consumes the contents of aData. aData will be emptied after this
287 // returns.
288 virtual void SetRawArrayData(nsTArray<float>&& aData) {
289 NS_ERROR("SetRawArrayData called on an engine that doesn't support it");
292 virtual void SetReverb(WebCore::Reverb* aBuffer,
293 uint32_t aImpulseChannelCount) {
294 NS_ERROR("SetReverb called on engine that doesn't support it");
298 * Produce the next block of audio samples, given input samples aInput
299 * (the mixed data for input 0).
300 * aInput is guaranteed to have float sample format (if it has samples at all)
301 * and to have been resampled to the sampling rate for the track, and to have
302 * exactly WEBAUDIO_BLOCK_SIZE samples.
303 * *aFinished is set to false by the caller. The callee must not set this to
304 * true unless silent output is produced. If set to true, we'll finish the
305 * track, consider this input inactive on any downstream nodes, and not
306 * call this again.
308 virtual void ProcessBlock(AudioNodeTrack* aTrack, GraphTime aFrom,
309 const AudioBlock& aInput, AudioBlock* aOutput,
310 bool* aFinished);
312 * Produce the next block of audio samples, before input is provided.
313 * ProcessBlock() will be called later, and it then should not change
314 * aOutput. This is used only for DelayNodeEngine in a feedback loop.
316 virtual void ProduceBlockBeforeInput(AudioNodeTrack* aTrack, GraphTime aFrom,
317 AudioBlock* aOutput) {
318 MOZ_ASSERT_UNREACHABLE("ProduceBlockBeforeInput called on wrong engine");
322 * Produce the next block of audio samples, given input samples in the aInput
323 * array. There is one input sample per port in aInput, in order.
324 * This is the multi-input/output version of ProcessBlock. Only one kind
325 * of ProcessBlock is called on each node. ProcessBlocksOnPorts() is called
326 * instead of ProcessBlock() if either the number of inputs or the number of
327 * outputs is greater than 1.
329 * The numbers of AudioBlocks in aInput and aOutput are always guaranteed to
330 * match the numbers of inputs and outputs for the node.
332 virtual void ProcessBlocksOnPorts(AudioNodeTrack* aTrack, GraphTime aFrom,
333 Span<const AudioBlock> aInput,
334 Span<AudioBlock> aOutput, bool* aFinished);
336 // IsActive() returns true if the engine needs to continue processing an
337 // unfinished track even when it has silent or no input connections. This
338 // includes tail-times and when sources have been scheduled to start. If
339 // returning false, then the track can be suspended.
340 virtual bool IsActive() const { return false; }
342 // Called on graph thread when the engine will not be used again.
343 virtual void OnGraphThreadDone() {}
345 bool HasNode() const {
346 MOZ_ASSERT(NS_IsMainThread());
347 return !!mNode;
350 dom::AudioNode* NodeMainThread() const {
351 MOZ_ASSERT(NS_IsMainThread());
352 return mNode;
355 void ClearNode() {
356 MOZ_ASSERT(NS_IsMainThread());
357 MOZ_ASSERT(mNode != nullptr);
358 mNode = nullptr;
361 uint16_t InputCount() const { return mInputCount; }
362 uint16_t OutputCount() const { return mOutputCount; }
364 virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
365 // NB: |mNode| is tracked separately so it is excluded here.
366 return 0;
369 virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
370 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
373 void SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
374 AudioNodeSizes& aUsage) const {
375 aUsage.mEngine = SizeOfIncludingThis(aMallocSizeOf);
376 aUsage.mNodeType = mNodeType;
379 private:
380 // This is cleared from AudioNode::DestroyMediaTrack()
381 dom::AudioNode* MOZ_NON_OWNING_REF mNode; // main thread only
382 const char* const mNodeType;
383 const uint16_t mInputCount;
384 const uint16_t mOutputCount;
386 protected:
387 const RefPtr<AbstractThread> mAbstractMainThread;
390 } // namespace mozilla
392 #endif /* MOZILLA_AUDIONODEENGINE_H_ */