Bug 974089 - Destroy WebAudio MediaStream when a source finishes. r=padenot
☠☠ backed out by 42c0f3d737f1 ☠ ☠
authorKarl Tomlinson <karlt+@karlt.net>
Wed, 10 Jun 2015 13:31:29 +0200
changeset 279095 e511c79f221109c3cc07c5c16387be39c0797bec
parent 279094 4b5c070f23b33236cffccb96c3755284882b9f92
child 279096 8c6a7d5efe3a6f439502afbbccec86a4e85e3d3e
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs974089
milestone41.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 974089 - Destroy WebAudio MediaStream when a source finishes. r=padenot
dom/media/webaudio/AudioBufferSourceNode.cpp
dom/media/webaudio/AudioNode.cpp
dom/media/webaudio/AudioNode.h
dom/media/webaudio/OscillatorNode.cpp
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp
+++ b/dom/media/webaudio/AudioBufferSourceNode.cpp
@@ -638,17 +638,19 @@ AudioBufferSourceNode::Start(double aWhe
     ns->SetDoubleParameter(START, mContext->DOMTimeToStreamTime(aWhen));
   }
 }
 
 void
 AudioBufferSourceNode::SendBufferParameterToStream(JSContext* aCx)
 {
   AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
-  MOZ_ASSERT(ns, "Why don't we have a stream here?");
+  if (!mStream) {
+    return;
+  }
 
   if (mBuffer) {
     float rate = mBuffer->SampleRate();
     nsRefPtr<ThreadSharedFloatArrayBufferList> data =
       mBuffer->GetThreadSharedChannelsForRate(aCx);
     ns->SetBuffer(data.forget());
     ns->SetInt32Parameter(SAMPLE_RATE, rate);
 
@@ -729,45 +731,55 @@ AudioBufferSourceNode::NotifyMainThreadS
       mNode->DispatchTrustedEvent(NS_LITERAL_STRING("ended"));
       return NS_OK;
     }
   private:
     nsRefPtr<AudioBufferSourceNode> mNode;
   };
 
   NS_DispatchToMainThread(new EndedEventDispatcher(this));
