author | Paul Adenot <paul@paul.cx> |
Fri, 05 Jun 2015 11:17:14 +0200 | |
changeset 318830 | 38ae3688a00bba02f5d47a65c5f58d84ef25b7bc |
parent 318829 | 518ab93137128a640a30c9e8b0617d80432e41a0 |
child 318831 | 1b34fb6f5b5f07489c57277da49b4680276cfe67 |
push id | 30854 |
push user | ryanvm@gmail.com |
push date | Fri, 21 Oct 2016 21:08:02 +0000 |
treeherder | mozilla-central@806054dd12bd [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dminor, ehsan |
bugs | 1130010 |
milestone | 52.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/media/webaudio/AudioNode.cpp +++ b/dom/media/webaudio/AudioNode.cpp @@ -286,24 +286,19 @@ void AudioNode::SendChannelMixingParametersToStream() { if (mStream) { mStream->SetChannelMixingParameters(mChannelCount, mChannelCountMode, mChannelInterpretation); } } -void -AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv) +bool +AudioNode::DisconnectFromOutputIfConnected(AudioNode& aDestination, uint32_t aOutputIndex, uint32_t aInputIndex) { - if (aOutput >= NumberOfOutputs()) { - aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); - return; - } - WEB_AUDIO_API_LOG("%f: %s %u Disconnect()", Context()->CurrentTime(), NodeType(), Id()); // An upstream node may be starting to play on the graph thread, and the // engine for a downstream node may be sending a PlayingRefChangeHandler // ADDREF message to this (main) thread. Wait for a round trip before // releasing nodes, to give engines receiving sound now time to keep their // nodes alive. @@ -317,60 +312,237 @@ AudioNode::Disconnect(uint32_t aOutput, { mNode = nullptr; return NS_OK; } private: RefPtr<AudioNode> mNode; }; - for (int32_t i = mOutputNodes.Length() - 1; i >= 0; --i) { - AudioNode* dest = mOutputNodes[i]; - for (int32_t j = dest->mInputNodes.Length() - 1; j >= 0; --j) { - InputNode& input = dest->mInputNodes[j]; - if (input.mInputNode == this && input.mOutputPort == aOutput) { - // Destroying the InputNode here sends a message to the graph thread - // to disconnect the streams, which should be sent before the - // RunAfterPendingUpdates() call below. - dest->mInputNodes.RemoveElementAt(j); - // Remove one instance of 'dest' from mOutputNodes. There could be - // others, and it's not correct to remove them all since some of them - // could be for different output ports. - RefPtr<AudioNode> output = mOutputNodes[i].forget(); - mOutputNodes.RemoveElementAt(i); - output->NotifyInputsChanged(); - if (mStream) { - RefPtr<nsIRunnable> runnable = new RunnableRelease(output.forget()); - mStream->RunAfterPendingUpdates(runnable.forget()); - } - break; + InputNode& input = aDestination.mInputNodes[aInputIndex]; + if (input.mInputNode != this) { + return false; + } + + // Destroying the InputNode here sends a message to the graph thread + // to disconnect the streams, which should be sent before the + // RunAfterPendingUpdates() call below. + aDestination.mInputNodes.RemoveElementAt(aInputIndex); + // Remove one instance of 'dest' from mOutputNodes. There could be + // others, and it's not correct to remove them all since some of them + // could be for different output ports. + RefPtr<AudioNode> output = mOutputNodes[aOutputIndex].forget(); + mOutputNodes.RemoveElementAt(aOutputIndex); + output->NotifyInputsChanged(); + if (mStream) { + nsCOMPtr<nsIRunnable> runnable = new RunnableRelease(output.forget()); + mStream->RunAfterPendingUpdates(runnable.forget()); + } + return true; +} + +bool +AudioNode::DisconnectFromParamIfConnected(AudioParam& aDestination, uint32_t aOutputIndex, uint32_t aInputIndex) +{ + MOZ_ASSERT(aOutputIndex < mOutputParams.Length()); + MOZ_ASSERT(aInputIndex < aDestination.InputNodes().Length()); + + const InputNode& input = aDestination.InputNodes()[aInputIndex]; + if (input.mInputNode != this) { + return false; + } + aDestination.RemoveInputNode(aInputIndex); + // 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(aOutputIndex); + return true; +} + +void +AudioNode::Disconnect(ErrorResult& aRv) +{ + for (int32_t outputIndex = mOutputNodes.Length() - 1; outputIndex >= 0; --outputIndex) { + AudioNode* dest = mOutputNodes[outputIndex]; + for (int32_t inputIndex = dest->mInputNodes.Length() - 1; inputIndex >= 0; --inputIndex) { + DisconnectFromOutputIfConnected(*dest, outputIndex, inputIndex); + } + } + + for (int32_t outputIndex = mOutputParams.Length() - 1; outputIndex >= 0; --outputIndex) { + AudioParam* dest = mOutputParams[outputIndex]; + for (int32_t inputIndex = dest->InputNodes().Length() - 1; inputIndex >= 0; --inputIndex) { + DisconnectFromParamIfConnected(*dest, outputIndex, inputIndex); + } + } + + // This disconnection may have disconnected a panner and a source. + Context()->UpdatePannerSource(); +} + +void +AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv) +{ + if (aOutput >= NumberOfOutputs()) { + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return; + } + + for (int32_t outputIndex = mOutputNodes.Length() - 1; outputIndex >= 0; --outputIndex) { + AudioNode* dest = mOutputNodes[outputIndex]; + for (int32_t inputIndex = dest->mInputNodes.Length() - 1; inputIndex >= 0; --inputIndex) { + InputNode& input = dest->mInputNodes[inputIndex]; + if (input.mOutputPort == aOutput) { + DisconnectFromOutputIfConnected(*dest, outputIndex, inputIndex); } } } - 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; + for (int32_t outputIndex = mOutputParams.Length() - 1; outputIndex >= 0; --outputIndex) { + AudioParam* dest = mOutputParams[outputIndex]; + for (int32_t inputIndex = dest->InputNodes().Length() - 1; inputIndex >= 0; --inputIndex) { + const InputNode& input = dest->InputNodes()[inputIndex]; + if (input.mOutputPort == aOutput) { + DisconnectFromParamIfConnected(*dest, outputIndex, inputIndex); } } } // This disconnection may have disconnected a panner and a source. Context()->UpdatePannerSource(); } void +AudioNode::Disconnect(AudioNode& aDestination, ErrorResult& aRv) +{ + bool wasConnected = false; + + size_t outputIndex = mOutputNodes.IndexOf(&aDestination); + if (outputIndex == nsTArray<InputNode>::NoIndex) { + aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); + return; + } + for (int32_t inputIndex = aDestination.mInputNodes.Length() - 1; inputIndex >= 0; --inputIndex) { + wasConnected |= DisconnectFromOutputIfConnected(aDestination, outputIndex, inputIndex); + } + + if (!wasConnected) { + aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); + return; + } + + // This disconnection may have disconnected a panner and a source. + Context()->UpdatePannerSource(); +} + +void +AudioNode::Disconnect(AudioNode& aDestination, uint32_t aOutput, ErrorResult& aRv) +{ + if (aOutput >= NumberOfOutputs()) { + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return; + } + + bool wasConnected = false; + + for (int32_t outputIndex = mOutputNodes.Length() - 1; outputIndex >= 0; --outputIndex) { + for (int32_t inputIndex = aDestination.mInputNodes.Length() - 1; inputIndex >= 0; --inputIndex) { + InputNode& input = aDestination.mInputNodes[inputIndex]; + if (input.mOutputPort == aOutput) { + wasConnected |= DisconnectFromOutputIfConnected(aDestination, outputIndex, inputIndex); + } + } + } + + if (!wasConnected) { + aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); + return; + } + + // This disconnection may have disconnected a panner and a source. + Context()->UpdatePannerSource(); +} + +void +AudioNode::Disconnect(AudioNode& aDestination, uint32_t aOutput, uint32_t aInput, ErrorResult& aRv) +{ + if (aOutput >= NumberOfOutputs()) { + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return; + } + + if (aInput >= aDestination.NumberOfInputs()) { + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return; + } + + bool wasConnected = false; + + for (int32_t outputIndex = mOutputNodes.Length() - 1; outputIndex >= 0; --outputIndex) { + for (int32_t inputIndex = aDestination.mInputNodes.Length() - 1; inputIndex >= 0; --inputIndex) { + InputNode& input = aDestination.mInputNodes[inputIndex]; + if (input.mOutputPort == aOutput && input.mInputPort == aInput) { + wasConnected |= DisconnectFromOutputIfConnected(aDestination, outputIndex, inputIndex); + break; + } + } + } + + if (!wasConnected) { + aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); + return; + } + + // This disconnection may have disconnected a panner and a source. + Context()->UpdatePannerSource(); +} + +void +AudioNode::Disconnect(AudioParam& aDestination, ErrorResult& aRv) +{ + bool wasConnected = false; + + for (int32_t outputIndex = mOutputParams.Length() - 1; outputIndex >= 0; --outputIndex) { + for (int32_t inputIndex = aDestination.InputNodes().Length() - 1; inputIndex >= 0; --inputIndex) { + wasConnected |= DisconnectFromParamIfConnected(aDestination, outputIndex, inputIndex); + } + } + + if (!wasConnected) { + aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); + return; + } +} + +void +AudioNode::Disconnect(AudioParam& aDestination, uint32_t aOutput, ErrorResult& aRv) +{ + if (aOutput >= NumberOfOutputs()) { + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return; + } + + bool wasConnected = false; + + for (int32_t outputIndex = mOutputParams.Length() - 1; outputIndex >= 0; --outputIndex) { + for (int32_t inputIndex = aDestination.InputNodes().Length() - 1; inputIndex >= 0; --inputIndex) { + const InputNode& input = aDestination.InputNodes()[inputIndex]; + if (input.mOutputPort == aOutput) { + wasConnected |= DisconnectFromParamIfConnected(aDestination, outputIndex, inputIndex); + } + } + } + + if (!wasConnected) { + aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); + return; + } +} + +void AudioNode::DestroyMediaStream() { if (mStream) { // Remove the node pointer on the engine. AudioNodeStream* ns = mStream; MOZ_ASSERT(ns, "How come we don't have a stream here?"); MOZ_ASSERT(ns->Engine()->NodeMainThread() == this, "Invalid node reference");
--- a/dom/media/webaudio/AudioNode.h +++ b/dom/media/webaudio/AudioNode.h @@ -89,17 +89,27 @@ public: } virtual AudioNode* Connect(AudioNode& aDestination, uint32_t aOutput, uint32_t aInput, ErrorResult& aRv); virtual void Connect(AudioParam& aDestination, uint32_t aOutput, ErrorResult& aRv); + virtual void Disconnect(ErrorResult& aRv); virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv); + virtual void Disconnect(AudioNode& aDestination, ErrorResult& aRv); + virtual void Disconnect(AudioNode& aDestination, uint32_t aOutput, + ErrorResult& aRv); + virtual void Disconnect(AudioNode& aDestination, + uint32_t aOutput, uint32_t aInput, + ErrorResult& aRv); + virtual void Disconnect(AudioParam& aDestination, ErrorResult& aRv); + virtual void Disconnect(AudioParam& aDestination, uint32_t aOutput, + ErrorResult& aRv); // Called after input nodes have been explicitly added or removed through // the Connect() or Disconnect() methods. virtual void NotifyInputsChanged() {} // Indicate that the node should continue indefinitely to behave as if an // input is connected, even though there is no longer a corresponding entry // in mInputNodes. Called after an input node has been removed because it // is being garbage collected. @@ -215,16 +225,18 @@ private: virtual void LastRelease() override { // We are about to be deleted, disconnect the object from the graph before // the derived type is destroyed. DisconnectFromGraph(); } // Callers must hold a reference to 'this'. void DisconnectFromGraph(); + bool DisconnectFromOutputIfConnected(AudioNode& aDestination, uint32_t aOutputIndex, uint32_t aInputIndex); + bool DisconnectFromParamIfConnected(AudioParam& aDestination, uint32_t aOutputIndex, uint32_t aInputIndex); protected: // Helpers for sending different value types to streams void SendDoubleParameterToStream(uint32_t aIndex, double aValue); void SendInt32ParameterToStream(uint32_t aIndex, int32_t aValue); void SendThreeDPointParameterToStream(uint32_t aIndex, const ThreeDPoint& aValue); void SendChannelMixingParametersToStream();
--- a/dom/media/webaudio/ScriptProcessorNode.h +++ b/dom/media/webaudio/ScriptProcessorNode.h @@ -45,35 +45,61 @@ public: void Connect(AudioParam& aDestination, uint32_t aOutput, ErrorResult& aRv) override { AudioNode::Connect(aDestination, aOutput, aRv); if (!aRv.Failed()) { UpdateConnectedStatus(); } } - + void Disconnect(ErrorResult& aRv) override + { + AudioNode::Disconnect(aRv); + UpdateConnectedStatus(); + } void Disconnect(uint32_t aOutput, ErrorResult& aRv) override { AudioNode::Disconnect(aOutput, aRv); - if (!aRv.Failed()) { - UpdateConnectedStatus(); - } + UpdateConnectedStatus(); } void NotifyInputsChanged() override { UpdateConnectedStatus(); } void NotifyHasPhantomInput() override { mHasPhantomInput = true; // No need to UpdateConnectedStatus() because there was previously an // input in InputNodes(). } - + void Disconnect(AudioNode& aDestination, ErrorResult& aRv) override + { + AudioNode::Disconnect(aDestination, aRv); + UpdateConnectedStatus(); + } + void Disconnect(AudioNode& aDestination, uint32_t aOutput, ErrorResult& aRv) override + { + AudioNode::Disconnect(aDestination, aOutput, aRv); + UpdateConnectedStatus(); + } + void Disconnect(AudioNode& aDestination, uint32_t aOutput, uint32_t aInput, ErrorResult& aRv) override + { + AudioNode::Disconnect(aDestination, aOutput, aInput, aRv); + UpdateConnectedStatus(); + } + void Disconnect(AudioParam& aDestination, ErrorResult& aRv) override + { + AudioNode::Disconnect(aDestination, aRv); + UpdateConnectedStatus(); + } + void Disconnect(AudioParam& aDestination, uint32_t aOutput, ErrorResult& aRv) override + { + AudioNode::Disconnect(aDestination, aOutput, aRv); + UpdateConnectedStatus(); + } void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv) override { if (aChannelCount != ChannelCount()) { aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); } return; } void SetChannelCountModeValue(ChannelCountMode aMode, ErrorResult& aRv) override
--- a/dom/webidl/AudioNode.webidl +++ b/dom/webidl/AudioNode.webidl @@ -24,17 +24,29 @@ enum ChannelInterpretation { [Pref="dom.webaudio.enabled"] interface AudioNode : EventTarget { [Throws] AudioNode 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 disconnect(optional unsigned long output = 0); + void disconnect(); + [Throws] + void disconnect(unsigned long output); + [Throws] + void disconnect(AudioNode destination); + [Throws] + void disconnect(AudioNode destination, unsigned long output); + [Throws] + void disconnect(AudioNode destination, unsigned long output, unsigned long input); + [Throws] + void disconnect(AudioParam destination); + [Throws] + void disconnect(AudioParam destination, unsigned long output); readonly attribute AudioContext context; readonly attribute unsigned long numberOfInputs; readonly attribute unsigned long numberOfOutputs; // Channel up-mixing and down-mixing rules for all inputs. [SetterThrows] attribute unsigned long channelCount;