Bug 836076 - Part 3: Make AudioParams call back into their owning node when they're modified; r=roc
authorEhsan Akhgari <ehsan@mozilla.com>
Mon, 28 Jan 2013 18:59:29 -0500
changeset 131572 69b18d52cfdcec5d744518bfecc6cd4144fec91f
parent 131571 f12bd589624fe85fdb67b2c85d27404dd8ac2869
child 131573 c80a10a30cf250920d2a28a426a35efec268b89a
push id317
push userbbajaj@mozilla.com
push dateTue, 07 May 2013 01:20:33 +0000
treeherdermozilla-release@159a10910249 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs836076
milestone21.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 836076 - Part 3: Make AudioParams call back into their owning node when they're modified; r=roc We need this in order to update the MediaStreamGraph thread when an AudioParam changes. This enables each AudioParam to be registered with a callback from its owner node, so that the owner node can have custom processing code for each AudioParam's mutation.
content/media/webaudio/AudioNode.h
content/media/webaudio/AudioParam.cpp
content/media/webaudio/AudioParam.h
content/media/webaudio/BiquadFilterNode.cpp
content/media/webaudio/DelayNode.cpp
content/media/webaudio/DynamicsCompressorNode.cpp
content/media/webaudio/GainNode.cpp
--- a/content/media/webaudio/AudioNode.h
+++ b/content/media/webaudio/AudioNode.h
@@ -127,16 +127,19 @@ public:
   void SetProduceOwnOutput(bool aCanProduceOwnOutput)
   {
     mCanProduceOwnOutput = aCanProduceOwnOutput;
     if (!aCanProduceOwnOutput) {
       UpdateOutputEnded();
     }
   }
 
+protected:
+  static void Callback(AudioNode* aNode) { /* not implemented */ }
+
 private:
   nsRefPtr<AudioContext> mContext;
 
 protected:
   // Must be set in the constructor. Must not be null.
   // If MaxNumberOfInputs() is > 0, then mStream must be a ProcessedMediaStream.
   nsRefPtr<MediaStream> mStream;
 
--- a/content/media/webaudio/AudioParam.cpp
+++ b/content/media/webaudio/AudioParam.cpp
@@ -8,27 +8,29 @@
 #include "nsContentUtils.h"
 #include "nsIDOMWindow.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/AudioParamBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(AudioParam, mContext)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(AudioParam, mNode)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioParam, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioParam, Release)
 
-AudioParam::AudioParam(AudioContext* aContext,
+AudioParam::AudioParam(AudioNode* aNode,
+                       AudioParam::CallbackType aCallback,
                        float aDefaultValue,
                        float aMinValue,
                        float aMaxValue)
   : AudioParamTimeline(aDefaultValue)
-  , mContext(aContext)
+  , mNode(aNode)
+  , mCallback(aCallback)
   , mDefaultValue(aDefaultValue)
   , mMinValue(aMinValue)
   , mMaxValue(aMaxValue)
 {
   MOZ_ASSERT(aDefaultValue >= aMinValue);
   MOZ_ASSERT(aDefaultValue <= aMaxValue);
   MOZ_ASSERT(aMinValue < aMaxValue);
   SetIsDOMBinding();
--- a/content/media/webaudio/AudioParam.h
+++ b/content/media/webaudio/AudioParam.h
@@ -8,17 +8,17 @@
 #define AudioParam_h_
 
 #include "AudioEventTimeline.h"
 #include "nsWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCOMPtr.h"
 #include "EnableWebAudioCheck.h"
 #include "nsAutoPtr.h"
-#include "AudioContext.h"
+#include "AudioNode.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/Util.h"
 #include "mozilla/ErrorResult.h"
 
 struct JSContext;
 class nsIDOMWindow;
 
 namespace mozilla {
@@ -27,39 +27,76 @@ namespace dom {
 
 typedef AudioEventTimeline<ErrorResult> AudioParamTimeline;
 
 class AudioParam MOZ_FINAL : public nsWrapperCache,
                              public EnableWebAudioCheck,
                              public AudioParamTimeline
 {
 public:
-  AudioParam(AudioContext* aContext,
+  typedef void (*CallbackType)(AudioNode*);
+
+  AudioParam(AudioNode* aNode,
+             CallbackType aCallback,
              float aDefaultValue,
              float aMinValue,
              float aMaxValue);
   virtual ~AudioParam();
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioParam)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AudioParam)
 
   AudioContext* GetParentObject() const
   {
-    return mContext;
+    return mNode->Context();
   }
 
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
                                bool* aTriedToWrap);
 
   // We override SetValueCurveAtTime to convert the Float32Array to the wrapper
   // object.
   void SetValueCurveAtTime(JSContext* cx, const Float32Array& aValues, double aStartTime, double aDuration, ErrorResult& aRv)
   {
     AudioParamTimeline::SetValueCurveAtTime(aValues.Data(), aValues.Length(),
                                             aStartTime, aDuration, aRv);
+    mCallback(mNode);
+  }
+
+  // We override the rest of the mutating AudioParamTimeline methods in order to make
+  // sure that the callback is called every time that this object gets mutated.
+  void SetValue(float aValue)
+  {
+    AudioParamTimeline::SetValue(aValue);
+    mCallback(mNode);
+  }
+  void SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv)
+  {
+    AudioParamTimeline::SetValueAtTime(aValue, aStartTime, aRv);
+    mCallback(mNode);
+  }
+  void LinearRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv)
+  {
+    AudioParamTimeline::LinearRampToValueAtTime(aValue, aEndTime, aRv);
+    mCallback(mNode);
+  }
+  void ExponentialRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv)
+  {
+    AudioParamTimeline::ExponentialRampToValueAtTime(aValue, aEndTime, aRv);
+    mCallback(mNode);
+  }
+  void SetTargetAtTime(float aTarget, double aStartTime, double aTimeConstant, ErrorResult& aRv)
+  {
+    AudioParamTimeline::SetTargetAtTime(aTarget, aStartTime, aTimeConstant, aRv);
+    mCallback(mNode);
+  }
+  void CancelScheduledValues(double aStartTime)
+  {
+    AudioParamTimeline::CancelScheduledValues(aStartTime);
+    mCallback(mNode);
   }
 
   float MinValue() const
   {
     return mMinValue;
   }
 
   float MaxValue() const
