Bug 866434 - Part 1: Make it possible to connect an AudioNode to an AudioParam; r=roc

This commit is contained in:
Ehsan Akhgari 2013-05-01 18:59:02 -04:00
parent 11c6d3c7eb
commit caeeb616ee
6 changed files with 153 additions and 6 deletions

View File

@ -13,14 +13,18 @@
namespace mozilla {
namespace dom {
static const uint32_t INVALID_PORT = 0xffffffff;
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(AudioNode, nsDOMEventTargetHelper)
tmp->DisconnectFromGraph();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputNodes)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputParams)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AudioNode, nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputNodes)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputParams)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(AudioNode, nsDOMEventTargetHelper)
@ -59,6 +63,7 @@ AudioNode::~AudioNode()
{
MOZ_ASSERT(mInputNodes.IsEmpty());
MOZ_ASSERT(mOutputNodes.IsEmpty());
MOZ_ASSERT(mOutputParams.IsEmpty());
}
static uint32_t
@ -114,6 +119,16 @@ AudioNode::DisconnectFromGraph()
output->mInputNodes.RemoveElementAt(inputIndex);
}
while (!mOutputParams.IsEmpty()) {
uint32_t i = mOutputParams.Length() - 1;
nsRefPtr<AudioParam> output = mOutputParams[i].forget();
mOutputParams.RemoveElementAt(i);
uint32_t inputIndex = FindIndexOfNode(output->InputNodes(), this);
// It doesn't matter which one we remove, since we're going to remove all
// entries for this node anyway.
output->RemoveInputNode(inputIndex);
}
DestroyMediaStream();
}
@ -159,6 +174,33 @@ AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
Context()->UpdatePannerSource();
}
void
AudioNode::Connect(AudioParam& aDestination, uint32_t aOutput,
ErrorResult& aRv)
{
if (aOutput >= NumberOfOutputs()) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
}
if (Context() != aDestination.GetParentObject()) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return;
}
if (FindIndexOfNodeWithPorts(aDestination.InputNodes(), this, INVALID_PORT, aOutput) !=
nsTArray<AudioNode::InputNode>::NoIndex) {
// connection already exists.
return;
}
mOutputParams.AppendElement(&aDestination);
InputNode* input = aDestination.AppendInputNode();
input->mInputNode = this;
input->mInputPort = INVALID_PORT;
input->mOutputPort = aOutput;
}
void
AudioNode::SendDoubleParameterToStream(uint32_t aIndex, double aValue)
{
@ -224,6 +266,21 @@ AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv)
}
}
for (int32_t i = mOutputParams.Length() - 1; i >= 0; --i) {
AudioParam* dest = mOutputParams[i];
for (int32_t j = dest->InputNodes().Length() - 1; j >= 0; --j) {
const InputNode& input = dest->InputNodes()[j];
if (input.mInputNode == this && input.mOutputPort == aOutput) {
dest->RemoveInputNode(j);
// Remove one instance of 'dest' from mOutputParams. There could be
// others, and it's not correct to remove them all since some of them
// could be for different output ports.
mOutputParams.RemoveElementAt(i);
break;
}
}
}
// This disconnection may have disconnected a panner and a source.
Context()->UpdatePannerSource();
}
@ -249,5 +306,11 @@ AudioNode::DestroyMediaStream()
}
}
void
AudioNode::RemoveOutputParam(AudioParam* aParam)
{
mOutputParams.RemoveElement(aParam);
}
}
}

View File

