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_INVALID_ACCESS_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; MediaStream* stream = aDestination.Stream(); MOZ_ASSERT(stream->AsProcessedStream()); ProcessedMediaStream* ps = static_cast<ProcessedMediaStream*>(stream); if (mStream) { // Setup our stream as an input to the AudioParam's stream MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number"); input->mStreamPort = ps->AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK, TRACK_ANY, 0, static_cast<uint16_t>(aOutput)); } }
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; } }
bool AudioNode::PassThrough() const { MOZ_ASSERT(NumberOfInputs() <= 1 && NumberOfOutputs() == 1); return mPassThrough; }
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(); }