@@ -68,17 +105,18 @@ public:
   }
 
   float DefaultValue() const
   {
     return mDefaultValue;
   }
 
 private:
-  nsRefPtr<AudioContext> mContext;
+  nsRefPtr<AudioNode> mNode;
+  CallbackType mCallback;
   const float mDefaultValue;
   const float mMinValue;
   const float mMaxValue;
 };
 
 }
 }
 
--- a/content/media/webaudio/BiquadFilterNode.cpp
+++ b/content/media/webaudio/BiquadFilterNode.cpp
@@ -23,19 +23,19 @@ static float
 Nyquist(AudioContext* aContext)
 {
   return 0.5f * aContext->SampleRate();
 }
 
 BiquadFilterNode::BiquadFilterNode(AudioContext* aContext)
   : AudioNode(aContext)
   , mType(BiquadTypeEnum::LOWPASS)
-  , mFrequency(new AudioParam(aContext, 350.f, 10.f, Nyquist(aContext)))
-  , mQ(new AudioParam(aContext, 1.f, 0.0001f, 1000.f))
-  , mGain(new AudioParam(aContext, 0.f, -40.f, 40.f))
+  , mFrequency(new AudioParam(this, Callback, 350.f, 10.f, Nyquist(aContext)))
+  , mQ(new AudioParam(this, Callback, 1.f, 0.0001f, 1000.f))
+  , mGain(new AudioParam(this, Callback, 0.f, -40.f, 40.f))
 {
 }
 
 JSObject*
 BiquadFilterNode::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return BiquadFilterNodeBinding::Wrap(aCx, aScope, this);
 }
--- a/content/media/webaudio/DelayNode.cpp
+++ b/content/media/webaudio/DelayNode.cpp
@@ -16,17 +16,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED_1(Del
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DelayNode)
 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
 
 NS_IMPL_ADDREF_INHERITED(DelayNode, AudioNode)
 NS_IMPL_RELEASE_INHERITED(DelayNode, AudioNode)
 
 DelayNode::DelayNode(AudioContext* aContext, double aMaxDelay)
   : AudioNode(aContext)
-  , mDelay(new AudioParam(aContext, 0.0f, 0.0f, float(aMaxDelay)))
+  , mDelay(new AudioParam(this, Callback, 0.0f, 0.0f, float(aMaxDelay)))
 {
 }
 
 JSObject*
 DelayNode::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return DelayNodeBinding::Wrap(aCx, aScope, this);
 }
--- a/content/media/webaudio/DynamicsCompressorNode.cpp
+++ b/content/media/webaudio/DynamicsCompressorNode.cpp
@@ -21,22 +21,22 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED_6(Dyn
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DynamicsCompressorNode)
 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
 
 NS_IMPL_ADDREF_INHERITED(DynamicsCompressorNode, AudioNode)
 NS_IMPL_RELEASE_INHERITED(DynamicsCompressorNode, AudioNode)
 
 DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
   : AudioNode(aContext)
-  , mThreshold(new AudioParam(aContext, -24.f, -100.f, 0.f))
-  , mKnee(new AudioParam(aContext, 30.f, 0.f, 40.f))
-  , mRatio(new AudioParam(aContext, 12.f, 1.f, 20.f))
-  , mReduction(new AudioParam(aContext, 0.f, -20.f, 0.f))
-  , mAttack(new AudioParam(aContext, 0.003f, 0.f, 1.f))
-  , mRelease(new AudioParam(aContext, 0.25f, 0.f, 1.f))
+  , mThreshold(new AudioParam(this, Callback, -24.f, -100.f, 0.f))
+  , mKnee(new AudioParam(this, Callback, 30.f, 0.f, 40.f))
+  , mRatio(new AudioParam(this, Callback, 12.f, 1.f, 20.f))
+  , mReduction(new AudioParam(this, Callback, 0.f, -20.f, 0.f))
+  , mAttack(new AudioParam(this, Callback, 0.003f, 0.f, 1.f))
+  , mRelease(new AudioParam(this, Callback, 0.25f, 0.f, 1.f))
 {
 }
 
 JSObject*
 DynamicsCompressorNode::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return DynamicsCompressorNodeBinding::Wrap(aCx, aScope, this);
 }
--- a/content/media/webaudio/GainNode.cpp
+++ b/content/media/webaudio/GainNode.cpp
@@ -16,17 +16,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED_1(Gai
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(GainNode)
 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
 
 NS_IMPL_ADDREF_INHERITED(GainNode, AudioNode)
 NS_IMPL_RELEASE_INHERITED(GainNode, AudioNode)
 
 GainNode::GainNode(AudioContext* aContext)
   : AudioNode(aContext)
-  , mGain(new AudioParam(aContext, 1.0f, 0.0f, 1.0f))
+  , mGain(new AudioParam(this, Callback, 1.0f, 0.0f, 1.0f))
 {
 }
 
 JSObject*
 GainNode::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return GainNodeBinding::Wrap(aCx, aScope, this);
 }