Bug 1195051 - Part 2: Mute the destination node when the AudioContext is suspended, and unmute when resumed; r=padenot
authorEhsan Akhgari <ehsan@mozilla.com>
Sat, 15 Aug 2015 18:36:13 -0400
changeset 258036 4abc258b07a7d019890454eb3b7620bb4a4d357b
parent 258035 4f1b7f9d6f23a9748bcbe3344bad1df5b6ef8426
child 258037 5a66bd178c4cdadcdb381550e33a6d7b6b971062
push id29241
push userkwierso@gmail.com
push dateTue, 18 Aug 2015 00:00:46 +0000
treeherdermozilla-central@6ae3e9ff53b2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1195051
milestone43.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 1195051 - Part 2: Mute the destination node when the AudioContext is suspended, and unmute when resumed; r=padenot
dom/media/webaudio/AudioContext.cpp
dom/media/webaudio/AudioDestinationNode.cpp
dom/media/webaudio/AudioDestinationNode.h
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -850,17 +850,17 @@ AudioContext::Suspend(ErrorResult& aRv)
     return promise.forget();
   }
 
   if (mAudioContextState == AudioContextState::Suspended) {
     promise->MaybeResolve(JS::UndefinedHandleValue);
     return promise.forget();
   }
 
-  Destination()->DestroyAudioChannelAgent();
+  Destination()->Suspend();
 
   MediaStream* ds = DestinationStream();
   if (ds) {
     ds->BlockStreamIfNeeded();
   }
 
   mPromiseGripArray.AppendElement(promise);
   Graph()->ApplyAudioContextOperation(DestinationStream()->AsAudioNodeStream(),
@@ -890,17 +890,17 @@ AudioContext::Resume(ErrorResult& aRv)
     return promise.forget();
   }
 
   if (mAudioContextState == AudioContextState::Running) {
     promise->MaybeResolve(JS::UndefinedHandleValue);
     return promise.forget();
   }
 
-  Destination()->CreateAudioChannelAgent();
+  Destination()->Resume();
 
   MediaStream* ds = DestinationStream();
   if (ds) {
     ds->UnblockStreamIfNeeded();
   }
 
   mPromiseGripArray.AppendElement(promise);
   Graph()->ApplyAudioContextOperation(DestinationStream()->AsAudioNodeStream(),
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -239,28 +239,33 @@ private:
 
 class DestinationNodeEngine final : public AudioNodeEngine
 {
 public:
   explicit DestinationNodeEngine(AudioDestinationNode* aNode)
     : AudioNodeEngine(aNode)
     , mVolume(1.0f)
     , mLastInputMuted(true)
+    , mSuspended(false)
   {
     MOZ_ASSERT(aNode);
   }
 
   virtual void ProcessBlock(AudioNodeStream* aStream,
                             const AudioChunk& aInput,
                             AudioChunk* aOutput,
                             bool* aFinished) override
   {
     *aOutput = aInput;
     aOutput->mVolume *= mVolume;
 
+    if (mSuspended) {
+      return;
+    }
+
     bool newInputMuted = aInput.IsNull() || aInput.IsMuted();
     if (newInputMuted != mLastInputMuted) {
       mLastInputMuted = newInputMuted;
 
       nsRefPtr<InputMutedRunnable> runnable =
         new InputMutedRunnable(aStream, newInputMuted);
       aStream->Graph()->
         DispatchToMainThreadAfterStreamStateUpdate(runnable.forget());
@@ -269,28 +274,40 @@ public:
 
   virtual void SetDoubleParameter(uint32_t aIndex, double aParam) override
   {
     if (aIndex == VOLUME) {
       mVolume = aParam;
     }
   }
 
+  virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam) override
+  {
+    if (aIndex == SUSPENDED) {
+      mSuspended = !!aParam;
+      if (mSuspended) {
+        mLastInputMuted = true;
+      }
+    }
+  }
+
   enum Parameters {
     VOLUME,
+    SUSPENDED,
   };
 
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
 private:
   float mVolume;
   bool mLastInputMuted;
+  bool mSuspended;
 };
 
 static bool UseAudioChannelService()
 {
   return Preferences::GetBool("media.useAudioChannelService");
 }
 
 static bool UseAudioChannelAPI()
@@ -447,16 +464,30 @@ AudioDestinationNode::Mute()
 void
 AudioDestinationNode::Unmute()
 {
   MOZ_ASSERT(Context() && !Context()->IsOffline());
   SendDoubleParameterToStream(DestinationNodeEngine::VOLUME, 1.0f);
 }
 
 void
+AudioDestinationNode::Suspend()
+{
+  DestroyAudioChannelAgent();
+  SendInt32ParameterToStream(DestinationNodeEngine::SUSPENDED, 1);
+}
+
+void
+AudioDestinationNode::Resume()
+{
+  CreateAudioChannelAgent();
+  SendInt32ParameterToStream(DestinationNodeEngine::SUSPENDED, 0);
+}
+
+void
 AudioDestinationNode::OfflineShutdown()
 {
   MOZ_ASSERT(Context() && Context()->IsOffline(),
              "Should only be called on a valid OfflineAudioContext");
 
   MediaStreamGraph::DestroyNonRealtimeInstance(mStream->Graph());
   mOfflineRenderingRef.Drop(this);
 }
--- a/dom/media/webaudio/AudioDestinationNode.h
+++ b/dom/media/webaudio/AudioDestinationNode.h
@@ -48,16 +48,19 @@ public:
                                ErrorResult& aRv) override;
 
   // Returns the stream or null after unlink.
   AudioNodeStream* Stream() { return mStream; }
 
   void Mute();
   void Unmute();
 
+  void Suspend();
+  void Resume();
+
   void StartRendering(Promise* aPromise);
 
   void OfflineShutdown();
 
   AudioChannel MozAudioChannelType() const;
   void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
 
   virtual void NotifyMainThreadStreamFinished() override;