b=910171 add a general means to keep active nodes alive from the AudioContext r=ehsan

AudioNodes that keep playing or tail-time references need to have these
references cleared when an AudioContext has completed or is shut down by the
window.

Storing references on the AudioContext instead of on the AudioNodes will allow
the AudioContext to report playing references to the cycle collector until
offline rendering starts for bug 914033.  This is not necessary for tail-time
references, but it is tidier to use the same code for playing and tail-time
references.

--HG--
extra : transplant_source : %E0%F1%06%BFV%B6XI%9BX%8E%8D7%3FsU%8F%F9%14r
This commit is contained in:
Karl Tomlinson 2013-09-17 11:53:40 +12:00
parent 92875436fc
commit cf1704526c
3 changed files with 49 additions and 3 deletions

View File

@ -440,6 +440,18 @@ AudioContext::RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob)
mDecodeJobs.RemoveElement(aDecodeJob);
}
void
AudioContext::RegisterActiveNode(AudioNode* aNode)
{
mActiveNodes.PutEntry(aNode);
}
void
AudioContext::UnregisterActiveNode(AudioNode* aNode)
{
mActiveNodes.RemoveEntry(aNode);
}
void
AudioContext::UnregisterAudioBufferSourceNode(AudioBufferSourceNode* aNode)
{
@ -526,6 +538,11 @@ AudioContext::Shutdown()
{
Suspend();
// Release references to active nodes.
// Active AudioNodes don't unregister in destructors, at which point the
// Node is already unregistered.
mActiveNodes.Clear();
// Stop all audio buffer source nodes, to make sure that they release
// their self-references.
// We first gather an array of the nodes and then call Stop on each one,

View File

@ -41,6 +41,7 @@ class AudioBuffer;
class AudioBufferSourceNode;
class AudioDestinationNode;
class AudioListener;
class AudioNode;
class BiquadFilterNode;
class ChannelMergerNode;
class ChannelSplitterNode;
@ -212,6 +213,20 @@ public:
MediaStreamGraph* Graph() const;
MediaStream* DestinationStream() const;
// Nodes register here if they will produce sound even if they have silent
// or no input connections. The AudioContext will keep registered nodes
// alive until the context is collected. This takes care of "playing"
// references and "tail-time" references.
void RegisterActiveNode(AudioNode* aNode);
// Nodes unregister when they have finished producing sound for the
// foreseeable future.
// Do NOT call UnregisterActiveNode from an AudioNode destructor.
// If the destructor is called, then the Node has already been unregistered.
// The destructor may be called during hashtable enumeration, during which
// unregistering would not be safe.
void UnregisterActiveNode(AudioNode* aNode);
void UnregisterAudioBufferSourceNode(AudioBufferSourceNode* aNode);
void UnregisterPannerNode(PannerNode* aNode);
void UnregisterOscillatorNode(OscillatorNode* aNode);
@ -239,6 +254,9 @@ private:
nsRefPtr<AudioListener> mListener;
MediaBufferDecoder mDecoder;
nsTArray<nsRefPtr<WebAudioDecodeJob> > mDecodeJobs;
// See RegisterActiveNode. These will keep the AudioContext alive while it
// is rendering and the window remains alive.
nsTHashtable<nsRefPtrHashKey<AudioNode> > mActiveNodes;
// Two hashsets containing all the PannerNodes and AudioBufferSourceNodes,
// to compute the doppler shift, and also to stop AudioBufferSourceNodes.
// These are all weak pointers.

View File

@ -102,9 +102,9 @@ private:
* real-time processing and output of this AudioNode.
*
* We track the incoming and outgoing connections to other AudioNodes.
* Outgoing connections have strong ownership. Also, AudioNodes add self
* references if they produce sound on their output even when they have silent
* or no input.
* Outgoing connections have strong ownership. Also, AudioNodes that will
* produce sound on their output even when they have silent or no input ask
* the AudioContext to keep them alive until the context is finished.
*/
class AudioNode : public nsDOMEventTargetHelper,
public EnableWebAudioCheck
@ -213,6 +213,17 @@ public:
virtual void NotifyInputConnected() {}
// MarkActive() asks the context to keep the AudioNode alive until the
// context is finished. This takes care of "playing" references and
// "tail-time" references.
void MarkActive() { Context()->RegisterActiveNode(this); }
// Active nodes call MarkInactive() when they have finished producing sound
// for the foreseeable future.
// Do not call MarkInactive from a node destructor. If the destructor is
// called, then the node is already inactive.
// MarkInactive() may delete |this|.
void MarkInactive() { Context()->UnregisterActiveNode(this); }
private:
friend class AudioBufferSourceNode;
// This could possibly delete 'this'.