зеркало из https://github.com/mozilla/gecko-dev.git
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.
This commit is contained in:
Родитель
76be8c28d9
Коммит
11367a7bea
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
nsAutoString id;
|
||||
id.AppendPrintf("%u", mId);
|
||||
obs->NotifyObservers(nullptr, "webaudio-node-demise", id.get());
|
||||
}
|
||||
#ifdef DEBUG
|
||||
mDemiseNotified = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ MediaStreamAudioSourceNode::MediaStreamAudioSourceNode(AudioContext* aContext,
|
|||
ProcessedMediaStream* outputStream = static_cast<ProcessedMediaStream*>(mStream.get());
|
||||
mInputPort = outputStream->AllocateInputPort(aMediaStream->GetStream(),
|
||||
MediaInputPort::FLAG_BLOCK_INPUT);
|
||||
mInputStream->AddConsumerToKeepAlive(this);
|
||||
mInputStream->AddConsumerToKeepAlive(static_cast<nsIDOMEventTarget*>(this));
|
||||
|
||||
PrincipalChanged(mInputStream); // trigger enabling/disabling of the connector
|
||||
mInputStream->AddPrincipalChangeObserver(this);
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[DEFAULT]
|
||||
|
||||
[test_AudioNodeDevtoolsAPI.html]
|
|
@ -8,3 +8,7 @@ MOCHITEST_MANIFESTS += [
|
|||
'blink/mochitest.ini',
|
||||
'mochitest.ini',
|
||||
]
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += [
|
||||
'chrome.ini'
|
||||
]
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test the devtool AudioNode API</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var ac = new AudioContext();
|
||||
var ids;
|
||||
var weak;
|
||||
(function() {
|
||||
var src1 = ac.createBufferSource();
|
||||
var src2 = ac.createBufferSource();
|
||||
ok(src2.id > src1.id, "The ID should be monotonic");
|
||||
ok(src1.id > ac.destination.id, "The ID of the destination node should be the lowest");
|
||||
ids = [src1.id, src2.id];
|
||||
weak = Components.utils.getWeakReference(src1);
|
||||
is(weak.get(), src1, "The node should support a weak reference");
|
||||
})();
|
||||
function observer(subject, topic, data) {
|
||||
var id = parseInt(data);
|
||||
var index = ids.indexOf(id);
|
||||
if (index != -1) {
|
||||
info("Dropping id " + id + " at index " + index);
|
||||
ids.splice(index, 1);
|
||||
if (ids.length == 0) {
|
||||
SimpleTest.executeSoon(function() {
|
||||
is(weak.get(), null, "The weak reference must be dropped now");
|
||||
Services.obs.removeObserver(observer, "webaudio-node-demise");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Services.obs.addObserver(observer, "webaudio-node-demise", false);
|
||||
|
||||
forceCC();
|
||||
forceCC();
|
||||
|
||||
function forceCC() {
|
||||
SpecialPowers.DOMWindowUtils.cycleCollect();
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -43,3 +43,9 @@ interface AudioNode : EventTarget {
|
|||
|
||||
};
|
||||
|
||||
// Mozilla extension
|
||||
partial interface AudioNode {
|
||||
[ChromeOnly]
|
||||
readonly attribute unsigned long id;
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче