content/media/AudioNodeEngine.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6 #ifndef MOZILLA_AUDIONODEENGINE_H_
michael@0 7 #define MOZILLA_AUDIONODEENGINE_H_
michael@0 8
michael@0 9 #include "AudioSegment.h"
michael@0 10 #include "mozilla/dom/AudioNode.h"
michael@0 11 #include "mozilla/MemoryReporting.h"
michael@0 12 #include "mozilla/Mutex.h"
michael@0 13
michael@0 14 namespace mozilla {
michael@0 15
michael@0 16 namespace dom {
michael@0 17 struct ThreeDPoint;
michael@0 18 class AudioParamTimeline;
michael@0 19 class DelayNodeEngine;
michael@0 20 }
michael@0 21
michael@0 22 class AudioNodeStream;
michael@0 23
michael@0 24 /**
michael@0 25 * This class holds onto a set of immutable channel buffers. The storage
michael@0 26 * for the buffers must be malloced, but the buffer pointers and the malloc
michael@0 27 * pointers can be different (e.g. if the buffers are contained inside
michael@0 28 * some malloced object).
michael@0 29 */
michael@0 30 class ThreadSharedFloatArrayBufferList : public ThreadSharedObject {
michael@0 31 public:
michael@0 32 /**
michael@0 33 * Construct with null data.
michael@0 34 */
michael@0 35 ThreadSharedFloatArrayBufferList(uint32_t aCount)
michael@0 36 {
michael@0 37 mContents.SetLength(aCount);
michael@0 38 }
michael@0 39
michael@0 40 struct Storage {
michael@0 41 Storage()
michael@0 42 {
michael@0 43 mDataToFree = nullptr;
michael@0 44 mSampleData = nullptr;
michael@0 45 }
michael@0 46 ~Storage() { free(mDataToFree); }
michael@0 47 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
michael@0 48 {
michael@0 49 // NB: mSampleData might not be owned, if it is it just points to
michael@0 50 // mDataToFree.
michael@0 51 return aMallocSizeOf(mDataToFree);
michael@0 52 }
michael@0 53 void* mDataToFree;
michael@0 54 const float* mSampleData;
michael@0 55 };
michael@0 56
michael@0 57 /**
michael@0 58 * This can be called on any thread.
michael@0 59 */
michael@0 60 uint32_t GetChannels() const { return mContents.Length(); }
michael@0 61 /**
michael@0 62 * This can be called on any thread.
michael@0 63 */
michael@0 64 const float* GetData(uint32_t aIndex) const { return mContents[aIndex].mSampleData; }
michael@0 65
michael@0 66 /**
michael@0 67 * Call this only during initialization, before the object is handed to
michael@0 68 * any other thread.
michael@0 69 */
michael@0 70 void SetData(uint32_t aIndex, void* aDataToFree, const float* aData)
michael@0 71 {
michael@0 72 Storage* s = &mContents[aIndex];
michael@0 73 free(s->mDataToFree);
michael@0 74 s->mDataToFree = aDataToFree;
michael@0 75 s->mSampleData = aData;
michael@0 76 }
michael@0 77
michael@0 78 /**
michael@0 79 * Put this object into an error state where there are no channels.
michael@0 80 */
michael@0 81 void Clear() { mContents.Clear(); }
michael@0 82
michael@0 83 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
michael@0 84 {
michael@0 85 size_t amount = ThreadSharedObject::SizeOfExcludingThis(aMallocSizeOf);
michael@0 86 amount += mContents.SizeOfExcludingThis(aMallocSizeOf);
michael@0 87 for (size_t i = 0; i < mContents.Length(); i++) {
michael@0 88 amount += mContents[i].SizeOfExcludingThis(aMallocSizeOf);
michael@0 89 }
michael@0 90
michael@0 91 return amount;
michael@0 92 }
michael@0 93
michael@0 94 private:
michael@0 95 AutoFallibleTArray<Storage,2> mContents;
michael@0 96 };
michael@0 97
michael@0 98 /**
michael@0 99 * Allocates an AudioChunk with fresh buffers of WEBAUDIO_BLOCK_SIZE float samples.
michael@0 100 * AudioChunk::mChannelData's entries can be cast to float* for writing.
michael@0 101 */
michael@0 102 void AllocateAudioBlock(uint32_t aChannelCount, AudioChunk* aChunk);
michael@0 103
michael@0 104 /**
michael@0 105 * aChunk must have been allocated by AllocateAudioBlock.
michael@0 106 */
michael@0 107 void WriteZeroesToAudioBlock(AudioChunk* aChunk, uint32_t aStart, uint32_t aLength);
michael@0 108
michael@0 109 /**
michael@0 110 * Copy with scale. aScale == 1.0f should be optimized.
michael@0 111 */
michael@0 112 void AudioBufferCopyWithScale(const float* aInput,
michael@0 113 float aScale,
michael@0 114 float* aOutput,
michael@0 115 uint32_t aSize);
michael@0 116
michael@0 117 /**
michael@0 118 * Pointwise multiply-add operation. aScale == 1.0f should be optimized.
michael@0 119 */
michael@0 120 void AudioBufferAddWithScale(const float* aInput,
michael@0 121 float aScale,
michael@0 122 float* aOutput,
michael@0 123 uint32_t aSize);
michael@0 124
michael@0 125 /**
michael@0 126 * Pointwise multiply-add operation. aScale == 1.0f should be optimized.
michael@0 127 */
michael@0 128 void AudioBlockAddChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
michael@0 129 float aScale,
michael@0 130 float aOutput[WEBAUDIO_BLOCK_SIZE]);
michael@0 131
michael@0 132 /**
michael@0 133 * Pointwise copy-scaled operation. aScale == 1.0f should be optimized.
michael@0 134 *
michael@0 135 * Buffer size is implicitly assumed to be WEBAUDIO_BLOCK_SIZE.
michael@0 136 */
michael@0 137 void AudioBlockCopyChannelWithScale(const float* aInput,
michael@0 138 float aScale,
michael@0 139 float* aOutput);
michael@0 140
michael@0 141 /**
michael@0 142 * Vector copy-scaled operation.
michael@0 143 */
michael@0 144 void AudioBlockCopyChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
michael@0 145 const float aScale[WEBAUDIO_BLOCK_SIZE],
michael@0 146 float aOutput[WEBAUDIO_BLOCK_SIZE]);
michael@0 147
michael@0 148 /**
michael@0 149 * Vector complex multiplication on arbitrary sized buffers.
michael@0 150 */
michael@0 151 void BufferComplexMultiply(const float* aInput,
michael@0 152 const float* aScale,
michael@0 153 float* aOutput,
michael@0 154 uint32_t aSize);
michael@0 155
michael@0 156 /**
michael@0 157 * Vector maximum element magnitude ( max(abs(aInput)) ).
michael@0 158 */
michael@0 159 float AudioBufferPeakValue(const float* aInput, uint32_t aSize);
michael@0 160
michael@0 161 /**
michael@0 162 * In place gain. aScale == 1.0f should be optimized.
michael@0 163 */
michael@0 164 void AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE],
michael@0 165 float aScale);
michael@0 166
michael@0 167 /**
michael@0 168 * In place gain. aScale == 1.0f should be optimized.
michael@0 169 */
michael@0 170 void AudioBufferInPlaceScale(float* aBlock,
michael@0 171 float aScale,
michael@0 172 uint32_t aSize);
michael@0 173
michael@0 174 /**
michael@0 175 * Upmix a mono input to a stereo output, scaling the two output channels by two
michael@0 176 * different gain value.
michael@0 177 * This algorithm is specified in the WebAudio spec.
michael@0 178 */
michael@0 179 void
michael@0 180 AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
michael@0 181 float aGainL, float aGainR,
michael@0 182 float aOutputL[WEBAUDIO_BLOCK_SIZE],
michael@0 183 float aOutputR[WEBAUDIO_BLOCK_SIZE]);
michael@0 184 /**
michael@0 185 * Pan a stereo source according to right and left gain, and the position
michael@0 186 * (whether the listener is on the left of the source or not).
michael@0 187 * This algorithm is specified in the WebAudio spec.
michael@0 188 */
michael@0 189 void
michael@0 190 AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE],
michael@0 191 const float aInputR[WEBAUDIO_BLOCK_SIZE],
michael@0 192 float aGainL, float aGainR, bool aIsOnTheLeft,
michael@0 193 float aOutputL[WEBAUDIO_BLOCK_SIZE],
michael@0 194 float aOutputR[WEBAUDIO_BLOCK_SIZE]);
michael@0 195
michael@0 196 /**
michael@0 197 * Return the sum of squares of all of the samples in the input.
michael@0 198 */
michael@0 199 float
michael@0 200 AudioBufferSumOfSquares(const float* aInput, uint32_t aLength);
michael@0 201
michael@0 202 /**
michael@0 203 * All methods of this class and its subclasses are called on the
michael@0 204 * MediaStreamGraph thread.
michael@0 205 */
michael@0 206 class AudioNodeEngine {
michael@0 207 public:
michael@0 208 // This should be compatible with AudioNodeStream::OutputChunks.
michael@0 209 typedef nsAutoTArray<AudioChunk, 1> OutputChunks;
michael@0 210
michael@0 211 explicit AudioNodeEngine(dom::AudioNode* aNode)
michael@0 212 : mNode(aNode)
michael@0 213 , mNodeMutex("AudioNodeEngine::mNodeMutex")
michael@0 214 , mInputCount(aNode ? aNode->NumberOfInputs() : 1)
michael@0 215 , mOutputCount(aNode ? aNode->NumberOfOutputs() : 0)
michael@0 216 {
michael@0 217 MOZ_ASSERT(NS_IsMainThread());
michael@0 218 MOZ_COUNT_CTOR(AudioNodeEngine);
michael@0 219 }
michael@0 220 virtual ~AudioNodeEngine()
michael@0 221 {
michael@0 222 MOZ_ASSERT(!mNode, "The node reference must be already cleared");
michael@0 223 MOZ_COUNT_DTOR(AudioNodeEngine);
michael@0 224 }
michael@0 225
michael@0 226 virtual dom::DelayNodeEngine* AsDelayNodeEngine() { return nullptr; }
michael@0 227
michael@0 228 virtual void SetStreamTimeParameter(uint32_t aIndex, TrackTicks aParam)
michael@0 229 {
michael@0 230 NS_ERROR("Invalid SetStreamTimeParameter index");
michael@0 231 }
michael@0 232 virtual void SetDoubleParameter(uint32_t aIndex, double aParam)
michael@0 233 {
michael@0 234 NS_ERROR("Invalid SetDoubleParameter index");
michael@0 235 }
michael@0 236 virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam)
michael@0 237 {
michael@0 238 NS_ERROR("Invalid SetInt32Parameter index");
michael@0 239 }
michael@0 240 virtual void SetTimelineParameter(uint32_t aIndex,
michael@0 241 const dom::AudioParamTimeline& aValue,
michael@0 242 TrackRate aSampleRate)
michael@0 243 {
michael@0 244 NS_ERROR("Invalid SetTimelineParameter index");
michael@0 245 }
michael@0 246 virtual void SetThreeDPointParameter(uint32_t aIndex,
michael@0 247 const dom::ThreeDPoint& aValue)
michael@0 248 {
michael@0 249 NS_ERROR("Invalid SetThreeDPointParameter index");
michael@0 250 }
michael@0 251 virtual void SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer)
michael@0 252 {
michael@0 253 NS_ERROR("SetBuffer called on engine that doesn't support it");
michael@0 254 }
michael@0 255 // This consumes the contents of aData. aData will be emptied after this returns.
michael@0 256 virtual void SetRawArrayData(nsTArray<float>& aData)
michael@0 257 {
michael@0 258 NS_ERROR("SetRawArrayData called on an engine that doesn't support it");
michael@0 259 }
michael@0 260
michael@0 261 /**
michael@0 262 * Produce the next block of audio samples, given input samples aInput
michael@0 263 * (the mixed data for input 0).
michael@0 264 * aInput is guaranteed to have float sample format (if it has samples at all)
michael@0 265 * and to have been resampled to the sampling rate for the stream, and to have
michael@0 266 * exactly WEBAUDIO_BLOCK_SIZE samples.
michael@0 267 * *aFinished is set to false by the caller. If the callee sets it to true,
michael@0 268 * we'll finish the stream and not call this again.
michael@0 269 */
michael@0 270 virtual void ProcessBlock(AudioNodeStream* aStream,
michael@0 271 const AudioChunk& aInput,
michael@0 272 AudioChunk* aOutput,
michael@0 273 bool* aFinished)
michael@0 274 {
michael@0 275 MOZ_ASSERT(mInputCount <= 1 && mOutputCount <= 1);
michael@0 276 *aOutput = aInput;
michael@0 277 }
michael@0 278 /**
michael@0 279 * Produce the next block of audio samples, before input is provided.
michael@0 280 * ProcessBlock() will be called later, and it then should not change
michael@0 281 * aOutput. This is used only for DelayNodeEngine in a feedback loop.
michael@0 282 */
michael@0 283 virtual void ProduceBlockBeforeInput(AudioChunk* aOutput)
michael@0 284 {
michael@0 285 NS_NOTREACHED("ProduceBlockBeforeInput called on wrong engine\n");
michael@0 286 }
michael@0 287
michael@0 288 /**
michael@0 289 * Produce the next block of audio samples, given input samples in the aInput
michael@0 290 * array. There is one input sample per active port in aInput, in order.
michael@0 291 * This is the multi-input/output version of ProcessBlock. Only one kind
michael@0 292 * of ProcessBlock is called on each node, depending on whether the
michael@0 293 * number of inputs and outputs are both 1 or not.
michael@0 294 *
michael@0 295 * aInput is always guaranteed to not contain more input AudioChunks than the
michael@0 296 * maximum number of inputs for the node. It is the responsibility of the
michael@0 297 * overrides of this function to make sure they will only add a maximum number
michael@0 298 * of AudioChunks to aOutput as advertized by the AudioNode implementation.
michael@0 299 * An engine may choose to produce fewer inputs than advertizes by the
michael@0 300 * corresponding AudioNode, in which case it will be interpreted as a channel
michael@0 301 * of silence.
michael@0 302 */
michael@0 303 virtual void ProcessBlocksOnPorts(AudioNodeStream* aStream,
michael@0 304 const OutputChunks& aInput,
michael@0 305 OutputChunks& aOutput,
michael@0 306 bool* aFinished)
michael@0 307 {
michael@0 308 MOZ_ASSERT(mInputCount > 1 || mOutputCount > 1);
michael@0 309 // Only produce one output port, and drop all other input ports.
michael@0 310 aOutput[0] = aInput[0];
michael@0 311 }
michael@0 312
michael@0 313 Mutex& NodeMutex() { return mNodeMutex;}
michael@0 314
michael@0 315 bool HasNode() const
michael@0 316 {
michael@0 317 return !!mNode;
michael@0 318 }
michael@0 319
michael@0 320 dom::AudioNode* Node() const
michael@0 321 {
michael@0 322 mNodeMutex.AssertCurrentThreadOwns();
michael@0 323 return mNode;
michael@0 324 }
michael@0 325
michael@0 326 dom::AudioNode* NodeMainThread() const
michael@0 327 {
michael@0 328 MOZ_ASSERT(NS_IsMainThread());
michael@0 329 return mNode;
michael@0 330 }
michael@0 331
michael@0 332 void ClearNode()
michael@0 333 {
michael@0 334 MOZ_ASSERT(NS_IsMainThread());
michael@0 335 MOZ_ASSERT(mNode != nullptr);
michael@0 336 mNodeMutex.AssertCurrentThreadOwns();
michael@0 337 mNode = nullptr;
michael@0 338 }
michael@0 339
michael@0 340 uint16_t InputCount() const { return mInputCount; }
michael@0 341 uint16_t OutputCount() const { return mOutputCount; }
michael@0 342
michael@0 343 virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
michael@0 344 {
michael@0 345 // NB: |mNode| is tracked separately so it is excluded here.
michael@0 346 return 0;
michael@0 347 }
michael@0 348
michael@0 349 virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
michael@0 350 {
michael@0 351 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
michael@0 352 }
michael@0 353
michael@0 354 void SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
michael@0 355 AudioNodeSizes& aUsage) const
michael@0 356 {
michael@0 357 aUsage.mEngine = SizeOfIncludingThis(aMallocSizeOf);
michael@0 358 aUsage.mDomNode = mNode->SizeOfIncludingThis(aMallocSizeOf);
michael@0 359 aUsage.mNodeType = mNode->NodeType();
michael@0 360 }
michael@0 361
michael@0 362 private:
michael@0 363 dom::AudioNode* mNode;
michael@0 364 Mutex mNodeMutex;
michael@0 365 const uint16_t mInputCount;
michael@0 366 const uint16_t mOutputCount;
michael@0 367 };
michael@0 368
michael@0 369 }
michael@0 370
michael@0 371 #endif /* MOZILLA_AUDIONODEENGINE_H_ */

mercurial