From dc411d889b59f7136a7e02a8987bd9d6f6e5caf4 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 10 Sep 2013 17:05:22 +1200 Subject: [PATCH] b=914030 shut down an AudioDestinationNode's graph on destruction, if not already r=ehsan This means that the graph will be shutdown properly, even if the AudioDestinationNode is unlinked before AudioContext::Shutdown() is called. Making MediaStreamGraph::DestroyNonRealtimeInstance() idempotent also makes AudioContext::Shutdown() idempotent. --HG-- extra : transplant_source : jZ%86%C5%C2n%17%EF%C2%C0y%ED%14%0E%17_dt%0C%07 --- content/media/MediaStreamGraph.cpp | 11 ++++++++++- content/media/MediaStreamGraph.h | 3 +++ content/media/webaudio/AudioContext.h | 2 +- content/media/webaudio/AudioDestinationNode.cpp | 13 +++++++++++++ content/media/webaudio/AudioDestinationNode.h | 2 ++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index 38a7ea050fd0..e1e42a8409c7 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -2352,9 +2352,12 @@ void MediaStreamGraph::DestroyNonRealtimeInstance(MediaStreamGraph* aGraph) { NS_ASSERTION(NS_IsMainThread(), "Main thread only"); - MOZ_ASSERT(aGraph != gGraph, "Should not destroy the global graph here"); + MOZ_ASSERT(aGraph->IsNonRealtime(), "Should not destroy the global graph here"); MediaStreamGraphImpl* graph = static_cast(aGraph); + if (graph->mForceShutDown) + return; // already done + if (!graph->mNonRealtimeProcessing) { // Start the graph, but don't produce anything graph->StartNonRealtimeProcessing(0); @@ -2421,6 +2424,12 @@ MediaStreamGraph::CreateAudioNodeStream(AudioNodeEngine* aEngine, return stream; } +bool +MediaStreamGraph::IsNonRealtime() const +{ + return this != gGraph; +} + void MediaStreamGraph::StartNonRealtimeProcessing(uint32_t aTicksToProcess) { diff --git a/content/media/MediaStreamGraph.h b/content/media/MediaStreamGraph.h index fb2d810266b6..4a05e493a8cc 100644 --- a/content/media/MediaStreamGraph.h +++ b/content/media/MediaStreamGraph.h @@ -975,6 +975,7 @@ public: // Main thread only static MediaStreamGraph* GetInstance(); static MediaStreamGraph* CreateNonRealtimeInstance(); + // Idempotent static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph); // Control API. @@ -1022,6 +1023,8 @@ public: * in main-thread stream state. */ int64_t GetCurrentGraphUpdateIndex() { return mGraphUpdatesSent; } + + bool IsNonRealtime() const; /** * Start processing non-realtime for a specific number of ticks. */ diff --git a/content/media/webaudio/AudioContext.h b/content/media/webaudio/AudioContext.h index a3e518c10f8e..19759604e339 100644 --- a/content/media/webaudio/AudioContext.h +++ b/content/media/webaudio/AudioContext.h @@ -79,7 +79,7 @@ public: return GetOwner(); } - void Shutdown(); + void Shutdown(); // idempotent void Suspend(); void Resume(); diff --git a/content/media/webaudio/AudioDestinationNode.cpp b/content/media/webaudio/AudioDestinationNode.cpp index c5aea724e3af..ff6ccad106fc 100644 --- a/content/media/webaudio/AudioDestinationNode.cpp +++ b/content/media/webaudio/AudioDestinationNode.cpp @@ -235,6 +235,19 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext, mStream = graph->CreateAudioNodeStream(engine, MediaStreamGraph::EXTERNAL_STREAM); } +void +AudioDestinationNode::DestroyMediaStream() +{ + if (!mStream) + return; + + MediaStreamGraph* graph = mStream->Graph(); + if (graph->IsNonRealtime()) { + MediaStreamGraph::DestroyNonRealtimeInstance(graph); + } + AudioNode::DestroyMediaStream(); +} + uint32_t AudioDestinationNode::MaxChannelCount() const { diff --git a/content/media/webaudio/AudioDestinationNode.h b/content/media/webaudio/AudioDestinationNode.h index 68f891d3d9be..1d239a463d01 100644 --- a/content/media/webaudio/AudioDestinationNode.h +++ b/content/media/webaudio/AudioDestinationNode.h @@ -25,6 +25,8 @@ public: uint32_t aLength = 0, float aSampleRate = 0.0f); + virtual void DestroyMediaStream() MOZ_OVERRIDE; + NS_DECL_ISUPPORTS_INHERITED virtual JSObject* WrapObject(JSContext* aCx,