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(uint32_t aOutput, ErrorResult& aRv) { if (aOutput >= NumberOfOutputs()) { aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return; } // 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. class RunnableRelease final : public nsRunnable { public: explicit RunnableRelease(already_AddRefed<AudioNode> aNode) : mNode(aNode) {} NS_IMETHODIMP Run() override { mNode = nullptr; return NS_OK; } private: nsRefPtr<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. nsRefPtr<AudioNode> output = mOutputNodes[i].forget(); mOutputNodes.RemoveElementAt(i); output->NotifyInputsChanged(); if (mStream) { nsRefPtr<nsIRunnable> runnable = new RunnableRelease(output.forget()); mStream->RunAfterPendingUpdates(runnable.forget()); } break; } } } 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(); }