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"
16 } // namespace WebCore
22 class AudioParamTimeline
;
23 class DelayNodeEngine
;
24 struct AudioTimelineEvent
;
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
{
40 * Construct with null channel data pointers.
42 explicit ThreadSharedFloatArrayBufferList(uint32_t aCount
) {
43 mContents
.SetLength(aCount
);
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()
58 struct Storage final
{
59 Storage() : mDataToFree(nullptr), mFree(nullptr), mSampleData(nullptr) {}
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
70 return aMallocSizeOf(mDataToFree
);
78 * This can be called on any thread.
80 uint32_t GetChannels() const { return mContents
.Length(); }
82 * This can be called on any thread.
84 const float* GetData(uint32_t aIndex
) const {
85 return mContents
[aIndex
].mSampleData
;
88 * This can be called on any thread, but only when the calling thread is the
91 float* GetDataForWrite(uint32_t aIndex
) {
92 MOZ_ASSERT(!IsShared());
93 return mContents
[aIndex
].mSampleData
;
97 * Call this only during initialization, before the object is handed to
100 void SetData(uint32_t aIndex
, void* aDataToFree
, void (*aFreeFunc
)(void*),
102 Storage
* s
= &mContents
[aIndex
];
104 s
->mFree(s
->mDataToFree
);
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
);
130 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const override
{
131 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf
);
135 AutoTArray
<Storage
, 2> mContents
;
139 * aChunk must have been allocated by AllocateAudioBlock.
141 void WriteZeroesToAudioBlock(AudioBlock
* aChunk
, uint32_t aStart
,
145 * Copy with scale. aScale == 1.0f should be optimized.
147 void AudioBufferCopyWithScale(const float* aInput
, float aScale
, float* aOutput
,
151 * Pointwise multiply-add operation. aScale == 1.0f should be optimized.
153 void AudioBufferAddWithScale(const float* aInput
, float aScale
, float* aOutput
,
157 * Pointwise multiply-add operation. aScale == 1.0f should be optimized.
159 void AudioBlockAddChannelWithScale(const float aInput
[WEBAUDIO_BLOCK_SIZE
],
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
,
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
{
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
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
308 virtual void ProcessBlock(AudioNodeTrack
* aTrack
, GraphTime aFrom
,
309 const AudioBlock
& aInput
, AudioBlock
* aOutput
,
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());
350 dom::AudioNode
* NodeMainThread() const {
351 MOZ_ASSERT(NS_IsMainThread());
356 MOZ_ASSERT(NS_IsMainThread());
357 MOZ_ASSERT(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.
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
;
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
;
387 const RefPtr
<AbstractThread
> mAbstractMainThread
;
390 } // namespace mozilla
392 #endif /* MOZILLA_AUDIONODEENGINE_H_ */