+  // Release stream resources.
+  // DestroyMediaStream() will remove this stream listener.
+  DestroyMediaStream();
 
   // Drop the playing reference
   // Warning: The below line might delete this.
   MarkInactive();
 }
 
 void
 AudioBufferSourceNode::SendPlaybackRateToStream(AudioNode* aNode)
 {
   AudioBufferSourceNode* This = static_cast<AudioBufferSourceNode*>(aNode);
+  if (!This->mStream) {
+    return;
+  }
   SendTimelineParameterToStream(This, PLAYBACKRATE, *This->mPlaybackRate);
 }
 
 void
 AudioBufferSourceNode::SendDetuneToStream(AudioNode* aNode)
 {
   AudioBufferSourceNode* This = static_cast<AudioBufferSourceNode*>(aNode);
   SendTimelineParameterToStream(This, DETUNE, *This->mDetune);
 }
 
 void
 AudioBufferSourceNode::SendDopplerShiftToStream(double aDopplerShift)
 {
+  MOZ_ASSERT(mStream, "Should have disconnected panner if no stream");
   SendDoubleParameterToStream(DOPPLERSHIFT, aDopplerShift);
 }
 
 void
 AudioBufferSourceNode::SendLoopParametersToStream()
 {
+  if (!mStream) {
+    return;
+  }
   // Don't compute and set the loop parameters unnecessarily
   if (mLoop && mBuffer) {
     float rate = mBuffer->SampleRate();
     double length = (double(mBuffer->Length()) / mBuffer->SampleRate());
     double actualLoopStart, actualLoopEnd;
     if (mLoopStart >= 0.0 && mLoopEnd > 0.0 &&
         mLoopStart < mLoopEnd) {
       MOZ_ASSERT(mLoopStart != 0.0 || mLoopEnd != 0.0);
--- a/dom/media/webaudio/AudioNode.cpp
+++ b/dom/media/webaudio/AudioNode.cpp
@@ -347,20 +347,22 @@ AudioNode::Disconnect(uint32_t aOutput, 
       if (input.mInputNode == this && input.mOutputPort == aOutput) {
         // Destroying the InputNode here sends a message to the graph thread
         // to disconnect the streams, which should be sent before the
         // RunAfterPendingUpdates() call below.
         dest->mInputNodes.RemoveElementAt(j);
         // Remove one instance of 'dest' from mOutputNodes. There could be
         // others, and it's not correct to remove them all since some of them
         // could be for different output ports.
-        nsCOMPtr<nsIRunnable> runnable =
-          new RunnableRelease(mOutputNodes[i].forget());
+        nsRefPtr<AudioNode> output = mOutputNodes[i].forget();
         mOutputNodes.RemoveElementAt(i);
-        mStream->RunAfterPendingUpdates(runnable.forget());
+        if (mStream) {
+          nsRefPtr<nsIRunnable> runnable = new RunnableRelease(output.forget());
+          mStream->RunAfterPendingUpdates(runnable.forget());
+        }
         break;
       }
     }
   }
 
   for (int32_t i = mOutputParams.Length() - 1; i >= 0; --i) {
     AudioParam* dest = mOutputParams[i];
     for (int32_t j = dest->InputNodes().Length() - 1; j >= 0; --j) {
--- a/dom/media/webaudio/AudioNode.h
+++ b/dom/media/webaudio/AudioNode.h
@@ -215,17 +215,17 @@ protected:
   void SendChannelMixingParametersToStream();
   static void SendTimelineParameterToStream(AudioNode* aNode, uint32_t aIndex,
                                             const AudioParamTimeline& aValue);
 
 private:
   nsRefPtr<AudioContext> mContext;
 
 protected:
-  // Must be set in the constructor. Must not be null.
+  // Must be set in the constructor. Must not be null unless finished.
   // If MaxNumberOfInputs() is > 0, then mStream must be a ProcessedMediaStream.
   nsRefPtr<MediaStream> mStream;
 
 private:
   // For every InputNode, there is a corresponding entry in mOutputNodes of the
   // InputNode's mInputNode.
   nsTArray<InputNode> mInputNodes;
   // For every mOutputNode entry, there is a corresponding entry in mInputNodes
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -420,29 +420,38 @@ OscillatorNode::WrapObject(JSContext* aC
 {
   return OscillatorNodeBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 OscillatorNode::SendFrequencyToStream(AudioNode* aNode)
 {
   OscillatorNode* This = static_cast<OscillatorNode*>(aNode);
+  if (!This->mStream) {
+    return;
+  }
   SendTimelineParameterToStream(This, OscillatorNodeEngine::FREQUENCY, *This->mFrequency);
 }
 
 void
 OscillatorNode::SendDetuneToStream(AudioNode* aNode)
 {
   OscillatorNode* This = static_cast<OscillatorNode*>(aNode);
+  if (!This->mStream) {
+    return;
+  }
   SendTimelineParameterToStream(This, OscillatorNodeEngine::DETUNE, *This->mDetune);
 }
 
 void
 OscillatorNode::SendTypeToStream()
 {
+  if (!mStream) {
+    return;
+  }
   if (mType == OscillatorType::Custom) {
     // The engine assumes we'll send the custom data before updating the type.
     SendPeriodicWaveToStream();
   }
   SendInt32ParameterToStream(OscillatorNodeEngine::TYPE, static_cast<int32_t>(mType));
 }
 
 void OscillatorNode::SendPeriodicWaveToStream()
@@ -531,16 +540,19 @@ OscillatorNode::NotifyMainThreadStreamFi
       mNode->DispatchTrustedEvent(NS_LITERAL_STRING("ended"));
       return NS_OK;
     }
   private:
     nsRefPtr<OscillatorNode> mNode;
   };
 
   NS_DispatchToMainThread(new EndedEventDispatcher(this));
+  // Release stream resources.
+  // DestroyMediaStream() will remove this stream listener.
+  DestroyMediaStream();
 
   // Drop the playing reference
   // Warning: The below line might delete this.
   MarkInactive();
 }
 
 }
 }