content/media/AudioNodeEngine.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/AudioNodeEngine.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,371 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +#ifndef MOZILLA_AUDIONODEENGINE_H_
    1.10 +#define MOZILLA_AUDIONODEENGINE_H_
    1.11 +
    1.12 +#include "AudioSegment.h"
    1.13 +#include "mozilla/dom/AudioNode.h"
    1.14 +#include "mozilla/MemoryReporting.h"
    1.15 +#include "mozilla/Mutex.h"
    1.16 +
    1.17 +namespace mozilla {
    1.18 +
    1.19 +namespace dom {
    1.20 +struct ThreeDPoint;
    1.21 +class AudioParamTimeline;
    1.22 +class DelayNodeEngine;
    1.23 +}
    1.24 +
    1.25 +class AudioNodeStream;
    1.26 +
    1.27 +/**
    1.28 + * This class holds onto a set of immutable channel buffers. The storage
    1.29 + * for the buffers must be malloced, but the buffer pointers and the malloc
    1.30 + * pointers can be different (e.g. if the buffers are contained inside
    1.31 + * some malloced object).
    1.32 + */
    1.33 +class ThreadSharedFloatArrayBufferList : public ThreadSharedObject {
    1.34 +public:
    1.35 +  /**
    1.36 +   * Construct with null data.
    1.37 +   */
    1.38 +  ThreadSharedFloatArrayBufferList(uint32_t aCount)
    1.39 +  {
    1.40 +    mContents.SetLength(aCount);
    1.41 +  }
    1.42 +
    1.43 +  struct Storage {
    1.44 +    Storage()
    1.45 +    {
    1.46 +      mDataToFree = nullptr;
    1.47 +      mSampleData = nullptr;
    1.48 +    }
    1.49 +    ~Storage() { free(mDataToFree); }
    1.50 +    size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
    1.51 +    {
    1.52 +      // NB: mSampleData might not be owned, if it is it just points to
    1.53 +      //     mDataToFree.
    1.54 +      return aMallocSizeOf(mDataToFree);
    1.55 +    }
    1.56 +    void* mDataToFree;
    1.57 +    const float* mSampleData;
    1.58 +  };
    1.59 +
    1.60 +  /**
    1.61 +   * This can be called on any thread.
    1.62 +   */
    1.63 +  uint32_t GetChannels() const { return mContents.Length(); }
    1.64 +  /**
    1.65 +   * This can be called on any thread.
    1.66 +   */
    1.67 +  const float* GetData(uint32_t aIndex) const { return mContents[aIndex].mSampleData; }
    1.68 +
    1.69 +  /**
    1.70 +   * Call this only during initialization, before the object is handed to
    1.71 +   * any other thread.
    1.72 +   */
    1.73 +  void SetData(uint32_t aIndex, void* aDataToFree, const float* aData)
    1.74 +  {
    1.75 +    Storage* s = &mContents[aIndex];
    1.76 +    free(s->mDataToFree);
    1.77 +    s->mDataToFree = aDataToFree;
    1.78 +    s->mSampleData = aData;
    1.79 +  }
    1.80 +
    1.81 +  /**
    1.82 +   * Put this object into an error state where there are no channels.
    1.83 +   */
    1.84 +  void Clear() { mContents.Clear(); }
    1.85 +
    1.86 +  virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
    1.87 +  {
    1.88 +    size_t amount = ThreadSharedObject::SizeOfExcludingThis(aMallocSizeOf);
    1.89 +    amount += mContents.SizeOfExcludingThis(aMallocSizeOf);
    1.90 +    for (size_t i = 0; i < mContents.Length(); i++) {
    1.91 +      amount += mContents[i].SizeOfExcludingThis(aMallocSizeOf);
    1.92 +    }
    1.93 +
    1.94 +    return amount;
    1.95 +  }
    1.96 +
    1.97 +private:
    1.98 +  AutoFallibleTArray<Storage,2> mContents;
    1.99 +};
   1.100 +
   1.101 +/**
   1.102 + * Allocates an AudioChunk with fresh buffers of WEBAUDIO_BLOCK_SIZE float samples.
   1.103 + * AudioChunk::mChannelData's entries can be cast to float* for writing.
   1.104 + */
   1.105 +void AllocateAudioBlock(uint32_t aChannelCount, AudioChunk* aChunk);
   1.106 +
   1.107 +/**
   1.108 + * aChunk must have been allocated by AllocateAudioBlock.
   1.109 + */
   1.110 +void WriteZeroesToAudioBlock(AudioChunk* aChunk, uint32_t aStart, uint32_t aLength);
   1.111 +
   1.112 +/**
   1.113 + * Copy with scale. aScale == 1.0f should be optimized.
   1.114 + */
   1.115 +void AudioBufferCopyWithScale(const float* aInput,
   1.116 +                              float aScale,
   1.117 +                              float* aOutput,
   1.118 +                              uint32_t aSize);
   1.119 +
   1.120 +/**
   1.121 + * Pointwise multiply-add operation. aScale == 1.0f should be optimized.
   1.122 + */
   1.123 +void AudioBufferAddWithScale(const float* aInput,
   1.124 +                             float aScale,
   1.125 +                             float* aOutput,
   1.126 +                             uint32_t aSize);
   1.127 +
   1.128 +/**
   1.129 + * Pointwise multiply-add operation. aScale == 1.0f should be optimized.
   1.130 + */
   1.131 +void AudioBlockAddChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
   1.132 +                                   float aScale,
   1.133 +                                   float aOutput[WEBAUDIO_BLOCK_SIZE]);
   1.134 +
   1.135 +/**
   1.136 + * Pointwise copy-scaled operation. aScale == 1.0f should be optimized.
   1.137 + *
   1.138 + * Buffer size is implicitly assumed to be WEBAUDIO_BLOCK_SIZE.
   1.139 + */
   1.140 +void AudioBlockCopyChannelWithScale(const float* aInput,
   1.141 +                                    float aScale,
   1.142 +                                    float* aOutput);
   1.143 +
   1.144 +/**
   1.145 + * Vector copy-scaled operation.
   1.146 + */
   1.147 +void AudioBlockCopyChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
   1.148 +                                    const float aScale[WEBAUDIO_BLOCK_SIZE],
   1.149 +                                    float aOutput[WEBAUDIO_BLOCK_SIZE]);
   1.150 +
   1.151 +/**
   1.152 + * Vector complex multiplication on arbitrary sized buffers.
   1.153 + */
   1.154 +void BufferComplexMultiply(const float* aInput,
   1.155 +                           const float* aScale,
   1.156 +                           float* aOutput,
   1.157 +                           uint32_t aSize);
   1.158 +
   1.159 +/**
   1.160 + * Vector maximum element magnitude ( max(abs(aInput)) ).
   1.161 + */
   1.162 +float AudioBufferPeakValue(const float* aInput, uint32_t aSize);
   1.163 +
   1.164 +/**
   1.165 + * In place gain. aScale == 1.0f should be optimized.
   1.166 + */
   1.167 +void AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE],
   1.168 +                            float aScale);
   1.169 +
   1.170 +/**
   1.171 + * In place gain. aScale == 1.0f should be optimized.
   1.172 + */
   1.173 +void AudioBufferInPlaceScale(float* aBlock,
   1.174 +                             float aScale,
   1.175 +                             uint32_t aSize);
   1.176 +
   1.177 +/**
   1.178 + * Upmix a mono input to a stereo output, scaling the two output channels by two
   1.179 + * different gain value.
   1.180 + * This algorithm is specified in the WebAudio spec.
   1.181 + */
   1.182 +void
   1.183 +AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
   1.184 +                          float aGainL, float aGainR,
   1.185 +                          float aOutputL[WEBAUDIO_BLOCK_SIZE],
   1.186 +                          float aOutputR[WEBAUDIO_BLOCK_SIZE]);
   1.187 +/**
   1.188 + * Pan a stereo source according to right and left gain, and the position
   1.189 + * (whether the listener is on the left of the source or not).
   1.190 + * This algorithm is specified in the WebAudio spec.
   1.191 + */
   1.192 +void
   1.193 +AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE],
   1.194 +                            const float aInputR[WEBAUDIO_BLOCK_SIZE],
   1.195 +                            float aGainL, float aGainR, bool aIsOnTheLeft,
   1.196 +                            float aOutputL[WEBAUDIO_BLOCK_SIZE],
   1.197 +                            float aOutputR[WEBAUDIO_BLOCK_SIZE]);
   1.198 +
   1.199 +/**
   1.200 + * Return the sum of squares of all of the samples in the input.
   1.201 + */
   1.202 +float
   1.203 +AudioBufferSumOfSquares(const float* aInput, uint32_t aLength);
   1.204 +
   1.205 +/**
   1.206 + * All methods of this class and its subclasses are called on the
   1.207 + * MediaStreamGraph thread.
   1.208 + */
   1.209 +class AudioNodeEngine {
   1.210 +public:
   1.211 +  // This should be compatible with AudioNodeStream::OutputChunks.
   1.212 +  typedef nsAutoTArray<AudioChunk, 1> OutputChunks;
   1.213 +
   1.214 +  explicit AudioNodeEngine(dom::AudioNode* aNode)
   1.215 +    : mNode(aNode)
   1.216 +    , mNodeMutex("AudioNodeEngine::mNodeMutex")
   1.217 +    , mInputCount(aNode ? aNode->NumberOfInputs() : 1)
   1.218 +    , mOutputCount(aNode ? aNode->NumberOfOutputs() : 0)
   1.219 +  {
   1.220 +    MOZ_ASSERT(NS_IsMainThread());
   1.221 +    MOZ_COUNT_CTOR(AudioNodeEngine);
   1.222 +  }
   1.223 +  virtual ~AudioNodeEngine()
   1.224 +  {
   1.225 +    MOZ_ASSERT(!mNode, "The node reference must be already cleared");
   1.226 +    MOZ_COUNT_DTOR(AudioNodeEngine);
   1.227 +  }
   1.228 +
   1.229 +  virtual dom::DelayNodeEngine* AsDelayNodeEngine() { return nullptr; }
   1.230 +
   1.231 +  virtual void SetStreamTimeParameter(uint32_t aIndex, TrackTicks aParam)
   1.232 +  {
   1.233 +    NS_ERROR("Invalid SetStreamTimeParameter index");
   1.234 +  }
   1.235 +  virtual void SetDoubleParameter(uint32_t aIndex, double aParam)
   1.236 +  {
   1.237 +    NS_ERROR("Invalid SetDoubleParameter index");
   1.238 +  }
   1.239 +  virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam)
   1.240 +  {
   1.241 +    NS_ERROR("Invalid SetInt32Parameter index");
   1.242 +  }
   1.243 +  virtual void SetTimelineParameter(uint32_t aIndex,
   1.244 +                                    const dom::AudioParamTimeline& aValue,
   1.245 +                                    TrackRate aSampleRate)
   1.246 +  {
   1.247 +    NS_ERROR("Invalid SetTimelineParameter index");
   1.248 +  }
   1.249 +  virtual void SetThreeDPointParameter(uint32_t aIndex,
   1.250 +                                       const dom::ThreeDPoint& aValue)
   1.251 +  {
   1.252 +    NS_ERROR("Invalid SetThreeDPointParameter index");
   1.253 +  }
   1.254 +  virtual void SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer)
   1.255 +  {
   1.256 +    NS_ERROR("SetBuffer called on engine that doesn't support it");
   1.257 +  }
   1.258 +  // This consumes the contents of aData.  aData will be emptied after this returns.
   1.259 +  virtual void SetRawArrayData(nsTArray<float>& aData)
   1.260 +  {
   1.261 +    NS_ERROR("SetRawArrayData called on an engine that doesn't support it");
   1.262 +  }
   1.263 +
   1.264 +  /**
   1.265 +   * Produce the next block of audio samples, given input samples aInput
   1.266 +   * (the mixed data for input 0).
   1.267 +   * aInput is guaranteed to have float sample format (if it has samples at all)
   1.268 +   * and to have been resampled to the sampling rate for the stream, and to have
   1.269 +   * exactly WEBAUDIO_BLOCK_SIZE samples.
   1.270 +   * *aFinished is set to false by the caller. If the callee sets it to true,
   1.271 +   * we'll finish the stream and not call this again.
   1.272 +   */
   1.273 +  virtual void ProcessBlock(AudioNodeStream* aStream,
   1.274 +                            const AudioChunk& aInput,
   1.275 +                            AudioChunk* aOutput,
   1.276 +                            bool* aFinished)
   1.277 +  {
   1.278 +    MOZ_ASSERT(mInputCount <= 1 && mOutputCount <= 1);
   1.279 +    *aOutput = aInput;
   1.280 +  }
   1.281 +  /**
   1.282 +   * Produce the next block of audio samples, before input is provided.
   1.283 +   * ProcessBlock() will be called later, and it then should not change
   1.284 +   * aOutput.  This is used only for DelayNodeEngine in a feedback loop.
   1.285 +   */
   1.286 +  virtual void ProduceBlockBeforeInput(AudioChunk* aOutput)
   1.287 +  {
   1.288 +    NS_NOTREACHED("ProduceBlockBeforeInput called on wrong engine\n");
   1.289 +  }
   1.290 +
   1.291 +  /**
   1.292 +   * Produce the next block of audio samples, given input samples in the aInput
   1.293 +   * array.  There is one input sample per active port in aInput, in order.
   1.294 +   * This is the multi-input/output version of ProcessBlock.  Only one kind
   1.295 +   * of ProcessBlock is called on each node, depending on whether the
   1.296 +   * number of inputs and outputs are both 1 or not.
   1.297 +   *
   1.298 +   * aInput is always guaranteed to not contain more input AudioChunks than the
   1.299 +   * maximum number of inputs for the node.  It is the responsibility of the
   1.300 +   * overrides of this function to make sure they will only add a maximum number
   1.301 +   * of AudioChunks to aOutput as advertized by the AudioNode implementation.
   1.302 +   * An engine may choose to produce fewer inputs than advertizes by the
   1.303 +   * corresponding AudioNode, in which case it will be interpreted as a channel
   1.304 +   * of silence.
   1.305 +   */
   1.306 +  virtual void ProcessBlocksOnPorts(AudioNodeStream* aStream,
   1.307 +                                    const OutputChunks& aInput,
   1.308 +                                    OutputChunks& aOutput,
   1.309 +                                    bool* aFinished)
   1.310 +  {
   1.311 +    MOZ_ASSERT(mInputCount > 1 || mOutputCount > 1);
   1.312 +    // Only produce one output port, and drop all other input ports.
   1.313 +    aOutput[0] = aInput[0];
   1.314 +  }
   1.315 +
   1.316 +  Mutex& NodeMutex() { return mNodeMutex;}
   1.317 +
   1.318 +  bool HasNode() const
   1.319 +  {
   1.320 +    return !!mNode;
   1.321 +  }
   1.322 +
   1.323 +  dom::AudioNode* Node() const
   1.324 +  {
   1.325 +    mNodeMutex.AssertCurrentThreadOwns();
   1.326 +    return mNode;
   1.327 +  }
   1.328 +
   1.329 +  dom::AudioNode* NodeMainThread() const
   1.330 +  {
   1.331 +    MOZ_ASSERT(NS_IsMainThread());
   1.332 +    return mNode;
   1.333 +  }
   1.334 +
   1.335 +  void ClearNode()
   1.336 +  {
   1.337 +    MOZ_ASSERT(NS_IsMainThread());
   1.338 +    MOZ_ASSERT(mNode != nullptr);
   1.339 +    mNodeMutex.AssertCurrentThreadOwns();
   1.340 +    mNode = nullptr;
   1.341 +  }
   1.342 +
   1.343 +  uint16_t InputCount() const { return mInputCount; }
   1.344 +  uint16_t OutputCount() const { return mOutputCount; }
   1.345 +
   1.346 +  virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   1.347 +  {
   1.348 +    // NB: |mNode| is tracked separately so it is excluded here.
   1.349 +    return 0;
   1.350 +  }
   1.351 +
   1.352 +  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   1.353 +  {
   1.354 +    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   1.355 +  }
   1.356 +
   1.357 +  void SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
   1.358 +                           AudioNodeSizes& aUsage) const
   1.359 +  {
   1.360 +    aUsage.mEngine = SizeOfIncludingThis(aMallocSizeOf);
   1.361 +    aUsage.mDomNode = mNode->SizeOfIncludingThis(aMallocSizeOf);
   1.362 +    aUsage.mNodeType = mNode->NodeType();
   1.363 +  }
   1.364 +
   1.365 +private:
   1.366 +  dom::AudioNode* mNode;
   1.367 +  Mutex mNodeMutex;
   1.368 +  const uint16_t mInputCount;
   1.369 +  const uint16_t mOutputCount;
   1.370 +};
   1.371 +
   1.372 +}
   1.373 +
   1.374 +#endif /* MOZILLA_AUDIONODEENGINE_H_ */

mercurial