bug 1391482 use AudioChunk to store and pass PeriodicWave data to engine r=padenot
authorKarl Tomlinson <karlt+@karlt.net>
Thu, 10 Aug 2017 20:26:20 +1200
changeset 377713 1967d3942792155a16855937329f519c63a66c6a
parent 377712 529abb028f5ae79bd3e3d7af8caa40035575ea27
child 377714 927b04969910f1fb988a0ff7fc1cb67f4ab0a951
push id32415
push userkwierso@gmail.com
push dateThu, 31 Aug 2017 02:52:55 +0000
treeherdermozilla-central@04b6be50a252 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1391482
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1391482 use AudioChunk to store and pass PeriodicWave data to engine r=padenot This is mostly to be consistent with other nodes so that only a single SetBuffer method is required to pass buffers from nodes to engines. AudioChunk also has the advantage of ThreadSharedFloatArrayBufferList that it keeps a record of the length of the buffer in the same struct, and so this is passed to the engine with the buffer. SharedBuffer needs one fewer allocation than ThreadSharedFloatArrayBufferList, but this is not a hot path. MozReview-Commit-ID: JsLcuFdFvRO
dom/media/webaudio/OscillatorNode.cpp
dom/media/webaudio/PeriodicWave.cpp
dom/media/webaudio/PeriodicWave.h
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -36,33 +36,31 @@ public:
     // Keep the default values in sync with OscillatorNode::OscillatorNode.
     , mFrequency(440.f)
     , mDetune(0.f)
     , mType(OscillatorType::Sine)
     , mPhase(0.)
     , mFinalFrequency(0.)
     , mPhaseIncrement(0.)
     , mRecomputeParameters(true)
