Bug 1044514 - AudioDestinationNode should not be kept alive by the event listener, r=ehsan

This commit is contained in:
Andrea Marchesini 2014-07-29 16:30:40 +01:00
parent 715a091a96
commit a83b79a685
3 changed files with 63 additions and 18 deletions

View File

@ -96,9 +96,10 @@ AudioContext::AudioContext(nsPIDOMWindow* aWindow,
// bound to the window.
mDestination = new AudioDestinationNode(this, aIsOffline, aChannel,
aNumberOfChannels, aLength, aSampleRate);
// We skip calling SetIsOnlyNodeForContext during mDestination's constructor,
// because we can only call SetIsOnlyNodeForContext after mDestination has
// been set up.
// We skip calling SetIsOnlyNodeForContext and the creation of the
// audioChannelAgent during mDestination's constructor, because we can only
// call them after mDestination has been set up.
mDestination->CreateAudioChannelAgent();
mDestination->SetIsOnlyNodeForContext(true);
}

View File

@ -258,8 +258,40 @@ static bool UseAudioChannelService()
return Preferences::GetBool("media.useAudioChannelService");
}
class EventProxyHandler MOZ_FINAL : public nsIDOMEventListener
{
public:
NS_DECL_ISUPPORTS
explicit EventProxyHandler(nsIDOMEventListener* aNode)
{
MOZ_ASSERT(aNode);
mWeakNode = do_GetWeakReference(aNode);
}
// nsIDOMEventListener
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) MOZ_OVERRIDE
{
nsCOMPtr<nsIDOMEventListener> listener = do_QueryReferent(mWeakNode);
if (!listener) {
return NS_OK;
}
auto node = static_cast<AudioDestinationNode*>(listener.get());
return node->HandleEvent(aEvent);
}
private:
~EventProxyHandler()
{ }
nsWeakPtr mWeakNode;
};
NS_IMPL_ISUPPORTS(EventProxyHandler, nsIDOMEventListener)
NS_IMPL_CYCLE_COLLECTION_INHERITED(AudioDestinationNode, AudioNode,
mAudioChannelAgent)
mAudioChannelAgent, mEventProxyHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioDestinationNode)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
@ -305,17 +337,6 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
ErrorResult rv;
SetMozAudioChannelType(aChannel, rv);
}
if (!aIsOffline && UseAudioChannelService()) {
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
if (target) {
target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
/* useCapture = */ true,
/* wantsUntrusted = */ false);
}
CreateAudioChannelAgent();
}
}
AudioDestinationNode::~AudioDestinationNode()
@ -347,7 +368,8 @@ AudioDestinationNode::DestroyMediaStream()
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
NS_ENSURE_TRUE_VOID(target);
target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
mEventProxyHelper,
/* useCapture = */ true);
}
@ -565,6 +587,24 @@ AudioDestinationNode::CheckAudioChannelPermissions(AudioChannel aValue)
void
AudioDestinationNode::CreateAudioChannelAgent()
{
if (mIsOffline || !UseAudioChannelService()) {
return;
}
if (!mEventProxyHelper) {
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
if (target) {
// We use a proxy because otherwise the event listerner would hold a
// reference of the destination node, and by extension, everything
// connected to it.
mEventProxyHelper = new EventProxyHandler(this);
target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
mEventProxyHelper,
/* useCapture = */ true,
/* wantsUntrusted = */ false);
}
}
if (mAudioChannelAgent) {
mAudioChannelAgent->StopPlaying();
}

View File

@ -17,6 +17,7 @@ namespace mozilla {
namespace dom {
class AudioContext;
class EventProxyHandler;
class AudioDestinationNode : public AudioNode
, public nsIDOMEventListener
@ -57,7 +58,7 @@ public:
void OfflineShutdown();
// nsIDOMEventListener
// nsIDOMEventListener - by proxy
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
AudioChannel MozAudioChannelType() const;
@ -73,6 +74,8 @@ public:
// When aIsOnlyNode is true, this is the only node for the AudioContext.
void SetIsOnlyNodeForContext(bool aIsOnlyNode);
void CreateAudioChannelAgent();
virtual const char* NodeType() const
{
return "AudioDestinationNode";
@ -88,7 +91,6 @@ protected:
private:
bool CheckAudioChannelPermissions(AudioChannel aValue);
void CreateAudioChannelAgent();
void SetCanPlay(bool aCanPlay);
@ -100,6 +102,8 @@ private:
nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
nsRefPtr<EventProxyHandler> mEventProxyHelper;
// Audio Channel Type.
AudioChannel mAudioChannel;
bool mIsOffline;