/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
AudioNode::~AudioNode() {
MOZ_ASSERT(mInputNodes.IsEmpty());
MOZ_ASSERT(mOutputNodes.IsEmpty());
MOZ_ASSERT(mOutputParams.IsEmpty());
MOZ_ASSERT(!mTrack, "The webaudio-node-demise notification must have been sent"); if (mContext) {
mContext->UnregisterNode(this);
}
}
void AudioNode::Initialize(const AudioNodeOptions& aOptions, ErrorResult& aRv) { if (aOptions.mChannelCount.WasPassed()) {
SetChannelCount(aOptions.mChannelCount.Value(), aRv); if (NS_WARN_IF(aRv.Failed())) { return;
}
}
if (aOptions.mChannelCountMode.WasPassed()) {
SetChannelCountModeValue(aOptions.mChannelCountMode.Value(), aRv); if (NS_WARN_IF(aRv.Failed())) { return;
}
}
if (aOptions.mChannelInterpretation.WasPassed()) {
SetChannelInterpretationValue(aOptions.mChannelInterpretation.Value(), aRv); if (NS_WARN_IF(aRv.Failed())) { return;
}
}
}
amount += mInputNodes.ShallowSizeOfExcludingThis(aMallocSizeOf); for (size_t i = 0; i < mInputNodes.Length(); i++) {
amount += mInputNodes[i].SizeOfExcludingThis(aMallocSizeOf);
}
// Just measure the array. The entire audio node graph is measured via the // MediaTrackGraph's tracks, so we don't want to double-count the elements.
amount += mOutputNodes.ShallowSizeOfExcludingThis(aMallocSizeOf);
amount += mOutputParams.ShallowSizeOfExcludingThis(aMallocSizeOf); for (size_t i = 0; i < mOutputParams.Length(); i++) {
amount += mOutputParams[i]->SizeOfIncludingThis(aMallocSizeOf);
}
void AudioNode::DisconnectFromGraph() {
MOZ_ASSERT(mRefCnt.get() > mInputNodes.Length(), "Caller should be holding a reference");
// The idea here is that we remove connections one by one, and at each step // the graph is in a valid state.
// Disconnect inputs. We don't need them anymore. while (!mInputNodes.IsEmpty()) {
InputNode inputNode = mInputNodes.PopLastElement();
inputNode.mInputNode->mOutputNodes.RemoveElement(this);
}
while (!mOutputNodes.IsEmpty()) {
RefPtr<AudioNode> output = mOutputNodes.PopLastElement();
size_t inputIndex = FindIndexOfNode(output->mInputNodes, this); // It doesn't matter which one we remove, since we're going to remove all // entries for this node anyway.
output->mInputNodes.RemoveElementAt(inputIndex); // This effects of this connection will remain.
output->NotifyHasPhantomInput();
}
while (!mOutputParams.IsEmpty()) {
RefPtr<AudioParam> output = mOutputParams.PopLastElement();
size_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);
}
DestroyMediaTrack();
}
AudioNode* AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
uint32_t aInput, ErrorResult& aRv) { if (aOutput >= NumberOfOutputs()) {
aRv.ThrowIndexSizeError(
nsPrintfCString("Output index %u is out of bounds", aOutput)); return nullptr;
}
if (aInput >= aDestination.NumberOfInputs()) {
aRv.ThrowIndexSizeError(
nsPrintfCString("Input index %u is out of bounds", aInput)); return nullptr;
}
if (Context() != aDestination.Context()) {
aRv.ThrowInvalidAccessError( "Can't connect nodes from different AudioContexts"); return nullptr;
}
// The MediaTrackGraph will handle cycle detection. We don't need to do it // here.
mOutputNodes.AppendElement(&aDestination);
InputNode* input = aDestination.mInputNodes.AppendElement();
input->mInputNode = this;
input->mInputPort = aInput;
input->mOutputPort = aOutput;
AudioNodeTrack* destinationTrack = aDestination.mTrack; if (mTrack && destinationTrack) { // Connect tracks in the MediaTrackGraph
MOZ_ASSERT(aInput <= UINT16_MAX, "Unexpected large input port number");
MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number");
input->mTrackPort = destinationTrack->AllocateInputPort(
mTrack, static_cast<uint16_t>(aInput), static_cast<uint16_t>(aOutput));
}
aDestination.NotifyInputsChanged();
return &aDestination;
}
void AudioNode::Connect(AudioParam& aDestination, uint32_t aOutput,
ErrorResult& aRv) { if (aOutput >= NumberOfOutputs()) {
aRv.ThrowIndexSizeError(
nsPrintfCString("Output index %u is out of bounds", aOutput)); return;
}
if (Context() != aDestination.GetParentObject()) {
aRv.ThrowInvalidAccessError( "Can't connect a node to an AudioParam from a different AudioContext"); return;
}
mozilla::MediaTrack* track = aDestination.Track();
MOZ_ASSERT(track->AsProcessedTrack());
ProcessedMediaTrack* ps = static_cast<ProcessedMediaTrack*>(track); if (mTrack) { // Setup our track as an input to the AudioParam's track
MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number");
input->mTrackPort =
ps->AllocateInputPort(mTrack, 0, static_cast<uint16_t>(aOutput));
}
}
void AudioNode::SendDoubleParameterToTrack(uint32_t aIndex, double aValue) {
MOZ_ASSERT(mTrack, "How come we don't have a track here?");
mTrack->SetDoubleParameter(aIndex, aValue);
}
void AudioNode::SendInt32ParameterToTrack(uint32_t aIndex, int32_t aValue) {
MOZ_ASSERT(mTrack, "How come we don't have a track here?");
mTrack->SetInt32Parameter(aIndex, aValue);
}
// 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 Runnable { public: explicit RunnableRelease(already_AddRefed<AudioNode> aNode)
: mozilla::Runnable("RunnableRelease"), mNode(aNode) {}
// 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 = std::move(mOutputNodes[aOutputNodeIndex]);
mOutputNodes.RemoveElementAt(aOutputNodeIndex); // Destroying the InputNode here sends a message to the graph thread // to disconnect the tracks, which should be sent before the // RunAfterPendingUpdates() call below.
destination->mInputNodes.RemoveElementAt(aInputIndex);
output->NotifyInputsChanged(); if (mTrack) {
nsCOMPtr<nsIRunnable> runnable = new RunnableRelease(output.forget());
mTrack->RunAfterPendingUpdates(runnable.forget());
} returntrue;
}
const InputNode& input = destination->InputNodes()[aInputIndex]; if (input.mInputNode != this) { returnfalse;
}
destination->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(aOutputParamIndex); returntrue;
}
void AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv) { if (aOutput >= NumberOfOutputs()) {
aRv.ThrowIndexSizeError(
nsPrintfCString("Output index %u is out of bounds", aOutput)); return;
}
if (!wasConnected) {
aRv.ThrowInvalidAccessError( "Trying to disconnect from a node we're not connected to"); return;
}
}
void AudioNode::Disconnect(AudioNode& aDestination, uint32_t aOutput,
ErrorResult& aRv) { if (aOutput >= NumberOfOutputs()) {
aRv.ThrowIndexSizeError(
nsPrintfCString("Output index %u is out of bounds", aOutput)); return;
}
if (!wasConnected) {
aRv.ThrowInvalidAccessError( "Trying to disconnect from an AudioParam we're not connected to"); return;
}
}
void AudioNode::Disconnect(AudioParam& aDestination, uint32_t aOutput,
ErrorResult& aRv) { if (aOutput >= NumberOfOutputs()) {
aRv.ThrowIndexSizeError(
nsPrintfCString("Output index %u is out of bounds", aOutput)); return;
}
if (!wasConnected) {
aRv.ThrowInvalidAccessError( "Trying to disconnect from an AudioParam we're not connected to"); return;
}
}
void AudioNode::DestroyMediaTrack() { if (mTrack) { // Remove the node pointer on the engine.
AudioNodeTrack* ns = mTrack;
MOZ_ASSERT(ns, "How come we don't have a track here?");
MOZ_ASSERT(ns->Engine()->NodeMainThread() == this, "Invalid node reference");
ns->Engine()->ClearNode();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.