-    , mCustomLength(0)
     , mCustomDisableNormalization(false)
   {
     MOZ_ASSERT(NS_IsMainThread());
     mBasicWaveFormCache = aDestination->Context()->GetBasicWaveFormCache();
   }
 
   void SetSourceStream(AudioNodeStream* aSource)
   {
     mSource = aSource;
   }
 
   enum Parameters {
     FREQUENCY,
     DETUNE,
     TYPE,
-    PERIODICWAVE_LENGTH,
     DISABLE_NORMALIZATION,
     START,
     STOP,
   };
   void RecvTimelineEvent(uint32_t aIndex,
                          AudioTimelineEvent& aEvent) override
   {
     mRecomputeParameters = true;
@@ -100,17 +98,16 @@ public:
   void SetInt32Parameter(uint32_t aIndex, int32_t aParam) override
   {
     switch (aIndex) {
       case TYPE:
         // Set the new type.
         mType = static_cast<OscillatorType>(aParam);
         if (mType == OscillatorType::Sine) {
           // Forget any previous custom data.
-          mCustomLength = 0;
           mCustomDisableNormalization = false;
           mPeriodicWave = nullptr;
           mRecomputeParameters = true;
         }
         switch (mType) {
           case OscillatorType::Sine:
             mPhase = 0.0;
             break;
@@ -121,41 +118,37 @@ public:
             break;
           case OscillatorType::Custom:
             break;
           default:
             NS_ERROR("Bad OscillatorNodeEngine type parameter.");
         }
         // End type switch.
         break;
-      case PERIODICWAVE_LENGTH:
-        MOZ_ASSERT(aParam >= 0, "negative custom array length");
-        mCustomLength = static_cast<uint32_t>(aParam);
-        break;
       case DISABLE_NORMALIZATION:
         MOZ_ASSERT(aParam >= 0, "negative custom array length");
         mCustomDisableNormalization = static_cast<uint32_t>(aParam);
         break;
       default:
         NS_ERROR("Bad OscillatorNodeEngine Int32Parameter.");
     }
     // End index switch.
   }
 
-  void SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer) override
+  void SetBuffer(AudioChunk&& aBuffer) override
   {
-    MOZ_ASSERT(mCustomLength, "Custom buffer sent before length");
-    RefPtr<ThreadSharedFloatArrayBufferList> custom = aBuffer;
-    MOZ_ASSERT(custom->GetChannels() == 2,
+    MOZ_ASSERT(aBuffer.ChannelCount() == 2,
                "PeriodicWave should have sent two channels");
-    mPeriodicWave = WebCore::PeriodicWave::create(mSource->SampleRate(),
-                                                  custom->GetData(0),
-                                                  custom->GetData(1),
-                                                  mCustomLength,
-                                                  mCustomDisableNormalization);
+    MOZ_ASSERT(aBuffer.mVolume == 1.0f);
+    mPeriodicWave =
+      WebCore::PeriodicWave::create(mSource->SampleRate(),
+                                    aBuffer.ChannelData<float>()[0],
+                                    aBuffer.ChannelData<float>()[1],
+                                    aBuffer.mDuration,
+                                    mCustomDisableNormalization);
   }
 
   void IncrementPhase()
   {
     const float twoPiFloat = float(2 * M_PI);
     mPhase += mPhaseIncrement;
     if (mPhase > twoPiFloat) {
       mPhase -= twoPiFloat;
@@ -392,17 +385,16 @@ public:
   AudioParamTimeline mFrequency;
   AudioParamTimeline mDetune;
   OscillatorType mType;
   float mPhase;
   float mFinalFrequency;
   float mPhaseIncrement;
   bool mRecomputeParameters;
   RefPtr<BasicWaveFormCache> mBasicWaveFormCache;
-  uint32_t mCustomLength;
   bool mCustomDisableNormalization;
   RefPtr<WebCore::PeriodicWave> mPeriodicWave;
 };
 
 OscillatorNode::OscillatorNode(AudioContext* aContext)
   : AudioScheduledSourceNode(aContext,
                              2,
                              ChannelCountMode::Max,
@@ -503,23 +495,20 @@ OscillatorNode::SendTypeToStream()
 }
 
 void OscillatorNode::SendPeriodicWaveToStream()
 {
   NS_ASSERTION(mType == OscillatorType::Custom,
                "Sending custom waveform to engine thread with non-custom type");
   MOZ_ASSERT(mStream, "Missing node stream.");
   MOZ_ASSERT(mPeriodicWave, "Send called without PeriodicWave object.");
-  SendInt32ParameterToStream(OscillatorNodeEngine::PERIODICWAVE_LENGTH,
-                             mPeriodicWave->DataLength());
   SendInt32ParameterToStream(OscillatorNodeEngine::DISABLE_NORMALIZATION,
                              mPeriodicWave->DisableNormalization());
-  RefPtr<ThreadSharedFloatArrayBufferList> data =
-    mPeriodicWave->GetThreadSharedBuffer();
-  mStream->SetBuffer(data.forget());
+  AudioChunk data = mPeriodicWave->GetThreadSharedBuffer();
+  mStream->SetBuffer(Move(data));
 }
 
 void
 OscillatorNode::Start(double aWhen, ErrorResult& aRv)
 {
   if (!WebAudioUtils::IsTimeValid(aWhen)) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return;
--- a/dom/media/webaudio/PeriodicWave.cpp
+++ b/dom/media/webaudio/PeriodicWave.cpp
@@ -25,41 +25,47 @@ PeriodicWave::PeriodicWave(AudioContext*
   : mContext(aContext)
   , mDisableNormalization(aDisableNormalization)
 {
   MOZ_ASSERT(aContext);
   MOZ_ASSERT(aRealData || aImagData);
 
   // Caller should have checked this and thrown.
   MOZ_ASSERT(aLength > 0);
-  mLength = aLength;
+  mCoefficients.mDuration = aLength;
 
-  // Copy coefficient data. The two arrays share an allocation.
-  mCoefficients = new ThreadSharedFloatArrayBufferList(2);
-  float* buffer = static_cast<float*>(malloc(aLength*sizeof(float)*2));
-  if (buffer == nullptr) {
+  // Copy coefficient data.
+  // The SharedBuffer and two arrays share a single allocation.
+  RefPtr<SharedBuffer> buffer =
+    SharedBuffer::Create(sizeof(float) * aLength * 2, fallible);
+  if (!buffer) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
+  auto data = static_cast<float*>(buffer->Data());
+  mCoefficients.mBuffer = Move(buffer);
+
   if (aRealData) {
-    PodCopy(buffer, aRealData, aLength);
+    PodCopy(data, aRealData, aLength);
   } else {
-    PodZero(buffer, aLength);
+    PodZero(data, aLength);
   }
-
-  mCoefficients->SetData(0, buffer, free, buffer);
+  mCoefficients.mChannelData.AppendElement(data);
 
+  data += aLength;
   if (aImagData) {
-    PodCopy(buffer+aLength, aImagData, aLength);
+    PodCopy(data, aImagData, aLength);
   } else {
-    PodZero(buffer+aLength, aLength);
+    PodZero(data, aLength);
   }
+  mCoefficients.mChannelData.AppendElement(data);
 
-  mCoefficients->SetData(1, nullptr, free, buffer+aLength);
+  mCoefficients.mVolume = 1.0f;
+  mCoefficients.mBufferFormat = AUDIO_FORMAT_FLOAT32;
 }
 
 /* static */ already_AddRefed<PeriodicWave>
 PeriodicWave::Constructor(const GlobalObject& aGlobal,
                           AudioContext& aAudioContext,
                           const PeriodicWaveOptions& aOptions,
                           ErrorResult& aRv)
 {
@@ -97,19 +103,17 @@ PeriodicWave::Constructor(const GlobalOb
 }
 
 size_t
 PeriodicWave::SizeOfExcludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const
 {
   // Not owned:
   // - mContext
   size_t amount = 0;
-  if (!mCoefficients->IsShared()) {
-    amount += mCoefficients->SizeOfIncludingThis(aMallocSizeOf);
-  }
+  amount += mCoefficients.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
 
   return amount;
 }
 
 size_t
 PeriodicWave::SizeOfIncludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const
 {
   return aMallocSizeOf(this) + SizeOfExcludingThisIfNotShared(aMallocSizeOf);
--- a/dom/media/webaudio/PeriodicWave.h
+++ b/dom/media/webaudio/PeriodicWave.h
@@ -41,37 +41,36 @@ public:
   {
     return mContext;
   }
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   uint32_t DataLength() const
   {
-    return mLength;
+    return mCoefficients.mDuration;
   }
 
   bool DisableNormalization() const
   {
     return mDisableNormalization;
   }
 
-  ThreadSharedFloatArrayBufferList* GetThreadSharedBuffer() const
+  const AudioChunk& GetThreadSharedBuffer() const
   {
     return mCoefficients;
   }
 
   size_t SizeOfExcludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const;
   size_t SizeOfIncludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const;
 
 private:
   ~PeriodicWave() = default;
 
+  AudioChunk mCoefficients;
   RefPtr<AudioContext> mContext;
-  RefPtr<ThreadSharedFloatArrayBufferList> mCoefficients;
-  uint32_t mLength;
   bool mDisableNormalization;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif