From 4f46b92922779b11c6d380b4af39361ec57de0ec Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 3 Jun 2014 18:28:18 -0400 Subject: [PATCH] Bug 1015783 - Add a devtools API for Web Audio; r=padenot,smaug See bug 980506 for an extensive discussion about this. This patch adds three APIs to AudioNode in order for us to be able to build awesome devtools on top of it. * Weak reference API. This patch allows one to hold a weak reference to all AudioNode's using Components.utils.getWeakReference(). That way, the devtool's inspection code would not change the lifetime of AudioNodes. * AudioNode.id This is a chrome-only unique and monotonically incrementing ID for AudioNode objects. It is supposed to be used in order for the devtools to be able to identify a node without having to keep it alive. * webaudio-node-demise This is an observer notification that is called every time an AudioNode gets destroyed inside Gecko. The ID of the corresponding node is passed to this notification. --- .../media/webaudio/AudioDestinationNode.cpp | 1 - content/media/webaudio/AudioDestinationNode.h | 2 - content/media/webaudio/AudioNode.cpp | 20 +++++++ content/media/webaudio/AudioNode.h | 12 +++- .../webaudio/MediaStreamAudioSourceNode.cpp | 2 +- content/media/webaudio/test/chrome.ini | 3 + content/media/webaudio/test/moz.build | 4 ++ .../test/test_AudioNodeDevtoolsAPI.html | 55 +++++++++++++++++++ dom/webidl/AudioNode.webidl | 6 ++ 9 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 content/media/webaudio/test/chrome.ini create mode 100644 content/media/webaudio/test/test_AudioNodeDevtoolsAPI.html diff --git a/content/media/webaudio/AudioDestinationNode.cpp b/content/media/webaudio/AudioDestinationNode.cpp index 255e80b5201..7d688bbf51d 100644 --- a/content/media/webaudio/AudioDestinationNode.cpp +++ b/content/media/webaudio/AudioDestinationNode.cpp @@ -227,7 +227,6 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(AudioDestinationNode, AudioNode, NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioDestinationNode) NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback) - NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(AudioDestinationNode, AudioNode) diff --git a/content/media/webaudio/AudioDestinationNode.h b/content/media/webaudio/AudioDestinationNode.h index f606340c009..d4220004488 100644 --- a/content/media/webaudio/AudioDestinationNode.h +++ b/content/media/webaudio/AudioDestinationNode.h @@ -12,7 +12,6 @@ #include "nsIDOMEventListener.h" #include "nsIAudioChannelAgent.h" #include "AudioChannelCommon.h" -#include "nsWeakReference.h" namespace mozilla { namespace dom { @@ -22,7 +21,6 @@ class AudioContext; class AudioDestinationNode : public AudioNode , public nsIDOMEventListener , public nsIAudioChannelAgentCallback - , public nsSupportsWeakReference , public MainThreadMediaStreamListener { public: diff --git a/content/media/webaudio/AudioNode.cpp b/content/media/webaudio/AudioNode.cpp index 3cfb1228b41..27094a4d479 100644 --- a/content/media/webaudio/AudioNode.cpp +++ b/content/media/webaudio/AudioNode.cpp @@ -14,6 +14,7 @@ namespace mozilla { namespace dom { static const uint32_t INVALID_PORT = 0xffffffff; +static uint32_t gId = 0; NS_IMPL_CYCLE_COLLECTION_CLASS(AudioNode) @@ -49,6 +50,7 @@ AudioNode::Release() } NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioNode) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) AudioNode::AudioNode(AudioContext* aContext, @@ -60,6 +62,10 @@ AudioNode::AudioNode(AudioContext* aContext, , mChannelCount(aChannelCount) , mChannelCountMode(aChannelCountMode) , mChannelInterpretation(aChannelInterpretation) + , mId(gId++) +#ifdef DEBUG + , mDemiseNotified(false) +#endif { MOZ_ASSERT(aContext); DOMEventTargetHelper::BindToOwner(aContext->GetParentObject()); @@ -72,6 +78,10 @@ AudioNode::~AudioNode() MOZ_ASSERT(mInputNodes.IsEmpty()); MOZ_ASSERT(mOutputNodes.IsEmpty()); MOZ_ASSERT(mOutputParams.IsEmpty()); +#ifdef DEBUG + MOZ_ASSERT(mDemiseNotified, + "The webaudio-node-demise notification must have been sent"); +#endif if (mContext) { mContext->UpdateNodeCount(-1); } @@ -385,6 +395,16 @@ AudioNode::DestroyMediaStream() mStream->Destroy(); mStream = nullptr; + + nsCOMPtr obs = services::GetObserverService(); + if (obs) { + nsAutoString id; + id.AppendPrintf("%u", mId); + obs->NotifyObservers(nullptr, "webaudio-node-demise", id.get()); + } +#ifdef DEBUG + mDemiseNotified = true; +#endif } } diff --git a/content/media/webaudio/AudioNode.h b/content/media/webaudio/AudioNode.h index 7909c238486..7b4e6370297 100644 --- a/content/media/webaudio/AudioNode.h +++ b/content/media/webaudio/AudioNode.h @@ -16,6 +16,7 @@ #include "MediaStreamGraph.h" #include "WebAudioUtils.h" #include "mozilla/MemoryReporting.h" +#include "nsWeakReference.h" namespace mozilla { @@ -82,7 +83,8 @@ private: * still alive, and will still be alive when it receives a message from the * engine. */ -class AudioNode : public DOMEventTargetHelper +class AudioNode : public DOMEventTargetHelper, + public nsSupportsWeakReference { protected: // You can only use refcounting to delete this object @@ -133,6 +135,8 @@ public: virtual uint16_t NumberOfInputs() const { return 1; } virtual uint16_t NumberOfOutputs() const { return 1; } + uint32_t Id() const { return mId; } + uint32_t ChannelCount() const { return mChannelCount; } virtual void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv) { @@ -266,6 +270,12 @@ private: uint32_t mChannelCount; ChannelCountMode mChannelCountMode; ChannelInterpretation mChannelInterpretation; + const uint32_t mId; +#ifdef DEBUG + // In debug builds, check to make sure that the node demise notification has + // been properly sent before the node is destroyed. + bool mDemiseNotified; +#endif }; } diff --git a/content/media/webaudio/MediaStreamAudioSourceNode.cpp b/content/media/webaudio/MediaStreamAudioSourceNode.cpp index f15b328abdd..f4f4a19fbe3 100644 --- a/content/media/webaudio/MediaStreamAudioSourceNode.cpp +++ b/content/media/webaudio/MediaStreamAudioSourceNode.cpp @@ -42,7 +42,7 @@ MediaStreamAudioSourceNode::MediaStreamAudioSourceNode(AudioContext* aContext, ProcessedMediaStream* outputStream = static_cast(mStream.get()); mInputPort = outputStream->AllocateInputPort(aMediaStream->GetStream(), MediaInputPort::FLAG_BLOCK_INPUT); - mInputStream->AddConsumerToKeepAlive(this); + mInputStream->AddConsumerToKeepAlive(static_cast(this)); PrincipalChanged(mInputStream); // trigger enabling/disabling of the connector mInputStream->AddPrincipalChangeObserver(this); diff --git a/content/media/webaudio/test/chrome.ini b/content/media/webaudio/test/chrome.ini new file mode 100644 index 00000000000..afa72caca65 --- /dev/null +++ b/content/media/webaudio/test/chrome.ini @@ -0,0 +1,3 @@ +[DEFAULT] + +[test_AudioNodeDevtoolsAPI.html] diff --git a/content/media/webaudio/test/moz.build b/content/media/webaudio/test/moz.build index cc44593339e..0b1d91ca7b1 100644 --- a/content/media/webaudio/test/moz.build +++ b/content/media/webaudio/test/moz.build @@ -8,3 +8,7 @@ MOCHITEST_MANIFESTS += [ 'blink/mochitest.ini', 'mochitest.ini', ] + +MOCHITEST_CHROME_MANIFESTS += [ + 'chrome.ini' +] diff --git a/content/media/webaudio/test/test_AudioNodeDevtoolsAPI.html b/content/media/webaudio/test/test_AudioNodeDevtoolsAPI.html new file mode 100644 index 00000000000..cd3a72c23b0 --- /dev/null +++ b/content/media/webaudio/test/test_AudioNodeDevtoolsAPI.html @@ -0,0 +1,55 @@ + + + + Test the devtool AudioNode API + + + + +
+
+
+ + diff --git a/dom/webidl/AudioNode.webidl b/dom/webidl/AudioNode.webidl index 9871b2617ca..ed077f953df 100644 --- a/dom/webidl/AudioNode.webidl +++ b/dom/webidl/AudioNode.webidl @@ -43,3 +43,9 @@ interface AudioNode : EventTarget { }; +// Mozilla extension +partial interface AudioNode { + [ChromeOnly] + readonly attribute unsigned long id; +}; +