@ -26,6 +26,7 @@ class ErrorResult;
namespace dom {
class AudioParam;
struct ThreeDPoint;
template<class T>
@ -108,6 +109,9 @@ public:
virtual void Connect(AudioNode& aDestination, uint32_t aOutput,
uint32_t aInput, ErrorResult& aRv);
virtual void Connect(AudioParam& aDestination, uint32_t aOutput,
ErrorResult& aRv);
virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv);
// The following two virtual methods must be implemented by each node type
@ -153,6 +157,7 @@ public:
AudioNode* mInputNode;
nsRefPtr<MediaInputPort> mStreamPort;
// The index of the input port this node feeds into.
// This is not used for connections to AudioParams.
uint32_t mInputPort;
// The index of the output port this node comes out of.
uint32_t mOutputPort;
@ -165,6 +170,8 @@ public:
return mInputNodes;
}
void RemoveOutputParam(AudioParam* aParam);
private:
// This could possibly delete 'this'.
void DisconnectFromGraph();
@ -197,6 +204,12 @@ private:
// exact matching entry, since mOutputNodes doesn't include the port
// identifiers and the same node could be connected on multiple ports.
nsTArray<nsRefPtr<AudioNode> > mOutputNodes;
// For every mOutputParams entry, there is a corresponding entry in
// AudioParam::mInputNodes of the mOutputParams entry. We won't necessarily be
// able to identify the exact matching entry, since mOutputParams doesn't
// include the port identifiers and the same node could be connected on
// multiple ports.
nsTArray<nsRefPtr<AudioParam> > mOutputParams;
uint32_t mChannelCount;
ChannelCountMode mChannelCountMode;
ChannelInterpretation mChannelInterpretation;

View File

@ -13,7 +13,30 @@
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(AudioParam, mNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioParam)
tmp->DisconnectFromGraph();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioParam)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AudioParam)
NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(AudioParam)
NS_IMETHODIMP_(nsrefcnt)
AudioParam::Release()
{
if (mRefCnt.get() == 1) {
// We are about to be deleted, disconnect the object from the graph before
// the derived type is destroyed.
DisconnectFromGraph();
}
NS_IMPL_CC_NATIVE_RELEASE_BODY(AudioParam)
}
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioParam, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioParam, Release)
@ -31,6 +54,7 @@ AudioParam::AudioParam(AudioNode* aNode,
AudioParam::~AudioParam()
{
MOZ_ASSERT(mInputNodes.IsEmpty());
}
JSObject*
@ -39,6 +63,21 @@ AudioParam::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
return AudioParamBinding::Wrap(aCx, aScope, this);
}
void
AudioParam::DisconnectFromGraph()
{
// Addref this temporarily so the refcount bumping below doesn't destroy us
// prematurely
nsRefPtr<AudioParam> kungFuDeathGrip = this;
while (!mInputNodes.IsEmpty()) {
uint32_t i = mInputNodes.Length() - 1;
nsRefPtr<AudioNode> input = mInputNodes[i].mInputNode;
mInputNodes.RemoveElementAt(i);
input->RemoveOutputParam(this);
}
}
}
}

View File

@ -37,7 +37,8 @@ public:
float aDefaultValue);
virtual ~AudioParam();
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioParam)
NS_IMETHOD_(nsrefcnt) AddRef(void);
NS_IMETHOD_(nsrefcnt) Release(void);
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AudioParam)
AudioContext* GetParentObject() const
@ -104,8 +105,32 @@ public:
return mDefaultValue;
}
const nsTArray<AudioNode::InputNode>& InputNodes() const
{
return mInputNodes;
}
void RemoveInputNode(uint32_t aIndex)
{
mInputNodes.RemoveElementAt(aIndex);
}
AudioNode::InputNode* AppendInputNode()
{
return mInputNodes.AppendElement();
}
void DisconnectFromGraph();
protected:
nsCycleCollectingAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
private:
nsRefPtr<AudioNode> mNode;
// For every InputNode, there is a corresponding entry in mOutputParams of the
// InputNode's mInputNode.
nsTArray<AudioNode::InputNode> mInputNodes;
CallbackType mCallback;
const float mDefaultValue;
};

View File

@ -46,6 +46,15 @@ public:
}
}
virtual void Connect(AudioParam& aDestination, uint32_t aOutput,
ErrorResult& aRv) MOZ_OVERRIDE
{
AudioNode::Connect(aDestination, aOutput, aRv);
if (!aRv.Failed()) {
mPlayingRef.Take(this);
}
}
virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv) MOZ_OVERRIDE
{
AudioNode::Disconnect(aOutput, aRv);

View File

@ -26,10 +26,8 @@ interface AudioNode : EventTarget {
[Throws]
void connect(AudioNode destination, optional unsigned long output = 0, optional unsigned long input = 0);
// [Throws]
// void connect(AudioParam destination, optional unsigned long output = 0);
[Throws]
void connect(AudioParam destination, optional unsigned long output = 0);
[Throws]
void disconnect(optional unsigned long output = 0);